From b594990071fd6cff1c530c2fb4139c9aaaba6e08 Mon Sep 17 00:00:00 2001 From: rubidium Date: Wed, 18 Aug 2010 22:40:17 +0000 Subject: [PATCH] (svn r20549) -Codechange: centralise the handling of the incoming commands (from clients and the server) --- src/network/core/tcp_game.h | 1 + src/network/network.cpp | 2 + src/network/network_client.cpp | 5 +- src/network/network_command.cpp | 99 ++++++++++++++++++++++----------- src/network/network_internal.h | 2 +- src/network/network_server.cpp | 25 +-------- 6 files changed, 73 insertions(+), 61 deletions(-) diff --git a/src/network/core/tcp_game.h b/src/network/core/tcp_game.h index f150a5f081..a7d3bb4620 100644 --- a/src/network/core/tcp_game.h +++ b/src/network/core/tcp_game.h @@ -122,6 +122,7 @@ public: 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); diff --git a/src/network/network.cpp b/src/network/network.cpp index e868bbd2f5..cf74c621bf 100644 --- a/src/network/network.cpp +++ b/src/network/network.cpp @@ -1181,6 +1181,8 @@ void NetworkGameLoop() 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 diff --git a/src/network/network_client.cpp b/src/network/network_client.cpp index a764a04101..ea478276b4 100644 --- a/src/network/network_client.cpp +++ b/src/network/network_client.cpp @@ -742,16 +742,13 @@ DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_COMMAND) 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; } diff --git a/src/network/network_command.cpp b/src/network/network_command.cpp index 6f6cae8865..1bec93c7ac 100644 --- a/src/network/network_command.cpp +++ b/src/network/network_command.cpp @@ -55,16 +55,19 @@ static CommandCallback * const _callback_table[] = { /** * 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(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,23 +99,11 @@ void CommandQueue::Free() } } - +/** 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(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) @@ -129,7 +120,6 @@ void NetworkSend_Command(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, Comma CommandPacket c; c.company = company; - c.next = NULL; c.tile = tile; c.p1 = p1; c.p2 = p2; @@ -148,15 +138,7 @@ void NetworkSend_Command(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, Comma 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 @@ void NetworkSyncCommandQueue(NetworkClientSocket *cs) 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 @@ void NetworkExecuteLocalCommandQueue() { 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 @@ void NetworkExecuteLocalCommandQueue() cp->cmd |= CMD_NETWORK_COMMAND; DoCommandP(cp, cp->my_cmd); - _local_execution_queue.Pop(); + queue.Pop(); free(cp); } @@ -225,6 +208,58 @@ void NetworkFreeLocalCommandQueue() _local_execution_queue.Free(); } +/** + * "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. diff --git a/src/network/network_internal.h b/src/network/network_internal.h index 3131cc10e4..7cb30e23d3 100644 --- a/src/network/network_internal.h +++ b/src/network/network_internal.h @@ -160,7 +160,7 @@ struct CommandPacket : CommandContainer { 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); diff --git a/src/network/network_server.cpp b/src/network/network_server.cpp index e9cb791d55..dc7d9d0f60 100644 --- a/src/network/network_server.cpp +++ b/src/network/network_server.cpp @@ -891,8 +891,6 @@ DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_MAP_OK) */ 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 @@ DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_COMMAND) 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; }