11/* *
22 * =============================================================================
3- * CS2Fixes
4- * Copyright (C) 2023 Source2ZE
3+ * CS2ServerGUI
4+ * Copyright (C) 2023-2025 Source2ZE
55 * =============================================================================
66 *
77 * This program is free software; you can redistribute it and/or modify it under
1919
2020#include " schema.h"
2121
22- #include " schemasystem/schemasystem.h"
23- #include " tier1/utlmap.h"
24- #include " tier0/memdbgon.h"
2522#include " entity/cbaseentity.h"
26- #include " interfaces .h"
27- #include " ../utils/plat .h"
23+ #include " utils/plat .h"
24+ #include " schemasystem/schemasystem .h"
2825
29- extern CGlobalVars *gpGlobals;
26+ # include " tier0/memdbgon.h "
3027
31- using SchemaKeyValueMap_t = CUtlMap <uint32_t , SchemaKey>;
32- using SchemaTableMap_t = CUtlMap <uint32_t , SchemaKeyValueMap_t* >;
28+ using SchemaKeyValueMap_t = std::map <uint32_t , SchemaKey>;
29+ using SchemaTableMap_t = std::map <uint32_t , SchemaKeyValueMap_t>;
3330
31+ static constexpr uint32_t g_ChainKey = hash_32_fnv1a_const(" __m_pChainEntity" );
3432
3533static bool IsFieldNetworked (SchemaClassFieldData_t& field)
3634{
37- for (int i = 0 ; i < field.m_nStaticMetadataCount ; i++)
38- {
39- static auto networkEnabled = hash_32_fnv1a_const (" MNetworkEnable" );
40- if (networkEnabled == hash_32_fnv1a_const (field.m_pStaticMetadata [i].m_pszName ))
41- return true ;
42- }
35+ for (int i = 0 ; i < field.m_nStaticMetadataCount ; i++)
36+ {
37+ static auto networkEnabled = hash_32_fnv1a_const (" MNetworkEnable" );
38+ if (networkEnabled == hash_32_fnv1a_const (field.m_pStaticMetadata [i].m_pszName ))
39+ return true ;
40+ }
41+
42+ return false ;
43+ }
4344
44- return false ;
45- }
45+ // Try to recursively find __m_pChainEntity in base classes
46+ // (e.g. CCSGameRules -> CTeamplayRules -> CMultiplayRules -> CGameRules, in this case it's in CGameRules)
47+ static void InitChainOffset (SchemaClassInfoData_t *pClassInfo, SchemaKeyValueMap_t &keyValueMap)
48+ {
49+ short fieldsSize = pClassInfo->m_nFieldCount ;
50+ SchemaClassFieldData_t* pFields = pClassInfo->m_pFields ;
51+
52+ for (int i = 0 ; i < fieldsSize; ++i)
53+ {
54+ SchemaClassFieldData_t& field = pFields[i];
55+
56+ if (hash_32_fnv1a_const (field.m_pszName ) != g_ChainKey)
57+ continue ;
58+
59+ std::pair<uint32_t , SchemaKey> keyValuePair;
60+ keyValuePair.first = g_ChainKey;
61+ keyValuePair.second .offset = field.m_nSingleInheritanceOffset ;
62+ keyValuePair.second .networked = IsFieldNetworked (field);
63+
64+ keyValueMap.insert (keyValuePair);
65+ return ;
66+ }
67+
68+ // Not the base class yet, keep looking
69+ if (pClassInfo->m_nBaseClassCount )
70+ return InitChainOffset (pClassInfo->m_pBaseClasses [0 ].m_pClass , keyValueMap);
71+ }
4672
47- static bool InitSchemaFieldsForClass (SchemaTableMap_t *tableMap, const char * className, uint32_t classKey )
73+ static void InitSchemaKeyValueMap (SchemaClassInfoData_t *pClassInfo, SchemaKeyValueMap_t& keyValueMap )
4874{
49- CSchemaSystemTypeScope* pType = Interfaces::g_pSchemaSystem2->FindTypeScopeForModule (MODULE_PREFIX " server" MODULE_EXT);
75+ short fieldsSize = pClassInfo->m_nFieldCount ;
76+ SchemaClassFieldData_t* pFields = pClassInfo->m_pFields ;
5077
51- if (!pType)
52- return false ;
78+ for (int i = 0 ; i < fieldsSize; ++i)
79+ {
80+ SchemaClassFieldData_t& field = pFields[i];
5381
54- SchemaClassInfoData_t* pClassInfo = pType->FindDeclaredClass (className).Get ();
82+ #ifdef _DEBUG
83+ Message (" %s::%s found at -> 0x%X - %llx\n " , pClassInfo->m_pszName , field.m_pszName , field.m_nSingleInheritanceOffset , &field);
84+ #endif
5585
56- if (!pClassInfo)
57- {
58- SchemaKeyValueMap_t *map = new SchemaKeyValueMap_t ( 0 , 0 , DefLessFunc ( uint32_t )) ;
59- tableMap-> Insert (classKey, map );
86+ std::pair< uint32_t , SchemaKey> keyValuePair;
87+ keyValuePair. first = hash_32_fnv1a_const (field. m_pszName );
88+ keyValuePair. second . offset = field. m_nSingleInheritanceOffset ;
89+ keyValuePair. second . networked = IsFieldNetworked (field );
6090
61- Warning (" InitSchemaFieldsForClass(): '%s' was not found!\n " , className);
62- return false ;
63- }
91+ keyValueMap.insert (keyValuePair);
92+ }
6493
65- short fieldsSize = pClassInfo->m_nFieldCount ;
66- SchemaClassFieldData_t* pFields = pClassInfo->m_pFields ;
94+ // If this is a child class there might be a parent class with __m_pChainEntity
95+ if (!keyValueMap.contains (g_ChainKey) && pClassInfo->m_nBaseClassCount )
96+ InitChainOffset (pClassInfo->m_pBaseClasses [0 ].m_pClass , keyValueMap);
97+ }
6798
68- SchemaKeyValueMap_t *keyValueMap = new SchemaKeyValueMap_t ( 0 , 0 , DefLessFunc ( uint32_t ));
69- keyValueMap-> EnsureCapacity (fieldsSize);
70- tableMap-> Insert (classKey, keyValueMap );
99+ static bool InitSchemaFieldsForClass (SchemaTableMap_t& tableMap, const char * className, uint32_t classKey)
100+ {
101+ CSchemaSystemTypeScope* pType = g_pSchemaSystem-> FindTypeScopeForModule (MODULE_PREFIX " server " MODULE_EXT );
71102
72- for (int i = 0 ; i < fieldsSize; ++i)
73- {
74- SchemaClassFieldData_t& field = pFields[i];
103+ if (!pType)
104+ return false ;
75105
76- #ifdef _DEBUG
77- Message (" %s::%s found at -> 0x%X - %llx\n " , className, field.m_pszName , field.m_nSingleInheritanceOffset , &field);
78- #endif
106+ SchemaClassInfoData_t* pClassInfo = pType->FindDeclaredClass (className).Get ();
107+
108+ if (!pClassInfo)
109+ {
110+ SchemaKeyValueMap_t map;
111+ tableMap.insert (std::make_pair (classKey, map));
112+
113+ Warning (" InitSchemaFieldsForClass(): '%s' was not found!\n " , className);
114+ return false ;
115+ }
79116
80- keyValueMap->Insert (hash_32_fnv1a_const (field.m_pszName ), {field.m_nSingleInheritanceOffset , IsFieldNetworked (field)});
81- }
117+ SchemaKeyValueMap_t& keyValueMap = tableMap.insert (std::make_pair (classKey, SchemaKeyValueMap_t ())).first ->second ;
82118
83- return true ;
119+ InitSchemaKeyValueMap (pClassInfo, keyValueMap);
120+
121+ return true ;
84122}
85123
86- int16_t schema::FindChainOffset (const char * className)
124+ int16_t schema::FindChainOffset (const char * className, uint32_t classNameHash )
87125{
88- CSchemaSystemTypeScope* pType = Interfaces::g_pSchemaSystem2->FindTypeScopeForModule (MODULE_PREFIX " server" MODULE_EXT);
126+ return schema::GetOffset (className, classNameHash, " __m_pChainEntity" , g_ChainKey).offset ;
127+ }
89128
90- if (!pType)
91- return false ;
129+ SchemaKey schema::GetOffset (const char * className, uint32_t classKey, const char * memberName, uint32_t memberKey)
130+ {
131+ static SchemaTableMap_t schemaTableMap;
92132
93- SchemaClassInfoData_t* pClassInfo = pType->FindDeclaredClass (className).Get ();
133+ if (!schemaTableMap.contains (classKey))
134+ {
135+ if (InitSchemaFieldsForClass (schemaTableMap, className, classKey))
136+ return GetOffset (className, classKey, memberName, memberKey);
94137
95- do
96- {
97- SchemaClassFieldData_t* pFields = pClassInfo->m_pFields ;
98- short fieldsSize = pClassInfo->m_nFieldCount ;
99- for (int i = 0 ; i < fieldsSize; ++i)
100- {
101- SchemaClassFieldData_t& field = pFields[i];
138+ return {0 , 0 };
139+ }
102140
103- if (V_strcmp (field.m_pszName , " __m_pChainEntity" ) == 0 )
104- {
105- return field.m_nSingleInheritanceOffset ;
106- }
107- }
108- } while ((pClassInfo = pClassInfo->m_pBaseClasses ->m_pClass ) != nullptr );
141+ SchemaKeyValueMap_t tableMap = schemaTableMap[classKey];
109142
110- return 0 ;
111- }
143+ if (!tableMap.contains (memberKey))
144+ {
145+ if (memberKey != g_ChainKey)
146+ Warning (" schema::GetOffset(): '%s' was not found in '%s'!\n " , memberName, className);
112147
113- SchemaKey schema::GetOffset (const char * className, uint32_t classKey, const char * memberName, uint32_t memberKey)
114- {
115- static SchemaTableMap_t schemaTableMap (0 , 0 , DefLessFunc (uint32_t ));
116- int16_t tableMapIndex = schemaTableMap.Find (classKey);
117- if (!schemaTableMap.IsValidIndex (tableMapIndex))
118- {
119- if (InitSchemaFieldsForClass (&schemaTableMap, className, classKey))
120- return GetOffset (className, classKey, memberName, memberKey);
121-
122- return { 0 , 0 };
123- }
124-
125- SchemaKeyValueMap_t *tableMap = schemaTableMap[tableMapIndex];
126- int16_t memberIndex = tableMap->Find (memberKey);
127- if (!tableMap->IsValidIndex (memberIndex))
128- {
129- Warning (" schema::GetOffset(): '%s' was not found in '%s'!\n " , memberName, className);
130- return { 0 , 0 };
131- }
132-
133- return tableMap->Element (memberIndex);
148+ return {0 , 0 };
149+ }
150+
151+ return tableMap[memberKey];
134152}
0 commit comments