Changeset - r208:122cd6a8baaf
[Not reviewed]
master
0 3 0
signde - 20 years ago 2004-09-11 22:10:31
signde@openttd.org
(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
3 files changed with 62 insertions and 12 deletions:
0 comments (0 inline, 0 general)
functions.h
Show inline comments
 
@@ -134,6 +134,7 @@ void NetworkStartSync(bool fcreset);
 
void NetworkClose(bool client);
 
void NetworkSendReadyPacket();
 
void NetworkSendSyncPackets();
 
void NetworkSendFrameSyncPackets();
 
bool NetworkCheckClientReady();
 

	
 
void NetworkIPListInit();
network.c
Show inline comments
 
@@ -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, 
 
	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(ClientSt
 
	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(ClientSt
 
	// 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(ClientSt
 
	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 
 
	}
 
}
 

	
 
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() {};
ttd.c
Show inline comments
 
@@ -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) {
0 comments (0 inline, 0 general)