Netgame - Status

Overview server_sync client_sync server_game_moves_sync client_game_moves_sync

Overview These variables are used to track the status of the netgame.
server_sync
Description When the server gets an "sdak" packet from a client, it contains the client frame_num. The server keeps track of server_sync for each client like this: players1[p].server_sync = frame_num - client_fn; // set server_sync in player struct
Variables Server: players1[p].server_sync (for each client)
Code

    if(PacketRead("sdak"))
    {
       int p = PacketGet1ByteInt();
       int client_fn = PacketGet4ByteInt();
       players1[p].server_sync = frame_num - client_fn;     // set server_sync in player struct
    }

server_sync is used to control when clients come active, when joining.

    if ((players[p].control_method == 2) && (players1[p].server_sync < 4) && (players1[p].server_sync > -2))
    {
       add_game_move(frame_num + 4, 1, p, players[p].color); // player becomes active in 4 frame!
    }

server_sync is also used to drop clients when their sync goes bad.

    void proc_player_drop(void)
    {
       for (int p=1; p < NUM_PLAYERS; p++)
          if (players[p].control_method == 2)
          {
             if ((players[p].active) && (players1[p].server_sync > 100)) // drop player
             {
                add_game_move(frame_num + 4, 1, p, 71); // make client inactive (reason sync > 100)
             }
          }
    }

client_sync
Description When the client receives an sdat packet, the frame_num sent by the server is compared the client's frame_num. players1[p].client_sync = sdat_frame_num - frame_num; This is used by the client to adjust its fps_timer, to stay 1 frame behind the server.
Variables Client: players1[p].client_sync (only for local client player)
Code

    if(PacketRead("sdat"))
    {
       int sdat_frame_num = PacketGet4ByteInt();
       players1[p].client_sync = sdat_frame_num - frame_num;
       int fps_chase = frame_speed + players1[p].client_sync - server_lead_frames;
       al_set_timer_speed(fps_timer, ( 1 / (float) fps_chase));
    }

server_game_moves_sync
Description When the server receives a 'cdat' packet with a client's game_move data, it is supposed to be tagged with a future frame_num. This is required so that there is time to sync the game_move back to the clients before its frame_num expires. server_game_moves_sync is how many frames the client's game_move data is ahead of the server's frame num. If it is greater than zero, this is normal. If it is exactly zero, the game_moves are arriving on the exact frame they are needed. This is cutting it very close. If it is less than zero: - the game move is late and will be discarded - server_game_moves_sync_err will be incremented - the move data is discarded (it will be as if the client never made the move) - this should not make the game go out of sync as all players states will still be the same
Variables Server: (for each player) players1[p].server_game_move_sync = 0; players1[p].server_game_move_sync_min = 99; players1[p].server_game_move_sync_err = 0; Client: players1[p].serr_c_sync_err players1[p].server_game_move_sync_err is synced back to the client with the 'serr' packet, where it is saved as players1[p].serr_c_sync_err. That way the client can know that the server dropped one of their 'cdat' packets because it was received too late.
Code

    if(PacketRead("cdat"))
    {
       int p = PacketGet1ByteInt();
       int fn = PacketGet4ByteInt();
       int cm = PacketGet1ByteInt();

       // how far ahead is the client's frame_num for this move, compared to server's frame_num
       int c_sync = players1[p].server_game_move_sync = fn - frame_num;

       // keep track of the minimum c_sync
       if (c_sync < players1[p].server_game_move_sync_min) players1[p].server_game_move_sync_min = c_sync;

       if (c_sync >= 0) add_game_move(fn, 5, p, cm); // add to game_move array
       else                                          // unless late, then drop and inc error
       {
          players1[p].server_game_move_sync_err++;
          Packet("serr"); // server error
          PacketPut1ByteInt(p);
          PacketPut1ByteInt(1); // error type 1
          PacketPut4ByteInt(frame_num);
          PacketPut4ByteInt(c_sync);
          PacketPut4ByteInt(players1[p].server_game_move_sync_err);
          ServerSendTo(packetbuffer, packetsize, who, p);
       }
    }

client_game_moves_sync
Description When a client receives an 'sdat' packet with game_moves, they are entered in the client's game_move array. If their frame_num is earlier than the client's current frame_num an error is flagged. This means that the client has received a game_move that happened in the past. The move will be applied on the server, but will never be applied on the client because it was received too late. This will definitely cause the client to go out of sync.
Variables Client: players1[p].client_game_move_sync; players1[p].client_game_move_sync_min; players1[p].client_game_move_sync_err;
Code

    cs = g0 - passcount;                                    // client_game_moves_sync
    players[p].client_game_moves_sync = cs;                 // set in player struct
    if (cs < 0 ) players[p].client_game_moves_sync_err++;   // check for error
    if (cs < players[p].client_game_moves_sync_min)
       players[p].client_game_moves_sync_min = cs;          // check and set min