PDA

View Full Version : Getting a client's real fps, realtime



IzNoGoD
9th May 2015, 14: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.