Added natives to CStrike ext to access assists/score in CSGO (bug 5525, r=asherkin).
authorNicholas Hastings <skamonkey@gmail.com>
Sat Dec 15 14:36:52 2012 -0500 (2012-12-15)
changeset 370654f55b538cb2
parent 3705 23ac06d0c633
child 3707 bb0d8923ff6c
Added natives to CStrike ext to access assists/score in CSGO (bug 5525, r=asherkin).
extensions/cstrike/natives.cpp
gamedata/sm-cstrike.games/game.csgo.txt
gamedata/sm-cstrike.games/game.css.txt
plugins/include/cstrike.inc
plugins/testsuite/cstrike-test.sp
     1.1 --- a/extensions/cstrike/natives.cpp	Fri Dec 14 15:18:30 2012 -0500
     1.2 +++ b/extensions/cstrike/natives.cpp	Sat Dec 15 14:36:52 2012 -0500
     1.3 @@ -600,74 +600,136 @@
     1.4  	return pContext->ThrowNativeError("Invalid team index passed (%i).", params[1]);
     1.5  }
     1.6  
     1.7 -static cell_t CS_SetMVPCount(IPluginContext *pContext, const cell_t *params)
     1.8 +template <typename T>
     1.9 +static inline T *GetPlayerVarAddressOrError(const char *pszGamedataName, IPluginContext *pContext, CBaseEntity *pPlayerEntity)
    1.10  {
    1.11 -	static void *addr;
    1.12 -	if (!addr)
    1.13 +	char szBaseName[128];
    1.14 +	g_pSM->Format(szBaseName, sizeof(szBaseName), "%sBase", pszGamedataName);
    1.15 +
    1.16 +	const char *pszBaseVar = g_pGameConf->GetKeyValue(szBaseName);
    1.17 +	if (pszBaseVar == NULL)
    1.18 +	{
    1.19 +		pContext->ThrowNativeError("Failed to locate %s key in gamedata", szBaseName);
    1.20 +		return NULL;
    1.21 +	}
    1.22 +
    1.23 +	int interimOffset = 0;
    1.24 +	sm_sendprop_info_t info;
    1.25 +	if (gamehelpers->FindSendPropInfo("CCSPlayer", pszBaseVar, &info))
    1.26  	{
    1.27 -		if (!g_pGameConf->GetMemSig("IncrementNumMVPs", &addr) || !addr)
    1.28 +		interimOffset = info.actual_offset;
    1.29 +	}
    1.30 +	else
    1.31 +	{
    1.32 +		datamap_t *pMap = gamehelpers->GetDataMap(pPlayerEntity);
    1.33 +		typedescription_t *td = gamehelpers->FindInDataMap(pMap, pszBaseVar);
    1.34 +		if (td)
    1.35  		{
    1.36 -			return pContext->ThrowNativeError("Failed to locate IncrementNumMVPs function");
    1.37 +#if SOURCE_ENGINE >= SE_LEFT4DEAD
    1.38 +			interimOffset = td->fieldOffset;
    1.39 +#else
    1.40 +			interimOffset = td->fieldOffset[TD_OFFSET_NORMAL];
    1.41 +#endif
    1.42  		}
    1.43  	}
    1.44  
    1.45 -	CBaseEntity *pEntity;
    1.46 -	if (!(pEntity = GetCBaseEntity(params[1], true)))
    1.47 +	if (interimOffset == 0)
    1.48 +	{
    1.49 +		pContext->ThrowNativeError("Failed to find property \"%s\" on player.", pszBaseVar);
    1.50 +		return NULL;
    1.51 +	}
    1.52 +		
    1.53 +
    1.54 +	int tempOffset;
    1.55 +	if (!g_pGameConf->GetOffset(pszGamedataName, &tempOffset))
    1.56 +	{
    1.57 +		pContext->ThrowNativeError("Failed to locate %s offset in gamedata", pszGamedataName);
    1.58 +		return NULL;
    1.59 +	}
    1.60 +
    1.61 +	return (T *)((intptr_t)pPlayerEntity + interimOffset + tempOffset);
    1.62 +}
    1.63 +
    1.64 +template <typename T>
    1.65 +static inline cell_t GetPlayerVar(IPluginContext *pContext, const cell_t *params, const char *varName)
    1.66 +{
    1.67 +	CBaseEntity *pPlayer = GetCBaseEntity(params[1], true);
    1.68 +	if (!pPlayer)
    1.69  	{
    1.70  		return pContext->ThrowNativeError("Client index %d is not valid", params[1]);
    1.71  	}
    1.72  
    1.73 -	static int mvpOffsetOffset = -1;
    1.74 -	static int mvpOffset;
    1.75 -
    1.76 -	if (mvpOffsetOffset == -1)
    1.77 -	{
    1.78 -		if (!g_pGameConf->GetOffset("MVPCountOffset", &mvpOffsetOffset))
    1.79 -		{
    1.80 -			mvpOffsetOffset = -1;
    1.81 -			return pContext->ThrowNativeError("Unable to find MVPCountOffset gamedata");
    1.82 -		}
    1.83 -
    1.84 -		mvpOffset = *(int *)((intptr_t)addr + mvpOffsetOffset);
    1.85 +	T *pVar = GetPlayerVarAddressOrError<T>(varName, pContext, pPlayer);
    1.86 +	if (pVar)
    1.87 +	{	
    1.88 +		return (cell_t)*pVar;
    1.89  	}
    1.90  
    1.91 -	*(int *)((intptr_t)pEntity + mvpOffset) = params[2];
    1.92 +	return 0;
    1.93 +}
    1.94 +
    1.95 +template <typename T>
    1.96 +static inline cell_t SetPlayerVar(IPluginContext *pContext, const cell_t *params, const char *varName)
    1.97 +{
    1.98 +	CBaseEntity *pPlayer = GetCBaseEntity(params[1], true);
    1.99 +	if (!pPlayer)
   1.100 +	{
   1.101 +		return pContext->ThrowNativeError("Client index %d is not valid", params[1]);
   1.102 +	}
   1.103  
   1.104 -	return 1;
   1.105 +	T *pVar = GetPlayerVarAddressOrError<T>(varName, pContext, pPlayer);
   1.106 +	if (pVar)
   1.107 +	{
   1.108 +		*pVar = (T)params[2];
   1.109 +	}
   1.110 +
   1.111 +	return 0;
   1.112 +}
   1.113 +
   1.114 +static cell_t CS_SetMVPCount(IPluginContext *pContext, const cell_t *params)
   1.115 +{
   1.116 +	return SetPlayerVar<int>(pContext, params, "MVPs");
   1.117  }
   1.118  
   1.119  static cell_t CS_GetMVPCount(IPluginContext *pContext, const cell_t *params)
   1.120  {
   1.121 -	static void *addr;
   1.122 -	if (!addr)
   1.123 -	{
   1.124 -		if (!g_pGameConf->GetMemSig("IncrementNumMVPs", &addr) || !addr)
   1.125 -		{
   1.126 -			return pContext->ThrowNativeError("Failed to locate IncrementNumMVPs function");
   1.127 -		}
   1.128 -	}
   1.129 +	return GetPlayerVar<int>(pContext, params, "MVPs");
   1.130 +}
   1.131  
   1.132 -	CBaseEntity *pEntity;
   1.133 -	if (!(pEntity = GetCBaseEntity(params[1], true)))
   1.134 -	{
   1.135 -		return pContext->ThrowNativeError("Client index %d is not valid", params[1]);
   1.136 -	}
   1.137 +static cell_t CS_SetClientContributionScore(IPluginContext *pContext, const cell_t *params)
   1.138 +{
   1.139 +#if SOURCE_ENGINE == SE_CSGO
   1.140 +	return SetPlayerVar<int>(pContext, params, "CScore");
   1.141 +#else
   1.142 +	return pContext->ThrowNativeError("SetClientContributionScore is not supported on this game");
   1.143 +#endif
   1.144 +}
   1.145  
   1.146 -	static int mvpOffsetOffset = -1;
   1.147 -	static int mvpOffset;
   1.148 +static cell_t CS_GetClientContributionScore(IPluginContext *pContext, const cell_t *params)
   1.149 +{
   1.150 +#if SOURCE_ENGINE == SE_CSGO
   1.151 +	return GetPlayerVar<int>(pContext, params, "CScore");
   1.152 +#else
   1.153 +	return pContext->ThrowNativeError("GetClientContributionScore is not supported on this game");
   1.154 +#endif
   1.155 +}
   1.156  
   1.157 -	if (mvpOffsetOffset == -1)
   1.158 -	{
   1.159 -		if (!g_pGameConf->GetOffset("MVPCountOffset", &mvpOffsetOffset))
   1.160 -		{
   1.161 -			mvpOffsetOffset = -1;
   1.162 -			return pContext->ThrowNativeError("Unable to find MVPCountOffset gamedata");
   1.163 -		}
   1.164 +static cell_t CS_SetClientAssists(IPluginContext *pContext, const cell_t *params)
   1.165 +{
   1.166 +#if SOURCE_ENGINE == SE_CSGO
   1.167 +	return SetPlayerVar<int>(pContext, params, "Assists");
   1.168 +#else
   1.169 +	return pContext->ThrowNativeError("SetClientAssists is not supported on this game");
   1.170 +#endif
   1.171 +}
   1.172  
   1.173 -		mvpOffset = *(int *)((intptr_t)addr + mvpOffsetOffset);
   1.174 -	}
   1.175 -
   1.176 -	return *(int *)((intptr_t)pEntity + mvpOffset);
   1.177 +static cell_t CS_GetClientAssists(IPluginContext *pContext, const cell_t *params)
   1.178 +{
   1.179 +#if SOURCE_ENGINE == SE_CSGO
   1.180 +	return GetPlayerVar<int>(pContext, params, "Assists");
   1.181 +#else
   1.182 +	return pContext->ThrowNativeError("GetClientAssists is not supported on this game");
   1.183 +#endif
   1.184  }
   1.185  
   1.186  sp_nativeinfo_t g_CSNatives[] = 
   1.187 @@ -686,6 +748,10 @@
   1.188  	{"CS_GetMVPCount",				CS_GetMVPCount},
   1.189  	{"CS_SetMVPCount",				CS_SetMVPCount},
   1.190  	{"CS_WeaponIDToAlias",			CS_WeaponIDToAlias},
   1.191 +	{"CS_GetClientContributionScore",	CS_GetClientContributionScore},
   1.192 +	{"CS_SetClientContributionScore",	CS_SetClientContributionScore},
   1.193 +	{"CS_GetClientAssists",			CS_GetClientAssists},
   1.194 +	{"CS_SetClientAssists",			CS_SetClientAssists},
   1.195  	{NULL,							NULL}
   1.196  };
   1.197  
     2.1 --- a/gamedata/sm-cstrike.games/game.csgo.txt	Fri Dec 14 15:18:30 2012 -0500
     2.2 +++ b/gamedata/sm-cstrike.games/game.csgo.txt	Sat Dec 15 14:36:52 2012 -0500
     2.3 @@ -42,13 +42,6 @@
     2.4  				"linux"		"159"
     2.5  				"mac"		"185"
     2.6  			}
     2.7 -			//Offset into IncrementNumMVPs to find MVP count offset from player
     2.8 -			"MVPCountOffset"
     2.9 -			{
    2.10 -				"windows"	"46"
    2.11 -				"linux"		"47"
    2.12 -				"mac"		"61"
    2.13 -			}
    2.14  			"ClanTagOffset"
    2.15  			{
    2.16  				"windows"	"15"
    2.17 @@ -115,13 +108,6 @@
    2.18  				"linux"		"@_ZN12CCSGameRules17CheckRestartRoundEv"
    2.19  				"mac"		"@_ZN12CCSGameRules17CheckRestartRoundEv"
    2.20  			}
    2.21 -			"IncrementNumMVPs"
    2.22 -			{
    2.23 -				"library"	"server"
    2.24 -				"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"
    2.25 -				"linux"		"@_ZN9CCSPlayer16IncrementNumMVPsE13CSMvpReason_t"
    2.26 -				"mac"		"@_ZN9CCSPlayer16IncrementNumMVPsE13CSMvpReason_t"
    2.27 -			}
    2.28  			"AliasToWeaponID"
    2.29  			{
    2.30  				"library"	"server"
    2.31 @@ -145,4 +131,60 @@
    2.32  			}
    2.33  		}
    2.34  	}
    2.35 +	
    2.36 +	"csgo"
    2.37 +	{
    2.38 +		"Keys"
    2.39 +		{
    2.40 +			"AssistsBase"		"m_iFrags"
    2.41 +		}
    2.42 +		
    2.43 +		"Offsets"
    2.44 +		{
    2.45 +			"Assists"
    2.46 +			{
    2.47 +				"windows"	"4"
    2.48 +				"linux"		"4"
    2.49 +				"mac"		"4"
    2.50 +			}
    2.51 +		}
    2.52 +	}
    2.53 +	
    2.54 +	"csgo"
    2.55 +	{
    2.56 +		"Keys"
    2.57 +		{
    2.58 +			"CScoreBase"		"m_iWeaponPurchasesThisRound"
    2.59 +		}
    2.60 +		
    2.61 +		"Offsets"
    2.62 +		{
    2.63 +			/* factors in 256 (size of m_iWeaponPurchasesThisRound array (int size * 64 maxplayers)) */
    2.64 +			"CScore"
    2.65 +			{
    2.66 +				"windows"	"276"
    2.67 +				"linux"		"276"
    2.68 +				"mac"		"276"
    2.69 +			}
    2.70 +		}
    2.71 +	}
    2.72 +	
    2.73 +	"csgo"
    2.74 +	{
    2.75 +		"Keys"
    2.76 +		{
    2.77 +			"MVPsBase"		"m_iWeaponPurchasesThisRound"
    2.78 +		}
    2.79 +		
    2.80 +		"Offsets"
    2.81 +		{
    2.82 +			"MVPs"
    2.83 +			{
    2.84 +				/* factors in 256 (size of m_iWeaponPurchasesThisRound array (int size * 64 maxplayers)) */
    2.85 +				"windows"	"256"
    2.86 +				"linux"		"256"
    2.87 +				"mac"		"256"
    2.88 +			}
    2.89 +		}
    2.90 +	}
    2.91  }
     3.1 --- a/gamedata/sm-cstrike.games/game.css.txt	Fri Dec 14 15:18:30 2012 -0500
     3.2 +++ b/gamedata/sm-cstrike.games/game.css.txt	Sat Dec 15 14:36:52 2012 -0500
     3.3 @@ -49,13 +49,6 @@
     3.4  				"linux"		"57"
     3.5  				"mac"		"481"
     3.6  			}
     3.7 -			//Offset into IncrementNumMVPs to find MVP count offset from player
     3.8 -			"MVPCountOffset"
     3.9 -			{
    3.10 -				"windows"	"60"
    3.11 -				"linux"		"49"
    3.12 -				"mac"		"62"
    3.13 -			}
    3.14  		}
    3.15  		"Signatures"
    3.16  		{
    3.17 @@ -145,12 +138,25 @@
    3.18  				"linux"		"@_ZN12CCSGameRules13CheckWinLimitEv"
    3.19  				"mac"		"@_ZN12CCSGameRules5ThinkEv"
    3.20  			}
    3.21 -			"IncrementNumMVPs"
    3.22 +		}
    3.23 +	}
    3.24 +	
    3.25 +	"cstrike"
    3.26 +	{
    3.27 +		"Keys"
    3.28 +		{
    3.29 +			"MVPsBase"		"m_bPlayerDominatingMe"
    3.30 +		}
    3.31 +		
    3.32 +		"Offsets"
    3.33 +		{
    3.34 +			"MVPs"
    3.35  			{
    3.36 -				"library"	"server"
    3.37 -				"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"
    3.38 -				"linux"		"@_ZN9CCSPlayer16IncrementNumMVPsE13CSMvpReason_t"
    3.39 -				"mac"		"@_ZN9CCSPlayer16IncrementNumMVPsE13CSMvpReason_t"
    3.40 +				/* factors in 66 (size of m_bPlayerDominatingMe array (bool size * (65 maxplayers + 1)))
    3.41 +				... plus another 3 because alignment(?) lolidk */
    3.42 +				"windows"	"69"
    3.43 +				"linux"		"69"
    3.44 +				"mac"		"69"
    3.45  			}
    3.46  		}
    3.47  	}
     4.1 --- a/plugins/include/cstrike.inc	Fri Dec 14 15:18:30 2012 -0500
     4.2 +++ b/plugins/include/cstrike.inc	Sat Dec 15 14:36:52 2012 -0500
     4.3 @@ -285,8 +285,8 @@
     4.4  
     4.5  /**
     4.6   * Gets a client's mvp count
     4.7 - * @param client		Client index to set mvp count for.
     4.8 - * @return				Returns the clients internal MVP count.
     4.9 + * @param client		Client index to get mvp count of.
    4.10 + * @return				Returns the client's internal MVP count.
    4.11   *
    4.12   * @error				Invalid client.
    4.13   */
    4.14 @@ -295,7 +295,7 @@
    4.15  /**
    4.16   * Sets a client's mvp count
    4.17   * @param client		Client index to set mvp count for.
    4.18 - * @param value			Value to set clients mvp count as.
    4.19 + * @param value			Value to set client's mvp count as.
    4.20   * @noreturn
    4.21   *
    4.22   * @error				Invalid client.
    4.23 @@ -303,6 +303,44 @@
    4.24  native CS_SetMVPCount(client, value);
    4.25  
    4.26  /**
    4.27 + * Gets a client's contribution score (CS:GO only)
    4.28 + * @param client		Client index to get score of.
    4.29 + * @return				Returns the client's score.
    4.30 + *
    4.31 + * @error				Invalid client.
    4.32 + */
    4.33 +native CS_GetClientContributionScore(client);
    4.34 +
    4.35 +/**
    4.36 + * Sets a client's contribution score (CS:GO only)
    4.37 + * @param client		Client index to set score for.
    4.38 + * @param value			Value to set client's score as.
    4.39 + * @noreturn
    4.40 + *
    4.41 + * @error				Invalid client.
    4.42 + */
    4.43 +native CS_SetClientContributionScore(client, value);
    4.44 +
    4.45 +/**
    4.46 + * Gets a client's assists (CS:GO only)
    4.47 + * @param client		Client index to get assists of.
    4.48 + * @return				Returns the client's assists.
    4.49 + *
    4.50 + * @error				Invalid client.
    4.51 + */
    4.52 +native CS_GetClientAssists(client);
    4.53 +
    4.54 +/**
    4.55 + * Sets a client's assists (CS:GO only)
    4.56 + * @param client		Client index to set assists for.
    4.57 + * @param value			Value to set client's assists as.
    4.58 + * @noreturn
    4.59 + *
    4.60 + * @error				Invalid client.
    4.61 + */
    4.62 +native CS_SetClientAssists(client, value);
    4.63 +
    4.64 +/**
    4.65   * Gets a weaponID from a alias
    4.66   * @param alias			Weapon alias to attempt to get an id for.
    4.67   * @return				Returns a weapon id or 0 if failed to find a match.
    4.68 @@ -350,6 +388,10 @@
    4.69  	MarkNativeAsOptional("CS_SetTeamScore");
    4.70  	MarkNativeAsOptional("CS_GetMVPCount");
    4.71  	MarkNativeAsOptional("CS_SetMVPCount");
    4.72 +	MarkNativeAsOptional("CS_GetClientContributionScore");
    4.73 +	MarkNativeAsOptional("CS_SetClientContributionScore");
    4.74 +	MarkNativeAsOptional("CS_GetClientAssists");
    4.75 +	MarkNativeAsOptional("CS_SetClientAssists");
    4.76  	MarkNativeAsOptional("CS_AliasToWeaponID");
    4.77  }
    4.78  #endif
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/plugins/testsuite/cstrike-test.sp	Sat Dec 15 14:36:52 2012 -0500
     5.3 @@ -0,0 +1,94 @@
     5.4 +#include <sourcemod>
     5.5 +#include <cstrike>
     5.6 +
     5.7 +stock GET_ARG_INT( arg, maxSize=64 )
     5.8 +{
     5.9 +	decl String:tempvar[maxSize];
    5.10 +	GetCmdArg( arg, tempvar, maxSize );
    5.11 +	return StringToInt( tempvar );
    5.12 +}
    5.13 +
    5.14 +public OnPluginStart()
    5.15 +{
    5.16 +	RegConsoleCmd( "get_mvps",    get_mvps    );
    5.17 +	RegConsoleCmd( "set_mvps",    set_mvps    );
    5.18 +	RegConsoleCmd( "get_score",   get_score   );
    5.19 +	RegConsoleCmd( "set_score",   set_score   );
    5.20 +	RegConsoleCmd( "get_assists", get_assists );
    5.21 +	RegConsoleCmd( "set_assists", set_assists );
    5.22 +}
    5.23 +
    5.24 +public Action:get_mvps( client, argc )
    5.25 +{
    5.26 +	ReplyToCommand( client, "Your MVP count is %d", CS_GetMVPCount( client ) );
    5.27 +	
    5.28 +	return Plugin_Handled;
    5.29 +}
    5.30 +
    5.31 +public Action:set_mvps( client, argc )
    5.32 +{
    5.33 +	new count = GET_ARG_INT( 1 );
    5.34 +	
    5.35 +	CS_SetMVPCount( client, count );
    5.36 +	ReplyToCommand( client, "Set your MVP count to %d", count );
    5.37 +	
    5.38 +	return Plugin_Handled;
    5.39 +}
    5.40 +
    5.41 +public Action:get_score( client, argc )
    5.42 +{
    5.43 +	if( GuessSDKVersion() != SOURCE_SDK_CSGO )
    5.44 +	{
    5.45 +		ReplyToCommand( client, "This command is only intended for CS:GO" );
    5.46 +		return Plugin_Handled;
    5.47 +	}
    5.48 +	
    5.49 +	ReplyToCommand( client, "Your contribution score is %d", CS_GetClientContributionScore( client ) );
    5.50 +
    5.51 +	return Plugin_Handled;
    5.52 +}
    5.53 +
    5.54 +public Action:set_score( client, argc )
    5.55 +{
    5.56 +	if( GuessSDKVersion() != SOURCE_SDK_CSGO )
    5.57 +	{
    5.58 +		ReplyToCommand( client, "This command is only intended for CS:GO" );
    5.59 +		return Plugin_Handled;
    5.60 +	}
    5.61 +	
    5.62 +	new count = GET_ARG_INT( 1 );
    5.63 +	
    5.64 +	CS_SetClientContributionScore( client, count );
    5.65 +	ReplyToCommand( client, "Set your contribution score to %d", count );
    5.66 +
    5.67 +	return Plugin_Handled;
    5.68 +}
    5.69 +
    5.70 +public Action:get_assists( client, argc )
    5.71 +{
    5.72 +	if( GuessSDKVersion() != SOURCE_SDK_CSGO )
    5.73 +	{
    5.74 +		ReplyToCommand( client, "This command is only intended for CS:GO" );
    5.75 +		return Plugin_Handled;
    5.76 +	}
    5.77 +	
    5.78 +	ReplyToCommand( client, "Your assist count is %d", CS_GetClientAssists( client ) );
    5.79 +
    5.80 +	return Plugin_Handled;
    5.81 +}
    5.82 +
    5.83 +public Action:set_assists( client, argc )
    5.84 +{
    5.85 +	if( GuessSDKVersion() != SOURCE_SDK_CSGO )
    5.86 +	{
    5.87 +		ReplyToCommand( client, "This command is only intended for CS:GO" );
    5.88 +		return Plugin_Handled;
    5.89 +	}
    5.90 +	
    5.91 +	new count = GET_ARG_INT( 1 );
    5.92 +	
    5.93 +	CS_SetClientAssists( client, count );
    5.94 +	ReplyToCommand( client, "Set your assist count to %d", count );
    5.95 +
    5.96 +	return Plugin_Handled;
    5.97 +}