extensions/cstrike/natives.cpp
changeset 3313 2ddc75e24c53
parent 3054 960d8c019a32
child 3324 e981678907dd
     1.1 --- a/extensions/cstrike/natives.cpp	Sat Jun 25 15:31:11 2011 -0700
     1.2 +++ b/extensions/cstrike/natives.cpp	Sun Jun 26 01:25:42 2011 -0700
     1.3 @@ -31,10 +31,11 @@
     1.4  
     1.5  #include "extension.h"
     1.6  #include "RegNatives.h"
     1.7 +#include <server_class.h>
     1.8  
     1.9  #define REGISTER_NATIVE_ADDR(name, code) \
    1.10  	void *addr; \
    1.11 -	if (!g_pGameConf->GetMemSig(name, &addr)) \
    1.12 +	if (!g_pGameConf->GetMemSig(name, &addr) || !addr) \
    1.13  	{ \
    1.14  		return pContext->ThrowNativeError("Failed to locate function"); \
    1.15  	} \
    1.16 @@ -71,6 +72,59 @@
    1.17  	return pUnk->GetBaseEntity();
    1.18  }
    1.19  
    1.20 +bool UTIL_FindDataTable(SendTable *pTable, const char *name, sm_sendprop_info_t *info, unsigned int offset)
    1.21 +{
    1.22 +	const char *pname;
    1.23 +	int props = pTable->GetNumProps();
    1.24 +	SendProp *prop;
    1.25 +	SendTable *table;
    1.26 +
    1.27 +	for (int i=0; i<props; i++)
    1.28 +	{
    1.29 +		prop = pTable->GetProp(i);
    1.30 +
    1.31 +		if ((table = prop->GetDataTable()) != NULL)
    1.32 +		{
    1.33 +			pname = table->GetName();
    1.34 +			if (pname && strcmp(name, pname) == 0)
    1.35 +			{
    1.36 +				info->prop = prop;
    1.37 +				info->actual_offset = offset + info->prop->GetOffset();
    1.38 +				return true;
    1.39 +			}
    1.40 +
    1.41 +			if (UTIL_FindDataTable(table, 
    1.42 +				name,
    1.43 +				info,
    1.44 +				offset + prop->GetOffset())
    1.45 +				)
    1.46 +			{
    1.47 +				return true;
    1.48 +			}
    1.49 +		}
    1.50 +	}
    1.51 +
    1.52 +	return false;
    1.53 +}
    1.54 +
    1.55 +//Taken From Sourcemod Core
    1.56 +unsigned int strncopy(char *dest, const char *src, size_t count)
    1.57 +{
    1.58 +	if (!count)
    1.59 +	{
    1.60 +		return 0;
    1.61 +	}
    1.62 +
    1.63 +	char *start = dest;
    1.64 +	while ((*src) && (--count))
    1.65 +	{
    1.66 +		*dest++ = *src++;
    1.67 +	}
    1.68 +	*dest = '\0';
    1.69 +
    1.70 +	return (dest - start);
    1.71 +}
    1.72 +
    1.73  static cell_t CS_RespawnPlayer(IPluginContext *pContext, const cell_t *params)
    1.74  {
    1.75  	static ICallWrapper *pWrapper = NULL;
    1.76 @@ -120,10 +174,165 @@
    1.77  	return 1;
    1.78  }
    1.79  
    1.80 +static cell_t CS_DropWeapon(IPluginContext *pContext, const cell_t *params)
    1.81 +{
    1.82 +	static ICallWrapper *pWrapper = NULL;
    1.83 +	if (!pWrapper)
    1.84 +	{
    1.85 +		REGISTER_NATIVE_ADDR("CSWeaponDrop",
    1.86 +			PassInfo pass[3]; \
    1.87 +			pass[0].flags = PASSFLAG_BYVAL; \
    1.88 +			pass[0].type  = PassType_Basic; \
    1.89 +			pass[0].size  = sizeof(CBaseEntity *); \
    1.90 +			pass[1].flags = PASSFLAG_BYVAL; \
    1.91 +			pass[1].type  = PassType_Basic; \
    1.92 +			pass[1].size  = sizeof(bool); \
    1.93 +			pass[2].flags = PASSFLAG_BYVAL; \
    1.94 +			pass[2].type  = PassType_Basic; \
    1.95 +			pass[2].size  = sizeof(bool); \
    1.96 +			pWrapper = g_pBinTools->CreateCall(addr, CallConv_ThisCall, NULL, pass, 3))
    1.97 +	}
    1.98 +
    1.99 +	CBaseEntity *pEntity;
   1.100 +	if (!(pEntity = GetCBaseEntity(params[1], true)))
   1.101 +	{
   1.102 +		return pContext->ThrowNativeError("Client index %d is not valid", params[1]);
   1.103 +	}
   1.104 +
   1.105 +	CBaseEntity *pWeapon;
   1.106 +	if (!(pWeapon = GetCBaseEntity(params[2], false)))
   1.107 +	{
   1.108 +		return pContext->ThrowNativeError("Weapon index %d is not valid", params[2]);
   1.109 +	}
   1.110 +
   1.111 +	//Psychonic is awesome for this
   1.112 +	sm_sendprop_info_t *spi = new sm_sendprop_info_t;
   1.113 +	IServerUnknown *pUnk = (IServerUnknown *)pWeapon;
   1.114 +	IServerNetworkable *pNet = pUnk->GetNetworkable();
   1.115 +
   1.116 +	if (!UTIL_FindDataTable(pNet->GetServerClass()->m_pTable, "DT_WeaponCSBase", spi, 0))
   1.117 +		return pContext->ThrowNativeError("Entity index %d is not a weapon", params[2]);
   1.118 +
   1.119 +	if (!gamehelpers->FindSendPropInfo("CBaseCombatWeapon", "m_hOwnerEntity", spi))
   1.120 +		return pContext->ThrowNativeError("Invalid entity index %d for weapon", params[2]);
   1.121 +
   1.122 +	CBaseHandle &hndl = *(CBaseHandle *)((uint8_t *)pWeapon + spi->actual_offset);
   1.123 +	if (params[1] != hndl.GetEntryIndex())
   1.124 +		return pContext->ThrowNativeError("Weapon %d is not owned by client %d", params[2], params[1]);
   1.125 +
   1.126 +	if (params[4] == 1 && g_pCSWeaponDropDetoured)
   1.127 +		g_pIgnoreCSWeaponDropDetour = true;
   1.128 +
   1.129 +	unsigned char vstk[sizeof(CBaseEntity *) * 2 + sizeof(bool) * 2];
   1.130 +	unsigned char *vptr = vstk;
   1.131 +
   1.132 +	// <psychonic> first one is always false. second is true to toss, false to just drop
   1.133 +	*(CBaseEntity **)vptr = pEntity;
   1.134 +	vptr += sizeof(CBaseEntity *);
   1.135 +	*(CBaseEntity **)vptr = pWeapon;
   1.136 +	vptr += sizeof(CBaseEntity *);
   1.137 +	*(bool *)vptr = false;
   1.138 +	vptr += sizeof(bool);
   1.139 +	*(bool *)vptr = (params[3]) ? true : false;
   1.140 +
   1.141 + 	pWrapper->Execute(vstk, NULL);
   1.142 +
   1.143 +	return 1;
   1.144 +}
   1.145 +
   1.146 +static cell_t CS_TerminateRound(IPluginContext *pContext, const cell_t *params)
   1.147 +{
   1.148 +	if (g_pSDKTools == NULL)
   1.149 +	{
   1.150 +		smutils->LogError(myself, "SDKTools interface not found. TerminateRound native disabled.");
   1.151 +	}
   1.152 +	else if (g_pSDKTools->GetInterfaceVersion() < 2)
   1.153 +	{
   1.154 +		//<psychonic> THIS ISN'T DA LIMBO STICK. LOW IS BAD
   1.155 +		return pContext->ThrowNativeError("SDKTools interface is outdated. TerminateRound native disabled.");
   1.156 +	}
   1.157 +
   1.158 +	static ICallWrapper *pWrapper = NULL;
   1.159 +
   1.160 +	if (!pWrapper)
   1.161 +	{
   1.162 +		REGISTER_NATIVE_ADDR("TerminateRound",
   1.163 +			PassInfo pass[2]; \
   1.164 +			pass[0].flags = PASSFLAG_BYVAL; \
   1.165 +			pass[0].type = PassType_Basic; \
   1.166 +			pass[0].size = sizeof(float); \
   1.167 +			pass[1].flags = PASSFLAG_BYVAL; \
   1.168 +			pass[1].type = PassType_Basic; \
   1.169 +			pass[1].size = sizeof(int); \
   1.170 +			pWrapper = g_pBinTools->CreateCall(addr, CallConv_ThisCall, NULL, pass, 2))
   1.171 +	}
   1.172 +
   1.173 +	void *gamerules = g_pSDKTools->GetGameRules();
   1.174 +	if (gamerules == NULL)
   1.175 +	{
   1.176 +		return pContext->ThrowNativeError("GameRules not available. TerminateRound native disabled.");
   1.177 +	}
   1.178 +
   1.179 +	if (params[3] == 1 && g_pTerminateRoundDetoured)
   1.180 +		g_pIgnoreTerminateDetour = true;
   1.181 +
   1.182 +	unsigned char vstk[sizeof(void *) + sizeof(float)+ sizeof(int)];
   1.183 +	unsigned char *vptr = vstk;
   1.184 +
   1.185 +	*(void **)vptr = gamerules;
   1.186 +	vptr += sizeof(void *);
   1.187 +	*(float *)vptr = sp_ctof(params[1]);
   1.188 +	vptr += sizeof(float);
   1.189 +	*(int*)vptr = params[2];
   1.190 +
   1.191 +	pWrapper->Execute(vstk, NULL);
   1.192 +
   1.193 +	return 1;
   1.194 +}
   1.195 +
   1.196 +static cell_t CS_GetTranslatedWeaponAlias(IPluginContext *pContext, const cell_t *params)
   1.197 +{
   1.198 +	static ICallWrapper *pWrapper = NULL;
   1.199 +
   1.200 +	if (!pWrapper)
   1.201 +	{
   1.202 +		REGISTER_NATIVE_ADDR("GetTranslatedWeaponAlias",
   1.203 +			PassInfo pass[1]; \
   1.204 +			PassInfo retpass[1]; \
   1.205 +			pass[0].flags = PASSFLAG_BYVAL; \
   1.206 +			pass[0].type = PassType_Basic; \
   1.207 +			pass[0].size = sizeof(char *); \
   1.208 +			retpass[0].flags = PASSFLAG_BYVAL; \
   1.209 +			retpass[0].type = PassType_Basic; \
   1.210 +			retpass[0].size = sizeof(char *); \
   1.211 +			pWrapper = g_pBinTools->CreateCall(addr, CallConv_Cdecl, &retpass[0], pass, 1))
   1.212 +	}
   1.213 +	char *dest, *weapon;
   1.214 +
   1.215 +	pContext->LocalToString(params[2], &dest);
   1.216 +	pContext->LocalToString(params[1], &weapon);
   1.217 +
   1.218 +	char *ret = new char[128];
   1.219 +
   1.220 +	unsigned char vstk[sizeof(char *)];
   1.221 +	unsigned char *vptr = vstk;
   1.222 +
   1.223 +	*(char **)vptr = weapon;
   1.224 +
   1.225 +	pWrapper->Execute(vstk, &ret);
   1.226 +
   1.227 +	strncopy(dest, ret, params[3]);
   1.228 +	
   1.229 +	return 1;
   1.230 +}
   1.231 +
   1.232  sp_nativeinfo_t g_CSNatives[] = 
   1.233  {
   1.234  	{"CS_RespawnPlayer",			CS_RespawnPlayer}, 
   1.235 -	{"CS_SwitchTeam",				CS_SwitchTeam}, 
   1.236 +	{"CS_SwitchTeam",				CS_SwitchTeam},
   1.237 +	{"CS_DropWeapon",				CS_DropWeapon},
   1.238 +	{"CS_TerminateRound",			CS_TerminateRound},
   1.239 +	{"CS_GetTranslatedWeaponAlias",	CS_GetTranslatedWeaponAlias},
   1.240  	{NULL,							NULL}
   1.241  };
   1.242