changeset 15867:86e5c7c3222e draft

(svn r20549) -Codechange: centralise the handling of the incoming commands (from clients and the server)
author rubidium <rubidium@openttd.org>
date Wed, 18 Aug 2010 22:40:17 +0000
parents 38a12fe3e755
children 5d8e60ba4e28
files src/network/core/tcp_game.h src/network/network.cpp src/network/network_client.cpp src/network/network_command.cpp src/network/network_internal.h src/network/network_server.cpp
diffstat 6 files changed, 73 insertions(+), 61 deletions(-) [+]
line wrap: on
line diff
--- a/src/network/core/tcp_game.h
+++ b/src/network/core/tcp_game.h
@@ -122,6 +122,7 @@
 
 	ClientStatus status;      ///< Status of this client
 
+	CommandQueue incoming_queue; ///< The command-queue awaiting handling
 	CommandQueue outgoing_queue; ///< The command-queue awaiting delivery
 
 	NetworkRecvStatus CloseConnection(bool error = true);
--- a/src/network/network.cpp
+++ b/src/network/network.cpp
@@ -1181,6 +1181,8 @@
 			f = NULL;
 		}
 #endif /* DEBUG_DUMP_COMMANDS */
+		NetworkDistributeCommands();
+
 		if (_frame_counter >= _frame_counter_max) {
 			/* Only check for active clients just before we're going to send out
 			 * the commands so we don't send multiple pause/unpause commands when
--- a/src/network/network_client.cpp
+++ b/src/network/network_client.cpp
@@ -742,16 +742,13 @@
 	const char *err = MY_CLIENT->Recv_Command(p, &cp);
 	cp.frame    = p->Recv_uint32();
 	cp.my_cmd   = p->Recv_bool();
-	cp.next     = NULL;
 
 	if (err != NULL) {
 		IConsolePrintF(CC_ERROR, "WARNING: %s from server, dropping...", err);
 		return NETWORK_RECV_STATUS_MALFORMED_PACKET;
 	}
 
-	/* The server did send us this command..
-	 *  queue it in our own queue, so we can handle it in the upcoming frame! */
-	NetworkAddCommandQueue(cp);
+	MY_CLIENT->incoming_queue.Append(&cp);
 
 	return NETWORK_RECV_STATUS_OKAY;
 }
--- a/src/network/network_command.cpp
+++ b/src/network/network_command.cpp
@@ -55,16 +55,19 @@
 /**
  * Append a CommandPacket at the end of the queue.
  * @param p The packet to append to the queue.
+ * @note A new instance of the CommandPacket will be made.
  */
 void CommandQueue::Append(CommandPacket *p)
 {
-	assert(p != NULL);
+	CommandPacket *add = MallocT<CommandPacket>(1);
+	*add = *p;
+	add->next = NULL;
 	if (this->first == NULL) {
-		this->first = p;
+		this->first = add;
 	} else {
-		this->last->next = p;
+		this->last->next = add;
 	}
-	this->last = p;
+	this->last = add;
 }
 
 /**
@@ -96,24 +99,12 @@
 	}
 }
 
-
+/** Local queue of packets waiting for handling. */
+static CommandQueue _local_wait_queue;
 /** Local queue of packets waiting for execution. */
 static CommandQueue _local_execution_queue;
 
 /**
- * Add a command to the local or client socket command queue,
- * based on the socket.
- * @param cp the command packet to add
- * @param cs the socket to send to (NULL = locally)
- */
-void NetworkAddCommandQueue(CommandPacket cp, NetworkClientSocket *cs)
-{
-	CommandPacket *new_cp = MallocT<CommandPacket>(1);
-	*new_cp = cp;
-	(cs == NULL ? _local_execution_queue : cs->outgoing_queue).Append(new_cp);
-}
-
-/**
  * Prepare a DoCommand to be send over the network
  * @param tile The tile to perform a command on (see #CommandProc)
  * @param p1 Additional data for the command (see #CommandProc)
@@ -129,7 +120,6 @@
 
 	CommandPacket c;
 	c.company  = company;
-	c.next     = NULL;
 	c.tile     = tile;
 	c.p1       = p1;
 	c.p2       = p2;
@@ -148,15 +138,7 @@
 		c.frame = _frame_counter_max + 1;
 		c.my_cmd = true;
 
-		NetworkAddCommandQueue(c);
-
-		/* Only the local client (in this case, the server) gets the callback */
-		c.callback = 0;
-		/* And we queue it for delivery to the clients */
-		NetworkClientSocket *cs;
-		FOR_ALL_CLIENT_SOCKETS(cs) {
-			if (cs->status > STATUS_MAP_WAIT) NetworkAddCommandQueue(c, cs);
-		}
+		_local_wait_queue.Append(&c);
 		return;
 	}
 
@@ -180,8 +162,7 @@
 	for (CommandPacket *p = _local_execution_queue.Peek(); p != NULL; p = p->next) {
 		CommandPacket c = *p;
 		c.callback = 0;
-		c.next = NULL;
-		NetworkAddCommandQueue(c, cs);
+		cs->outgoing_queue.Append(&c);
 	}
 }
 
@@ -192,8 +173,10 @@
 {
 	assert(IsLocalCompany());
 
+	CommandQueue &queue = (_network_server ? _local_execution_queue : NetworkClientSocket::Get(0)->incoming_queue);
+
 	CommandPacket *cp;
-	while ((cp = _local_execution_queue.Peek()) != NULL) {
+	while ((cp = queue.Peek()) != NULL) {
 		/* The queue is always in order, which means
 		 * that the first element will be executed first. */
 		if (_frame_counter < cp->frame) break;
@@ -209,7 +192,7 @@
 		cp->cmd |= CMD_NETWORK_COMMAND;
 		DoCommandP(cp, cp->my_cmd);
 
-		_local_execution_queue.Pop();
+		queue.Pop();
 		free(cp);
 	}
 
@@ -226,6 +209,58 @@
 }
 
 /**
+ * "Send" a particular CommandPacket to all clients.
+ * @param cp    The command that has to be distributed.
+ * @param owner The client that owns the command,
+ */
+static void DistributeCommandPacket(CommandPacket cp, const NetworkClientSocket *owner)
+{
+	CommandCallback *callback = cp.callback;
+	cp.frame = _frame_counter_max + 1;
+
+	NetworkClientSocket *cs;
+	FOR_ALL_CLIENT_SOCKETS(cs) {
+		if (cs->status >= STATUS_MAP) {
+			/* Callbacks are only send back to the client who sent them in the
+			 *  first place. This filters that out. */
+			cp.callback = (cs != owner) ? NULL : callback;
+			cp.my_cmd = (cs == owner);
+			cs->outgoing_queue.Append(&cp);
+		}
+	}
+
+	cp.callback = (cs != owner) ? NULL : callback;
+	cp.my_cmd = (cs == owner);
+	_local_execution_queue.Append(&cp);
+}
+
+/**
+ * "Send" a particular CommandQueue to all clients.
+ * @param queue The queue of commands that has to be distributed.
+ * @param owner The client that owns the commands,
+ */
+static void DistributeQueue(CommandQueue *queue, const NetworkClientSocket *owner)
+{
+	CommandPacket *cp;
+	while ((cp = queue->Pop()) != NULL) {
+		DistributeCommandPacket(*cp, owner);
+		free(cp);
+	}
+}
+
+void NetworkDistributeCommands()
+{
+	/* First send the server's commands. */
+	DistributeQueue(&_local_wait_queue, NULL);
+
+	/* Then send the queues of the others. */
+	NetworkClientSocket *cs;
+	FOR_ALL_CLIENT_SOCKETS(cs) {
+		DistributeQueue(&cs->incoming_queue, cs);
+	}
+}
+
+/**
  * Receives a command from the network.
  * @param p the packet to read from.
  * @param cp the struct to write the data to.
--- a/src/network/network_internal.h
+++ b/src/network/network_internal.h
@@ -160,7 +160,7 @@
 	bool my_cmd;         ///< did the command originate from "me"
 };
 
-void NetworkAddCommandQueue(CommandPacket cp, NetworkClientSocket *cs = NULL);
+void NetworkDistributeCommands();
 void NetworkExecuteLocalCommandQueue();
 void NetworkFreeLocalCommandQueue();
 void NetworkSyncCommandQueue(NetworkClientSocket *cs);
--- a/src/network/network_server.cpp
+++ b/src/network/network_server.cpp
@@ -891,8 +891,6 @@
  */
 DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_COMMAND)
 {
-	NetworkClientSocket *new_cs;
-
 	/* The client was never joined.. so this is impossible, right?
 	 *  Ignore the packet, give the client a warning, and close his connection */
 	if (cs->status < STATUS_DONE_MAP || cs->HasClientQuit()) {
@@ -947,28 +945,7 @@
 
 	if (GetCommandFlags(cp.cmd) & CMD_CLIENT_ID) cp.p2 = cs->client_id;
 
-	/* The frame can be executed in the same frame as the next frame-packet
-	 *  That frame just before that frame is saved in _frame_counter_max */
-	cp.frame = _frame_counter_max + 1;
-	cp.next  = NULL;
-
-	CommandCallback *callback = cp.callback;
-
-	/* Queue the command for the clients (are send at the end of the frame
-	 *   if they can handle it ;)) */
-	FOR_ALL_CLIENT_SOCKETS(new_cs) {
-		if (new_cs->status >= STATUS_MAP) {
-			/* Callbacks are only send back to the client who sent them in the
-			 *  first place. This filters that out. */
-			cp.callback = (new_cs != cs) ? NULL : callback;
-			cp.my_cmd = (new_cs == cs);
-			NetworkAddCommandQueue(cp, new_cs);
-		}
-	}
-
-	cp.callback = NULL;
-	cp.my_cmd = false;
-	NetworkAddCommandQueue(cp);
+	cs->incoming_queue.Append(&cp);
 	return NETWORK_RECV_STATUS_OKAY;
 }