1
0
Fork 0

(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
release/0.4.5
signde 2004-09-11 22:10:31 +00:00
parent 1c373cd0af
commit 34ecc0d778
3 changed files with 62 additions and 12 deletions

View File

@ -134,6 +134,7 @@ void NetworkStartSync(bool fcreset);
void NetworkClose(bool client); void NetworkClose(bool client);
void NetworkSendReadyPacket(); void NetworkSendReadyPacket();
void NetworkSendSyncPackets(); void NetworkSendSyncPackets();
void NetworkSendFrameSyncPackets();
bool NetworkCheckClientReady(); bool NetworkCheckClientReady();
void NetworkIPListInit(); void NetworkIPListInit();

View File

@ -84,6 +84,7 @@ enum {
PACKET_TYPE_READY, PACKET_TYPE_READY,
PACKET_TYPE_ACK, PACKET_TYPE_ACK,
PACKET_TYPE_SYNC, PACKET_TYPE_SYNC,
PACKET_TYPE_FSYNC,
PACKET_TYPE_XMIT, PACKET_TYPE_XMIT,
PACKET_TYPE_COMMAND, PACKET_TYPE_COMMAND,
}; };
@ -114,12 +115,18 @@ typedef struct SyncPacket {
uint32 random_seed_2; uint32 random_seed_2;
} SyncPacket; } 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. // sent from server -> client as an acknowledgement that the server received the command.
// the command will be executed at the current value of "max". // the command will be executed at the current value of "max".
typedef struct AckPacket { typedef struct AckPacket {
byte packet_length; byte packet_length;
byte packet_type; byte packet_type;
byte when; int16 when;
} AckPacket; } AckPacket;
typedef struct ReadyPacket { typedef struct ReadyPacket {
@ -197,6 +204,7 @@ static uint32 _my_seed_list[16][2];
static bool _network_ready_sent; static bool _network_ready_sent;
static uint16 _network_ready_ahead = 1; static uint16 _network_ready_ahead = 1;
static uint16 _network_client_timeout; static uint16 _network_client_timeout;
static uint32 _frame_fsync_last;
typedef struct FutureSeeds { typedef struct FutureSeeds {
uint32 frame; uint32 frame;
@ -356,6 +364,16 @@ static void QueueClear(CommandQueue *nq) {
nq->last = &nq->head; 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 // 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. // that should be executed this frame. if there are, execute them.
void NetworkProcessCommands() void NetworkProcessCommands()
@ -468,7 +486,7 @@ void NetworkSendCommand(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, Comman
qp->callback = callback; qp->callback = callback;
// so the server knows when to execute it. // 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. // calculate the amount of extra bytes.
nump = 8; nump = 8;
@ -510,7 +528,6 @@ static void HandleCommandPacket(ClientState *cs, CommandPacket *np)
QueuedCommand *qp; QueuedCommand *qp;
ClientState *c; ClientState *c;
AckPacket ap; AckPacket ap;
int i;
DEBUG(net, 2) ("[NET] cmd size %d", np->packet_length); 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 // put it into the command queue
qp = AllocQueuedCommand(&_command_queue); qp = AllocQueuedCommand(&_command_queue);
qp->cp = *np; qp->cp = *np;
i = _frame_counter_max - (_frame_counter + 3);
if (i<0) { qp->frame = _frame_counter_max - GetNextSyncFrame();
qp->frame = _frame_counter_max ;
} else {
qp->frame = _frame_counter + 3;
}
qp->callback = NULL; 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); memcpy(&qp->cp.dp, np->dp, np->packet_length - COMMAND_PACKET_BASE_SIZE);
ap.packet_type = PACKET_TYPE_ACK; ap.packet_type = PACKET_TYPE_ACK;
ap.when = _frame_counter_max-(qp->frame); ap.when = GetNextSyncFrame();
ap.packet_length = sizeof(AckPacket); ap.packet_length = sizeof(AckPacket);
DEBUG(net,4)("[NET] NewACK: frame=%i %i",ap.when,_frame_counter_max - GetNextSyncFrame());
// send it to the peers // send it to the peers
if (_networking_server) { 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. // sent from server -> client as an acknowledgement that the server received the command.
// the command will be executed at the current value of "max". // the command will be executed at the current value of "max".
static void HandleAckPacket(AckPacket * ap) static void HandleAckPacket(AckPacket * ap)
@ -751,6 +770,9 @@ static bool ReadPackets(ClientState *cs)
assert(!_networking_server); assert(!_networking_server);
HandleSyncPacket((SyncPacket*)packet); HandleSyncPacket((SyncPacket*)packet);
break; break;
case PACKET_TYPE_FSYNC:
HandleFSyncPacket((FrameSyncPacket *)packet);
break;
case PACKET_TYPE_ACK: case PACKET_TYPE_ACK:
assert(!_networking_server); assert(!_networking_server);
HandleAckPacket((AckPacket*)packet); HandleAckPacket((AckPacket*)packet);
@ -916,7 +938,26 @@ void NetworkSendSyncPackets()
// send it to all the clients and mark them unready // send it to all the clients and mark them unready
for(cs=_clients;cs->socket != INVALID_SOCKET; cs++) { for(cs=_clients;cs->socket != INVALID_SOCKET; cs++) {
cs->ready=false; 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) { if (fcreset) {
_frame_counter_max = 0; _frame_counter_max = 0;
_frame_counter_srv = 0; _frame_counter_srv = 0;
_frame_fsync_last = 0;
} }
_num_future_seed = 0; _num_future_seed = 0;
_sync_seed_1 = _sync_seed_2 = 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 NetworkSendCommand(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallback *callback) {}
void NetworkProcessCommands() {} void NetworkProcessCommands() {}
void NetworkStartSync(bool fcreset) {} void NetworkStartSync(bool fcreset) {}
void NetworkSendReadyPacket() {}
void NetworkSendSyncPackets() {}
void NetworkSendFrameSyncPackets() {}
bool NetworkCheckClientReady() { return true; }
void NetworkCoreInit() { _network_available=false; }; void NetworkCoreInit() { _network_available=false; };
void NetworkCoreShutdown() {}; void NetworkCoreShutdown() {};
void NetworkCoreDisconnect() {}; void NetworkCoreDisconnect() {};

3
ttd.c
View File

@ -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. // client: make sure client's time is synched to the server by running frames quickly up to where the server is.
if (!_networking_server) { if (!_networking_server) {
while (_frame_counter < _frame_counter_srv) { while (_frame_counter < _frame_counter_srv) {
NetworkCoreLoop(true);
StateGameLoop(); StateGameLoop();
NetworkProcessCommands(); // need to process queue to make sure that packets get executed. 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 // client: don't exceed the max count told by the server
if (_frame_counter < _frame_counter_max) { if (_frame_counter < _frame_counter_max) {
@ -1010,6 +1012,7 @@ void GameLoop()
if (_frame_counter < _frame_counter_max) { if (_frame_counter < _frame_counter_max) {
StateGameLoop(); StateGameLoop();
NetworkProcessCommands(); // to check if we got any new commands belonging to the current frame before we increase it. 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 // server: wait until all clients were ready for going on
if (_frame_counter == _frame_counter_max) { if (_frame_counter == _frame_counter_max) {