From d80e0af376dfcdebd154a07b187b7c6c0caa5e79 Mon Sep 17 00:00:00 2001 From: Alienmario Date: Sat, 31 Aug 2024 13:29:30 +0200 Subject: [PATCH] Populate CPlayerResource, Add CPlayerState The CPlayerState accessor avoids having to create a temporary game_score entity when updating scores. --- gamedata/srccoop.games.txt | 15 +++ scripting/include/srccoop/classdef.inc | 177 ++++++++++++++++++------- scripting/srccoop.sp | 2 +- 3 files changed, 143 insertions(+), 51 deletions(-) diff --git a/gamedata/srccoop.games.txt b/gamedata/srccoop.games.txt index da2f4978..0173f7fc 100644 --- a/gamedata/srccoop.games.txt +++ b/gamedata/srccoop.games.txt @@ -16,6 +16,11 @@ "windows" "ServerGameDLL010" "linux" "ServerGameDLL010" } + "IServerGameClients" + { + "windows" "ServerGameClients003" + "linux" "ServerGameClients003" + } "IEngineSoundServer" { "windows" "IEngineSoundServer003" @@ -40,6 +45,16 @@ "windows" "10" "linux" "10" } + "CServerGameClients::GetPlayerState" // CPlayerState *CServerGameClients::GetPlayerState( edict_t *player ) + { + "windows" "11" + "linux" "11" + } + "CPlayerState::frags" + { + "windows" "44" + "linux" "44" + } } "Signatures" { diff --git a/scripting/include/srccoop/classdef.inc b/scripting/include/srccoop/classdef.inc index e8727a5b..c34b4d05 100644 --- a/scripting/include/srccoop/classdef.inc +++ b/scripting/include/srccoop/classdef.inc @@ -8,6 +8,8 @@ #pragma newdecls required #pragma semicolon 1 +IServerGameClients g_ServerGameClients; + ConVar ai_los_mode; Handle g_pGlobalEntityGetIndex; @@ -32,8 +34,10 @@ Handle g_pIsNPC; Handle g_pSendWeaponAnim; Handle g_pWeaponSwitch; Handle g_pWorldSpaceCenter; +Handle g_pGetPlayerState; int g_iCSoundSize = -1; +int g_iCPlayerState_frags = -1; stock void InitClassdef(GameData pGameConfig) { @@ -43,6 +47,13 @@ stock void InitClassdef(GameData pGameConfig) if (g_iCSoundSize <= 0) SetFailState("Could not obtain CSound struct size"); + g_iCPlayerState_frags = pGameConfig.GetOffset("CPlayerState::frags"); + if (g_iCPlayerState_frags < 0) + SetFailState("Invalid offset CPlayerState::frags"); + + if (!(g_ServerGameClients = IServerGameClients(GetInterface(pGameConfig, "server", "IServerGameClients")))) + SetFailState("Could not get interface for %s", "IServerGameClients"); + char szSetCollisionBounds[] = "CBaseEntity::SetCollisionBounds"; StartPrepSDKCall(SDKCall_Entity); if (!PrepSDKCall_SetFromConf(pGameConfig, SDKConf_Signature, szSetCollisionBounds)) @@ -283,6 +294,17 @@ stock void InitClassdef(GameData pGameConfig) if (!(g_pWorldSpaceCenter = EndPrepSDKCall())) SetFailState("Could not prep SDK call %s", szWorldSpaceCenter); } + char szGetPlayerState[] = "CServerGameClients::GetPlayerState"; + StartPrepSDKCall(SDKCall_Raw); + if (!PrepSDKCall_SetFromConf(pGameConfig, SDKConf_Virtual, szGetPlayerState)) + LogMessage("Could not obtain gamedata offset %s", szGetPlayerState); + else + { + PrepSDKCall_AddParameter(SDKType_Edict, SDKPass_Pointer); + PrepSDKCall_SetReturnInfo(SDKType_PlainOldData, SDKPass_Plain); + if (!(g_pGetPlayerState = EndPrepSDKCall())) SetFailState("Could not prep SDK call %s", szGetPlayerState); + } + #if defined SRCCOOP_BLACKMESA InitClassdefBM(pGameConfig); #endif @@ -1985,12 +2007,7 @@ methodmap CBasePlayer < CBaseCombatCharacter public void SetScore(const int iScore) { SetEntProp(this.GetEntIndex(), Prop_Data, "m_iFrags", iScore); - - // Force server to actually recognize the score update - CBaseEntity pTempGameScore = CBaseEntity(CreateEntityByName("game_score")); - pTempGameScore.Spawn(); - pTempGameScore.AcceptInput("ApplyScore", this); - pTempGameScore.Kill(); + g_ServerGameClients.GetPlayerState(this).SetScore(iScore); } /** * Modifies the player's score by the provided points @@ -2331,61 +2348,92 @@ methodmap CPlayerResource < CBaseEntity } public static CPlayerResource Get() { - return CPlayerResource(FindEntityByClassname(-1, "player_manager")); + return CPlayerResource(GetPlayerResourceEntity()); } - public int GetTeam(CBasePlayer pPlayer) + public int GetPing(CBasePlayer pPlayer) { - int iEntIndex = pPlayer.GetEntIndex(); - bool bOutOfBounds = (iEntIndex > MaxClients) || (iEntIndex < 0); - if (bOutOfBounds) - ThrowError("Received out of bounds index %d; range is 0-%i", MaxClients); - - int iMemberOffset = GetEntSendPropOffs(this.GetEntIndex(), "m_bConnected"); - if (iMemberOffset == -1) - ThrowError("Unable to retrieve offset %s", "m_iTeam"); - - return Deref(this.GetAddress() + iMemberOffset + (iEntIndex * 4), NumberType_Int32); + return GetEntProp(this.entindex, Prop_Send, "m_iPing", _, pPlayer.entindex); } - public void SetTeam(CBasePlayer pPlayer, const int iTeamNum) + public void SetPing(CBasePlayer pPlayer, int iPing) { - int iEntIndex = pPlayer.GetEntIndex(); - bool bOutOfBounds = (iEntIndex > MaxClients) || (iEntIndex < 0); - if (bOutOfBounds) - ThrowError("Received out of bounds index %d; range is 0-%i", MaxClients); - - int iMemberOffset = GetEntSendPropOffs(this.GetEntIndex(), "m_iTeam"); - if (iMemberOffset == -1) - ThrowError("Unable to retrieve offset %s", "m_iTeam"); - - StoreToAddress(this.GetAddress() + iMemberOffset + (iEntIndex * 4), iTeamNum, NumberType_Int32); + SetEntProp(this.entindex, Prop_Send, "m_iPing", iPing, _, pPlayer.entindex); + } + public int GetScore(CBasePlayer pPlayer) + { + return GetEntProp(this.entindex, Prop_Send, "m_iScore", _, pPlayer.entindex); + } + public void SetScore(CBasePlayer pPlayer, int iScore) + { + SetEntProp(this.entindex, Prop_Send, "m_iScore", iScore, _, pPlayer.entindex); + } + public int GetDeaths(CBasePlayer pPlayer) + { + return GetEntProp(this.entindex, Prop_Send, "m_iDeaths", _, pPlayer.entindex); + } + public void SetDeaths(CBasePlayer pPlayer, int iDeaths) + { + SetEntProp(this.entindex, Prop_Send, "m_iDeaths", iDeaths, _, pPlayer.entindex); } public bool IsConnected(CBasePlayer pPlayer) { - int iEntIndex = pPlayer.GetEntIndex(); - bool bOutOfBounds = (iEntIndex > MaxClients) || (iEntIndex < 0); - if (bOutOfBounds) - ThrowError("Received out of bounds index %d; range is 0-%i", MaxClients); - - int iMemberOffset = GetEntSendPropOffs(this.GetEntIndex(), "m_bConnected"); - if (iMemberOffset == -1) - ThrowError("Unable to retrieve offset %s", "m_bConnected"); - - return view_as(Deref(this.GetAddress() + iMemberOffset + (iEntIndex * 4), NumberType_Int32)); + return view_as(GetEntProp(this.entindex, Prop_Send, "m_bConnected", _, pPlayer.entindex)); } - public void SetConnected(CBasePlayer pPlayer, const bool bConnected) + public void SetConnected(CBasePlayer pPlayer, bool bConnected) { - int iEntIndex = pPlayer.GetEntIndex(); - bool bOutOfBounds = (iEntIndex > MaxClients) || (iEntIndex < 0); - if (bOutOfBounds) - ThrowError("Received out of bounds index %d; range is 0-%i", MaxClients); - - int iMemberOffset = GetEntSendPropOffs(this.GetEntIndex(), "m_bConnected"); - if (iMemberOffset == -1) - ThrowError("Unable to retrieve offset %s", "m_bConnected"); - - StoreToAddress(this.GetAddress() + iMemberOffset + (iEntIndex * 4), view_as(bConnected), NumberType_Int32); + SetEntProp(this.entindex, Prop_Send, "m_bConnected", bConnected, _, pPlayer.entindex); + } + public int GetTeam(CBasePlayer pPlayer) + { + return GetEntProp(this.entindex, Prop_Send, "m_iTeam", _, pPlayer.entindex); + } + public void SetTeam(CBasePlayer pPlayer, int iTeam) + { + SetEntProp(this.entindex, Prop_Send, "m_iTeam", iTeam, _, pPlayer.entindex); + } + public bool IsAlive(CBasePlayer pPlayer) + { + return view_as(GetEntProp(this.entindex, Prop_Send, "m_bAlive", _, pPlayer.entindex)); + } + public void SetAlive(CBasePlayer pPlayer, bool bAlive) + { + SetEntProp(this.entindex, Prop_Send, "m_bAlive", bAlive, _, pPlayer.entindex); + } + public int GetHealth(CBasePlayer pPlayer) + { + return GetEntProp(this.entindex, Prop_Send, "m_iHealth", _, pPlayer.entindex); + } + public void SetHealth(CBasePlayer pPlayer, int iHealth) + { + SetEntProp(this.entindex, Prop_Send, "m_iHealth", iHealth, _, pPlayer.entindex); + } + + #if defined SRCCOOP_BLACKMESA + public int GetAccountId(CBasePlayer pPlayer) + { + return GetEntProp(this.entindex, Prop_Send, "m_iAccountID", _, pPlayer.entindex); + } + public void SetAccountId(CBasePlayer pPlayer, int iAccountID) + { + SetEntProp(this.entindex, Prop_Send, "m_iAccountID", iAccountID, _, pPlayer.entindex); + } + public bool IsValid(CBasePlayer pPlayer) + { + return view_as(GetEntProp(this.entindex, Prop_Send, "m_bValid", _, pPlayer.entindex)); + } + public void SetValid(CBasePlayer pPlayer, bool bValid) + { + SetEntProp(this.entindex, Prop_Send, "m_bValid", bValid, _, pPlayer.entindex); + } + public int GetFrags(CBasePlayer pPlayer) + { + return GetEntProp(this.entindex, Prop_Send, "m_iFrags", _, pPlayer.entindex); } + public void SetFrags(CBasePlayer pPlayer, int iFrags) + { + SetEntProp(this.entindex, Prop_Send, "m_iFrags", iFrags, _, pPlayer.entindex); + } + #endif // SRCCOOP_BLACKMESA } methodmap CFuncLadder < CBaseEntity @@ -2540,6 +2588,35 @@ methodmap IServerGameDLL } } +/** + * The player state is an embedded class inside of player that is shared with the engine. + * The Engine uses some of this data for responding to external server queries. + */ +methodmap CPlayerState +{ + public int GetScore() + { + return LoadFromAddress(view_as
(this) + g_iCPlayerState_frags, NumberType_Int32); + } + public void SetScore(int iScore) + { + StoreToAddress(view_as
(this) + g_iCPlayerState_frags, iScore, NumberType_Int32); + } +} + +methodmap IServerGameClients +{ + public IServerGameClients(Address pAddress) + { + return view_as(pAddress); + } + + public CPlayerState GetPlayerState(CBasePlayer pPlayer) + { + return SDKCall(g_pGetPlayerState, this, pPlayer.entindex); + } +} + methodmap CTraceRay < Handle { public CTraceRay(const float vecPosition[3], const float vecRayType[3], const int iTraceMask, const RayType eRayType, const TraceEntityFilter fnFilter, const any pData) diff --git a/scripting/srccoop.sp b/scripting/srccoop.sp index 3048b2fc..70930b98 100644 --- a/scripting/srccoop.sp +++ b/scripting/srccoop.sp @@ -21,7 +21,7 @@ void LoadGameData() g_serverOS = view_as(pGameConfig.GetOffset("_OS_Detector_")); if (!(g_ServerGameDLL = IServerGameDLL(GetInterface(pGameConfig, "server", "IServerGameDLL")))) - SetFailState("Could not get interface for %s", "g_ServerGameDLL"); + SetFailState("Could not get interface for %s", "IServerGameDLL"); // Calls