torsdag den 14. juni 2012

Networked Variables in the Source engine

I needed a way to hook networked props/get offsets simply in the source engine, so I implemented ghetto's/altimor's recursive solution in my netvars class.

 netvars.h:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#pragma once
 
 
#include "main.h"
 
 
class CNetworkedVariableManager
{
public:
 
    // stores all tables, and all props inside those
    CNetworkedVariableManager( void );
 
 
    // calls GetProp wrapper to get the absolute offset of the prop
    int GetOffset( const char *tableName, const char *propName );
 
 
    // calls GetProp wrapper to get prop and sets the proxy of the prop
    bool HookProp( const char *tableName, const char *propName, RecvVarProxyFn function );
 
 
private:
 
    // wrapper so we can use recursion without too much performance loss
    int GetProp( const char *tableName, const char *propName, RecvProp **prop = 0 );
 
 
    // uses recursion to return a the relative offset to the given prop and sets the prop param
    int GetProp( RecvTable *recvTable, const char *propName, RecvProp **prop = 0 );
 
 
    RecvTable *GetTable( const char *tableName );
 
 
    std::vector<RecvTable*>    m_tables;
};
 
 
extern CNetworkedVariableManager *g_NetworkedVariableManager;

netvars.cpp:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
#include "main.h"
 
 
CNetworkedVariableManager *g_NetworkedVariableManager = 0;
 
 
CNetworkedVariableManager::CNetworkedVariableManager( void )
{
    m_tables.clear();
 
 
    ClientClass *clientClass = g_InterfaceManager->Client()->GetOriginalMethod<GetAllClasses_t>( INDEX_GETALLCLASSES )( g_InterfaceManager->Client()->thisptr() );
 
    if ( !clientClass )
    {
        LOG_ERROR( "ClientClass was not found" );
        return;
    }
 
 
    while ( clientClass )
    {
        RecvTable *recvTable = clientClass->m_pRecvTable;
 
 
        m_tables.push_back( recvTable );
 
 
        clientClass = clientClass->m_pNext;
    }
}
 
 
// calls GetProp wrapper to get the absolute offset of the prop
int CNetworkedVariableManager::GetOffset( const char *tableName, const char *propName )
{
    int offset = GetProp( tableName, propName );
 
    if ( !offset )
    {
        LOG_ERROR( "Failed to find offset for prop: %s from table: %s", propName, tableName );
        return 0;
    }
 
 
    return offset;
}
 
 
// calls GetProp wrapper to get prop and sets the proxy of the prop
bool CNetworkedVariableManager::HookProp( const char *tableName, const char *propName, RecvVarProxyFn function )
{
    RecvProp *recvProp = 0;
    GetProp( tableName, propName, &recvProp );
 
 
    if ( !recvProp )
    {
        LOG_ERROR( "Failed to hook prop: %s from table: %s", propName, tableName );
        return false;
    }
 
 
    recvProp->m_ProxyFn = function;
 
    return true;
}
 
 
// wrapper so we can use recursion without too much performance loss
int CNetworkedVariableManager::GetProp( const char *tableName, const char *propName, RecvProp **prop )
{
    RecvTable *recvTable = GetTable( tableName );
 
    if ( !recvTable )
    {
        LOG_ERROR( "Failed to find table: %s", tableName );
        return 0;
    }
 
 
    int offset = GetProp( recvTable, propName, prop );
 
    if ( !offset )
    {
        LOG_ERROR( "Failed to find prop: %s from table: %s", propName, tableName );
        return 0;
    }
 
 
    return offset;
}
 
 
// uses recursion to return a the relative offset to the given prop and sets the prop param
int CNetworkedVariableManager::GetProp( RecvTable *recvTable, const char *propName, RecvProp **prop )
{
    int extraOffset = 0;
 
    for ( int i = 0; i < recvTable->m_nProps; ++i )
    {
        RecvProp *recvProp = &recvTable->m_pProps[i];
 
 
        RecvTable *child = recvProp->m_pDataTable;
 
        if ( child
            && ( child->m_nProps > 0 ) )
        {
            int tmp = GetProp( child, propName, prop );
 
            if ( tmp )
            {
                extraOffset += ( recvProp->m_Offset + tmp );
            }
        }
 
 
        if ( stricmp( recvProp->m_pVarName, propName ) )
        {
            continue;
        }
 
 
        if ( prop )
        {
            *prop = recvProp;
        }
 
        return ( recvProp->m_Offset + extraOffset );
    }
 
    return extraOffset;
}
 
 
RecvTable *CNetworkedVariableManager::GetTable( const char *tableName )
{
    if ( m_tables.empty() )
    {
        LOG_ERROR( "Failed to find table: %s (m_tables is empty)", tableName );
        return 0;
    }
 
 
    for each ( RecvTable *table in m_tables )
    {
        if ( !table )
        {
            continue;
        }
 
 
        if ( stricmp( table->m_pNetTableName, tableName ) == 0 )
        {
            return table;
        }
    }
 
    return 0;
}

example usages:
1
2
3
4
5
// we need to construct this manually
g_NetworkedVariableManager = new CNetworkedVariableManager();
 
// hook netvar proxy
g_NetworkedVariableManager->HookProp( "DT_CSPlayer", "m_angEyeAngles[0]", CSPlayer_EyeAnglesX );
1
2
3
4
5
Vector CPlayer::GetViewOffset( void )
{
 static int offset = g_NetworkedVariableManager->GetOffset( "DT_BasePlayer", "m_vecViewOffset[0]" );
 return *Member<Vector*>( this, offset );
}

Ingen kommentarer:

Send en kommentar