Update CS:GO team score gamedata.
3 * =============================================================================
4 * SourceMod SDKTools Extension
5 * Copyright (C) 2004-2010 AlliedModders LLC. All rights reserved.
6 * =============================================================================
8 * This program is free software; you can redistribute it and/or modify it under
9 * the terms of the GNU General Public License, version 3.0, as published by the
10 * Free Software Foundation.
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
17 * You should have received a copy of the GNU General Public License along with
18 * this program. If not, see <http://www.gnu.org/licenses/>.
20 * As a special exception, AlliedModders LLC gives you permission to link the
21 * code of this program (as well as its derivative works) to "Half-Life 2," the
22 * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
23 * by the Valve Corporation. You must obey the GNU General Public License in
24 * all respects for all other code used. Additionally, AlliedModders LLC grants
25 * this exception to all derivative works. AlliedModders LLC defines further
26 * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
27 * or <http://www.sourcemod.net/license.php>.
32 #include "extension.h"
37 CallHelper s_Teleport;
38 CallHelper s_GetVelocity;
39 CallHelper s_EyeAngles;
41 class CTraceFilterSimple : public CTraceFilterEntitiesOnly
44 CTraceFilterSimple(const IHandleEntity *passentity): m_pPassEnt(passentity)
47 virtual bool ShouldHitEntity(IHandleEntity *pServerEntity, int contentsMask)
49 if (pServerEntity == m_pPassEnt)
56 const IHandleEntity *m_pPassEnt;
63 return s_Teleport.supported;
68 if (g_pGameConf->GetOffset("Teleport", &offset))
71 info[0].flags = info[1].flags = info[2].flags = PASSFLAG_BYVAL;
72 info[0].size = info[1].size = info[2].size = sizeof(void *);
73 info[0].type = info[1].type = info[2].type = PassType_Basic;
75 s_Teleport.call = g_pBinTools->CreateVCall(offset, 0, 0, NULL, info, 3);
77 if (s_Teleport.call != NULL)
79 s_Teleport.supported = true;
83 s_Teleport.setup = true;
85 return s_Teleport.supported;
88 void Teleport(CBaseEntity *pEntity, Vector *origin, QAngle *ang, Vector *velocity)
90 unsigned char params[sizeof(void *) * 4];
91 unsigned char *vptr = params;
92 *(CBaseEntity **)vptr = pEntity;
93 vptr += sizeof(CBaseEntity *);
94 *(Vector **)vptr = origin;
95 vptr += sizeof(Vector *);
96 *(QAngle **)vptr = ang;
97 vptr += sizeof(QAngle *);
98 *(Vector **)vptr = velocity;
100 s_Teleport.call->Execute(params, NULL);
103 bool IsTeleportSupported()
105 return SetupTeleport();
108 bool SetupGetVelocity()
110 if (s_GetVelocity.setup)
112 return s_GetVelocity.supported;
116 if (g_pGameConf->GetOffset("GetVelocity", &offset))
119 info[0].flags = info[1].flags = PASSFLAG_BYVAL;
120 info[0].size = info[1].size = sizeof(void *);
121 info[0].type = info[1].type = PassType_Basic;
123 s_GetVelocity.call = g_pBinTools->CreateVCall(offset, 0, 0, NULL, info, 2);
125 if (s_GetVelocity.call != NULL)
127 s_GetVelocity.supported = true;
131 s_GetVelocity.setup = true;
133 return s_GetVelocity.supported;
136 void GetVelocity(CBaseEntity *pEntity, Vector *velocity, AngularImpulse *angvelocity)
138 unsigned char params[sizeof(void *) * 3];
139 unsigned char *vptr = params;
140 *(CBaseEntity **)vptr = pEntity;
141 vptr += sizeof(CBaseEntity *);
142 *(Vector **)vptr = velocity;
143 vptr += sizeof(Vector *);
144 *(AngularImpulse **)vptr = angvelocity;
146 s_GetVelocity.call->Execute(params, NULL);
149 bool IsGetVelocitySupported()
151 return SetupGetVelocity();
154 bool SetupGetEyeAngles()
156 if (s_EyeAngles.setup)
158 return s_EyeAngles.supported;
162 if (g_pGameConf->GetOffset("EyeAngles", &offset))
165 info[0].flags = PASSFLAG_BYVAL;
166 info[0].size = sizeof(void *);
167 info[0].type = PassType_Basic;
169 s_EyeAngles.call = g_pBinTools->CreateVCall(offset, 0, 0, info, NULL, 0);
171 if (s_EyeAngles.call != NULL)
173 s_EyeAngles.supported = true;
177 s_EyeAngles.setup = true;
179 return s_EyeAngles.supported;
182 bool GetEyeAngles(CBaseEntity *pEntity, QAngle *pAngles)
184 if (!IsEyeAnglesSupported())
189 QAngle *pRetAngle = NULL;
190 unsigned char params[sizeof(void *)];
191 unsigned char *vptr = params;
193 *(CBaseEntity **)vptr = pEntity;
195 s_EyeAngles.call->Execute(params, &pRetAngle);
197 if (pRetAngle == NULL)
202 *pAngles = *pRetAngle;
207 int GetClientAimTarget(edict_t *pEdict, bool only_players)
209 CBaseEntity *pEntity = pEdict->GetUnknown() ? pEdict->GetUnknown()->GetBaseEntity() : NULL;
219 /* Get the private information we need */
220 #if SOURCE_ENGINE == SE_DOTA
221 serverClients->ClientEarPosition(IndexOfEdict(pEdict), &eye_position);
223 serverClients->ClientEarPosition(pEdict, &eye_position);
226 if (!GetEyeAngles(pEntity, &eye_angles))
232 AngleVectors(eye_angles, &aim_dir);
233 VectorNormalize(aim_dir);
235 Vector vec_end = eye_position + aim_dir * 8000;
238 ray.Init(eye_position, vec_end);
241 CTraceFilterSimple simple(pEdict->GetIServerEntity());
243 enginetrace->TraceRay(ray, MASK_SOLID|CONTENTS_DEBRIS|CONTENTS_HITBOX, &simple, &tr);
245 if (tr.fraction == 1.0f || tr.m_pEnt == NULL)
250 int ent_ref = gamehelpers->EntityToBCompatRef(tr.m_pEnt);
251 int ent_index = gamehelpers->ReferenceToIndex(ent_ref);
253 IGamePlayer *pTargetPlayer = playerhelpers->GetGamePlayer(ent_index);
254 if (pTargetPlayer != NULL && !pTargetPlayer->IsInGame())
258 else if (only_players && pTargetPlayer == NULL)
266 bool IsEyeAnglesSupported()
268 return SetupGetEyeAngles();
271 bool GetPlayerInfo(int client, player_info_t *info)
273 #if SOURCE_ENGINE >= SE_ORANGEBOX
274 return engine->GetPlayerInfo(client, info);
276 return (iserver) ? iserver->GetPlayerInfo(client-1, info) : false;
280 void ShutdownHelpers()
282 s_Teleport.Shutdown();
283 s_GetVelocity.Shutdown();
284 s_EyeAngles.Shutdown();
287 bool FindNestedDataTable(SendTable *pTable, const char *name)
289 if (strcmp(pTable->GetName(), name) == 0)
294 int props = pTable->GetNumProps();
297 for (int i=0; i<props; i++)
299 prop = pTable->GetProp(i);
300 if (prop->GetDataTable())
302 if (FindNestedDataTable(prop->GetDataTable(), name))
312 char *UTIL_SendFlagsToString(int flags, int type)
314 static char str[1024];
317 if (flags & SPROP_UNSIGNED)
319 strcat(str, "Unsigned|");
321 if (flags & SPROP_COORD)
323 strcat(str, "Coord|");
325 if (flags & SPROP_NOSCALE)
327 strcat(str, "NoScale|");
329 if (flags & SPROP_ROUNDDOWN)
331 strcat(str, "RoundDown|");
333 if (flags & SPROP_ROUNDUP)
335 strcat(str, "RoundUp|");
337 if (flags & SPROP_NORMAL)
341 strcat(str, "VarInt|");
345 strcat(str, "Normal|");
348 if (flags & SPROP_EXCLUDE)
350 strcat(str, "Exclude|");
352 if (flags & SPROP_XYZE)
354 strcat(str, "XYZE|");
356 if (flags & SPROP_INSIDEARRAY)
358 strcat(str, "InsideArray|");
360 if (flags & SPROP_PROXY_ALWAYS_YES)
362 strcat(str, "AlwaysProxy|");
364 if (flags & SPROP_CHANGES_OFTEN)
366 strcat(str, "ChangesOften|");
368 if (flags & SPROP_IS_A_VECTOR_ELEM)
370 strcat(str, "VectorElem|");
372 if (flags & SPROP_COLLAPSIBLE)
374 strcat(str, "Collapsible|");
376 #if SOURCE_ENGINE >= SE_ORANGEBOX
377 if (flags & SPROP_COORD_MP)
379 strcat(str, "CoordMP|");
381 if (flags & SPROP_COORD_MP_LOWPRECISION)
383 strcat(str, "CoordMPLowPrec|");
385 if (flags & SPROP_COORD_MP_INTEGRAL)
387 strcat(str, "CoordMpIntegral|");
391 int len = strlen(str) - 1;
394 str[len] = 0; // Strip the final '|'
400 void UTIL_DrawSendTable_XML(FILE *fp, SendTable *pTable, int space_count)
404 for (int i = 0; i < space_count; i++)
408 spaces[space_count] = '\0';
410 const char *type_name;
411 SendTable *pOtherTable;
414 fprintf(fp, " %s<sendtable name=\"%s\">\n", spaces, pTable->GetName());
415 for (int i = 0; i < pTable->GetNumProps(); i++)
417 pProp = pTable->GetProp(i);
419 fprintf(fp, " %s<property name=\"%s\">\n", spaces, pProp->GetName());
421 if ((type_name = GetDTTypeName(pProp->GetType())) != NULL)
423 fprintf(fp, " %s<type>%s</type>\n", spaces, type_name);
427 fprintf(fp, " %s<type>%d</type>\n", spaces, pProp->GetType());
430 fprintf(fp, " %s<offset>%d</offset>\n", spaces, pProp->GetOffset());
431 fprintf(fp, " %s<bits>%d</bits>\n", spaces, pProp->m_nBits);
432 fprintf(fp, " %s<flags>%s</flags>\n", spaces, UTIL_SendFlagsToString(pProp->GetFlags(), pProp->GetType()));
434 if ((pOtherTable = pTable->GetProp(i)->GetDataTable()) != NULL)
436 UTIL_DrawSendTable_XML(fp, pOtherTable, space_count + 3);
439 fprintf(fp, " %s</property>\n", spaces);
441 fprintf(fp, " %s</sendtable>\n", spaces);
444 void UTIL_DrawServerClass_XML(FILE *fp, ServerClass *sc)
446 fprintf(fp, "<serverclass name=\"%s\">\n", sc->GetName());
447 UTIL_DrawSendTable_XML(fp, sc->m_pTable, 0);
448 fprintf(fp, "</serverclass>\n");
451 void UTIL_DrawSendTable(FILE *fp, SendTable *pTable, int level = 1)
456 for (int i = 0; i < pTable->GetNumProps(); i++)
458 pProp = pTable->GetProp(i);
459 if (pProp->GetDataTable())
461 fprintf(fp, "%*sTable: %s (offset %d) (type %s)\n",
465 pProp->GetDataTable()->GetName());
467 UTIL_DrawSendTable(fp, pProp->GetDataTable(), level + 1);
471 type = GetDTTypeName(pProp->GetType());
476 "%*sMember: %s (offset %d) (type %s) (bits %d) (%s)\n",
482 UTIL_SendFlagsToString(pProp->GetFlags(), pProp->GetType()));
487 "%*sMember: %s (offset %d) (type %d) (bits %d) (%s)\n",
493 UTIL_SendFlagsToString(pProp->GetFlags(), pProp->GetType()));
499 CON_COMMAND(sm_dump_netprops_xml, "Dumps the networkable property table as an XML file")
501 #if SOURCE_ENGINE <= SE_DARKMESSIAH
507 META_CONPRINT("Usage: sm_dump_netprops_xml <file>\n");
511 const char *file = args.Arg(1);
512 if (!file || file[0] == '\0')
514 META_CONPRINT("Usage: sm_dump_netprops_xml <file>\n");
518 char path[PLATFORM_MAX_PATH];
519 g_pSM->BuildPath(Path_Game, path, sizeof(path), "%s", file);
522 if ((fp = fopen(path, "wt")) == NULL)
524 META_CONPRINTF("Could not open file \"%s\"\n", path);
528 fprintf(fp, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n");
529 fprintf(fp, "<!-- Dump of all network properties for \"%s\" follows -->\n\n", g_pSM->GetGameFolderName());
531 ServerClass *pBase = gamedll->GetAllServerClasses();
532 while (pBase != NULL)
534 UTIL_DrawServerClass_XML(fp, pBase);
535 pBase = pBase->m_pNext;
541 CON_COMMAND(sm_dump_netprops, "Dumps the networkable property table as a text file")
543 #if SOURCE_ENGINE <= SE_DARKMESSIAH
549 META_CONPRINT("Usage: sm_dump_netprops <file>\n");
553 const char *file = args.Arg(1);
554 if (!file || file[0] == '\0')
556 META_CONPRINT("Usage: sm_dump_netprops <file>\n");
560 char path[PLATFORM_MAX_PATH];
561 g_pSM->BuildPath(Path_Game, path, sizeof(path), "%s", file);
564 if ((fp = fopen(path, "wt")) == NULL)
566 META_CONPRINTF("Could not open file \"%s\"\n", path);
570 fprintf(fp, "// Dump of all network properties for \"%s\" follows\n//\n\n", g_pSM->GetGameFolderName());
572 ServerClass *pBase = gamedll->GetAllServerClasses();
573 while (pBase != NULL)
575 fprintf(fp, "%s (type %s)\n", pBase->GetName(), pBase->m_pTable->GetName());
576 UTIL_DrawSendTable(fp, pBase->m_pTable);
577 pBase = pBase->m_pNext;
583 #if defined SUBPLATFORM_SECURECRT
584 void _ignore_invalid_parameter(
585 const wchar_t * expression,
586 const wchar_t * function,
587 const wchar_t * file,
592 /* Wow we don't care, thanks Microsoft. */
596 CEntityFactoryDictionary *GetEntityFactoryDictionary()
598 static CEntityFactoryDictionary *dict = NULL;
600 #if SOURCE_ENGINE == SE_TF2 \
601 || SOURCE_ENGINE == SE_CSS \
602 || SOURCE_ENGINE == SE_DODS \
603 || SOURCE_ENGINE == SE_HL2DM \
604 || SOURCE_ENGINE == SE_SDK2013 \
605 || SOURCE_ENGINE == SE_NUCLEARDAWN
606 dict = (CEntityFactoryDictionary *) servertools->GetEntityFactoryDictionary();
611 if (g_pGameConf->GetMemSig("EntityFactoryFinder", (void **) &addr) && addr)
614 if (!g_pGameConf->GetOffset("EntityFactoryOffset", &offset) || !offset)
618 dict = *reinterpret_cast<CEntityFactoryDictionary **>((intptr_t) addr + offset);
624 ICallWrapper *pWrapper = NULL;
627 retData.flags = PASSFLAG_BYVAL;
628 retData.size = sizeof(void *);
629 retData.type = PassType_Basic;
632 if (!g_pGameConf->GetMemSig("EntityFactory", &addr) || !addr)
636 if (!g_pGameConf->GetMemSig("EntityFactoryCaller", &addr) || !addr)
639 if (!g_pGameConf->GetOffset("EntityFactoryCallOffset", &offset))
642 // Get relative offset to function
643 int32_t funcOffset = *(int32_t *)((intptr_t)addr + offset);
645 // Get real address of function
646 // Address of signature + offset of relative offset + sizeof(int32_t) offset + relative offset
647 addr = (void *)((intptr_t)addr + offset + 4 + funcOffset);
650 pWrapper = g_pBinTools->CreateCall(addr, CallConv_Cdecl, &retData, NULL, 0);
654 void *returnData = NULL;
656 pWrapper->Execute(NULL, &returnData);
660 if (returnData == NULL)
665 dict = (CEntityFactoryDictionary *) returnData;
673 CON_COMMAND(sm_dump_classes, "Dumps the class list as a text file")
675 #if SOURCE_ENGINE <= SE_DARKMESSIAH
681 META_CONPRINT("Usage: sm_dump_classes <file>\n");
685 const char *file = args.Arg(1);
686 if (!file || file[0] == '\0')
688 META_CONPRINT("Usage: sm_dump_classes <file>\n");
692 CEntityFactoryDictionary *dict = GetEntityFactoryDictionary();
695 META_CONPRINT("Failed to locate function\n");
699 char path[PLATFORM_MAX_PATH];
700 g_pSM->BuildPath(Path_Game, path, sizeof(path), "%s", file);
703 if ((fp = fopen(path, "wt")) == NULL)
705 META_CONPRINTF("Could not open file \"%s\"\n", path);
712 #if defined SUBPLATFORM_SECURECRT
713 _invalid_parameter_handler handler = _set_invalid_parameter_handler(_ignore_invalid_parameter);
716 time_t t = g_pSM->GetAdjustedTime();
717 size_t written = strftime(buffer, sizeof(buffer), "%d/%m/%Y", localtime(&t));
719 #if defined SUBPLATFORM_SECURECRT
720 _set_invalid_parameter_handler(handler);
723 fprintf(fp, "// Dump of all classes for \"%s\" as at %s\n//\n\n", g_pSM->GetGameFolderName(), buffer);
725 sm_datatable_info_t info;
726 for ( int i = dict->m_Factories.First(); i != dict->m_Factories.InvalidIndex(); i = dict->m_Factories.Next( i ) )
728 IServerNetworkable *entity = dict->Create(dict->m_Factories.GetElementName(i));
729 ServerClass *sclass = entity->GetServerClass();
730 fprintf(fp,"%s - %s\n",sclass->GetName(), dict->m_Factories.GetElementName(i));
732 if (!gamehelpers->FindDataMapInfo(gamehelpers->GetDataMap(entity->GetBaseEntity()), "m_iEFlags", &info))
735 int *eflags = (int *)((char *)entity->GetBaseEntity() + info.actual_offset);
736 *eflags |= (1<<0); // EFL_KILLME
743 char *UTIL_DataFlagsToString(int flags)
745 static char str[1024];
748 if (flags & FTYPEDESC_GLOBAL)
750 strcat(str, "Global|");
752 if (flags & FTYPEDESC_SAVE)
754 strcat(str, "Save|");
756 if (flags & FTYPEDESC_KEY)
760 if (flags & FTYPEDESC_INPUT)
762 strcat(str, "Input|");
764 if (flags & FTYPEDESC_OUTPUT)
766 strcat(str, "Output|");
768 if (flags & FTYPEDESC_FUNCTIONTABLE)
770 strcat(str, "FunctionTable|");
772 if (flags & FTYPEDESC_PTR)
776 if (flags & FTYPEDESC_OVERRIDE)
778 strcat(str, "Override|");
781 int len = strlen(str) - 1;
784 str[len] = 0; // Strip the final '|'
790 void UTIL_DrawDataTable(FILE *fp, datamap_t *pMap, int level)
794 for (int i=0; i<level; i++)
799 spaces[level] = '\0';
801 const char *externalname;
806 for (int i=0; i<pMap->dataNumFields; i++)
808 if (pMap->dataDesc[i].fieldName == NULL)
813 if (pMap->dataDesc[i].td)
815 fprintf(fp, " %sSub-Class Table (%d Deep): %s - %s\n", spaces, level+1, pMap->dataDesc[i].fieldName, pMap->dataDesc[i].td->dataClassName);
816 UTIL_DrawDataTable(fp, pMap->dataDesc[i].td, level+1);
820 externalname = pMap->dataDesc[i].externalName;
821 flags = UTIL_DataFlagsToString(pMap->dataDesc[i].flags);
823 if (externalname == NULL)
825 fprintf(fp,"%s- %s (%s)(%i Bytes)\n", spaces, pMap->dataDesc[i].fieldName, flags, pMap->dataDesc[i].fieldSizeInBytes);
829 fprintf(fp,"%s- %s (%s)(%i Bytes) - %s\n", spaces, pMap->dataDesc[i].fieldName, flags, pMap->dataDesc[i].fieldSizeInBytes, externalname);
833 pMap = pMap->baseMap;
837 CON_COMMAND(sm_dump_datamaps, "Dumps the data map list as a text file")
839 #if SOURCE_ENGINE <= SE_DARKMESSIAH
845 META_CONPRINT("Usage: sm_dump_datamaps <file>\n");
849 const char *file = args.Arg(1);
850 if (!file || file[0] == '\0')
852 META_CONPRINT("Usage: sm_dump_datamaps <file>\n");
856 CEntityFactoryDictionary *dict = GetEntityFactoryDictionary();
859 META_CONPRINT("Failed to locate function\n");
863 char path[PLATFORM_MAX_PATH];
864 g_pSM->BuildPath(Path_Game, path, sizeof(path), "%s", file);
867 if ((fp = fopen(path, "wt")) == NULL)
869 META_CONPRINTF("Could not open file \"%s\"\n", path);
876 #if defined SUBPLATFORM_SECURECRT
877 _invalid_parameter_handler handler = _set_invalid_parameter_handler(_ignore_invalid_parameter);
880 time_t t = g_pSM->GetAdjustedTime();
881 size_t written = strftime(buffer, sizeof(buffer), "%d/%m/%Y", localtime(&t));
883 #if defined SUBPLATFORM_SECURECRT
884 _set_invalid_parameter_handler(handler);
887 fprintf(fp, "// Dump of all datamaps for \"%s\" as at %s\n//\n//\n", g_pSM->GetGameFolderName(), buffer);
890 fprintf(fp, "// Flag Details:\n//\n");
892 fprintf(fp, "// Global: This field is masked for global entity save/restore\n");
893 fprintf(fp, "// Save: This field is saved to disk\n");
894 fprintf(fp, "// Key: This field can be requested and written to by string name at load time\n");
895 fprintf(fp, "// Input: This field can be written to by string name at run time, and a function called\n");
896 fprintf(fp, "// Output: This field propogates it's value to all targets whenever it changes\n");
897 fprintf(fp, "// FunctionTable: This is a table entry for a member function pointer\n");
898 fprintf(fp, "// Ptr: This field is a pointer, not an embedded object\n");
899 fprintf(fp, "// Override: The field is an override for one in a base class (only used by prediction system for now)\n");
901 fprintf(fp, "//\n\n");
903 static int offsEFlags = -1;
904 for ( int i = dict->m_Factories.First(); i != dict->m_Factories.InvalidIndex(); i = dict->m_Factories.Next( i ) )
906 IServerNetworkable *entity = dict->Create(dict->m_Factories.GetElementName(i));
907 ServerClass *sclass = entity->GetServerClass();
908 datamap_t *pMap = gamehelpers->GetDataMap(entity->GetBaseEntity());
910 fprintf(fp,"%s - %s\n", sclass->GetName(), dict->m_Factories.GetElementName(i));
912 UTIL_DrawDataTable(fp, pMap, 0);
914 if (offsEFlags == -1)
916 sm_datatable_info_t info;
917 if (!gamehelpers->FindDataMapInfo(pMap, "m_iEFlags", &info))
922 offsEFlags = info.actual_offset;
925 int *eflags = (int *)((char *)entity->GetBaseEntity() + offsEFlags);
926 *eflags |= (1<<0); // EFL_KILLME