This should work on any Source Engine game. Enjoy.
Could be better but I wrote and tested this in under 15 minutes.
CNetVarMgr.h
Code:
class CNetVarMgr_NetVar
{
public:
CNetVarMgr_NetVar(const char* DataTable_Name = NULL, const char* NetVar_Name = NULL, RecvVarProxyFn Hook_Proxy = NULL);
const char* GetDataTableName();
void SetDataTableName(const char* DataTable_Name = NULL);
const char* GetNetVarName();
void SetNetVarName(const char* NetVar_Name = NULL);
int GetOffset();
void SetOffset(int Offset = NULL);
RecvVarProxyFn GetOriginalProxy();
void SetOriginalProxy(RecvVarProxyFn Original_Proxy = NULL);
RecvVarProxyFn GetHookProxy();
void SetHookProxy(RecvVarProxyFn Hook_Proxy = NULL);
private:
const char* datatable_name = NULL;
const char* netvar_name = NULL;
int offset = NULL;
RecvVarProxyFn original_proxy = NULL;
RecvVarProxyFn hook_proxy = NULL;
};
class CNetVarMgr_Que
{
public:
CNetVarMgr_Que(const char* DataTable_Name, CNetVarMgr_NetVar* &Manager_Variable);
const char* GetDataTableName();
void SetDataTableName(const char* DataTable_Name = NULL);
CNetVarMgr_NetVar* GetNetVar(UINT Index = NULL);
CNetVarMgr_NetVar* GetNetVar(const char* NetVar_Name = NULL);
void AddNetVar(CNetVarMgr_NetVar* &Manager_Variable);
CNetVarMgr_NetVar* Back();
void Clear();
private:
const char* datatable_name;
std::vector<CNetVarMgr_NetVar*>netvars;
};
class CNetVarMgr
{
public:
void Initialize();
CNetVarMgr_Que* GetQue(UINT Index = NULL);
CNetVarMgr_Que* GetQue(const char* DataTable_Name = NULL);
void Get(const char* DataTable_Name, const char* NetVar_Name, CNetVarMgr_NetVar* &Manager_Variable, RecvVarProxyFn Hook_Proxy = NULL);
void CreateQue();
void RunQue();
void ClearQue();
// PUT NETVAR MANAGER VARIABLES HERE
// EXAMPLE:
// CNetVarMgr_NetVar* m_angEyeAngles_x;
private:
std::vector<CNetVarMgr_Que*>que;
};
extern CNetVarMgr g_NetVarMgr;
CNetVarMgr.cpp
Code:
#include "CNetVarMgr.h"
CNetVarMgr g_NetVarMgr;
void CNetVarMgr::CreateQue()
{
// GET AND HOOK NETVARS HERE
// Get(DATATABLE_NAME, NETVAR_NAME, NETVAR_MANAGER_VARIABLE, NETVAR_PROXY_HOOK)
// GET EXAMPLE:
// Get("DT_GMOD_Player", "m_angEyeAngles[0]", m_angEyeAngles_x);
// HOOK EXAMPLE:
// Get("DT_GMOD_Player", "m_angEyeAngles[0]", m_angEyeAngles_x, Hooked_m_angEyeAngles_x);
}
void CNetVarMgr::Initialize()
{
CreateQue();
RunQue();
ClearQue();
}
CNetVarMgr_Que* CNetVarMgr::GetQue(UINT Index)
{
return que[Index];
}
CNetVarMgr_Que* CNetVarMgr::GetQue(const char* DataTable_Name)
{
CNetVarMgr_Que* output_que = nullptr;
for (UINT i = 0; i < que.size(); i++)
{
CNetVarMgr_Que* tmp_que = GetQue(i);
if (tmp_que)
{
if (strcmp(tmp_que->GetDataTableName(), DataTable_Name) == 0)
{
output_que = tmp_que;
break;
}
}
}
return output_que;
}
void CNetVarMgr::Get(const char* DataTable_Name, const char* NetVar_Name, CNetVarMgr_NetVar* &Manager_Variable, RecvVarProxyFn Hook_Proxy)
{
Manager_Variable = new CNetVarMgr_NetVar(DataTable_Name, NetVar_Name, Hook_Proxy);
CNetVarMgr_Que* tmp_que = GetQue(DataTable_Name);
if (tmp_que)
{
tmp_que->AddNetVar(Manager_Variable);
}
else
{
que.push_back(new CNetVarMgr_Que(DataTable_Name, Manager_Variable));
}
}
void CNetVarMgr::RunQue()
{
for (ClientClass* clientclass = g_pClient->GetAllClasses(); clientclass; clientclass = clientclass->m_pNext)
{
RecvTable* classtbl = clientclass->m_pRecvTable;
CNetVarMgr_Que* tmp_que = GetQue(classtbl->GetName());
if (tmp_que)
{
RecvProp* props[3];
CNetVarMgr_NetVar* tmp_netvars[3];
for (int n1 = 0; n1 < classtbl->GetNumProps(); ++n1)
{
props[0] = classtbl->GetProp(n1);
if (isdigit(props[0]->m_pVarName[0]))
continue;
tmp_netvars[0] = tmp_que->GetNetVar(props[0]->GetName());
if (tmp_netvars[0])
{
tmp_netvars[0]->SetOffset(props[0]->GetOffset());
tmp_netvars[0]->SetOriginalProxy(props[0]->GetProxyFn());
if (tmp_netvars[0]->GetHookProxy())
{
props[0]->SetProxyFn(tmp_netvars[0]->GetHookProxy());
}
}
if (!props[0]->m_pDataTable)
continue;
for (int n2 = 0; n2 < props[0]->m_pDataTable->m_nProps; ++n2)
{
props[1] = props[0]->m_pDataTable->GetProp(n2);
if (isdigit(props[1]->m_pVarName[0]))
continue;
tmp_netvars[1] = tmp_que->GetNetVar(props[1]->GetName());
if (tmp_netvars[1])
{
tmp_netvars[1]->SetOffset(props[1]->GetOffset());
tmp_netvars[1]->SetOriginalProxy(props[1]->GetProxyFn());
if (tmp_netvars[1]->GetHookProxy())
{
props[1]->SetProxyFn(tmp_netvars[1]->GetHookProxy());
}
}
if (!props[1]->m_pDataTable)
continue;
for (int n3 = 0; n3 < props[1]->m_pDataTable->m_nProps; ++n3)
{
props[2] = props[1]->m_pDataTable->GetProp(n3);
if (isdigit(props[2]->m_pVarName[0]))
continue;
tmp_netvars[2] = tmp_que->GetNetVar(props[2]->GetName());
if (tmp_netvars[2])
{
tmp_netvars[2]->SetOffset(props[2]->GetOffset());
tmp_netvars[2]->SetOriginalProxy(props[2]->GetProxyFn());
if (tmp_netvars[2]->GetHookProxy())
{
props[2]->SetProxyFn(tmp_netvars[2]->GetHookProxy());
}
}
}
}
}
}
}
}
void CNetVarMgr::ClearQue()
{
for (UINT i = 0; i < que.size(); i++)
{
CNetVarMgr_Que* tmp_que = GetQue(i);
if (tmp_que)
{
tmp_que->Clear();
}
}
que.clear();
}
CNetVarMgr_Que::CNetVarMgr_Que(const char* DataTable_Name, CNetVarMgr_NetVar* &Manager_Variable)
{
SetDataTableName(DataTable_Name);
AddNetVar(Manager_Variable);
}
const char* CNetVarMgr_Que::GetDataTableName()
{
return datatable_name;
}
void CNetVarMgr_Que::SetDataTableName(const char* DataTable_Name)
{
datatable_name = DataTable_Name;
}
CNetVarMgr_NetVar* CNetVarMgr_Que::GetNetVar(UINT Index)
{
return netvars[Index];
}
CNetVarMgr_NetVar* CNetVarMgr_Que::GetNetVar(const char* NetVar_Name)
{
CNetVarMgr_NetVar* output_netvar = nullptr;
for (UINT i = 0; i < netvars.size(); i++)
{
CNetVarMgr_NetVar* tmp_netvar = GetNetVar(i);
if (tmp_netvar)
{
if (strcmp(tmp_netvar->GetNetVarName(), NetVar_Name) == 0)
{
output_netvar = tmp_netvar;
break;
}
}
}
return output_netvar;
}
void CNetVarMgr_Que::AddNetVar(CNetVarMgr_NetVar* &Manager_Variable)
{
netvars.push_back(Manager_Variable);
}
CNetVarMgr_NetVar* CNetVarMgr_Que::Back()
{
return netvars.back();
}
void CNetVarMgr_Que::Clear()
{
netvars.clear();
}
CNetVarMgr_NetVar::CNetVarMgr_NetVar(const char* DataTable_Name, const char* NetVar_Name, RecvVarProxyFn Hook_Proxy)
{
SetDataTableName(DataTable_Name);
SetNetVarName(NetVar_Name);
SetHookProxy(Hook_Proxy);
}
const char* CNetVarMgr_NetVar::GetDataTableName()
{
return datatable_name;
}
void CNetVarMgr_NetVar::SetDataTableName(const char* DataTable_Name)
{
datatable_name = DataTable_Name;
}
const char* CNetVarMgr_NetVar::GetNetVarName()
{
return netvar_name;
}
void CNetVarMgr_NetVar::SetNetVarName(const char* NetVar_Name)
{
netvar_name = NetVar_Name;
}
int CNetVarMgr_NetVar::GetOffset()
{
return offset;
}
void CNetVarMgr_NetVar::SetOffset(int Offset)
{
offset = Offset;
}
RecvVarProxyFn CNetVarMgr_NetVar::GetOriginalProxy()
{
return original_proxy;
}
void CNetVarMgr_NetVar::SetOriginalProxy(RecvVarProxyFn Original_Proxy)
{
original_proxy = Original_Proxy;
}
RecvVarProxyFn CNetVarMgr_NetVar::GetHookProxy()
{
return hook_proxy;
}
void CNetVarMgr_NetVar::SetHookProxy(RecvVarProxyFn Hook_Proxy)
{
hook_proxy = Hook_Proxy;
}
Call g_NetVarMgr.Initialize() when you want your NetVars to be found.
Call GetOffset() of the NetVar Manager Variable to get the Offset of the stored NetVar.
Call GetOriginalProxy() of the NetVar Manager Variable to get and/or run the Original Proxy of the stored NetVar.
Mostly just used inside of your NetVar Proxy Hook.
EXPLANATION
For the sake of this explanation lets say you already have a Dynamic NetVar Offset System and that it is only 1 function.
Something along the lines of GetOffset(DATATABLE, NETVAR) that scans the Client Classes and returns the Offset.
m_Local: 237
m_vecPunchAngle: 505
m_hConstraintEntity: 1601
m_iHealth: 1960
m_lifeState: 3219
m_iObserverMode: 3565
m_hObserverTarget: 3912
m_fFlags: 4257
m_iTeamNum: 4453
m_hOwnerEntity: 4653
m_hActiveWeapon: 4942
m_iClip1: 5215
m_iClip2: 5497
m_flNextPrimaryAttack: 5784
m_flNextSecondaryAttack: 6068
m_nTickBase: 6388
m_vecOrigin: 6596
m_vecViewOffset[0]: 6875
m_vecViewOffset[1]: 7174
m_vecViewOffset[2]: 7474
Above is a chart of NetVars that I used in order with a 1 function Offset System.
Next to the NetVars in the chart is the approximate total number of for statement loops it has to go through before getting the NetVar.
IE: ( Loops_Before_GetOffset_Function_Call + Loops_to_NetVar )
Using the IE above the total loop count will always be the largest loop count displayed.
An approximate total of 7474 loops to get all 20 of those NetVars. A bit excessive even when you get all NetVars only once.
However, when I use the same NetVars in the same order with my system this is what it displays.
m_Local: 237
m_vecPunchAngle: 248
m_hConstraintEntity: 323
m_iHealth: 339
m_lifeState: 340
m_iObserverMode: 345
m_hObserverTarget: 346
m_fFlags: 344
m_iTeamNum: 361
m_hOwnerEntity: 365
m_hActiveWeapon: 491
m_iClip1: 624
m_iClip2: 625
m_flNextPrimaryAttack: 630
m_flNextSecondaryAttack: 631
m_nTickBase: 315
m_vecOrigin: 354
m_vecViewOffset[0]: 278
m_vecViewOffset[1]: 279
m_vecViewOffset[2]: 280
An approximate total of 631 loops to get all 20 NetVars.
6843 loops less than before to do exactly the same thing.
The loop count of my system may seem a little wierd because my system organizes the NetVars by DataTable in the Que.
Also the first NetVar you add will either have a loop count equal to or a little more than the 1 function Offset System
due to the Que's vector size.
If you see a mistake or something that could be improved let me know. I am always open to helpful ideas.