From ed4faf7c114495db7426023c2b47914523fcdfd1 Mon Sep 17 00:00:00 2001 From: Arkshine Date: Fri, 17 Jul 2015 00:26:30 +0200 Subject: [PATCH] Fix player not being internally disconnected in some situation + add client_disconnected forward --- amxmodx/CGameConfigs.cpp | 12 ++++ amxmodx/CGameConfigs.h | 2 + amxmodx/CMisc.cpp | 2 + amxmodx/CMisc.h | 1 + amxmodx/meta_api.cpp | 76 ++++++++++++++++++++++ gamedata/common.games/functions.engine.txt | 27 ++++++++ gamedata/common.games/master.games.txt | 7 ++ plugins/admincmd.sma | 2 +- plugins/adminhelp.sma | 2 +- plugins/adminslots.sma | 2 +- plugins/cstrike/miscstats.sma | 2 +- plugins/cstrike/stats_logging.sma | 2 +- plugins/dod/stats.sma | 2 +- plugins/dod/stats_logging.sma | 2 +- plugins/include/amxmodx.inc | 18 ++++- plugins/multilingual.sma | 2 +- plugins/ns/nscommands.sma | 2 +- plugins/tfc/stats_logging.sma | 2 +- plugins/ts/stats_logging.sma | 2 +- public/memtools/CDetour/detours.h | 4 ++ support/PackageScript | 1 + 21 files changed, 158 insertions(+), 14 deletions(-) create mode 100644 gamedata/common.games/functions.engine.txt diff --git a/amxmodx/CGameConfigs.cpp b/amxmodx/CGameConfigs.cpp index f6e21e9a..0c007b78 100644 --- a/amxmodx/CGameConfigs.cpp +++ b/amxmodx/CGameConfigs.cpp @@ -13,6 +13,7 @@ CGameConfigManager ConfigManager; static CGameMasterReader MasterReader; +IGameConfig *CommonConfig; // // GAME CONFIG @@ -886,6 +887,17 @@ CGameConfigManager::~CGameConfigManager() { } +void CGameConfigManager::OnAmxxStartup() +{ + char error[256] = ""; + + if (!LoadGameConfigFile("common.games", &CommonConfig, error, sizeof(error))) + { + AMXXLOG_Log("Could not read common.games gamedata: %s", error); + return; + } +} + bool CGameConfigManager::LoadGameConfigFile(const char *file, IGameConfig **config, char *error, size_t maxlength) { CGameConfig *configFromCache; diff --git a/amxmodx/CGameConfigs.h b/amxmodx/CGameConfigs.h index e908bdb7..d7bcfc6e 100644 --- a/amxmodx/CGameConfigs.h +++ b/amxmodx/CGameConfigs.h @@ -152,6 +152,7 @@ class CGameConfigManager : public IGameConfigManager public: + void OnAmxxStartup(); void RemoveCachedConfig(CGameConfig *config); private: @@ -164,5 +165,6 @@ class CGameConfigManager : public IGameConfigManager }; extern CGameConfigManager ConfigManager; +extern IGameConfig *CommonConfig; #endif // _INCLUDE_GAMECONFIG_H_ diff --git a/amxmodx/CMisc.cpp b/amxmodx/CMisc.cpp index d2ff30a3..514d5013 100755 --- a/amxmodx/CMisc.cpp +++ b/amxmodx/CMisc.cpp @@ -20,6 +20,7 @@ void CPlayer::Init(edict_t* e, int i) initialized = false; ingame = false; authorized = false; + disconnecting = false; teamIdsInitialized = false; current = 0; @@ -42,6 +43,7 @@ void CPlayer::Disconnect() ingame = false; initialized = false; authorized = false; + disconnecting = false; teamIdsInitialized = false; if (Menu *pMenu = get_menu_by_id(newmenu)) diff --git a/amxmodx/CMisc.h b/amxmodx/CMisc.h index 5b7368cb..b64e0764 100755 --- a/amxmodx/CMisc.h +++ b/amxmodx/CMisc.h @@ -37,6 +37,7 @@ public: bool initialized; bool ingame; bool authorized; + bool disconnecting; bool vgui; bool teamIdsInitialized; diff --git a/amxmodx/meta_api.cpp b/amxmodx/meta_api.cpp index f90fc534..cb3279d8 100755 --- a/amxmodx/meta_api.cpp +++ b/amxmodx/meta_api.cpp @@ -28,6 +28,9 @@ #include "CLibrarySys.h" #include "CFileSystem.h" #include "gameconfigs.h" +#include "CGameConfigs.h" +#include +#include plugin_info_t Plugin_info = { @@ -112,6 +115,8 @@ int mPlayerIndex; int mState; int g_srvindex; +CDetour *DropClientDetour; + cvar_t init_amxmodx_version = {"amxmodx_version", "", FCVAR_SERVER | FCVAR_SPONLY}; cvar_t init_amxmodx_modules = {"amxmodx_modules", "", FCVAR_SPONLY}; cvar_t init_amxmodx_debug = {"amx_debug", "1", FCVAR_SPONLY}; @@ -128,6 +133,7 @@ cvar_t* mp_timelimit = NULL; int FF_ClientCommand = -1; int FF_ClientConnect = -1; int FF_ClientDisconnect = -1; +int FF_ClientDisconnected = -1; int FF_ClientInfoChanged = -1; int FF_ClientPutInServer = -1; int FF_PluginInit = -1; @@ -487,6 +493,7 @@ int C_Spawn(edict_t *pent) FF_ClientCommand = registerForward("client_command", ET_STOP, FP_CELL, FP_DONE); 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_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); @@ -648,9 +655,18 @@ void C_ServerDeactivate() for (int i = 1; i <= gpGlobals->maxClients; ++i) { CPlayer *pPlayer = GET_PLAYER_POINTER_I(i); + if (pPlayer->initialized) + { + // deprecated executeForwards(FF_ClientDisconnect, static_cast(pPlayer->index)); + if (DropClientDetour && !pPlayer->disconnecting) + { + executeForwards(FF_ClientDisconnected, static_cast(pPlayer->index), FALSE, prepareCharArray(const_cast(""), 0), 0); + } + } + if (pPlayer->ingame) { pPlayer->Disconnect(); @@ -811,18 +827,59 @@ BOOL C_ClientConnect_Post(edict_t *pEntity, const char *pszName, const char *psz void C_ClientDisconnect(edict_t *pEntity) { CPlayer *pPlayer = GET_PLAYER_POINTER(pEntity); + if (pPlayer->initialized) + { + // deprecated executeForwards(FF_ClientDisconnect, static_cast(pPlayer->index)); + + if (DropClientDetour && !pPlayer->disconnecting) + { + executeForwards(FF_ClientDisconnected, static_cast(pPlayer->index), FALSE, prepareCharArray(const_cast(""), 0), 0); + } + } if (pPlayer->ingame) { --g_players_num; } + pPlayer->Disconnect(); RETURN_META(MRES_IGNORED); } +// void SV_DropClient(client_t *cl, qboolean crash, const char *fmt, ...); +DETOUR_DECL_STATIC3_VAR(SV_DropClient, void, client_t*, cl, qboolean, crash, const char*, format) +{ + char buffer[1024]; + + va_list ap; + va_start(ap, format); + ke::SafeVsnprintf(buffer, sizeof(buffer) - 1, format, ap); + va_end(ap); + + CPlayer *pPlayer; + + if (cl->edict) + { + pPlayer = GET_PLAYER_POINTER(cl->edict); + + if (pPlayer->initialized) + { + pPlayer->disconnecting = true; + executeForwards(FF_ClientDisconnected, pPlayer->index, TRUE, prepareCharArray(buffer, sizeof(buffer), true), sizeof(buffer) - 1); + } + } + + DETOUR_STATIC_CALL(SV_DropClient)(cl, crash, "%s", buffer); + + if (cl->edict) + { + pPlayer->Disconnect(); + } +} + void C_ClientPutInServer_Post(edict_t *pEntity) { CPlayer *pPlayer = GET_PLAYER_POINTER(pEntity); @@ -1489,6 +1546,20 @@ C_DLLEXPORT int Meta_Attach(PLUG_LOADTIME now, META_FUNCTIONS *pFunctionTable, m g_CvarManager.CreateCvarHook(); + ConfigManager.OnAmxxStartup(); + + void *address = nullptr; + + if (CommonConfig && CommonConfig->GetMemSig("SV_DropClient", &address)) + { + DropClientDetour = DETOUR_CREATE_STATIC_FIXED(SV_DropClient, address); + DropClientDetour->EnableDetour(); + } + else + { + AMXXLOG_Log("client_disconnected forward has been disabled - check your gamedata files."); + } + GET_IFACE("filesystem_stdio", g_FileSystem, FILESYSTEM_INTERFACE_VERSION); return (TRUE); @@ -1534,6 +1605,11 @@ C_DLLEXPORT int Meta_Detach(PLUG_LOADTIME now, PL_UNLOAD_REASON reason) ClearLibraries(LibSource_Plugin); ClearLibraries(LibSource_Module); + if (DropClientDetour) + { + DropClientDetour->Destroy(); + } + return (TRUE); } diff --git a/gamedata/common.games/functions.engine.txt b/gamedata/common.games/functions.engine.txt new file mode 100644 index 00000000..f219d70e --- /dev/null +++ b/gamedata/common.games/functions.engine.txt @@ -0,0 +1,27 @@ +/** + * Do not edit this file. Any changes will be overwritten by the gamedata + * updater or by upgrading your AMX Mod X install. + * + * To override data in this file, create a subdirectory named "custom" and + * place your own gamedata file(s) inside of it. Such files will be parsed + * after AMXX's own. + * + * For more information, see http://wiki.alliedmods.net/Gamedata_Updating_(AMX_Mod_X) + */ + +"Games" +{ + "#default" + { + "Signatures" + { + "SV_DropClient" // void SV_DropClient(client_t *cl, qboolean crash, const char *fmt, ...); + { + "library" "engine" + "windows" "\x55\x8B\x2A\x81\x2A\x2A\x2A\x2A\x2A\x8B\x2A\x2A\x53\x56\x8D" + "linux" "@SV_DropClient" + "mac" "@SV_DropClient" + } + } + } +} diff --git a/gamedata/common.games/master.games.txt b/gamedata/common.games/master.games.txt index 2da3a5aa..47e1476e 100644 --- a/gamedata/common.games/master.games.txt +++ b/gamedata/common.games/master.games.txt @@ -21,6 +21,13 @@ "engine" "engine_ls" } + "functions.engine.txt" + { + "engine" "engine_ds" + "engine" "engine_ls" + } + + // // Counter-Strike diff --git a/plugins/admincmd.sma b/plugins/admincmd.sma index 4c70038f..68f29fe0 100755 --- a/plugins/admincmd.sma +++ b/plugins/admincmd.sma @@ -125,7 +125,7 @@ stock GetInfo(i, name[], namesize, auth[], authsize, ip[], ipsize, &access) access = g_Access[target]; } -public client_disconnect(id) +public client_disconnected(id) { if (!is_user_bot(id)) { diff --git a/plugins/adminhelp.sma b/plugins/adminhelp.sma index 6d1caf91..56b835c1 100755 --- a/plugins/adminhelp.sma +++ b/plugins/adminhelp.sma @@ -34,7 +34,7 @@ public client_putinserver(id) } } -public client_disconnect(id) +public client_disconnected(id) { remove_task(id) } diff --git a/plugins/adminslots.sma b/plugins/adminslots.sma index 90eef653..2f5c9c0e 100755 --- a/plugins/adminslots.sma +++ b/plugins/adminslots.sma @@ -56,7 +56,7 @@ public client_authorized(id) server_cmd("kick #%d ^"%L^"", get_user_userid(id), id, "DROPPED_RES") } -public client_disconnect(id) +public client_disconnected(id) { if (get_pcvar_num(g_HidePtr)) { diff --git a/plugins/cstrike/miscstats.sma b/plugins/cstrike/miscstats.sma index 3b6de0d2..89ecb000 100755 --- a/plugins/cstrike/miscstats.sma +++ b/plugins/cstrike/miscstats.sma @@ -472,7 +472,7 @@ public client_putinserver(id) g_connected[id] = true } -public client_disconnect(id) +public client_disconnected(id) { g_connected[id] = false } diff --git a/plugins/cstrike/stats_logging.sma b/plugins/cstrike/stats_logging.sma index de4f7047..02c5bbeb 100755 --- a/plugins/cstrike/stats_logging.sma +++ b/plugins/cstrike/stats_logging.sma @@ -23,7 +23,7 @@ public plugin_init() register_plugin("CS Stats Logging", AMXX_VERSION_STR, "AMXX Dev Team") } -public client_disconnect(id) +public client_disconnected(id) { if (!g_inGame[id]) return diff --git a/plugins/dod/stats.sma b/plugins/dod/stats.sma index e9313b1a..79aee492 100755 --- a/plugins/dod/stats.sma +++ b/plugins/dod/stats.sma @@ -819,7 +819,7 @@ new NumOfLeaders new LeaderID new PScore[MAX_PLAYERS + 1] -public client_disconnect(id) { +public client_disconnected(id) { if ( !LeadSounds || isDSMActive() ) return PLUGIN_CONTINUE if ( PScore[id] == LeaderScore && LeaderScore > 0 ){ NumOfLeaders -- diff --git a/plugins/dod/stats_logging.sma b/plugins/dod/stats_logging.sma index 9635a66e..8e6bc071 100755 --- a/plugins/dod/stats_logging.sma +++ b/plugins/dod/stats_logging.sma @@ -21,7 +21,7 @@ new g_pingCount[MAX_PLAYERS + 1] public plugin_init() register_plugin("Stats Logging",AMXX_VERSION_STR,"AMXX Dev Team") -public client_disconnect(id) { +public client_disconnected(id) { if ( is_user_bot( id ) || !is_user_connected(id) || !isDSMActive() ) return PLUGIN_CONTINUE remove_task( id ) new szTeam[16],szName[MAX_NAME_LENGTH],szAuthid[32], iStats[9], iHits[8], szWeapon[16] diff --git a/plugins/include/amxmodx.inc b/plugins/include/amxmodx.inc index 3d2023bf..3770eb85 100755 --- a/plugins/include/amxmodx.inc +++ b/plugins/include/amxmodx.inc @@ -156,16 +156,28 @@ forward client_connect(id); forward client_authorized(id); /** - * Called when a client is disconnecting from the server. + * @deprecated This function does not catch all cases. + */ +#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. * - * @param id Client index + * @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 maxlen Maximum size of buffer * * @noreturn */ -forward client_disconnect(id); +forward client_disconnected(id, bool:drop, message[], maxlen); /** * Called when a client attempts to execute a command. diff --git a/plugins/multilingual.sma b/plugins/multilingual.sma index 253fda3c..759ca132 100755 --- a/plugins/multilingual.sma +++ b/plugins/multilingual.sma @@ -48,7 +48,7 @@ public client_putinserver(id) } } -public client_disconnect(id) +public client_disconnected(id) { remove_task(id) } diff --git a/plugins/ns/nscommands.sma b/plugins/ns/nscommands.sma index faef04be..f65b2bca 100755 --- a/plugins/ns/nscommands.sma +++ b/plugins/ns/nscommands.sma @@ -100,7 +100,7 @@ public msgScoreInfo() { g_Class[id]=read_data(g_ScoreInfo_Class); g_Team[id]=read_data(g_ScoreInfo_Team); } -public client_disconnect(id) { +public client_disconnected(id) { g_Class[id]=0; g_Team[id]=-1; } diff --git a/plugins/tfc/stats_logging.sma b/plugins/tfc/stats_logging.sma index 9a6750a8..e844803d 100755 --- a/plugins/tfc/stats_logging.sma +++ b/plugins/tfc/stats_logging.sma @@ -20,7 +20,7 @@ new g_pingCount[MAX_PLAYERS + 1] public plugin_init() register_plugin("TFC Stats Logging",AMXX_VERSION_STR,"AMXX Dev Team") -public client_disconnect(id) { +public client_disconnected(id) { if ( is_user_bot( id ) ) return PLUGIN_CONTINUE remove_task( id ) new szTeam[16],szName[MAX_NAME_LENGTH],szAuthid[32], iStats[8], iHits[8], szWeapon[24] diff --git a/plugins/ts/stats_logging.sma b/plugins/ts/stats_logging.sma index 91631995..bb8b651e 100755 --- a/plugins/ts/stats_logging.sma +++ b/plugins/ts/stats_logging.sma @@ -22,7 +22,7 @@ new g_pingCount[MAX_PLAYERS + 1] public plugin_init() register_plugin("Stats Logging",AMXX_VERSION_STR,"AMXX Dev Team") -public client_disconnect(id) { +public client_disconnected(id) { if ( is_user_bot( id ) ) return PLUGIN_CONTINUE remove_task( id ) new szTeam[16],szName[MAX_NAME_LENGTH],szAuthid[32], iStats[8], iHits[8], szWeapon[16] diff --git a/public/memtools/CDetour/detours.h b/public/memtools/CDetour/detours.h index b0335191..1eb59617 100644 --- a/public/memtools/CDetour/detours.h +++ b/public/memtools/CDetour/detours.h @@ -70,6 +70,10 @@ ret name(p1type p1name, p2type p2name, p3type p3name) ret (*name##_Actual)(p1type, p2type, p3type, p4type) = NULL; \ ret name(p1type p1name, p2type p2name, p3type p3name, p4type p4name) +#define DETOUR_DECL_STATIC3_VAR(name, ret, p1type, p1name, p2type, p2name, p3type, p3name) \ +ret (*name##_Actual)(p1type, p2type, p3type, ...) = NULL; \ +ret name(p1type p1name, p2type p2name, p3type p3name, ...) + #define DETOUR_DECL_MEMBER0(name, ret) \ class name##Class \ { \ diff --git a/support/PackageScript b/support/PackageScript index 88c53844..3dc7cd78 100644 --- a/support/PackageScript +++ b/support/PackageScript @@ -400,6 +400,7 @@ CopyFiles('gamedata/modules.games', 'base/addons/amxmodx/data/gamedata/modules.g CopyFiles('gamedata/common.games', 'base/addons/amxmodx/data/gamedata/common.games', [ 'master.games.txt', + 'functions.engine.txt', 'globalvars.engine.txt', ] )