diff --git a/amxmodx/CMisc.cpp b/amxmodx/CMisc.cpp index 3e7e5d4f..97765d96 100755 --- a/amxmodx/CMisc.cpp +++ b/amxmodx/CMisc.cpp @@ -59,6 +59,10 @@ void CPlayer::Disconnect() { ingame = false; initialized = false; authorized = false; + + while (!cvarQueryQueue.empty()) + cvarQueryQueue.pop(); + bot = 0; } diff --git a/amxmodx/CMisc.h b/amxmodx/CMisc.h index 9699a13e..4ba3f510 100755 --- a/amxmodx/CMisc.h +++ b/amxmodx/CMisc.h @@ -62,9 +62,15 @@ public: // class CPlayer // ***************************************************** +struct ClientCvarQuery_Info +{ + bool querying; // Are we actually waiting for a response at the moment? + String cvarName; + int resultFwd; +}; + class CPlayer { - public: edict_t* pEdict; @@ -106,6 +112,8 @@ public: Vector thisTrace; Vector lastHit; + CQueue cvarQueryQueue; + void Init( edict_t* e , int i ); void Disconnect(); void PutInServer(); diff --git a/amxmodx/amxmodx.cpp b/amxmodx/amxmodx.cpp index a300d462..69799ab5 100755 --- a/amxmodx/amxmodx.cpp +++ b/amxmodx/amxmodx.cpp @@ -2921,6 +2921,56 @@ static cell AMX_NATIVE_CALL int3(AMX *amx, cell *params) return 0; } +/*********************************************************************/ + + + +// native query_client_cvar(id, const cvar[], const resultfunc[]) +static cell AMX_NATIVE_CALL query_client_cvar(AMX *amx, cell *params) +{ + if (!g_NewDLL_Available) + { + LogError(amx, AMX_ERR_NATIVE, "NewDLL functions are not available. Blame (your) metamod (version)"); + return 0; + } + + int id = params[1]; + if (id < 1 || id > gpGlobals->maxClients) + { + LogError(amx, AMX_ERR_NATIVE, "Invalid player id %d", id); + return 0; + } + + CPlayer *pPlayer = GET_PLAYER_POINTER_I(id); + + if (!pPlayer->initialized || pPlayer->bot) + { + LogError(amx, AMX_ERR_NATIVE, "Player %d is either not connected or a bot", id); + return 0; + } + + int dummy; + const char *cvarname = get_amxstring(amx, params[2], 0, dummy); + const char *resultfuncname = get_amxstring(amx, params[3], 1, dummy); + + // public clientcvarquery_result(id, const cvar[], const result[]) + int iFunc = registerSPForwardByName(amx, resultfuncname, FP_CELL, FP_STRING, FP_STRING, FP_DONE); + if (iFunc == -1) + { + LogError(amx, AMX_ERR_NATIVE, "Function \"%s\" is not present", resultfuncname); + return 0; + } + + ClientCvarQuery_Info *queryObject = new ClientCvarQuery_Info; + queryObject->querying = false; + queryObject->cvarName.assign(cvarname); + queryObject->resultFwd = iFunc; + + pPlayer->cvarQueryQueue.push(queryObject); + + return 1; +} + AMX_NATIVE_INFO amxmod_Natives[] = { { "client_cmd", client_cmd }, { "client_print", client_print }, @@ -3089,5 +3139,6 @@ AMX_NATIVE_INFO amxmod_Natives[] = { { "lang_phrase", lang_phrase}, { "mkdir", amx_mkdir}, { "int3", int3}, + { "query_client_cvar", query_client_cvar }, { NULL, NULL } }; diff --git a/amxmodx/amxmodx.h b/amxmodx/amxmodx.h index 3d82ddd1..d838e0b5 100755 --- a/amxmodx/amxmodx.h +++ b/amxmodx/amxmodx.h @@ -176,6 +176,7 @@ extern float g_game_restarting; extern float g_game_timeleft; extern float g_task_time; extern float g_auth_time; +extern bool g_NewDLL_Available; extern hudtextparms_t g_hudset; //extern int g_edict_point; extern int g_players_num; diff --git a/amxmodx/meta_api.cpp b/amxmodx/meta_api.cpp index b8f06fd7..3131cf49 100755 --- a/amxmodx/meta_api.cpp +++ b/amxmodx/meta_api.cpp @@ -97,6 +97,7 @@ bool g_IsNewMM = false; bool g_NeedsP = false; bool g_coloredmenus; bool g_activated = false; +bool g_NewDLL_Available=false; #ifdef MEMORY_TEST float g_next_memreport_time; @@ -818,6 +819,22 @@ void C_StartFrame_Post( void ) g_tasksMngr.startFrame(); + + // Dispatch client cvar queries + for(int i = 1; i <= gpGlobals->maxClients; ++i) + { + CPlayer* pPlayer = GET_PLAYER_POINTER_I(i); + if (pPlayer->pEdict && pPlayer->initialized && !pPlayer->cvarQueryQueue.empty()) + { + if (!IS_QUERYING_CLIENT_CVAR(PLID, pPlayer->pEdict)) + { + QUERY_CLIENT_CVAR_VALUE(pPlayer->pEdict, pPlayer->cvarQueryQueue.front()->cvarName.c_str()); + pPlayer->cvarQueryQueue.front()->querying = true; + } + } + } + + RETURN_META(MRES_IGNORED); } @@ -1004,6 +1021,26 @@ void C_AlertMessage_Post(ALERT_TYPE atype, char *szFmt, ...) RETURN_META(MRES_IGNORED); } +void C_CvarValue(const edict_t *pEdict, const char *value) +{ + CPlayer *pPlayer = GET_PLAYER_POINTER(pEdict); + if (pPlayer->cvarQueryQueue.empty()) + RETURN_META(MRES_IGNORED); + + ClientCvarQuery_Info *pQuery = pPlayer->cvarQueryQueue.front(); + + if (pPlayer->cvarQueryQueue.front()->querying) + { + executeForwards(pQuery->resultFwd, ENTINDEX(pEdict), pQuery->cvarName.c_str(), value); + unregisterSPForward(pQuery->resultFwd); + delete pQuery; + pPlayer->cvarQueryQueue.pop(); + RETURN_META(MRES_HANDLED); + } + + RETURN_META(MRES_IGNORED); +} + bool m_NeedsP = false; C_DLLEXPORT int Meta_Query(char *ifvers, plugin_info_t **pPlugInfo, mutil_funcs_t *pMetaUtilFuncs) @@ -1091,8 +1128,8 @@ C_DLLEXPORT int Meta_Attach(PLUG_LOADTIME now, META_FUNCTIONS *pFunctionTable, m gMetaFunctionTable.pfnGetEntityAPI2_Post = GetEntityAPI2_Post; gMetaFunctionTable.pfnGetEngineFunctions = GetEngineFunctions; gMetaFunctionTable.pfnGetEngineFunctions_Post = GetEngineFunctions_Post; -#ifdef FAKEMETA gMetaFunctionTable.pfnGetNewDLLFunctions = GetNewDLLFunctions; +#ifdef FAKEMETA gMetaFunctionTable.pfnGetNewDLLFunctions_Post = GetNewDLLFunctions_Post; #endif @@ -1354,17 +1391,30 @@ C_DLLEXPORT int GetEngineFunctions_Post(enginefuncs_t *pengfuncsFromEngine, int #endif } -#ifdef FAKEMETA NEW_DLL_FUNCTIONS gNewDLLFunctionTable; C_DLLEXPORT int GetNewDLLFunctions(NEW_DLL_FUNCTIONS *pNewFunctionTable, int *interfaceVersion) { + // default metamod does not call this if the gamedll doesn't provide it + g_NewDLL_Available = true; + + gNewDLLFunctionTable.pfnCvarValue = C_CvarValue; +#ifdef FAKEMETA return g_FakeMeta.GetNewDLLFunctions(pNewFunctionTable, interfaceVersion, &gNewDLLFunctionTable); +#else + memcpy(pNewFunctionTable, &gNewDLLFunctionTable, sizeof(NEW_DLL_FUNCTIONS)); + return 1; +#endif } + +#ifdef FAKEMETA + NEW_DLL_FUNCTIONS gNewDLLFunctionTable_Post; C_DLLEXPORT int GetNewDLLFunctions_Post(NEW_DLL_FUNCTIONS *pNewFunctionTable, int *interfaceVersion) { return g_FakeMeta.GetNewDLLFunctions_Post(pNewFunctionTable, interfaceVersion, &gNewDLLFunctionTable_Post); + memcpy(pNewFunctionTable, &gNewDLLFunctionTable_Post, sizeof(NEW_DLL_FUNCTIONS)); + return 1; } -#endif +#endif \ No newline at end of file