Purple Martians
Technical Code Descriptions
Netgame - Control and Monitoring
Overview
dsync and dsync_avg
ping and ping_avg
Client player position correction
Server late cdats
Client base resets
Overview
These variables are used to control and monitor the status of netgame.
dsync and dsync_avg
Description
The timing offset between the client and the server. See Client Timing Sync
Calculated by clients when processing 'stdf' packets.
A rolling average of dsync called dsync_avg is also calculated and used in client_timer_adjust().
Clients also send dsync to the server with 'stak' packets, so the server also has a dsync value for each client.
Variables
mPlayer.loc[p].dsync
mPlayer.loc[p].dsync_avg
Code
See Client Timing Sync
The client uses dsync_avg to adjust it's timing offset with reference to the server.
The server uses dsync for display over.
ping and ping_avg
Description
The round trip ping response times between client and the server.
Clients calculate and store their own ping time, as well as a rolling average.
The server calculates and stores ping times for each client.
Variables
mPlayer.loc[p].ping
mPlayer.loc[p].ping_avg
Code
The method of calculating ping is described here: ping
The client uses the ping average to set client_chase_offset here: Determine the setpoint
Client player position correction
Description
On the client, when a new state is applied, measure the amount each player's position is corrected.
This measures the amount of warping of players' positions when corrected by the server.
There are 2 classes, the local player, and all remote players.
The local client player usually has less correction, because it plays back locally stored moves after applying states.
These are not used to set anything, rather they are used to debug and get some measure of how well netgame is performing.
They can be viewed in client and server debug overlays, and in server remote control graphs.
Variables
float mPlayer.loc[p].old_x; // old players position, used to calc corrections
float mPlayer.loc[p].old_y;
float mPlayer.loc[p].client_loc_plr_cor;
float mPlayer.loc[p].client_rmt_plr_cor;
float mPlayer.loc[p].client_loc_plr_cor_max;
float mPlayer.loc[p].client_rmt_plr_cor_max;
float mPlayer.loc[p].client_loc_plr_cor_avg;
float mPlayer.loc[p].client_rmt_plr_cor_avg;
Code
void mwNetgame::client_apply_dif(void)
{
...
// make a copy of players' pos
for (int pp=0; pp < NUM_PLAYERS; pp++)
if (mPlayer.syn[pp].active)
{
mPlayer.loc[pp].old_x = mPlayer.syn[pp].x;
mPlayer.loc[pp].old_y = mPlayer.syn[pp].y;
}
// apply dif to base
apply_state_dif(base, client_state_dif, STATE_SIZE);
// copy to game vars and set new frame number
state_to_game_vars(base);
mLoop.frame_num = client_state_dif_dst;
// if we rewound time, play it back
if (ff>0) mLoop.loop_frame(ff);
// calc players' corrections
mPlayer.loc[p].client_rmt_plr_cor = 0; // reset max remote
for (int pp=0; pp < NUM_PLAYERS; pp++)
if (mPlayer.syn[pp].active)
{
float cor = sqrt(pow((mPlayer.loc[pp].old_x - mPlayer.syn[pp].x), 2) + pow((mPlayer.loc[pp].old_y - mPlayer.syn[pp].y), 2)); // hypotenuse distance
if (p == pp) mPlayer.loc[p].client_loc_plr_cor = cor; // save local cor
else if (cor > mPlayer.loc[p].client_rmt_plr_cor) mPlayer.loc[p].client_rmt_plr_cor = cor; // save max remote cor
}
// add data to tally
mTally_client_loc_plr_cor_last_sec[p].add_data(mPlayer.loc[p].client_loc_plr_cor);
mTally_client_rmt_plr_cor_last_sec[p].add_data(mPlayer.loc[p].client_rmt_plr_cor);
}
Server late cdats
Description
On the server, when a cdat packet is received too late to be applied, it is discarded and counted.
Variables
mPlayer.syn[p].late_cdats;
Code
void mwNetgame::server_proc_cdat_packet(int i)
{
...
// determine the cutoff frame for late cdats
int of = mStateHistory[0].oldest_state_frame_num;
if (cdat_frame_num < of)
{
mPlayer.syn[p].late_cdats++;
mTally_late_cdats_last_sec[p].add_data(1); // add to tally
mLog.addf(LOG_NET_cdat, p, "rx cdat p:%d fn:[%d] sync:[%d] late - droppped\n", p, cdat_frame_num, mPlayer.loc[p].server_game_move_sync);
}
else
{
mGameMoves.add_game_move(cdat_frame_num, 5, p, cm); // add to game_move array
mLog.addf(LOG_NET_cdat, p, "rx cdat p:%d fn:[%d] sync:[%d] gmep:[%d] - entered\n", p, cdat_frame_num, mPlayer.loc[p].server_game_move_sync, mGameMoves.entry_pos);
if (cdat_frame_num < server_dirty_frame) server_dirty_frame = cdat_frame_num;
}
}
Client base resets
Description
When the server does not have a valid last_ack_state for a client and has to send a dif state based on zero, client_base_resets is incremented.
Dif states based on zero are much larger than regular difs.
They typically take 7-8 packets to send, vs 1-2 packets for regular state difs.
Variables
mPlayer.loc[p].client_base_resets;
Code
void mwNetgame::client_apply_dif(void)
{
if (client_state_dif_src == 0) mPlayer.loc[p].client_base_resets++; // server sent a dif based on zero
else
....
void mwNetgame::server_send_dif(int frame_num)
{
// get client's most recent base state (the last one acknowledged to the server)
// if not found, leaves base as is (zero)
mStateHistory[p].get_last_ack_state(base, base_frame_num);
if (base_frame_num == 0) mPlayer.loc[p].client_base_resets++;
...