IzNoGoD
9th May 2015, 13:54
After studying the cod4x source for a few hours i found a way to get a client's real fps in cod2.
Basically, this hooks every call the code makes when a client issues a SV_ClientThink() command serverside (this happens for each client frame).
This way, you can not only get a client's real fps (which is unspoofable), but also detect if a client has major fps drops (and maybe adjust his settings on the fly to counter this?)
patch:
libcod.cpp:
cHook *hook_clientmovethink;
void clientmovethink(int a1, int a2, int a3)
{
extern int playerinfo_size;
int clid = (a1 - *(int*)0x842308C) / playerinfo_size; //is svs.clients
clfpstemp[clid]++;
hook_clientmovethink->unhook();
int (*sig)(int a1, int a2, int a3);
*(int *)&sig = hook_clientmovethink->from;
int ret = sig(a1, a2, a3);
hook_clientmovethink->hook();
}
...
hook_clientmovethink = new cHook(0x8090DAC, (int) clientmovethink);
hook_clientmovethink->hook();
(cod2 1.3 only)
player.cpp:
int clfps[64][20];
int clfpstemp[64];
int clfpsindex = 0;
void gsc_player_resetfps(int id)
{
for(int i = 0; i < sizeof(clfps[0]) / sizeof(int); i++)
clfps[id][i] = -1;
clfpstemp[id] = 0;
stackPushInt(0);
}
void gsc_player_getfps(int id)
{
int total = 0;
for(int i = 0; i < sizeof(clfps[0]) / sizeof(int); i++)
{
if(clfps[id][i] == -1)
{
stackPushInt(-1);
return;
}
total += clfps[id][i];
}
stackPushInt(total);
}
void gsc_player_fpsnextframe()
{
for(int i = 0; i < sizeof(clfpstemp) / sizeof(int); i++)
{
clfps[i][clfpsindex] = clfpstemp[i];
clfpstemp[i] = 0;
}
clfpsindex++;
if(clfpsindex >= sizeof(clfps[0]) / sizeof(int))
clfpsindex = 0;
stackPushInt(0);
}
with appropriate changes to player.hpp and gsc.cpp to support this.
gsc code: call resetfps() when a client joins, call fpsnextframe() on each new frame and use getfps() to obtain a client's current fps.
The fps returned is filtered through a 20-frame moving-average filter and is pretty darn accurate.
Basically, this hooks every call the code makes when a client issues a SV_ClientThink() command serverside (this happens for each client frame).
This way, you can not only get a client's real fps (which is unspoofable), but also detect if a client has major fps drops (and maybe adjust his settings on the fly to counter this?)
patch:
libcod.cpp:
cHook *hook_clientmovethink;
void clientmovethink(int a1, int a2, int a3)
{
extern int playerinfo_size;
int clid = (a1 - *(int*)0x842308C) / playerinfo_size; //is svs.clients
clfpstemp[clid]++;
hook_clientmovethink->unhook();
int (*sig)(int a1, int a2, int a3);
*(int *)&sig = hook_clientmovethink->from;
int ret = sig(a1, a2, a3);
hook_clientmovethink->hook();
}
...
hook_clientmovethink = new cHook(0x8090DAC, (int) clientmovethink);
hook_clientmovethink->hook();
(cod2 1.3 only)
player.cpp:
int clfps[64][20];
int clfpstemp[64];
int clfpsindex = 0;
void gsc_player_resetfps(int id)
{
for(int i = 0; i < sizeof(clfps[0]) / sizeof(int); i++)
clfps[id][i] = -1;
clfpstemp[id] = 0;
stackPushInt(0);
}
void gsc_player_getfps(int id)
{
int total = 0;
for(int i = 0; i < sizeof(clfps[0]) / sizeof(int); i++)
{
if(clfps[id][i] == -1)
{
stackPushInt(-1);
return;
}
total += clfps[id][i];
}
stackPushInt(total);
}
void gsc_player_fpsnextframe()
{
for(int i = 0; i < sizeof(clfpstemp) / sizeof(int); i++)
{
clfps[i][clfpsindex] = clfpstemp[i];
clfpstemp[i] = 0;
}
clfpsindex++;
if(clfpsindex >= sizeof(clfps[0]) / sizeof(int))
clfpsindex = 0;
stackPushInt(0);
}
with appropriate changes to player.hpp and gsc.cpp to support this.
gsc code: call resetfps() when a client joins, call fpsnextframe() on each new frame and use getfps() to obtain a client's current fps.
The fps returned is filtered through a 20-frame moving-average filter and is pretty darn accurate.