From 3568fb87478ac89f12964bc79b0a6179b28b2529 Mon Sep 17 00:00:00 2001 From: Vincent Herbet Date: Sat, 25 Feb 2017 11:50:52 +0100 Subject: [PATCH] Add client_remove() forward and fix a bug with client not internally disconnected (#414) * Rename client_disconnected to client_disconnecting * Add client_disconnected as post forward * Fix client not properly disconnected internally Introduced in #264. Edict is reset once SV_DropClient is called, so that second check would be always false. * Reflect changes on the concerned plugins * Revert renaming, let's add only client_remove as post forward --- amxmodx/meta_api.cpp | 27 +++++++++++++++++++++------ plugins/adminslots.sma | 4 ++-- plugins/include/amxmodx.inc | 25 ++++++++++++++++++++----- 3 files changed, 43 insertions(+), 13 deletions(-) diff --git a/amxmodx/meta_api.cpp b/amxmodx/meta_api.cpp index 8d60979e..521a4e2e 100755 --- a/amxmodx/meta_api.cpp +++ b/amxmodx/meta_api.cpp @@ -136,6 +136,7 @@ int FF_ClientCommand = -1; int FF_ClientConnect = -1; int FF_ClientDisconnect = -1; int FF_ClientDisconnected = -1; +int FF_ClientRemove = -1; int FF_ClientInfoChanged = -1; int FF_ClientPutInServer = -1; int FF_PluginInit = -1; @@ -498,6 +499,7 @@ int C_Spawn(edict_t *pent) FF_ClientConnect = registerForward("client_connect", ET_IGNORE, FP_CELL, FP_DONE); FF_ClientDisconnect = registerForward("client_disconnect", ET_IGNORE, FP_CELL, FP_DONE); FF_ClientDisconnected = registerForward("client_disconnected", ET_IGNORE, FP_CELL, FP_CELL, FP_ARRAY, FP_CELL, FP_DONE); + FF_ClientRemove = registerForward("client_remove", ET_IGNORE, FP_CELL, FP_CELL, FP_STRING, FP_DONE); FF_ClientInfoChanged = registerForward("client_infochanged", ET_IGNORE, FP_CELL, FP_DONE); FF_ClientPutInServer = registerForward("client_putinserver", ET_IGNORE, FP_CELL, FP_DONE); FF_PluginCfg = registerForward("plugin_cfg", ET_IGNORE, FP_DONE); @@ -688,8 +690,15 @@ void C_ServerDeactivate() if (pPlayer->ingame) { + auto wasDisconnecting = pPlayer->disconnecting; + pPlayer->Disconnect(); --g_players_num; + + if (!wasDisconnecting && DropClientDetour) + { + executeForwards(FF_ClientRemove, static_cast(pPlayer->index), FALSE, const_cast("")); + } } } @@ -881,8 +890,15 @@ void C_ClientDisconnect(edict_t *pEntity) --g_players_num; } + auto wasDisconnecting = pPlayer->disconnecting; + pPlayer->Disconnect(); + if (!wasDisconnecting && DropClientDetour) + { + executeForwards(FF_ClientRemove, static_cast(pPlayer->index), FALSE, const_cast("")); + } + RETURN_META(MRES_IGNORED); } @@ -896,12 +912,10 @@ DETOUR_DECL_STATIC3_VAR(SV_DropClient, void, client_t*, cl, qboolean, crash, con ke::SafeVsprintf(buffer, sizeof(buffer) - 1, format, ap); va_end(ap); - CPlayer *pPlayer; + auto pPlayer = cl->edict ? GET_PLAYER_POINTER(cl->edict) : nullptr; - if (cl->edict) + if (pPlayer) { - pPlayer = GET_PLAYER_POINTER(cl->edict); - if (pPlayer->initialized) { pPlayer->disconnecting = true; @@ -911,9 +925,10 @@ DETOUR_DECL_STATIC3_VAR(SV_DropClient, void, client_t*, cl, qboolean, crash, con DETOUR_STATIC_CALL(SV_DropClient)(cl, crash, "%s", buffer); - if (cl->edict) + if (pPlayer) { pPlayer->Disconnect(); + executeForwards(FF_ClientRemove, pPlayer->index, TRUE, buffer); } } @@ -1597,7 +1612,7 @@ C_DLLEXPORT int Meta_Attach(PLUG_LOADTIME now, META_FUNCTIONS *pFunctionTable, m } else { - AMXXLOG_Log("client_disconnected forward has been disabled - check your gamedata files."); + AMXXLOG_Log("client_disconnected and client_remove forwards have been disabled - check your gamedata files."); } GET_IFACE("filesystem_stdio", g_FileSystem, FILESYSTEM_INTERFACE_VERSION); diff --git a/plugins/adminslots.sma b/plugins/adminslots.sma index 2f5c9c0e..53f5d24d 100755 --- a/plugins/adminslots.sma +++ b/plugins/adminslots.sma @@ -56,11 +56,11 @@ public client_authorized(id) server_cmd("kick #%d ^"%L^"", get_user_userid(id), id, "DROPPED_RES") } -public client_disconnected(id) +public client_remove(id) { if (get_pcvar_num(g_HidePtr)) { - setVisibleSlots(get_playersnum(1) - 1, MaxClients - get_pcvar_num(g_ResPtr)) + setVisibleSlots(get_playersnum(1), MaxClients - get_pcvar_num(g_ResPtr)) } } diff --git a/plugins/include/amxmodx.inc b/plugins/include/amxmodx.inc index ebdc1bd2..6b98de84 100755 --- a/plugins/include/amxmodx.inc +++ b/plugins/include/amxmodx.inc @@ -178,24 +178,39 @@ forward client_authorized(id, const authid[]); #pragma deprecated Use client_disconnected() instead. forward client_disconnect(id); -/** + /** * Called when a client is disconnected from the server. * * @note This will be called in some additional cases that client_disconnect doesn't cover, * most notably when a client aborts the connection process. It is guaranteed to pair * with the client_connect() forward. - * @note By this point it is already too late to do anything that directly - * affects the client. + * @note When this fires the player entity is still valid (e.g. is_user_connected(id) will + * return true), but no networked commands will reach the client. * * @param id Client index - * @param drop If true, client has been explicitly dropped by game - * @param message If drop is true, a disconnected message or buffer to copy a new message to + * @param drop If true, the game has explicitly dropped the client + * @param message If drop is true, a writable buffer containing the disconnect info message * @param maxlen Maximum size of buffer * * @noreturn */ forward client_disconnected(id, bool:drop, message[], maxlen); +/** + * Called when a client entity has been removed from the server. + * + * @note This fires after the client_disconnected() forward, when the player entity has been + * removed (e.g. is_user_connected(id) will return false). + * + * @param id Client index + * @param drop If true, the game has explicitly dropped the client + * @param message If drop is true, contains the disconnect info message + * + * @noreturn + */ +forward client_remove(id, bool:drop, const message[]); + + /** * Called when a client attempts to execute a command. *