diff --git a/extensions/cstrike/natives.cpp b/extensions/cstrike/natives.cpp index b36dd9e1..3e1dcd0a 100644 --- a/extensions/cstrike/natives.cpp +++ b/extensions/cstrike/natives.cpp @@ -600,74 +600,136 @@ static cell_t CS_GetTeamScore(IPluginContext *pContext, const cell_t *params) return pContext->ThrowNativeError("Invalid team index passed (%i).", params[1]); } -static cell_t CS_SetMVPCount(IPluginContext *pContext, const cell_t *params) +template +static inline T *GetPlayerVarAddressOrError(const char *pszGamedataName, IPluginContext *pContext, CBaseEntity *pPlayerEntity) { - static void *addr; - if (!addr) + char szBaseName[128]; + g_pSM->Format(szBaseName, sizeof(szBaseName), "%sBase", pszGamedataName); + + const char *pszBaseVar = g_pGameConf->GetKeyValue(szBaseName); + if (pszBaseVar == NULL) { - if (!g_pGameConf->GetMemSig("IncrementNumMVPs", &addr) || !addr) + pContext->ThrowNativeError("Failed to locate %s key in gamedata", szBaseName); + return NULL; + } + + int interimOffset = 0; + sm_sendprop_info_t info; + if (gamehelpers->FindSendPropInfo("CCSPlayer", pszBaseVar, &info)) + { + interimOffset = info.actual_offset; + } + else + { + datamap_t *pMap = gamehelpers->GetDataMap(pPlayerEntity); + typedescription_t *td = gamehelpers->FindInDataMap(pMap, pszBaseVar); + if (td) { - return pContext->ThrowNativeError("Failed to locate IncrementNumMVPs function"); +#if SOURCE_ENGINE >= SE_LEFT4DEAD + interimOffset = td->fieldOffset; +#else + interimOffset = td->fieldOffset[TD_OFFSET_NORMAL]; +#endif } } - CBaseEntity *pEntity; - if (!(pEntity = GetCBaseEntity(params[1], true))) + if (interimOffset == 0) + { + pContext->ThrowNativeError("Failed to find property \"%s\" on player.", pszBaseVar); + return NULL; + } + + + int tempOffset; + if (!g_pGameConf->GetOffset(pszGamedataName, &tempOffset)) + { + pContext->ThrowNativeError("Failed to locate %s offset in gamedata", pszGamedataName); + return NULL; + } + + return (T *)((intptr_t)pPlayerEntity + interimOffset + tempOffset); +} + +template +static inline cell_t GetPlayerVar(IPluginContext *pContext, const cell_t *params, const char *varName) +{ + CBaseEntity *pPlayer = GetCBaseEntity(params[1], true); + if (!pPlayer) { return pContext->ThrowNativeError("Client index %d is not valid", params[1]); } - static int mvpOffsetOffset = -1; - static int mvpOffset; - - if (mvpOffsetOffset == -1) - { - if (!g_pGameConf->GetOffset("MVPCountOffset", &mvpOffsetOffset)) - { - mvpOffsetOffset = -1; - return pContext->ThrowNativeError("Unable to find MVPCountOffset gamedata"); - } - - mvpOffset = *(int *)((intptr_t)addr + mvpOffsetOffset); + T *pVar = GetPlayerVarAddressOrError(varName, pContext, pPlayer); + if (pVar) + { + return (cell_t)*pVar; } - *(int *)((intptr_t)pEntity + mvpOffset) = params[2]; + return 0; +} - return 1; +template +static inline cell_t SetPlayerVar(IPluginContext *pContext, const cell_t *params, const char *varName) +{ + CBaseEntity *pPlayer = GetCBaseEntity(params[1], true); + if (!pPlayer) + { + return pContext->ThrowNativeError("Client index %d is not valid", params[1]); + } + + T *pVar = GetPlayerVarAddressOrError(varName, pContext, pPlayer); + if (pVar) + { + *pVar = (T)params[2]; + } + + return 0; +} + +static cell_t CS_SetMVPCount(IPluginContext *pContext, const cell_t *params) +{ + return SetPlayerVar(pContext, params, "MVPs"); } static cell_t CS_GetMVPCount(IPluginContext *pContext, const cell_t *params) { - static void *addr; - if (!addr) - { - if (!g_pGameConf->GetMemSig("IncrementNumMVPs", &addr) || !addr) - { - return pContext->ThrowNativeError("Failed to locate IncrementNumMVPs function"); - } - } + return GetPlayerVar(pContext, params, "MVPs"); +} - CBaseEntity *pEntity; - if (!(pEntity = GetCBaseEntity(params[1], true))) - { - return pContext->ThrowNativeError("Client index %d is not valid", params[1]); - } +static cell_t CS_SetClientContributionScore(IPluginContext *pContext, const cell_t *params) +{ +#if SOURCE_ENGINE == SE_CSGO + return SetPlayerVar(pContext, params, "CScore"); +#else + return pContext->ThrowNativeError("SetClientContributionScore is not supported on this game"); +#endif +} - static int mvpOffsetOffset = -1; - static int mvpOffset; +static cell_t CS_GetClientContributionScore(IPluginContext *pContext, const cell_t *params) +{ +#if SOURCE_ENGINE == SE_CSGO + return GetPlayerVar(pContext, params, "CScore"); +#else + return pContext->ThrowNativeError("GetClientContributionScore is not supported on this game"); +#endif +} - if (mvpOffsetOffset == -1) - { - if (!g_pGameConf->GetOffset("MVPCountOffset", &mvpOffsetOffset)) - { - mvpOffsetOffset = -1; - return pContext->ThrowNativeError("Unable to find MVPCountOffset gamedata"); - } +static cell_t CS_SetClientAssists(IPluginContext *pContext, const cell_t *params) +{ +#if SOURCE_ENGINE == SE_CSGO + return SetPlayerVar(pContext, params, "Assists"); +#else + return pContext->ThrowNativeError("SetClientAssists is not supported on this game"); +#endif +} - mvpOffset = *(int *)((intptr_t)addr + mvpOffsetOffset); - } - - return *(int *)((intptr_t)pEntity + mvpOffset); +static cell_t CS_GetClientAssists(IPluginContext *pContext, const cell_t *params) +{ +#if SOURCE_ENGINE == SE_CSGO + return GetPlayerVar(pContext, params, "Assists"); +#else + return pContext->ThrowNativeError("GetClientAssists is not supported on this game"); +#endif } sp_nativeinfo_t g_CSNatives[] = @@ -686,6 +748,10 @@ sp_nativeinfo_t g_CSNatives[] = {"CS_GetMVPCount", CS_GetMVPCount}, {"CS_SetMVPCount", CS_SetMVPCount}, {"CS_WeaponIDToAlias", CS_WeaponIDToAlias}, + {"CS_GetClientContributionScore", CS_GetClientContributionScore}, + {"CS_SetClientContributionScore", CS_SetClientContributionScore}, + {"CS_GetClientAssists", CS_GetClientAssists}, + {"CS_SetClientAssists", CS_SetClientAssists}, {NULL, NULL} }; diff --git a/gamedata/sm-cstrike.games/game.csgo.txt b/gamedata/sm-cstrike.games/game.csgo.txt index 99000ae3..fadfceca 100644 --- a/gamedata/sm-cstrike.games/game.csgo.txt +++ b/gamedata/sm-cstrike.games/game.csgo.txt @@ -42,13 +42,6 @@ "linux" "159" "mac" "185" } - //Offset into IncrementNumMVPs to find MVP count offset from player - "MVPCountOffset" - { - "windows" "46" - "linux" "47" - "mac" "61" - } "ClanTagOffset" { "windows" "15" @@ -115,13 +108,6 @@ "linux" "@_ZN12CCSGameRules17CheckRestartRoundEv" "mac" "@_ZN12CCSGameRules17CheckRestartRoundEv" } - "IncrementNumMVPs" - { - "library" "server" - "windows" "\x55\x8B\xEC\xA1\x2A\x2A\x2A\x2A\x8B\x50\x34\x81\xEC\x2A\x2A\x2A\x2A\x57\x8B\xF9\xB9\x2A\x2A\x2A\x2A\xFF\xD2\x85\xC0\x74" - "linux" "@_ZN9CCSPlayer16IncrementNumMVPsE13CSMvpReason_t" - "mac" "@_ZN9CCSPlayer16IncrementNumMVPsE13CSMvpReason_t" - } "AliasToWeaponID" { "library" "server" @@ -145,4 +131,60 @@ } } } + + "csgo" + { + "Keys" + { + "AssistsBase" "m_iFrags" + } + + "Offsets" + { + "Assists" + { + "windows" "4" + "linux" "4" + "mac" "4" + } + } + } + + "csgo" + { + "Keys" + { + "CScoreBase" "m_iWeaponPurchasesThisRound" + } + + "Offsets" + { + /* factors in 256 (size of m_iWeaponPurchasesThisRound array (int size * 64 maxplayers)) */ + "CScore" + { + "windows" "276" + "linux" "276" + "mac" "276" + } + } + } + + "csgo" + { + "Keys" + { + "MVPsBase" "m_iWeaponPurchasesThisRound" + } + + "Offsets" + { + "MVPs" + { + /* factors in 256 (size of m_iWeaponPurchasesThisRound array (int size * 64 maxplayers)) */ + "windows" "256" + "linux" "256" + "mac" "256" + } + } + } } diff --git a/gamedata/sm-cstrike.games/game.css.txt b/gamedata/sm-cstrike.games/game.css.txt index 2fe56cc3..05337ddb 100644 --- a/gamedata/sm-cstrike.games/game.css.txt +++ b/gamedata/sm-cstrike.games/game.css.txt @@ -49,13 +49,6 @@ "linux" "57" "mac" "481" } - //Offset into IncrementNumMVPs to find MVP count offset from player - "MVPCountOffset" - { - "windows" "60" - "linux" "49" - "mac" "62" - } } "Signatures" { @@ -145,12 +138,25 @@ "linux" "@_ZN12CCSGameRules13CheckWinLimitEv" "mac" "@_ZN12CCSGameRules5ThinkEv" } - "IncrementNumMVPs" + } + } + + "cstrike" + { + "Keys" + { + "MVPsBase" "m_bPlayerDominatingMe" + } + + "Offsets" + { + "MVPs" { - "library" "server" - "windows" "\x55\x8B\xEC\x83\xEC\x2A\x89\x2A\x2A\xA1\x2A\x2A\x2A\x2A\x8B\x48\x2A\x89\x2A\x2A\x33\xD2\x83\x7D\x2A\x00\x0F\x95\xC2\x0F\xB6\xC2\x85\xC0\x74\x2A\x68" - "linux" "@_ZN9CCSPlayer16IncrementNumMVPsE13CSMvpReason_t" - "mac" "@_ZN9CCSPlayer16IncrementNumMVPsE13CSMvpReason_t" + /* factors in 66 (size of m_bPlayerDominatingMe array (bool size * (65 maxplayers + 1))) + ... plus another 3 because alignment(?) lolidk */ + "windows" "69" + "linux" "69" + "mac" "69" } } } diff --git a/plugins/include/cstrike.inc b/plugins/include/cstrike.inc index 93d0b0f2..861079bf 100644 --- a/plugins/include/cstrike.inc +++ b/plugins/include/cstrike.inc @@ -285,8 +285,8 @@ native CS_SetTeamScore(team, value); /** * Gets a client's mvp count - * @param client Client index to set mvp count for. - * @return Returns the clients internal MVP count. + * @param client Client index to get mvp count of. + * @return Returns the client's internal MVP count. * * @error Invalid client. */ @@ -295,13 +295,51 @@ native CS_GetMVPCount(client); /** * Sets a client's mvp count * @param client Client index to set mvp count for. - * @param value Value to set clients mvp count as. + * @param value Value to set client's mvp count as. * @noreturn * * @error Invalid client. */ native CS_SetMVPCount(client, value); +/** + * Gets a client's contribution score (CS:GO only) + * @param client Client index to get score of. + * @return Returns the client's score. + * + * @error Invalid client. + */ +native CS_GetClientContributionScore(client); + +/** + * Sets a client's contribution score (CS:GO only) + * @param client Client index to set score for. + * @param value Value to set client's score as. + * @noreturn + * + * @error Invalid client. + */ +native CS_SetClientContributionScore(client, value); + +/** + * Gets a client's assists (CS:GO only) + * @param client Client index to get assists of. + * @return Returns the client's assists. + * + * @error Invalid client. + */ +native CS_GetClientAssists(client); + +/** + * Sets a client's assists (CS:GO only) + * @param client Client index to set assists for. + * @param value Value to set client's assists as. + * @noreturn + * + * @error Invalid client. + */ +native CS_SetClientAssists(client, value); + /** * Gets a weaponID from a alias * @param alias Weapon alias to attempt to get an id for. @@ -350,6 +388,10 @@ public __ext_cstrike_SetNTVOptional() MarkNativeAsOptional("CS_SetTeamScore"); MarkNativeAsOptional("CS_GetMVPCount"); MarkNativeAsOptional("CS_SetMVPCount"); + MarkNativeAsOptional("CS_GetClientContributionScore"); + MarkNativeAsOptional("CS_SetClientContributionScore"); + MarkNativeAsOptional("CS_GetClientAssists"); + MarkNativeAsOptional("CS_SetClientAssists"); MarkNativeAsOptional("CS_AliasToWeaponID"); } #endif diff --git a/plugins/testsuite/cstrike-test.sp b/plugins/testsuite/cstrike-test.sp new file mode 100644 index 00000000..601f6460 --- /dev/null +++ b/plugins/testsuite/cstrike-test.sp @@ -0,0 +1,94 @@ +#include +#include + +stock GET_ARG_INT( arg, maxSize=64 ) +{ + decl String:tempvar[maxSize]; + GetCmdArg( arg, tempvar, maxSize ); + return StringToInt( tempvar ); +} + +public OnPluginStart() +{ + RegConsoleCmd( "get_mvps", get_mvps ); + RegConsoleCmd( "set_mvps", set_mvps ); + RegConsoleCmd( "get_score", get_score ); + RegConsoleCmd( "set_score", set_score ); + RegConsoleCmd( "get_assists", get_assists ); + RegConsoleCmd( "set_assists", set_assists ); +} + +public Action:get_mvps( client, argc ) +{ + ReplyToCommand( client, "Your MVP count is %d", CS_GetMVPCount( client ) ); + + return Plugin_Handled; +} + +public Action:set_mvps( client, argc ) +{ + new count = GET_ARG_INT( 1 ); + + CS_SetMVPCount( client, count ); + ReplyToCommand( client, "Set your MVP count to %d", count ); + + return Plugin_Handled; +} + +public Action:get_score( client, argc ) +{ + if( GuessSDKVersion() != SOURCE_SDK_CSGO ) + { + ReplyToCommand( client, "This command is only intended for CS:GO" ); + return Plugin_Handled; + } + + ReplyToCommand( client, "Your contribution score is %d", CS_GetClientContributionScore( client ) ); + + return Plugin_Handled; +} + +public Action:set_score( client, argc ) +{ + if( GuessSDKVersion() != SOURCE_SDK_CSGO ) + { + ReplyToCommand( client, "This command is only intended for CS:GO" ); + return Plugin_Handled; + } + + new count = GET_ARG_INT( 1 ); + + CS_SetClientContributionScore( client, count ); + ReplyToCommand( client, "Set your contribution score to %d", count ); + + return Plugin_Handled; +} + +public Action:get_assists( client, argc ) +{ + if( GuessSDKVersion() != SOURCE_SDK_CSGO ) + { + ReplyToCommand( client, "This command is only intended for CS:GO" ); + return Plugin_Handled; + } + + ReplyToCommand( client, "Your assist count is %d", CS_GetClientAssists( client ) ); + + return Plugin_Handled; +} + +public Action:set_assists( client, argc ) +{ + if( GuessSDKVersion() != SOURCE_SDK_CSGO ) + { + ReplyToCommand( client, "This command is only intended for CS:GO" ); + return Plugin_Handled; + } + + new count = GET_ARG_INT( 1 ); + + CS_SetClientAssists( client, count ); + ReplyToCommand( client, "Set your assist count to %d", count ); + + return Plugin_Handled; +}