fixed amb1808 - KickClient() is delayed and does not crash -- KickClientEx() is the old functionality
fixed
amb1808 - KickClient() is delayed and does not crash -- KickClientEx() is the old functionality
1.1 --- a/core/HalfLife2.cpp Sun Jul 06 00:02:11 2008 +0000
1.2 +++ b/core/HalfLife2.cpp Sun Jul 06 00:45:26 2008 +0000
1.3 @@ -511,3 +511,31 @@
1.4 return m_CommandStack.front().cmd;
1.5 #endif
1.6 }
1.7 +
1.8 +void CHalfLife2::AddDelayedKick(int client, int userid, const char *msg)
1.9 +{
1.10 + DelayedKickInfo kick;
1.11 +
1.12 + kick.client = client;
1.13 + kick.userid = userid;
1.14 + UTIL_Format(kick.buffer, sizeof(kick.buffer), "%s", msg);
1.15 +
1.16 + m_DelayedKicks.push(kick);
1.17 +}
1.18 +
1.19 +void CHalfLife2::ProcessDelayedKicks()
1.20 +{
1.21 + while (!m_DelayedKicks.empty())
1.22 + {
1.23 + DelayedKickInfo info = m_DelayedKicks.first();
1.24 + m_DelayedKicks.pop();
1.25 +
1.26 + CPlayer *player = g_Players.GetPlayerByIndex(info.client);
1.27 + if (player == NULL || player->GetUserId() != info.userid)
1.28 + {
1.29 + continue;
1.30 + }
1.31 +
1.32 + player->Kick(info.buffer);
1.33 + }
1.34 +}
2.1 --- a/core/HalfLife2.h Sun Jul 06 00:02:11 2008 +0000
2.2 +++ b/core/HalfLife2.h Sun Jul 06 00:45:26 2008 +0000
2.3 @@ -79,6 +79,13 @@
2.4 #endif
2.5 };
2.6
2.7 +struct DelayedKickInfo
2.8 +{
2.9 + int userid;
2.10 + int client;
2.11 + char buffer[384];
2.12 +};
2.13 +
2.14 class CHalfLife2 :
2.15 public SMGlobalClass,
2.16 public IGameHelpers
2.17 @@ -110,6 +117,8 @@
2.18 void PopCommandStack();
2.19 const CCommand *PeekCommandStack();
2.20 const char *CurrentCommandName();
2.21 + void AddDelayedKick(int client, int userid, const char *msg);
2.22 + void ProcessDelayedKicks();
2.23 #if !defined METAMOD_PLAPI_VERSION
2.24 bool IsOriginalEngine();
2.25 #endif
2.26 @@ -125,6 +134,7 @@
2.27 Queue<DelayedFakeCliCmd *> m_CmdQueue;
2.28 CStack<DelayedFakeCliCmd *> m_FreeCmds;
2.29 CStack<CachedCommandInfo> m_CommandStack;
2.30 + Queue<DelayedKickInfo> m_DelayedKicks;
2.31 };
2.32
2.33 extern CHalfLife2 g_HL2;
3.1 --- a/core/frame_hooks.cpp Sun Jul 06 00:02:11 2008 +0000
3.2 +++ b/core/frame_hooks.cpp Sun Jul 06 00:45:26 2008 +0000
3.3 @@ -44,6 +44,7 @@
3.4 /* Frame based hooks */
3.5 g_DBMan.RunFrame();
3.6 g_HL2.ProcessFakeCliCmdQueue();
3.7 + g_HL2.ProcessDelayedKicks();
3.8 g_SourceMod.ProcessGameFrameHooks(simulating);
3.9
3.10 float curtime = *g_pUniversalTime;
4.1 --- a/core/smn_player.cpp Sun Jul 06 00:02:11 2008 +0000
4.2 +++ b/core/smn_player.cpp Sun Jul 06 00:45:26 2008 +0000
4.3 @@ -1258,10 +1258,64 @@
4.4 if (!pPlayer)
4.5 {
4.6 return pContext->ThrowNativeError("Client index %d is invalid", client);
4.7 - } else if (!pPlayer->IsConnected()) {
4.8 + }
4.9 + else if (!pPlayer->IsConnected())
4.10 + {
4.11 return pContext->ThrowNativeError("Client %d is not connected", client);
4.12 }
4.13
4.14 + /* Ignore duplicate kicks */
4.15 + if (pPlayer->IsInKickQueue())
4.16 + {
4.17 + return 1;
4.18 + }
4.19 +
4.20 + pPlayer->MarkAsBeingKicked();
4.21 +
4.22 + if (pPlayer->IsFakeClient())
4.23 + {
4.24 + char kickcmd[40];
4.25 + UTIL_Format(kickcmd, sizeof(kickcmd), "kick %s\n", pPlayer->GetName());
4.26 +
4.27 + engine->ServerCommand(kickcmd);
4.28 + return 1;
4.29 + }
4.30 +
4.31 + g_SourceMod.SetGlobalTarget(client);
4.32 +
4.33 + char buffer[256];
4.34 + g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
4.35 +
4.36 + if (pContext->GetContext()->n_err != SP_ERROR_NONE)
4.37 + {
4.38 + return 0;
4.39 + }
4.40 +
4.41 + g_HL2.AddDelayedKick(client, pPlayer->GetUserId(), buffer);
4.42 +
4.43 + return 1;
4.44 +}
4.45 +
4.46 +static cell_t KickClientEx(IPluginContext *pContext, const cell_t *params)
4.47 +{
4.48 + int client = params[1];
4.49 +
4.50 + CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
4.51 + if (!pPlayer)
4.52 + {
4.53 + return pContext->ThrowNativeError("Client index %d is invalid", client);
4.54 + }
4.55 + else if (!pPlayer->IsConnected())
4.56 + {
4.57 + return pContext->ThrowNativeError("Client %d is not connected", client);
4.58 + }
4.59 +
4.60 + /* Ignore duplicate kicks */
4.61 + if (pPlayer->IsInKickQueue())
4.62 + {
4.63 + return 1;
4.64 + }
4.65 +
4.66 pPlayer->MarkAsBeingKicked();
4.67
4.68 if (pPlayer->IsFakeClient())
4.69 @@ -1460,6 +1514,7 @@
4.70 {"ShowActivityEx", ShowActivityEx},
4.71 {"ShowActivity2", ShowActivity2},
4.72 {"KickClient", KickClient},
4.73 + {"KickClientEx", KickClientEx},
4.74 {"RunAdminCacheChecks", RunAdminCacheChecks},
4.75 {"NotifyPostAdminCheck", NotifyPostAdminCheck},
4.76 {"IsClientInKickQueue", IsClientInKickQueue},
5.1 --- a/plugins/include/clients.inc Sun Jul 06 00:02:11 2008 +0000
5.2 +++ b/plugins/include/clients.inc Sun Jul 06 00:45:26 2008 +0000
5.3 @@ -634,7 +634,28 @@
5.4 native GetClientOfUserId(userid);
5.5
5.6 /**
5.7 - * Disconnects a client from the server.
5.8 + * Disconnects a client from the server as soon as the next frame starts.
5.9 + *
5.10 + * Note: Originally, KickClient() was immediate. The delay was introduced
5.11 + * because despite warnings, plugins were using it in ways that would crash.
5.12 + * The new safe version can break cases that rely on immediate disconnects,
5.13 + * but ensures that plugins do not accidentally cause crashes.
5.14 + *
5.15 + * If you need immediate disconnects, use KickClientEx().
5.16 + *
5.17 + * Note: IsClientInKickQueue() will return true before the kick occurs.
5.18 + *
5.19 + * @param client Client index.
5.20 + * @param format Optional formatting rules for disconnect reason.
5.21 + * Note that a period is automatically appended to the string by the engine.
5.22 + * @param ... Variable number of format parameters.
5.23 + * @noreturn
5.24 + * @error Invalid client index, or client not connected.
5.25 + */
5.26 +native KickClient(client, const String:format[]="", any:...);
5.27 +
5.28 +/**
5.29 + * Immediately disconnects a client from the server.
5.30 *
5.31 * Kicking clients from certain events or callbacks may cause crashes. If in
5.32 * doubt, create a short (0.1 second) timer to kick the client in the next
5.33 @@ -647,7 +668,7 @@
5.34 * @noreturn
5.35 * @error Invalid client index, or client not connected.
5.36 */
5.37 -native KickClient(client, const String:format[]="", any:...);
5.38 +native KickClientEx(client, const String:format[]="", any:...);
5.39
5.40 /**
5.41 * Changes a client's team through the mod's generic team changing function.