cssdm_utils.cpp
author Ruben Gonzalez <drifter01620@gmail.com>
Wed Oct 01 11:50:24 2014 -0400 (2014-10-01)
changeset 193 277c856152b0
parent 139 df5cbb604269
permissions -rw-r--r--
Update linix CS:GO gamedata
     1 /**
     2  * vim: set ts=4 :
     3  * ===============================================================
     4  * CS:S DM, Copyright (C) 2004-2007 AlliedModders LLC. 
     5  * By David "BAILOPAN" Anderson
     6  * All rights reserved.
     7  * ===============================================================
     8  *
     9  * This program is free software; you can redistribute it and/or modify
    10  * it under the terms of the GNU General Public License as published by
    11  * the Free Software Foundation; either version 2 of the License, or (at
    12  * your option) any later version.
    13  * 
    14  * This program is distributed in the hope that it will be useful, but
    15  * WITHOUT ANY WARRANTY; without even the implied warranty of
    16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    17  * General Public License for more details.
    18  * 
    19  * You should have received a copy of the GNU General Public License
    20  * along with this program; see the file COPYING; if not, write to the
    21  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
    22  * MA 02110-1301 USA
    23  * 
    24  * Version: $Id$
    25  */
    26 
    27 #include "cssdm_headers.h"
    28 #include "cssdm_players.h"
    29 #include "cssdm_utils.h"
    30 #include "cssdm_includesdk.h"
    31 #include <sh_list.h>
    32 #include <sh_memory.h>
    33 
    34 using namespace SourceHook;
    35 
    36 List<ICallWrapper *> g_CallWrappers;
    37 ICallWrapper *g_pRoundRespawn = NULL;
    38 ICallWrapper *g_pWeaponGetSlot = NULL;
    39 ICallWrapper *g_pDropWeapon = NULL;
    40 ICallWrapper *g_pRemoveAllItems = NULL;
    41 ICallWrapper *g_pGiveAmmo = NULL;
    42 int g_RagdollOffset = 0;
    43 int g_LifeStateOffset = 0;
    44 int g_DefuserOffset = 0;
    45 
    46 void DM_ProtectMemory(void *addr, int length, int prot);
    47 
    48 CBaseEntity *DM_GetBaseEntity(int index)
    49 {
    50 	edict_t *pEdict = gamehelpers->EdictOfIndex(index);
    51 	if (!pEdict || pEdict->IsFree())
    52 	{
    53 		return NULL;
    54 	}
    55 	IServerUnknown *pUnknown = pEdict->GetUnknown();
    56 	if (!pUnknown)
    57 	{
    58 		return NULL;
    59 	}
    60 	return pUnknown->GetBaseEntity();
    61 }
    62 
    63 CBaseEntity *DM_GetAndClearRagdoll(CBaseEntity *pEntity, int &serial)
    64 {
    65 	if (!g_RagdollOffset)
    66 	{
    67 		return NULL;
    68 	}
    69 
    70 	unsigned char *ptr = (unsigned char *)pEntity + g_RagdollOffset;
    71 	CBaseHandle &ph = *(CBaseHandle *)ptr;
    72 
    73 	if (!ph.IsValid())
    74 	{
    75 		return NULL;
    76 	}
    77 
    78 	int index = ph.GetEntryIndex();
    79 	serial = ph.GetSerialNumber();
    80 
    81 	if (!index)
    82 	{
    83 		return NULL;
    84 	}
    85 
    86 	CBaseEntity *pRagdoll = DM_GetBaseEntity(index);
    87 
    88 	ph.Set(NULL);
    89 
    90 	return pRagdoll;
    91 }
    92 
    93 void DM_RespawnPlayer(int client)
    94 {
    95 	dm_player_t *player = DM_GetPlayer(client);
    96 	if (!player || !player->pEntity)
    97 	{
    98 		return;
    99 	}
   100 
   101 	if (player->respawn_timer)
   102 	{
   103 		timersys->KillTimer(player->respawn_timer);
   104 		player->respawn_timer = NULL;
   105 	}
   106 
   107 	CBaseEntity *pEntity = player->pEntity;
   108 	g_pRoundRespawn->Execute(&pEntity, NULL);
   109 }
   110 
   111 class variant_t
   112 {
   113 public:
   114 	union
   115 	{
   116 		bool bVal;
   117 		string_t iszVal;
   118 		int iVal;
   119 		float flVal;
   120 		float vecVal[3];
   121 		color32 rgbaVal;
   122 	};
   123 	CBaseHandle eVal; // this can't be in the union because it has a constructor.
   124 	fieldtype_t fieldType;
   125 };
   126 
   127 struct inputdata_t
   128 {
   129 	CBaseEntity *pActivator;		// The entity that initially caused this chain of output events.
   130 	CBaseEntity *pCaller;			// The entity that fired this particular output.
   131 	variant_t value;				// The data parameter for this output.
   132 	int nOutputID;					// The unique ID of the output that was fired.
   133 };
   134 
   135 void DM_RemoveEntity(CBaseEntity *pEntity)
   136 {
   137 	datamap_t *pMap = gamehelpers->GetDataMap(pEntity);
   138 
   139 	if(!pMap)
   140 		return;
   141 
   142 	typedescription_t *pDesc = gamehelpers->FindInDataMap(pMap, "InputKill");
   143 
   144 	if(!pDesc)
   145 		return;
   146 
   147 	inputdata_t data;
   148 	(pEntity->*pDesc->inputFunc)(data);
   149 }
   150 
   151 bool DM_IsPlayerAlive(int client)
   152 {
   153 	dm_player_t *player = DM_GetPlayer(client);
   154 	if (!player || !player->pEntity || !g_LifeStateOffset)
   155 	{
   156 		return false;
   157 	}
   158 
   159 	if (!g_LifeStateOffset)
   160 	{
   161 		return player->pInfo->IsDead() ? false : true;
   162 	}
   163 
   164 	unsigned char *ptr = (unsigned char *)(player->pEntity) + g_LifeStateOffset;
   165 	return (*(char *)ptr == LIFE_ALIVE);
   166 }
   167 
   168 bool DM_CheckSerial(edict_t *pEdict, int serial)
   169 {
   170 	int new_serial = (serial & ((1 << NUM_NETWORKED_EHANDLE_SERIAL_NUMBER_BITS) - 1));
   171 	return (pEdict->m_NetworkSerialNumber == new_serial);
   172 }
   173 
   174 CBaseEntity *DM_GetWeaponFromSlot(CBaseEntity *pEntity, int slot)
   175 {
   176 	unsigned char vstk[sizeof(CBaseEntity *) + sizeof(int)];
   177 	*(CBaseEntity **)(&vstk[0]) = pEntity;
   178 	*(int *)(&vstk[sizeof(CBaseEntity *)]) = slot;
   179 
   180 	CBaseEntity *pWeapon = NULL;
   181 
   182 	g_pWeaponGetSlot->Execute(vstk, &pWeapon);
   183 
   184 	return pWeapon;
   185 }
   186 
   187 void DM_DropWeapon(CBaseEntity *pEntity, CBaseEntity *pWeapon)
   188 {
   189 	unsigned char vstk[sizeof(CBaseEntity *) * 2 + sizeof(bool) * 2];
   190 	unsigned char *vptr = vstk;
   191 
   192 	*(CBaseEntity **)vptr = pEntity;
   193 	vptr += sizeof(CBaseEntity *);
   194 	*(CBaseEntity **)vptr = pWeapon;
   195 	vptr += sizeof(CBaseEntity *);
   196 	*(bool *)vptr = true;
   197 	vptr += sizeof(bool);
   198 	*(bool *)vptr = false;
   199 	//vptr += sizeof(bool);
   200 
   201 	g_pDropWeapon->Execute(vstk, NULL);
   202 }
   203 
   204 void DM_RemoveAllItems(CBaseEntity *pEntity, bool removeSuit)
   205 {
   206 	unsigned char vstk[sizeof(CBaseEntity *) + sizeof(bool)];
   207 	unsigned char *vptr = vstk;
   208 
   209 	*(CBaseEntity **)vptr = pEntity;
   210 	vptr += sizeof(CBaseEntity *);
   211 	*(bool *)vptr = removeSuit;
   212 	//vptr += sizeof(bool);
   213 
   214 	g_pRemoveAllItems->Execute(vstk, NULL);
   215 }
   216 
   217 void DM_SetDefuseKit(CBaseEntity *pEntity, bool defuseKit)
   218 {
   219 	if (!g_DefuserOffset)
   220 	{
   221 		return;
   222 	}
   223 
   224 	*(bool *)((unsigned char *)pEntity + g_DefuserOffset) = defuseKit;
   225 }
   226 
   227 int DM_GiveAmmo(CBaseEntity *pEntity, int type, int count, bool noSound)
   228 {
   229 	unsigned char vstk[sizeof(CBaseEntity *) + sizeof(int)*2 + sizeof(bool)];
   230 	unsigned char *vptr = vstk;
   231 
   232 	*(CBaseEntity **)vptr = pEntity;
   233 	vptr += sizeof(CBaseEntity *);
   234 	*(int *)vptr = count;
   235 	vptr += sizeof(int);
   236 	*(int *)vptr = type;
   237 	vptr += sizeof(int);
   238 	*(bool *)vptr = noSound;
   239 	//vptr += sizeof(bool);
   240 
   241 	int ret;
   242 	g_pGiveAmmo->Execute(vstk, &ret);
   243 
   244 	return ret;
   245 }
   246 
   247 size_t DM_StringToBytes(const char *str, unsigned char buffer[], size_t maxlength)
   248 {
   249 	size_t real_bytes = 0;
   250 	size_t length = strlen(str);
   251 
   252 	for (size_t i=0; i<length; i++)
   253 	{
   254 		if (real_bytes >= maxlength)
   255 		{
   256 			break;
   257 		}
   258 		buffer[real_bytes++] = (unsigned char)str[i];
   259 		if (str[i] == '\\'
   260 			&& str[i+1] == 'x')
   261 		{
   262 			if (i + 3 >= length)
   263 			{
   264 				continue;
   265 			}
   266 			/* Get the hex part */
   267 			char s_byte[3];
   268 			int r_byte;
   269 			s_byte[0] = str[i+2];
   270 			s_byte[1] = str[i+3];
   271 			s_byte[2] = '\n';
   272 			/* Read it as an integer */
   273 			sscanf(s_byte, "%x", &r_byte);
   274 			/* Save the value */
   275 			buffer[real_bytes-1] = (unsigned char)r_byte;
   276 			/* Adjust index */
   277 			i += 3;
   278 		}
   279 	}
   280 
   281 	return real_bytes;
   282 }
   283 
   284 void DM_ApplyPatch(void *address, int offset, const dmpatch_t *patch, dmpatch_t *restore)
   285 {
   286 	unsigned char *addr = (unsigned char *)address + offset;
   287 
   288 	SourceHook::SetMemAccess(addr, 20, SH_MEM_READ|SH_MEM_WRITE|SH_MEM_EXEC);
   289 
   290 	if (restore)
   291 	{
   292 		for (size_t i=0; i<patch->bytes; i++)
   293 		{
   294 			restore->patch[i] = addr[i];
   295 		}
   296 		restore->bytes = patch->bytes;
   297 	}
   298 
   299 	for (size_t i=0; i<patch->bytes; i++)
   300 	{
   301 		addr[i] = patch->patch[i];
   302 	}
   303 }
   304 
   305 void DM_SetMemPatchable(void *address, size_t size)
   306 {
   307 	SourceHook::SetMemAccess(address, (int)size, SH_MEM_READ|SH_MEM_WRITE|SH_MEM_EXEC);
   308 }
   309 
   310 #define GET_PROPERTY(cls, name, var) \
   311 	if ( (prop = gamehelpers->FindInSendTable(cls, name)) == NULL ) { \
   312 		snprintf(error, maxlength, "Could not find property: %s", name); \
   313 		return false; \
   314 	} \
   315 	var = prop->GetOffset();
   316 
   317 bool InitializeUtils(char *error, size_t maxlength)
   318 {
   319 	void *addr;
   320 	int offset;
   321 	SourceMod::PassInfo pass[4];
   322 
   323 	/** ROUNDRESPAWN */
   324 	g_pDmConf->GetMemSig("RoundRespawn", &addr);
   325 	g_pRoundRespawn = bintools->CreateCall(addr, CallConv_ThisCall, NULL, NULL, 0);
   326 	g_CallWrappers.push_back(g_pRoundRespawn);
   327 	
   328 	/** WEAPON_GETSLOT */
   329 	g_pDmConf->GetOffset("Weapon_GetSlot", &offset);
   330 	pass[0].flags = PASSFLAG_BYVAL;
   331 	pass[0].size = sizeof(int);
   332 	pass[0].type = PassType_Basic;
   333 	pass[1].flags = PASSFLAG_BYVAL;
   334 	pass[1].size = sizeof(CBaseEntity *);
   335 	pass[1].type = PassType_Basic;
   336 	g_pWeaponGetSlot = bintools->CreateVCall(offset, 0, 0, &pass[1], &pass[0], 1);
   337 	g_CallWrappers.push_back(g_pWeaponGetSlot);
   338 
   339 	/** CSWEAPONDROP */
   340 	g_pDmConf->GetMemSig("CSWeaponDrop", &addr);
   341 	pass[0].flags = pass[1].flags = pass[2].flags  = PASSFLAG_BYVAL;
   342 	pass[0].type = pass[1].type = pass[2].type = PassType_Basic;
   343 	pass[0].size = sizeof(CBaseEntity *);
   344 	pass[1].size = pass[2].size = sizeof(bool);
   345 	g_pDropWeapon = bintools->CreateCall(addr, CallConv_ThisCall, NULL, pass, 3);
   346 	g_CallWrappers.push_back(g_pDropWeapon);
   347 
   348 	/** REMOVEALLITEMS */
   349 	g_pDmConf->GetOffset("RemoveAllItems", &offset);
   350 	pass[0].flags = PASSFLAG_BYVAL;
   351 	pass[0].size = sizeof(bool);
   352 	pass[0].type = PassType_Basic;
   353 	g_pRemoveAllItems = bintools->CreateVCall(offset, 0, 0, NULL, pass, 1);
   354 	g_CallWrappers.push_back(g_pRemoveAllItems);
   355 
   356 	/** GIVEAMMO */
   357 	g_pDmConf->GetOffset("GiveAmmo", &offset);
   358 	pass[0].flags = pass[1].flags = pass[2].flags = pass[3].flags = PASSFLAG_BYVAL;
   359 	pass[0].size = pass[1].size = pass[2].size = sizeof(int);
   360 	pass[3].size = sizeof(bool);
   361 	pass[0].type = pass[1].type = pass[2].type = pass[3].type = PassType_Basic;
   362 	g_pGiveAmmo = bintools->CreateVCall(offset, 0, 0, &pass[3], pass, 3);
   363 	g_CallWrappers.push_back(g_pGiveAmmo);
   364 
   365 	/** PROPERTIES */
   366 	sm_sendprop_info_t prop;
   367 	if(!gamehelpers->FindSendPropInfo("CCSPlayer", "m_hRagdoll", &prop))
   368 	{
   369 		snprintf(error, maxlength, "Failed to get prop info for m_hRagdoll");
   370 		return false;
   371 	}
   372 	g_RagdollOffset = prop.actual_offset;
   373 	if(!gamehelpers->FindSendPropInfo("CCSPlayer", "m_lifeState", &prop))
   374 	{
   375 		snprintf(error, maxlength, "Failed to get prop info for m_lifeState");
   376 		return false;
   377 	}
   378 	g_LifeStateOffset = prop.actual_offset;
   379 	if(!gamehelpers->FindSendPropInfo("CCSPlayer", "m_bHasDefuser", &prop))
   380 	{
   381 		snprintf(error, maxlength, "Failed to get prop info for m_bHasDefuser");
   382 		return false;
   383 	}
   384 	g_DefuserOffset = prop.actual_offset;
   385 
   386 	return true;
   387 }
   388 
   389 void ShutdownUtils()
   390 {
   391 	List<ICallWrapper *>::iterator iter;
   392 	for (iter = g_CallWrappers.begin();
   393 		 iter != g_CallWrappers.end();
   394 		 iter++)
   395 	{
   396 		(*iter)->Destroy();
   397 	}
   398 	g_CallWrappers.clear();
   399 }