Cstrike: cs_set/reset_user_model/team - Stagger user's info updates across multiple frames (bug 3134)

This commit is contained in:
Arkshine
2015-07-06 20:05:48 +02:00
parent aedde87f42
commit 8be119aa6a
13 changed files with 752 additions and 121 deletions

View File

@ -42,11 +42,16 @@ StringHashMap<int> ItemAliasList;
int TeamOffset;
int MenuOffset;
server_static_t *ServerStatic;
double *RealTime;
void InitializeHacks()
{
CtrlDetours_ClientCommand(true);
CtrlDetours_BuyCommands(true);
CtrlDetours_Natives(true);
InitGlobalVars();
}
void ShutdownHacks()
@ -301,8 +306,8 @@ void CtrlDetours_ClientCommand(bool set)
#endif
ClientCommandDetour = DETOUR_CREATE_STATIC_FIXED(C_ClientCommand, base);
OffsetConfig->GetOffsetByClass("CBasePlayer", "m_iTeam", &TeamOffset);
OffsetConfig->GetOffsetByClass("CBasePlayer", "m_iMenu", &MenuOffset);
CommonConfig->GetOffsetByClass("CBasePlayer", "m_iTeam", &TeamOffset);
CommonConfig->GetOffsetByClass("CBasePlayer", "m_iMenu", &MenuOffset);
if (!ClientCommandDetour || !UseBotArgs || !BotArgs || !TeamOffset || !MenuOffset)
{
@ -506,3 +511,28 @@ void CtrlDetours_Natives(bool set)
}
}
}
void InitGlobalVars()
{
void *address = nullptr;
#if defined(WIN32)
int offset = 0;
if (CommonConfig->GetOffset("svs", &offset))
{
uintptr_t base = *reinterpret_cast<uintptr_t*>(reinterpret_cast<byte*>(g_engfuncs.pfnGetCurrentPlayer) + offset);
ServerStatic = reinterpret_cast<server_static_t*>(base - 4);
}
#else
if (CommonConfig->GetMemSig("svs", &address))
{
ServerStatic = reinterpret_cast<server_static_t*>(address);
}
#endif
if (CommonConfig->GetAddress("realtime", &address))
{
RealTime = reinterpret_cast<double*>(*reinterpret_cast<uintptr_t*>(address));
}
}

View File

@ -17,8 +17,10 @@
#include <amxxmodule.h>
#include <IGameConfigs.h>
#include <CDetour/detours.h>
#include <engine_strucs.h>
void InitializeHacks();
void InitGlobalVars();
void ShutdownHacks();
void ToggleDetour_ClientCommands(bool enable);
void ToggleDetour_BuyCommands(bool enable);
@ -26,7 +28,7 @@ void ToggleDetour_BuyCommands(bool enable);
extern AMX_NATIVE_INFO CstrikeNatives[];
extern IGameConfig *MainConfig;
extern IGameConfig *OffsetConfig;
extern IGameConfig *CommonConfig;
extern int ForwardInternalCommand;
extern int ForwardOnBuy;
@ -40,6 +42,10 @@ extern UTIL_FindEntityByStringFunc CS_UTIL_FindEntityByString;
extern CDetour *GiveDefaultItemsDetour;
extern enginefuncs_t *g_pengfuncsTable;
extern DLL_FUNCTIONS *g_pFunctionTable;
extern bool NoKifesMode;
extern server_static_t *ServerStatic;
extern double *RealTime;
#endif // CSTRIKE_HACKS_H

View File

@ -18,9 +18,7 @@
#include "CstrikeUserMessages.h"
#include "CstrikeHLTypeConversion.h"
#include <CDetour/detours.h>
CCstrikePlayer g_players[33];
int Zooming[33];
#include <am-vector.h>
bool NoKifesMode = false;
@ -536,7 +534,7 @@ static cell AMX_NATIVE_CALL cs_set_user_team(AMX *amx, cell *params)
set_pdata<int>(pPlayer, m_iModelName, model);
}
MDLL_ClientUserInfoChanged(pPlayer, GETINFOKEYBUFFER(pPlayer));
Players[index].ResetModel(pPlayer);
char teaminfo[32];
@ -863,17 +861,11 @@ static cell AMX_NATIVE_CALL cs_set_user_model(AMX *amx, cell *params)
return 0;
}
char modelName[32];
int length;
const char *newModel = MF_GetAmxString(amx, params[2], 0, &length);
strcpy(modelName, MF_GetAmxString(amx, params[2], 0, &length));
g_players[index].SetModel(modelName);
g_players[index].SetModelled(true);
EnableMessageHooks();
SETCLIENTKEYVALUE(index, GETINFOKEYBUFFER(pPlayer), "model", const_cast<char*>(g_players[index].GetModel()));
Players[index].SetModel(newModel);
Players[index].UpdateModel(MF_GetPlayerEdict(index));
return 1;
}
@ -886,9 +878,7 @@ static cell AMX_NATIVE_CALL cs_reset_user_model(AMX *amx, cell *params)
CHECK_PLAYER(index);
edict_t *pPlayer = MF_GetPlayerEdict(index);
g_players[index].SetModelled(false);
MDLL_ClientUserInfoChanged(pPlayer, GETINFOKEYBUFFER(pPlayer));
Players[index].ResetModel(pPlayer);
return 1;
}
@ -1317,7 +1307,7 @@ static cell AMX_NATIVE_CALL cs_set_user_zoom(AMX *amx, cell *params)
int mode = params[3];
int weapon = *static_cast<int *>(MF_PlayerPropAddr(index, Player_CurrentWeapon));
Zooming[index] = 0;
Players[index].ResetZoom();
if (type == CS_RESET_ZOOM)
{
@ -1365,7 +1355,7 @@ static cell AMX_NATIVE_CALL cs_set_user_zoom(AMX *amx, cell *params)
if (!mode)
{
Zooming[index] = value;
Players[index].SetZoom(value);
EnableMessageHooks();
}
@ -1766,42 +1756,3 @@ AMX_NATIVE_INFO CstrikeNatives[] =
{nullptr, nullptr}
};
void ClientDisconnect(edict_t *pEntity)
{
int index = ENTINDEX(pEntity);
g_players[index].SetModelled(false);
Zooming[index] = 0;
RETURN_META(MRES_IGNORED);
}
void ClientUserInfoChanged(edict_t *pEntity, char *infobuffer)
{
int index = ENTINDEX(pEntity);
if(g_players[index].GetModelled() && pEntity->v.deadflag == DEAD_NO)
{
RETURN_META(MRES_SUPERCEDE);
}
else
{
RETURN_META(MRES_IGNORED);
}
}
void PlayerPostThink(edict_t* pPlayer)
{
int entityIndex = ENTINDEX(pPlayer);
if(g_players[entityIndex].GetModelled())
{
if (g_players[entityIndex].GetInspectModel() && strcmp(g_players[entityIndex].GetModel(), GETCLIENTKEYVALUE(GETINFOKEYBUFFER(pPlayer), "model")) != 0)
{
//LOG_CONSOLE(PLID, "%s should have model %s and currently has %s", STRING(pPlayer->v.netname), (char*)g_players[entityIndex].GetModel(), GETCLIENTKEYVALUE(GETINFOKEYBUFFER(pPlayer), "model"));
SETCLIENTKEYVALUE(entityIndex, GETINFOKEYBUFFER(pPlayer), "model", (char*)g_players[entityIndex].GetModel());
g_players[entityIndex].SetInspectModel(false);
}
}
RETURN_META(MRES_IGNORED);
}

View File

@ -12,47 +12,49 @@
//
#include "CstrikePlayer.h"
#include <string.h> // strcpy()
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CPlayer Players[33];
ke::Vector<int> ModelsUpdateQueue;
CCstrikePlayer::CCstrikePlayer()
void ClientDisconnect(edict_t *pEntity)
{
modelled = false;
inspectModel = false;
int index = ENTINDEX(pEntity);
Players[index].ResetModel();
Players[index].ResetZoom();
RETURN_META(MRES_IGNORED);
}
bool CCstrikePlayer::GetModelled()
void ClientUserInfoChanged(edict_t *pEntity, char *infobuffer)
{
return modelled;
if (pEntity->pvPrivateData)
{
Players[ENTINDEX(pEntity)].UpdateModel(pEntity);
}
RETURN_META(MRES_IGNORED);
}
bool CCstrikePlayer::SetModelled(bool modelledIn)
void SetClientKeyValue(int clientIndex, char *infobuffer, const char *key, const char *value)
{
if (!modelledIn)
SetInspectModel(false);
if (!strcmp(key, "model") && Players[clientIndex].HasModel(value))
{
RETURN_META(MRES_SUPERCEDE);
}
return modelled = modelledIn;
RETURN_META(MRES_IGNORED);
}
const char* CCstrikePlayer::GetModel()
void StartFrame()
{
return model;
}
if (ModelsUpdateQueue.empty())
{
g_pFunctionTable->pfnStartFrame = nullptr;
RETURN_META(MRES_IGNORED);
}
void CCstrikePlayer::SetModel(const char* modelIn)
{
strcpy(model, modelIn);
}
ServerStatic->clients[ModelsUpdateQueue.popCopy()].sendinfo = true;
bool CCstrikePlayer::GetInspectModel()
{
return inspectModel;
}
void CCstrikePlayer::SetInspectModel(bool inspectModelIn)
{
inspectModel = inspectModelIn;
RETURN_META(MRES_IGNORED);
}

View File

@ -11,30 +11,125 @@
// Counter-Strike Module
//
#if !defined(INCLUDED_CCSTRIKEPLAYER)
#define INCLUDED_CCSTRIKEPLAYER
#ifndef _CSTRIKE_PLAYER_H_
#define _CSTRIKE_PLAYER_H_
class CCstrikePlayer
#include <amxxmodule.h>
#include "CstrikeUtils.h"
#include "CstrikeHacks.h"
#include <am-vector.h>
extern ke::Vector<int> ModelsUpdateQueue;
void StartFrame();
void ClientUserInfoChanged(edict_t *pEntity, char *infobuffer);
void SetClientKeyValue(int clientIndex, char *infobuffer, const char *key, const char *value);
class CPlayer
{
public:
CCstrikePlayer();
public:
bool GetModelled();
bool SetModelled(bool modelledIn);
const char* GetModel();
void SetModel(const char* modelIn);
CPlayer()
{
ResetModel();
ResetZoom();
}
bool GetInspectModel();
void SetInspectModel(bool inspectModelIn);
bool HasModel(const char *model = nullptr)
{
if (*m_Model != '\0')
{
if (model && *model)
{
return strcmp(m_Model, model) != 0;
}
return true;
}
private:
bool inspectModel;
bool modelled;
char model[32];
return false;
}
void SetModel(const char* modelIn)
{
if (modelIn && *modelIn)
{
strncopy(m_Model, modelIn, sizeof(m_Model));
}
else
{
ResetModel();
}
}
void ResetModel(edict_t *pPlayer = nullptr)
{
*m_Model = '\0';
if (pPlayer)
{
MDLL_ClientUserInfoChanged(pPlayer, GETINFOKEYBUFFER(pPlayer));
PostponeModeUpdate(ENTINDEX(pPlayer) - 1);
}
}
void UpdateModel(edict_t *pPlayer)
{
if (!HasModel())
{
return;
}
char *infobuffer = GETINFOKEYBUFFER(pPlayer);
if (strcmp(GETCLIENTKEYVALUE(infobuffer, "model"), m_Model) != 0)
{
int index = ENTINDEX(pPlayer);
SETCLIENTKEYVALUE(index, infobuffer, "model", m_Model);
PostponeModeUpdate(index - 1);
}
}
int GetZoom()
{
return m_Zooming;
}
void SetZoom(int value)
{
m_Zooming = value;
}
void ResetZoom()
{
m_Zooming = 0;
}
private:
void PostponeModeUpdate(int index)
{
ServerStatic->clients[index].sendinfo = false;
ModelsUpdateQueue.append(index);
if (!g_pFunctionTable->pfnStartFrame)
{
g_pFunctionTable->pfnStartFrame = StartFrame;
g_pFunctionTable->pfnClientUserInfoChanged = ClientUserInfoChanged;
g_pengfuncsTable->pfnSetClientKeyValue = SetClientKeyValue;
}
}
private:
char m_Model[32];
int m_Zooming;
};
extern CCstrikePlayer g_players[33];
extern int Zooming[33];
extern CPlayer Players[33];
#endif // !defined(INCLUDED_CCSTRIKEPLAYER)
#endif // _CSTRIKE_PLAYER_H_

View File

@ -76,14 +76,15 @@ void OnMessageBegin(int msg_dest, int msg_type, const float *pOrigin, edict_t *p
if (msg_type == MessageIdSetFOV)
{
int index = ENTINDEX(pEntity);
int zoom = Players[index].GetZoom();
if (Zooming[index])
if (zoom)
{
GET_OFFSET_NO_ERROR("CBasePlayer", m_iFOV);
if (get_pdata<int>(pEntity, m_iFOV) != Zooming[index])
if (get_pdata<int>(pEntity, m_iFOV) != zoom)
{
set_pdata<int>(pEntity, m_iFOV, Zooming[index]);
set_pdata<int>(pEntity, m_iFOV, zoom);
ShouldBlock = true;
ShouldBlockHLTV = true;
@ -96,11 +97,8 @@ void OnMessageBegin(int msg_dest, int msg_type, const float *pOrigin, edict_t *p
{
int index = ENTINDEX(pEntity);
if (Zooming[index])
Zooming[index] = 0;
if (g_players[index].GetModelled())
g_players[index].SetInspectModel(true);
if (Players[index].GetZoom())
Players[index].ResetZoom();
}
break;
}

View File

@ -78,7 +78,7 @@ bool UTIL_CheckForPublic(const char *publicname);
static int member = -1; \
if (member == -1) \
{ \
if (!OffsetConfig->GetOffsetByClass(classname, #member, &member) || member < 0)\
if (!CommonConfig->GetOffsetByClass(classname, #member, &member) || member < 0)\
{ \
MF_LogError(amx, AMX_ERR_NATIVE, "Invalid %s offset. Native %s is disabled", #member, __FUNCTION__);\
return 0; \
@ -89,7 +89,7 @@ bool UTIL_CheckForPublic(const char *publicname);
static int member = -1; \
if (member == -1) \
{ \
if (!OffsetConfig->GetOffsetByClass(classname, #member, &member) || member < 0)\
if (!CommonConfig->GetOffsetByClass(classname, #member, &member) || member < 0)\
{ \
return; \
} \

View File

@ -17,9 +17,10 @@
#include "CstrikeHacks.h"
#include "CstrikeHLTypeConversion.h"
#include <IGameConfigs.h>
#include "engine_strucs.h"
IGameConfig *MainConfig;
IGameConfig *OffsetConfig;
IGameConfig *CommonConfig;
IGameConfigManager *ConfigManager;
int AmxxCheckGame(const char *game)
@ -49,7 +50,7 @@ void OnAmxxAttach()
error[0] = '\0';
if (!ConfigManager->LoadGameConfigFile("common.games", &OffsetConfig, error, sizeof(error)) && error[0] != '\0')
if (!ConfigManager->LoadGameConfigFile("common.games", &CommonConfig, error, sizeof(error)) && error[0] != '\0')
{
MF_Log("Could not read common.games gamedata: %s", error);
return;
@ -79,12 +80,17 @@ void OnPluginsLoaded()
{
G_OffsetHandler = new OffsetHandler;
}
// Used with model natives, enabled on demand.
g_pengfuncsTable->pfnSetClientKeyValue = nullptr;
g_pFunctionTable->pfnClientUserInfoChanged = nullptr;
g_pFunctionTable->pfnStartFrame = nullptr;
}
void OnAmxxDetach()
{
ConfigManager->CloseGameConfigFile(MainConfig);
ConfigManager->CloseGameConfigFile(OffsetConfig);
ConfigManager->CloseGameConfigFile(CommonConfig);
ShutdownHacks();
}

View File

@ -122,11 +122,11 @@
// #define FN_ClientKill ClientKill /* pfnClientKill() (wd) Player has typed "kill" */
// #define FN_ClientPutInServer ClientPutInServer /* pfnClientPutInServer() (wd) Client is entering the game */
// #define FN_ClientCommand ClientCommand /* pfnClientCommand() (wd) Player has sent a command (typed or from a bind) */
#define FN_ClientUserInfoChanged ClientUserInfoChanged /* pfnClientUserInfoChanged() (wd) Client has updated their setinfo structure */
// #define FN_ClientUserInfoChanged ClientUserInfoChanged /* pfnClientUserInfoChanged() (wd) Client has updated their setinfo structure */
// #define FN_ServerActivate ServerActivate /* pfnServerActivate() (wd) Server is starting a new map */
// #define FN_ServerDeactivate ServerDeactivate /* pfnServerDeactivate() (wd) Server is leaving the map (shutdown or changelevel); SDK2 */
// #define FN_PlayerPreThink PlayerPreThink /* pfnPlayerPreThink() */
#define FN_PlayerPostThink PlayerPostThink /* pfnPlayerPostThink() */
// #define FN_PlayerPostThink PlayerPostThink /* pfnPlayerPostThink() */
// #define FN_StartFrame StartFrame /* pfnStartFrame() */
// #define FN_ParmsNewLevel ParmsNewLevel /* pfnParmsNewLevel() */
// #define FN_ParmsChangeLevel ParmsChangeLevel /* pfnParmsChangeLevel() */