mirror of https://github.com/OpenTTD/OpenTTD
(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 networkrelease/0.4.5
parent
1c373cd0af
commit
34ecc0d778
|
@ -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();
|
||||||
|
|
70
network.c
70
network.c
|
@ -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
3
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.
|
// 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) {
|
||||||
|
|
Loading…
Reference in New Issue