From 34ecc0d7787523ad5d0f276fce5c562c71bcd6fb Mon Sep 17 00:00:00 2001 From: signde Date: Sat, 11 Sep 2004 22:10:31 +0000 Subject: (svn r209) -Fix: network code based desync -Feature: framesync packets to hold the clients framecount near the servers -Fix: command queue now aligns the commands to be processed right after an sync or framesync packet -Fix: added stubs for compiling without network --- functions.h | 1 + network.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++----------- ttd.c | 3 +++ 3 files changed, 62 insertions(+), 12 deletions(-) diff --git a/functions.h b/functions.h index 778b57517..9816a56af 100644 --- a/functions.h +++ b/functions.h @@ -134,6 +134,7 @@ void NetworkStartSync(bool fcreset); void NetworkClose(bool client); void NetworkSendReadyPacket(); void NetworkSendSyncPackets(); +void NetworkSendFrameSyncPackets(); bool NetworkCheckClientReady(); void NetworkIPListInit(); diff --git a/network.c b/network.c index a368d3ce4..3b8407e15 100644 --- a/network.c +++ b/network.c @@ -84,6 +84,7 @@ enum { PACKET_TYPE_READY, PACKET_TYPE_ACK, PACKET_TYPE_SYNC, + PACKET_TYPE_FSYNC, PACKET_TYPE_XMIT, PACKET_TYPE_COMMAND, }; @@ -114,12 +115,18 @@ typedef struct SyncPacket { uint32 random_seed_2; } SyncPacket; +typedef struct FrameSyncPacket { + byte packet_length; + byte packet_type; + byte frames; // where is the server currently executing? this is negatively relative to the old value of max. +} FrameSyncPacket; + // sent from server -> client as an acknowledgement that the server received the command. // the command will be executed at the current value of "max". typedef struct AckPacket { byte packet_length; byte packet_type; - byte when; + int16 when; } AckPacket; typedef struct ReadyPacket { @@ -197,6 +204,7 @@ static uint32 _my_seed_list[16][2]; static bool _network_ready_sent; static uint16 _network_ready_ahead = 1; static uint16 _network_client_timeout; +static uint32 _frame_fsync_last; typedef struct FutureSeeds { uint32 frame; @@ -356,6 +364,16 @@ static void QueueClear(CommandQueue *nq) { nq->last = &nq->head; } +static int GetNextSyncFrame() +{ + uint32 newframe; + if (_frame_fsync_last == 0) return -1; + newframe = (_frame_fsync_last + 9); + if ( (newframe + 4) > _frame_counter_max) return -1; + return (_frame_counter_max - newframe); + +} + // go through the player queues for each player and see if there are any pending commands // that should be executed this frame. if there are, execute them. void NetworkProcessCommands() @@ -468,7 +486,7 @@ void NetworkSendCommand(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, Comman qp->callback = callback; // so the server knows when to execute it. - qp->frame = _frame_counter + 5; + qp->frame = _frame_counter_max - GetNextSyncFrame(); // calculate the amount of extra bytes. nump = 8; @@ -510,7 +528,6 @@ static void HandleCommandPacket(ClientState *cs, CommandPacket *np) QueuedCommand *qp; ClientState *c; AckPacket ap; - int i; DEBUG(net, 2) ("[NET] cmd size %d", np->packet_length); @@ -519,14 +536,8 @@ static void HandleCommandPacket(ClientState *cs, CommandPacket *np) // put it into the command queue qp = AllocQueuedCommand(&_command_queue); qp->cp = *np; - - i = _frame_counter_max - (_frame_counter + 3); - if (i<0) { - qp->frame = _frame_counter_max ; - } else { - qp->frame = _frame_counter + 3; - } + qp->frame = _frame_counter_max - GetNextSyncFrame(); qp->callback = NULL; @@ -534,8 +545,9 @@ static void HandleCommandPacket(ClientState *cs, CommandPacket *np) memcpy(&qp->cp.dp, np->dp, np->packet_length - COMMAND_PACKET_BASE_SIZE); ap.packet_type = PACKET_TYPE_ACK; - ap.when = _frame_counter_max-(qp->frame); + ap.when = GetNextSyncFrame(); ap.packet_length = sizeof(AckPacket); + DEBUG(net,4)("[NET] NewACK: frame=%i %i",ap.when,_frame_counter_max - GetNextSyncFrame()); // send it to the peers if (_networking_server) { @@ -597,6 +609,13 @@ static void HandleSyncPacket(SyncPacket *sp) } } +static void HandleFSyncPacket(FrameSyncPacket *fsp) +{ + DEBUG(net,3)("[NET] FSYNC: srv=%i %i",fsp->frames,(_frame_counter_max - fsp->frames)); + if (fsp->frames < 4) return; + _frame_fsync_last = _frame_counter_srv = _frame_counter_max - fsp->frames; +} + // sent from server -> client as an acknowledgement that the server received the command. // the command will be executed at the current value of "max". static void HandleAckPacket(AckPacket * ap) @@ -751,6 +770,9 @@ static bool ReadPackets(ClientState *cs) assert(!_networking_server); HandleSyncPacket((SyncPacket*)packet); break; + case PACKET_TYPE_FSYNC: + HandleFSyncPacket((FrameSyncPacket *)packet); + break; case PACKET_TYPE_ACK: assert(!_networking_server); HandleAckPacket((AckPacket*)packet); @@ -916,7 +938,26 @@ void NetworkSendSyncPackets() // send it to all the clients and mark them unready for(cs=_clients;cs->socket != INVALID_SOCKET; cs++) { cs->ready=false; - SendBytes(cs, &sp, sizeof(sp)); + SendBytes(cs, &sp, sp.packet_length); + } + +} + +void NetworkSendFrameSyncPackets() +{ + ClientState *cs; + FrameSyncPacket fsp; + if ((_frame_counter + 4) < _frame_counter_max) if ((_frame_fsync_last + 4 < _frame_counter)) { + // this packet mantains some information about on which frame the server is + fsp.frames = _frame_counter_max - _frame_counter; + fsp.packet_type = PACKET_TYPE_FSYNC; + fsp.packet_length = sizeof (FrameSyncPacket); + // send it to all the clients and mark them unready + for(cs=_clients;cs->socket != INVALID_SOCKET; cs++) { + cs->ready=false; + SendBytes(cs, &fsp, fsp.packet_length); + } + _frame_fsync_last = _frame_counter; } } @@ -1293,6 +1334,7 @@ void NetworkStartSync(bool fcreset) if (fcreset) { _frame_counter_max = 0; _frame_counter_srv = 0; + _frame_fsync_last = 0; } _num_future_seed = 0; _sync_seed_1 = _sync_seed_2 = 0; @@ -1863,6 +1905,10 @@ void NetworkSend() {} void NetworkSendCommand(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallback *callback) {} void NetworkProcessCommands() {} void NetworkStartSync(bool fcreset) {} +void NetworkSendReadyPacket() {} +void NetworkSendSyncPackets() {} +void NetworkSendFrameSyncPackets() {} +bool NetworkCheckClientReady() { return true; } void NetworkCoreInit() { _network_available=false; }; void NetworkCoreShutdown() {}; void NetworkCoreDisconnect() {}; diff --git a/ttd.c b/ttd.c index 036cbb868..ffc747724 100644 --- a/ttd.c +++ b/ttd.c @@ -995,8 +995,10 @@ void GameLoop() // client: make sure client's time is synched to the server by running frames quickly up to where the server is. if (!_networking_server) { while (_frame_counter < _frame_counter_srv) { + NetworkCoreLoop(true); StateGameLoop(); NetworkProcessCommands(); // need to process queue to make sure that packets get executed. + NetworkCoreLoop(false); } // client: don't exceed the max count told by the server if (_frame_counter < _frame_counter_max) { @@ -1010,6 +1012,7 @@ void GameLoop() if (_frame_counter < _frame_counter_max) { StateGameLoop(); NetworkProcessCommands(); // to check if we got any new commands belonging to the current frame before we increase it. + NetworkSendFrameSyncPackets(); } // server: wait until all clients were ready for going on if (_frame_counter == _frame_counter_max) { -- cgit v1.2.3-54-g00ecf