From 8991ed6e761aaa6cf06e2e45874bbe69fa3fb1a7 Mon Sep 17 00:00:00 2001 From: Cyp Date: Tue, 9 Feb 2010 18:43:53 +0100 Subject: [PATCH] newnet: Replace use of NETMSG with NetQueue. Breaks multiplayer, which never really worked, anyway. Compiles, links and runs, but freezes in multiplayer. --- lib/netplay/netlog.c | 4 +- lib/netplay/netlog.h | 2 +- lib/netplay/netplay.c | 722 ++++++++++++++++----------------------- lib/netplay/netplay.h | 19 +- lib/netplay/netqueue.cpp | 153 +++------ lib/netplay/netqueue.h | 74 +++- lib/netplay/nettypes.cpp | 647 ++++++++++++++++++++--------------- lib/netplay/nettypes.h | 59 +++- src/multibot.c | 101 +++--- src/multigifts.c | 32 +- src/multigifts.h | 8 +- src/multiint.c | 72 ++-- src/multijoin.c | 6 +- src/multijoin.h | 2 +- src/multiopt.c | 18 +- src/multiplay.c | 154 ++++----- src/multirecv.h | 68 ++-- src/multistat.c | 6 +- src/multistat.h | 4 +- src/multistruct.c | 31 +- src/multisync.c | 28 +- src/structure.c | 2 +- 22 files changed, 1098 insertions(+), 1114 deletions(-) diff --git a/lib/netplay/netlog.c b/lib/netplay/netlog.c index 6d0e3353f..4379e7e8a 100644 --- a/lib/netplay/netlog.c +++ b/lib/netplay/netlog.c @@ -190,7 +190,7 @@ BOOL NETstopLogging(void) return true; } -void NETlogPacket(NETMSG *msg, BOOL received) +/*void NETlogPacket(NETMSG *msg, BOOL received) { if (msg->type >= NUM_GAME_PACKETS) { @@ -198,7 +198,7 @@ void NETlogPacket(NETMSG *msg, BOOL received) } packetcount[received][msg->type]++; packetsize[received][msg->type] += msg->size; -} +}*/ BOOL NETlogEntry(const char *str,UDWORD a,UDWORD b) { diff --git a/lib/netplay/netlog.h b/lib/netplay/netlog.h index e20a1ee95..f907119be 100644 --- a/lib/netplay/netlog.h +++ b/lib/netplay/netlog.h @@ -32,7 +32,7 @@ extern "C" BOOL NETstartLogging(void); BOOL NETstopLogging(void); BOOL NETlogEntry( const char *str, UDWORD a, UDWORD b ); -void NETlogPacket(NETMSG *msg, BOOL received); +//void NETlogPacket(NETMSG *msg, BOOL received); #ifdef __cplusplus } diff --git a/lib/netplay/netplay.c b/lib/netplay/netplay.c index 6a059dc37..71b45e75a 100644 --- a/lib/netplay/netplay.c +++ b/lib/netplay/netplay.c @@ -105,9 +105,6 @@ static void setSockErr(int error) char masterserver_name[255] = {'\0'}; static unsigned int masterserver_port = 0, gameserver_port = 0; -#define MAX_CONNECTED_PLAYERS 8 -#define MAX_TMP_SOCKETS 16 - #define NET_TIMEOUT_DELAY 2500 // we wait this amount of time for socket activity #define NET_READ_TIMEOUT 0 /* @@ -145,7 +142,7 @@ void NETresetGamePassword(void); /* * Network globals, these are part of the new network API */ -NETMSG NetMsg; +//NETMSG NetMsg; SYNC_COUNTER sync_counter; // keeps track on how well we are in sync // //////////////////////////////////////////////////////////////////////// // Types @@ -185,13 +182,11 @@ typedef struct bool ready; } Socket; -typedef struct +/*typedef struct { - Socket* socket; - char* buffer; - unsigned int buffer_start; - unsigned int bytes; -} NETBUFSOCKET; + Socket * socket; + uint8_t * buffer; +} NETBUFSOCKET;*/ typedef struct { @@ -220,8 +215,8 @@ int mapDownloadProgress; */ static Socket* tcp_socket = NULL; //socket used to talk to lobbyserver/ host machine -static NETBUFSOCKET* bsocket = NULL; //buffered socket (holds tcp_socket) (clients only?) -static NETBUFSOCKET* connected_bsocket[MAX_CONNECTED_PLAYERS] = { NULL }; +static Socket *bsocket = NULL; //buffered socket (holds tcp_socket) (clients only?) +static Socket *connected_bsocket[MAX_CONNECTED_PLAYERS] = { NULL }; static SocketSet* socket_set = NULL; // UPnP @@ -256,9 +251,9 @@ extern LOBBY_ERROR_TYPES LobbyError; // from src/multiint.c ** ie ("trunk", "2.1.3", ...) ************************************************************************************ **/ -char VersionString[VersionStringSize] = "trunk, netcode 3.32"; -static int NETCODE_VERSION_MAJOR = 2; -static int NETCODE_VERSION_MINOR = 35; +char VersionString[VersionStringSize] = "trunk, netcode++ 3.36"; +static int NETCODE_VERSION_MAJOR = 3; +static int NETCODE_VERSION_MINOR = 36; static int NETCODE_HASH = 0; // unused for now #if defined(WZ_OS_WIN) @@ -1168,53 +1163,21 @@ void NETresetGamePassword(void) // *********** Socket with buffer that read NETMSGs ****************** -static NETBUFSOCKET* NET_createBufferedSocket(void) -{ - NETBUFSOCKET* bs = (NETBUFSOCKET*)malloc(sizeof(*bs)); - - bs->socket = NULL; - bs->buffer = NULL; - bs->buffer_start = 0; - bs->bytes = 0; - - return bs; -} - -static void NET_destroyBufferedSocket(NETBUFSOCKET* bs) -{ - free(bs->buffer); - free(bs); -} - -static void NET_initBufferedSocket(NETBUFSOCKET* bs, Socket* s) -{ - bs->socket = s; - if (bs->buffer == NULL) { - bs->buffer = (char*)malloc(NET_BUFFER_SIZE); - } - bs->buffer_start = 0; - bs->bytes = 0; -} - -static BOOL NET_fillBuffer(NETBUFSOCKET* bs, SocketSet* socket_set) +static size_t NET_fillBuffer(Socket **pSocket, SocketSet* socket_set, uint8_t *bufstart, int bufsize) { + Socket *socket = *pSocket; ssize_t size; - char* bufstart = bs->buffer + bs->buffer_start + bs->bytes; - const int bufsize = NET_BUFFER_SIZE - bs->buffer_start - bs->bytes; - - if (bs->buffer_start != 0 - || !bs->socket->ready) + if (!socket->ready) { - return false; + return 0; } - size = readNoInt(bs->socket, bufstart, bufsize); + size = readNoInt(socket, bufstart, bufsize); if (size != 0 && size != SOCKET_ERROR) { - bs->bytes += size; - return true; + return size; } else { @@ -1224,98 +1187,33 @@ static BOOL NET_fillBuffer(NETBUFSOCKET* bs, SocketSet* socket_set) } else { - debug(LOG_WARNING, "%s tcp_socket %p is now invalid", strSockError(getSockErr()), bs->socket); + debug(LOG_WARNING, "%s tcp_socket %p is now invalid", strSockError(getSockErr()), socket); } // an error occured, or the remote host has closed the connection. if (socket_set != NULL) { - delSocket(socket_set, bs->socket); + delSocket(socket_set, socket); } - ASSERT(bs->bytes < NET_BUFFER_SIZE, "Socket buffer is too small!"); + ASSERT(size <= bufsize, "Socket buffer is too small!"); - if (bs->bytes > NET_BUFFER_SIZE) + if (size > bufsize) { - debug(LOG_ERROR, "Fatal connection error: buffer size of (%d) was too small, current byte count was %d", NET_BUFFER_SIZE, bs->bytes); + debug(LOG_ERROR, "Fatal connection error: buffer size of (%d) was too small, current byte count was %zd", bufsize, size); } - if (tcp_socket == bs->socket) + if (tcp_socket == socket) { debug(LOG_NET, "Host connection was lost!"); tcp_socket = NULL; //Game is pretty much over --should just end everything when HOST dies. NetPlay.isHostAlive = false; } - socketClose(bs->socket); - bs->socket = NULL; + socketClose(socket); + *pSocket = NULL; } - return false; -} - -// Check if we have a full message waiting for us. If not, return false and wait for more data. -// If there is a data remnant somewhere in the buffer except at its beginning, move it to the -// beginning. -static BOOL NET_recvMessage(NETBUFSOCKET* bs) -{ - NETMSG *pMsg = &NetMsg; - unsigned int size; - const NETMSG* message = (NETMSG*)(bs->buffer + bs->buffer_start); - const unsigned int headersize = sizeof(message->size) - + sizeof(message->type) - + sizeof(message->destination) - + sizeof(message->source); - - if (headersize > bs->bytes) - { - goto error; - } - - size = ntohs(message->size) + headersize; - - if (size > bs->bytes) - { - goto error; - } - - memcpy(pMsg, message, size); - pMsg->size = ntohs(message->size); - bs->buffer_start += size; - bs->bytes -= size; - - return true; - -error: - if (bs->buffer_start != 0) - { - static char* tmp_buffer = NULL; - char* buffer_start = bs->buffer + bs->buffer_start; - char* tmp; - - // Create tmp buffer if necessary - if (tmp_buffer == NULL) - { - tmp_buffer = (char*)malloc(NET_BUFFER_SIZE); - } - - // Move remaining contents into tmp buffer - memcpy(tmp_buffer, buffer_start, bs->bytes); - - // swap tmp buffer with buffer - tmp = bs->buffer; - bs->buffer = tmp_buffer; - tmp_buffer = tmp; - - if (tmp_buffer) - { - free(tmp_buffer); - tmp_buffer = NULL; - } - // Now data is in the beginning of the buffer - bs->buffer_start = 0; - } - - return false; + return 0; } void NET_InitPlayers() @@ -1336,7 +1234,9 @@ void NET_InitPlayers() NetPlay.players[i].needFile = false; NetPlay.players[i].wzFile.isCancelled = false; NetPlay.players[i].wzFile.isSending = false; + NETinitQueue(NETnetQueue(i)); } + NETinitQueue(NETbroadcastQueue()); NetPlay.hostPlayer = NET_HOST_ONLY; // right now, host starts always at index zero NetPlay.playercount = 0; debug(LOG_NET, "Players initialized"); @@ -1344,7 +1244,7 @@ void NET_InitPlayers() void NETBroadcastPlayerInfo(uint32_t index) { - NETbeginEncode(NET_PLAYER_INFO, NET_ALL_PLAYERS); + NETbeginEncode(NETbroadcastQueue(), NET_PLAYER_INFO); NETuint32_t(&index); NETbool(&NetPlay.players[index].allocated); NETbool(&NetPlay.players[index].heartbeat); @@ -1406,18 +1306,17 @@ static void NETplayerClientDisconnect(uint32_t index) { if(connected_bsocket[index]) { - debug(LOG_NET, "Player (%u) has left unexpectedly, closing socket %p", - index, connected_bsocket[index]->socket); + debug(LOG_NET, "Player (%u) has left unexpectedly, closing socket %p", index, connected_bsocket[index]); // Although we can get a error result from DelSocket, it don't really matter here. - delSocket(socket_set, connected_bsocket[index]->socket); - socketClose(connected_bsocket[index]->socket); - connected_bsocket[index]->socket = NULL; + delSocket(socket_set, connected_bsocket[index]); + socketClose(connected_bsocket[index]); + connected_bsocket[index] = NULL; NetPlay.players[index].heartbeat = false; - // Announce to the world. This is really icky, because we may be calling the send - // function recursively. We really ought to have a send queue... - NETbeginEncode(NET_PLAYER_DROPPED, NET_ALL_PLAYERS); + // Announce to the world. This was really icky, because we may have been calling the send + // function recursively. We really ought to have had a send queue, and now we finally do... + NETbeginEncode(NETbroadcastQueue(), NET_PLAYER_DROPPED); NETuint32_t(&index); NETend(); } @@ -1436,13 +1335,12 @@ static void NETplayerLeaving(UDWORD index) { if(connected_bsocket[index]) { - debug(LOG_NET, "Player (%u) has left nicely, closing socket %p", - index, connected_bsocket[index]->socket); + debug(LOG_NET, "Player (%u) has left nicely, closing socket %p", index, connected_bsocket[index]); // Although we can get a error result from DelSocket, it don't really matter here. - delSocket(socket_set, connected_bsocket[index]->socket); - socketClose(connected_bsocket[index]->socket); - connected_bsocket[index]->socket = NULL; + delSocket(socket_set, connected_bsocket[index]); + socketClose(connected_bsocket[index]); + connected_bsocket[index] = NULL; } else { @@ -1459,8 +1357,8 @@ static void NETplayerDropped(UDWORD index) { uint32_t id = index; - // Send message type speciffically for dropped / disconnects - NETbeginEncode(NET_PLAYER_DROPPED, NET_ALL_PLAYERS); + // Send message type specifically for dropped / disconnects + NETbeginEncode(NETbroadcastQueue(), NET_PLAYER_DROPPED); NETuint32_t(&id); NETend(); debug(LOG_INFO, "NET_PLAYER_DROPPED received for player %d", id); @@ -1518,7 +1416,7 @@ SDWORD NETgetGameFlags(UDWORD flag) static void NETsendGameFlags(void) { - NETbeginEncode(NET_GAME_FLAGS, NET_ALL_PLAYERS); + NETbeginEncode(NETbroadcastQueue(), NET_GAME_FLAGS); { // Send the amount of game flags we're about to send uint8_t i, count = ARRAY_SIZE(NetGameFlags); @@ -2028,9 +1926,9 @@ int NETclose(void) if(bsocket) { // need delSocket() as well, socket_set or tmp_socket_set? - debug(LOG_NET, "Closing bsocket %p socket %p (tcp_socket=%p)", bsocket, bsocket->socket, tcp_socket); - //socketClose(bsocket->socket); - NET_destroyBufferedSocket(bsocket); + debug(LOG_NET, "Closing bsocket %p socket %p (tcp_socket=%p)", bsocket, bsocket, tcp_socket); + // Why is there a commeted out socketClose there? + //socketClose(bsocket); bsocket=NULL; } @@ -2038,12 +1936,8 @@ int NETclose(void) { if (connected_bsocket[i]) { - if(connected_bsocket[i]->socket) - { - debug(LOG_NET, "Closing connected_bsocket[%u], %p", i, connected_bsocket[i]->socket); - socketClose(connected_bsocket[i]->socket); - } - NET_destroyBufferedSocket(connected_bsocket[i]); + debug(LOG_NET, "Closing connected_bsocket[%u], %p", i, connected_bsocket[i]); + socketClose(connected_bsocket[i]); connected_bsocket[i]=NULL; } NET_DestroyPlayer(i); @@ -2174,9 +2068,8 @@ UDWORD NETgetPacketsRecvd(void) // //////////////////////////////////////////////////////////////////////// // Send a message to a player, option to guarantee message -BOOL NETsend(NETMSG *msg, UDWORD player) +BOOL NETsend(uint8_t player, const uint8_t *rawData, ssize_t rawLen) { - int size; ssize_t result = 0; if(!NetPlay.bComms) @@ -2184,101 +2077,43 @@ BOOL NETsend(NETMSG *msg, UDWORD player) return true; } - if (player >= MAX_CONNECTED_PLAYERS) return false; - msg->destination = player; - msg->source = selectedPlayer; + if (player >= MAX_CONNECTED_PLAYERS && player != NET_ALL_PLAYERS) return false; - size = msg->size + sizeof(msg->size) + sizeof(msg->type) + sizeof(msg->destination) + sizeof(msg->source); - - NETlogPacket(msg, false); - msg->size = htons(msg->size); + //NETlogPacket(msg, false); if (NetPlay.isHost) { - if ( player < MAX_CONNECTED_PLAYERS - && connected_bsocket[player] != NULL - && connected_bsocket[player]->socket != NULL - && (result = writeAll(connected_bsocket[player]->socket, - msg, size) == size)) + int firstPlayer = player == NET_ALL_PLAYERS ? 0 : player; + int lastPlayer = player == NET_ALL_PLAYERS ? MAX_CONNECTED_PLAYERS - 1 : player; + for (player = firstPlayer; player <= lastPlayer; ++player) { - nStats.bytesSent += size; - nStats.packetsSent += 1; - return true; - } - else if (result == SOCKET_ERROR) - { - // Write error, most likely client disconnect. - debug(LOG_ERROR, "Failed to send message: %s", strSockError(getSockErr())); - NETplayerClientDisconnect(player); - } - } - else - { - if (tcp_socket && (result = writeAll(tcp_socket, msg, size) == size)) + // We are the host, send directly to player. + if (connected_bsocket[player] != NULL) { - return true; - } - else if (result == SOCKET_ERROR) - { - // Write error, most likely client disconnect. - debug(LOG_ERROR, "Failed to send message: %s", strSockError(getSockErr())); - socketClose(tcp_socket); - tcp_socket = NULL; - } - - } - - return false; -} - -// //////////////////////////////////////////////////////////////////////// -// broadcast a message to all players. -BOOL NETbcast(NETMSG *msg) -{ - int size; - - if(!NetPlay.bComms) - { - return true; - } - - msg->destination = NET_ALL_PLAYERS; - msg->source = selectedPlayer; - - size = msg->size + sizeof(msg->size) + sizeof(msg->type) + sizeof(msg->destination) + sizeof(msg->source); - - NETlogPacket(msg, false); - msg->size = htons(msg->size); - - if (NetPlay.isHost) - { - unsigned int i; - - for (i = 0; i < MAX_CONNECTED_PLAYERS; ++i) - { - if ( connected_bsocket[i] == NULL - || connected_bsocket[i]->socket == NULL) - { - continue; - } - else - { - if (writeAll(connected_bsocket[i]->socket, msg, size) == SOCKET_ERROR) + result = writeAll(connected_bsocket[player], rawData, rawLen); + if (result == rawLen) + { + nStats.bytesSent += rawLen; + nStats.packetsSent += 1; + } + else if (result == SOCKET_ERROR) { // Write error, most likely client disconnect. debug(LOG_ERROR, "Failed to send message: %s", strSockError(getSockErr())); - NETplayerClientDisconnect(i); + NETplayerClientDisconnect(player); } } } + return true; } - else + else if (player == NetPlay.hostPlayer) { - if (!tcp_socket) + // We are a client, send directly to player, who happens to be the host. + if (tcp_socket && (result = writeAll(tcp_socket, rawData, rawLen) == rawLen)) { - return false; + return true; } - if (writeAll(tcp_socket, msg, size) == SOCKET_ERROR) + else if (result == SOCKET_ERROR) { // Write error, most likely client disconnect. debug(LOG_ERROR, "Failed to send message: %s", strSockError(getSockErr())); @@ -2288,24 +2123,81 @@ BOOL NETbcast(NETMSG *msg) NetPlay.players[NetPlay.hostPlayer].heartbeat = false; // mark host as dead //Game is pretty much over --should just end everything when HOST dies. NetPlay.isHostAlive = false; - return false; + } + } + else + { + // We are a client and can't send the data directly, ask the host to send the data to the player. + uint8_t sender = selectedPlayer; + uint16_t len; + while (rawLen > 0) + { + len = MIN(rawLen, 10000); + NETbeginEncode(NETnetQueue(NET_HOST_ONLY), NET_SEND_TO_PLAYER); + NETuint8_t(&sender); + NETuint8_t(&player); + NETuint16_t(&len); // Send length. + NETbin((uint8_t *)rawData, len); // Sends length again. Cast away const. + NETend(); + rawData += len; + rawLen -= len; } } - nStats.bytesSent += size; - nStats.packetsSent += 1; - - return true; + return false; } + /////////////////////////////////////////////////////////////////////////// // Check if a message is a system message -static BOOL NETprocessSystemMessage(void) +static BOOL NETprocessSystemMessage(NETQUEUE playerQueue, uint8_t type) { - NETMSG *pMsg = &NetMsg; - - switch (pMsg->type) + switch (type) { + case NET_SEND_TO_PLAYER: + { + uint8_t sender; + uint8_t receiver; + uint8_t data[10000]; + uint16_t len = sizeof(data); + NETbeginDecode(playerQueue, NET_SEND_TO_PLAYER); + NETuint8_t(&sender); + NETuint8_t(&receiver); + NETuint16_t(&len); // Get length. + NETbin(data, len); // Gets and discards length. + if (!NETend()) + { + debug(LOG_ERROR, "Incomplete NET_SEND_TO_PLAYER."); + break; + } + if ((receiver == selectedPlayer || receiver == NET_ALL_PLAYERS) && playerQueue.index == NetPlay.hostPlayer) + { + // Message was sent to us via the host. + if (sender != selectedPlayer) // TODO Tell host not to send us our own broadcast messages. + { + NETinsertRawData(NETnetQueue(sender), data, len); + } + } + else if (NetPlay.isHost && sender == playerQueue.index) + { + // We are the host, and player is asking us to send the message to receiver. + NETbeginEncode(NETnetQueue(receiver), NET_SEND_TO_PLAYER); + NETuint8_t(&sender); + NETuint8_t(&receiver); + NETuint16_t(&len); // Send length. + NETbin(data, len); // Sends length again. + NETend(); + if (receiver == NET_ALL_PLAYERS) + { + NETinsertRawData(NETnetQueue(sender), data, len); // Message is also for the host. + } + } + else + { + debug(LOG_ERROR, "Player %d sent us a NET_SEND_TO_PLAYER addressed to %d from %d. We are %d.", playerQueue.index, receiver, sender, selectedPlayer); + } + break; + } case NET_PLAYER_STATS: { recvMultiStats(); @@ -2316,7 +2208,7 @@ static BOOL NETprocessSystemMessage(void) { uint32_t index; - NETbeginDecode(NET_PLAYER_INFO); + NETbeginDecode(playerQueue, NET_PLAYER_INFO); // Retrieve the player's ID NETuint32_t(&index); @@ -2327,6 +2219,12 @@ static BOOL NETprocessSystemMessage(void) NETend(); break; } + if (index != playerQueue.index && playerQueue.index != NET_HOST_ONLY) + { + debug(LOG_WARNING, "MSG_PLAYER_INFO: Player %d trying to change info about player %d.", playerQueue.index, index); + NETend(); + break; + } // Retrieve the rest of the data NETbool(&NetPlay.players[index].allocated); @@ -2338,8 +2236,14 @@ static BOOL NETprocessSystemMessage(void) NETint32_t(&NetPlay.players[index].position); NETint32_t(&NetPlay.players[index].team); NETbool(&NetPlay.players[index].ready); - NETuint32_t(&NetPlay.hostPlayer); + NETuint32_t(&NetPlay.hostPlayer); // Does this make sense at all? NETend(); + if (NetPlay.hostPlayer != NET_HOST_ONLY) + { + // Exactly what was the point of letting anyone change the host? This codebase is confusing. + debug(LOG_WARNING, "MSG_PLAYER_INFO: Player %d thinks that player %d is the host...", playerQueue.index, NetPlay.hostPlayer); + NetPlay.hostPlayer = NET_HOST_ONLY; + } debug(LOG_NET, "Receiving MSG_PLAYER_INFO for player %u (%s)", (unsigned int)index, NetPlay.players[index].allocated ? "human" : "AI"); // update the color to the local array setPlayerColour(index, NetPlay.players[index].colour); @@ -2357,7 +2261,7 @@ static BOOL NETprocessSystemMessage(void) { uint8_t index; - NETbeginDecode(NET_PLAYER_JOINED); + NETbeginDecode(playerQueue, NET_PLAYER_JOINED); NETuint8_t(&index); NETend(); @@ -2373,14 +2277,19 @@ static BOOL NETprocessSystemMessage(void) { uint32_t index; - NETbeginDecode(NET_PLAYER_LEAVING); + NETbeginDecode(playerQueue, NET_PLAYER_LEAVING); NETuint32_t(&index); NETend(); + if (playerQueue.index != NetPlay.hostPlayer && index != playerQueue.index) + { + debug(LOG_WARNING, "Player %d left, but accidentally set player %d as leaving.", playerQueue.index, index); + index = playerQueue.index; + } + if(connected_bsocket[index]) { - debug(LOG_NET, "Receiving NET_PLAYER_LEAVING for player %u on socket %p", - (unsigned int)index, connected_bsocket[index]->socket); + debug(LOG_NET, "Receiving NET_PLAYER_LEAVING for player %u on socket %p", (unsigned int)index, connected_bsocket[index]); } else { // dropped from join screen most likely @@ -2397,7 +2306,7 @@ static BOOL NETprocessSystemMessage(void) { debug(LOG_NET, "Receiving game flags"); - NETbeginDecode(NET_GAME_FLAGS); + NETbeginDecode(playerQueue, NET_GAME_FLAGS); { static unsigned int max_flags = ARRAY_SIZE(NetGameFlags); // Retrieve the amount of game flags that we should receive @@ -2472,12 +2381,9 @@ static void NETcheckPlayers(void) // Receive a message over the current connection. We return true if there // is a message for the higher level code to process, and false otherwise. // We should not block here. -BOOL NETrecv(uint8_t *type) +BOOL NETrecvNet(NETQUEUE *queue, uint8_t *type) { - NETMSG *pMsg = &NetMsg; - static unsigned int current = 0; - BOOL received; - int size; + uint32_t current; if (!NetPlay.bComms) { @@ -2491,168 +2397,104 @@ BOOL NETrecv(uint8_t *type) NETcheckPlayers(); // make sure players are still alive & well - do { -receive_message: - received = false; + if (socket_set == NULL || checkSockets(socket_set, NET_READ_TIMEOUT) <= 0) + { + return false; + } - if (NetPlay.isHost) + for (current = 0; current < MAX_CONNECTED_PLAYERS; ++current) + { + Socket **pSocket = NetPlay.isHost ? &connected_bsocket[current] : &bsocket; + uint8_t buffer[NET_BUFFER_SIZE]; + size_t dataLen; + + if (!NetPlay.isHost && current != NET_HOST_ONLY) { - if (connected_bsocket[current] == NULL) + continue; // Don't have a socket open to this player. + } + + if (*pSocket == NULL) + { + continue; + } + + dataLen = NET_fillBuffer(pSocket, socket_set, buffer, sizeof(buffer)); + if (dataLen > 0) + { + // we received some data, add to buffer + NETinsertRawData(NETnetQueue(current), buffer, dataLen); + } + else if (*pSocket == NULL) + { + // If there is a error in NET_fillBuffer() then socket is already invalid. + // This means that the player dropped / disconnected for whatever reason. + debug(LOG_WARNING, "Player, (player %u) seems to have dropped/disconnected.", (unsigned)current); + + if (NetPlay.isHost) { - return false; - } - - received = NET_recvMessage(connected_bsocket[current]); - - if (received == false) - { - uint32_t i = (current + 1) % 8; - - if (socket_set == NULL - || checkSockets(socket_set, NET_READ_TIMEOUT) <= 0) - { - return false; - } - for (;;) - { - ASSERT(i < MAX_CONNECTED_PLAYERS, "Bad player number %u (current was %u)", i, current); - if (connected_bsocket[i] == NULL || connected_bsocket[i]->socket == NULL) - { - // do nothing - } - else if (NET_fillBuffer(connected_bsocket[i], socket_set)) - { - // we received some data, add to buffer - received = NET_recvMessage(connected_bsocket[i]); - if (i == pMsg->source) // prevent spoofing - { - current = i; - break; - } - } - else if (connected_bsocket[i]->socket == NULL) - { - // If there is a error in NET_fillBuffer() then socket is already invalid. - // This means that the player dropped / disconnected for whatever reason. - debug(LOG_WARNING, "Player, (player %u) seems to have dropped/disconnected.", i); - - // Send message type speciffically for dropped / disconnects - NETbeginEncode(NET_PLAYER_DROPPED, NET_ALL_PLAYERS); - NETuint32_t(&i); - NETend(); - debug(LOG_INFO, "sending NET_PLAYER_DROPPED for player %d (invalid socket)", i); - NET_DestroyPlayer(i); // just clears array - MultiPlayerLeave(i); // more cleanup - NET_PlayerConnectionStatus = 2; //DROPPED_CONNECTION - NetPlay.players[i].kick = true; //they are going to get kicked. - } - - if (++i == MAX_CONNECTED_PLAYERS) - { - i = 0; - } - - if (i == current+1) - { - return false; - } - } + // Send message type specifically for dropped / disconnects + NETbeginEncode(NETbroadcastQueue(), NET_PLAYER_DROPPED); + NETuint32_t(¤t); + NETend(); + debug(LOG_INFO, "sending NET_PLAYER_DROPPED for player %d (invalid socket)", (int)current); + NET_DestroyPlayer(current); // just clears array + MultiPlayerLeave(current); // more cleanup + NET_PlayerConnectionStatus = 2; // Display DROPPED_CONNECTION icon ingame. + NetPlay.players[current].kick = true; // they are going to get kicked. } } - else + } + + for (current = 0; current < MAX_CONNECTED_PLAYERS; ++current) + { + *queue = NETnetQueue(current); + while (NETisMessageReady(*queue)) { - // we are a client - if (bsocket == NULL) + *type = NETmessageType(*queue); + if (!NETprocessSystemMessage(*queue, *type)) { - return false; + return true; // We couldn't process the message, let the caller deal with it.. + } + } + } + + //NETlogPacket(pMsg, true); + + return false; +} + +BOOL NETrecvGame(NETQUEUE *queue, uint8_t *type) +{ + uint32_t current; + for (current = 0; current < MAX_PLAYERS; ++current) + { + /* //TODO + if (gameQueueTime[current] > gameTime) + { + continue; // Any remaining messages are not scheduled yet. + } + */ + + *queue = NETgameQueue(current); + while (NETisMessageReady(*queue)) + { + *type = NETmessageType(*queue); + if (!NETprocessSystemMessage(*queue, *type)) + { + return true; // We couldn't process the message, let the caller deal with it.. } else { - received = NET_recvMessage(bsocket); - - if (received == false) - { - if ( socket_set != NULL - && checkSockets(socket_set, NET_READ_TIMEOUT) > 0 - && NET_fillBuffer(bsocket, socket_set)) - { - received = NET_recvMessage(bsocket); - } - } + debug(LOG_WARNING, "There was a system message in a game queue..."); } } - if (received == false) - { - return false; - } - else - { - size = pMsg->size + sizeof(pMsg->size) + sizeof(pMsg->type) - + sizeof(pMsg->destination) + sizeof(pMsg->source); - if (!NetPlay.isHost) - { - // do nothing - } - else if (pMsg->destination == NET_ALL_PLAYERS) - { - unsigned int j; + /* //TODO + break; // Still waiting for messages from this player. + */ + } - pMsg->size = ntohs(pMsg->size); - - // we are the host, and have received a broadcast packet; distribute it - for (j = 0; j < MAX_CONNECTED_PLAYERS; ++j) - { - if ( j != current - && connected_bsocket[j] != NULL - && connected_bsocket[j]->socket != NULL) - { - if (writeAll(connected_bsocket[j]->socket, pMsg, size) == SOCKET_ERROR) - { - // Write error, most likely client disconnect. - debug(LOG_ERROR, "Failed to send message: %s", strSockError(getSockErr())); - socketClose(connected_bsocket[j]->socket); - connected_bsocket[j]->socket = NULL; - } - } - } - } - else if (pMsg->destination != selectedPlayer) - { - // message was not meant for us; send it further - if ( pMsg->destination < MAX_CONNECTED_PLAYERS - && connected_bsocket[pMsg->destination] != NULL - && connected_bsocket[pMsg->destination]->socket != NULL) - { - debug(LOG_NET, "Reflecting message type %hhu to %hhu", pMsg->type, pMsg->destination); - pMsg->size = ntohs(pMsg->size); - - if (writeAll(connected_bsocket[pMsg->destination]->socket, pMsg, size) == SOCKET_ERROR) - { - // Write error, most likely client disconnect. - debug(LOG_ERROR, "Failed to send message: %s", strSockError(getSockErr())); - socketClose(connected_bsocket[pMsg->destination]->socket); - connected_bsocket[pMsg->destination]->socket = NULL; - } - } - else - { - debug(LOG_NET, "Cannot reflect message type %hhu to %hhu", pMsg->type, pMsg->destination); - } - - goto receive_message; - } - - nStats.bytesRecvd += size; - nStats.packetsRecvd += 1; - } - - } while (NETprocessSystemMessage() == true); - - NETlogPacket(pMsg, true); - - *type = pMsg->type; - return true; + return false; } // //////////////////////////////////////////////////////////////////////// @@ -2692,9 +2534,9 @@ BOOL NETsetupTCPIP(const char *machine) #define MAX_FILE_TRANSFER_PACKET 2048 UBYTE NETsendFile(char *fileName, UDWORD player) { - int32_t bytesRead = 0; + int32_t bytesRead = 0; uint8_t sendto = 0; - char inBuff[MAX_FILE_TRANSFER_PACKET]; + uint8_t inBuff[MAX_FILE_TRANSFER_PACKET]; // We are not the host, so we don't care. (in fact, this would be a error) if (!NetPlay.isHost) @@ -2708,7 +2550,7 @@ UBYTE NETsendFile(char *fileName, UDWORD player) bytesRead = PHYSFS_read(NetPlay.players[player].wzFile.pFileHandle, inBuff,1, MAX_FILE_TRANSFER_PACKET); sendto = (uint8_t) player; - NETbeginEncode(NET_FILE_PAYLOAD, sendto); + NETbeginEncode(NETnetQueue(sendto), NET_FILE_PAYLOAD); NETint32_t(&NetPlay.players[player].wzFile.fileSize_32); // total bytes in this file. (we don't support 64bit yet) NETint32_t(&bytesRead); // bytes in this packet NETint32_t(&NetPlay.players[player].wzFile.currPos); // start byte @@ -2729,11 +2571,11 @@ UBYTE NETsendFile(char *fileName, UDWORD player) /* @TODO more error checking (?) different file types (?) */ // recv file. it returns % of the file so far recvd. -UBYTE NETrecvFile(void) +UBYTE NETrecvFile(NETQUEUE queue) { int32_t fileSize = 0, currPos = 0, bytesRead = 0; char fileName[256]; - char outBuff[MAX_FILE_TRANSFER_PACKET]; + uint8_t outBuff[MAX_FILE_TRANSFER_PACKET]; static PHYSFS_file *pFileHandle; static bool isLoop = false; @@ -2741,7 +2583,7 @@ UBYTE NETrecvFile(void) memset(outBuff, 0x0, sizeof(outBuff)); //read incoming bytes. - NETbeginDecode(NET_FILE_PAYLOAD); + NETbeginDecode(queue, NET_FILE_PAYLOAD); NETint32_t(&fileSize); // total bytes in this file. NETint32_t(&bytesRead); // bytes in this packet NETint32_t(&currPos); // start byte @@ -2763,7 +2605,7 @@ UBYTE NETrecvFile(void) PHYSFS_close(fin); NETend(); - NETbeginEncode(NET_FILE_CANCELLED, NET_HOST_ONLY); + NETbeginEncode(NETnetQueue(NET_HOST_ONLY), NET_FILE_CANCELLED); NETuint32_t(&selectedPlayer); NETuint32_t(&reason); NETend(); @@ -2778,7 +2620,7 @@ UBYTE NETrecvFile(void) NETend(); // we should never get here, it means, that the game can't detect the level, but we have the file. // so we kick this player out. - NETbeginEncode(NET_FILE_CANCELLED, NET_HOST_ONLY); + NETbeginEncode(NETnetQueue(NET_HOST_ONLY), NET_FILE_CANCELLED); NETuint32_t(&selectedPlayer); NETuint32_t(&reason); NETend(); @@ -3057,6 +2899,7 @@ static void NETallowJoining(void) if (tmp_socket[i] == NULL // Make sure that we're not out of sockets && (tmp_socket[i] = socketAccept(tcp_socket)) != NULL) { + NETinitQueue(NETnetTmpQueue(i)); addSocket(tmp_socket_set, tmp_socket[i]); if (checkSockets(tmp_socket_set, NET_TIMEOUT_DELAY) > 0 && tmp_socket[i]->ready @@ -3117,7 +2960,8 @@ static void NETallowJoining(void) if ( tmp_socket[i] != NULL && tmp_socket[i]->ready) { - ssize_t size = readNoInt(tmp_socket[i], &NetMsg, sizeof(NetMsg)); + uint8_t buffer[NET_BUFFER_SIZE]; + ssize_t size = readNoInt(tmp_socket[i], buffer, sizeof(buffer)); if (size == 0 || size == SOCKET_ERROR) { @@ -3128,14 +2972,18 @@ static void NETallowJoining(void) } else { - debug(LOG_NET, "Client socket ecountered error: %s", strSockError(getSockErr())); + debug(LOG_NET, "Client socket encountered error: %s", strSockError(getSockErr())); } delSocket(tmp_socket_set, tmp_socket[i]); socketClose(tmp_socket[i]); tmp_socket[i] = NULL; + continue; } - else if (NetMsg.type == NET_JOIN) + + NETinsertRawData(NETnetTmpQueue(i), buffer, size); + + if (NETisMessageReady(NETnetTmpQueue(i)) && NETmessageType(NETnetTmpQueue(i)) == NET_JOIN) { uint8_t j; int8_t index; @@ -3148,7 +2996,7 @@ static void NETallowJoining(void) char GamePassword[password_string_size] = { '\0' }; int32_t Hash_Data = 0; // Not currently used - NETbeginDecode(NET_JOIN); + NETbeginDecode(NETnetTmpQueue(i), NET_JOIN); NETstring(name, sizeof(name)); NETint32_t(&MajorVersion); // NETCODE_VERSION_MAJOR NETint32_t(&MinorVersion); // NETCODE_VERSION_MINOR @@ -3169,9 +3017,10 @@ static void NETallowJoining(void) } delSocket(tmp_socket_set, tmp_socket[i]); - NET_initBufferedSocket(connected_bsocket[index], tmp_socket[i]); - addSocket(socket_set, connected_bsocket[index]->socket); + connected_bsocket[index] = tmp_socket[i]; tmp_socket[i] = NULL; + addSocket(socket_set, connected_bsocket[index]); + NETmoveQueue(NETnetTmpQueue(i), NETnetQueue(index)); if (!NETisCorrectVersion(MajorVersion, MinorVersion)) { @@ -3196,7 +3045,7 @@ static void NETallowJoining(void) if (rejected) { - NETbeginEncode(NET_REJECTED, index); + NETbeginEncode(NETnetQueue(index), NET_REJECTED); NETuint8_t(&rejected); NETend(); @@ -3204,18 +3053,17 @@ static void NETallowJoining(void) NET_DestroyPlayer(index); allow_joining = true; - delSocket(socket_set, connected_bsocket[index]->socket); - socketClose(connected_bsocket[index]->socket); - connected_bsocket[index]->socket = NULL; + delSocket(socket_set, connected_bsocket[index]); + socketClose(connected_bsocket[index]); + connected_bsocket[index] = NULL; return; } - NETbeginEncode(NET_ACCEPTED, index); + NETbeginEncode(NETnetQueue(index), NET_ACCEPTED); NETuint8_t((uint8_t *)&index); NETend(); - debug(LOG_NET, "Player, %s, with index of %u has joined using socket %p", name, - (unsigned int)index, connected_bsocket[index]->socket); + debug(LOG_NET, "Player, %s, with index of %u has joined using socket %p", name, (unsigned int)index, connected_bsocket[index]); // Increment player count gamestruct.desc.dwCurrentPlayers++; @@ -3227,14 +3075,14 @@ static void NETallowJoining(void) { if (NetPlay.players[j].allocated && index != j) { - NETbeginEncode(NET_PLAYER_JOINED, index); + NETbeginEncode(NETnetQueue(index), NET_PLAYER_JOINED); NETuint8_t(&j); NETend(); } } // Send info about newcomer to all players. - NETbeginEncode(NET_PLAYER_JOINED, NET_ALL_PLAYERS); + NETbeginEncode(NETbroadcastQueue(), NET_PLAYER_JOINED); NETuint8_t((uint8_t *)&index); NETend(); @@ -3304,7 +3152,8 @@ BOOL NEThostGame(const char* SessionName, const char* PlayerName, // allocate socket storage for all possible players for (i = 0; i < MAX_CONNECTED_PLAYERS; ++i) { - connected_bsocket[i] = NET_createBufferedSocket(); + connected_bsocket[i] = NULL; + NETinitQueue(NETnetQueue(i)); } NetPlay.isHost = true; @@ -3620,12 +3469,12 @@ connect_succesfull: return false; } // Allocate memory for a new socket - bsocket = NET_createBufferedSocket(); - // NOTE: tcp_socket = bsocket->socket now! - NET_initBufferedSocket(bsocket, tcp_socket); + NETinitQueue(NETnetQueue(NET_HOST_ONLY)); + // NOTE: tcp_socket = bsocket now! + bsocket = tcp_socket; // Send a join message to the host - NETbeginEncode(NET_JOIN, NET_HOST_ONLY); + NETbeginEncode(NETnetQueue(NET_HOST_ONLY), NET_JOIN); // Casting constness away, because NETstring is const-incorrect // when sending/encoding a packet. NETstring((char*)playername, 64); @@ -3640,9 +3489,10 @@ connect_succesfull: // Loop until we've been accepted into the game for (;;) { + NETQUEUE queue; uint8_t type = NUM_GAME_PACKETS; - NETrecv(&type); + NETrecvNet(&queue, &type); // FIXME: shouldn't there be some sort of rejection message? if (SDL_GetTicks() > i + 5000) @@ -3655,14 +3505,13 @@ connect_succesfull: // :) uint8_t index; - NETbeginDecode(NET_ACCEPTED); + NETbeginDecode(queue, NET_ACCEPTED); // Retrieve the player ID the game host arranged for us NETuint8_t(&index); NETend(); selectedPlayer = index; - debug(LOG_NET, "NET_ACCEPTED received. Accepted into the game - I'm player %u using bsocket %p, tcp_socket=%p", - (unsigned int)index, bsocket->socket, tcp_socket); + debug(LOG_NET, "NET_ACCEPTED received. Accepted into the game - I'm player %u using bsocket %p, tcp_socket=%p", (unsigned int)index, bsocket, tcp_socket); NetPlay.isHost = false; NetPlay.isHostAlive = true; @@ -3683,8 +3532,9 @@ connect_succesfull: // :( uint8_t rejection = 0; - NETbeginDecode(NET_REJECTED); + NETbeginDecode(queue, NET_REJECTED); // WRY??? + // And why "wry"? NETuint8_t(&rejection); NETend(); diff --git a/lib/netplay/netplay.h b/lib/netplay/netplay.h index f9de974d9..5b5020d9d 100644 --- a/lib/netplay/netplay.h +++ b/lib/netplay/netplay.h @@ -121,7 +121,7 @@ typedef enum NET_POSITIONREQUEST, //65 position in GUI player list NET_DATA_CHECK, //66 Data integrity check NET_HOST_DROPPED, //67 Host has dropped - NET_FUTURE1, //68 future use + NET_SEND_TO_PLAYER, //68 Was future use, now actually using! (Normally, things marked "for future use" never ever get used.) NET_FUTURE2, //69 " NET_FUTURE3, //70 " NET_FILE_REQUESTED, //71 Player has requested a file (map/mod/?) @@ -141,6 +141,9 @@ typedef enum #define SESSION_JOINDISABLED 1 +#define MAX_CONNECTED_PLAYERS 8 +#define MAX_TMP_SOCKETS 16 + typedef struct { //Available game storage... JUST FOR REFERENCE! int32_t dwSize; int32_t dwFlags; @@ -202,14 +205,14 @@ typedef struct { uint64_t unsentisMPDirtyBit; } SYNC_COUNTER; -typedef struct { +/*typedef struct { uint16_t size; // used size of body uint8_t type; // type of packet uint8_t destination; // player to send to, or NET_ALL_PLAYERS uint8_t source; // player it is sent from char body[MaxMsgSize]; // msg buffer BOOL status; // If the packet compiled or not (this is _not_ sent!) -} NETMSG; +} NETMSG;*/ typedef struct { @@ -278,7 +281,7 @@ typedef struct { // variables extern NETPLAY NetPlay; -extern NETMSG NetMsg; +//extern NETMSG NetMsg; extern SYNC_COUNTER sync_counter; // update flags extern bool netPlayersUpdated; @@ -287,12 +290,12 @@ extern int mapDownloadProgress; // //////////////////////////////////////////////////////////////////////// // functions available to you. extern int NETinit(BOOL bFirstCall); // init -extern BOOL NETsend(NETMSG *msg, UDWORD player); // send to player -extern BOOL NETbcast(NETMSG *msg); // broadcast to everyone -extern BOOL NETrecv(uint8_t *type); // recv a message if possible +BOOL NETsend(uint8_t player, const uint8_t *rawData, ssize_t rawLen); ///< send to player, or broadcast if player == NET_ALL_PLAYERS. +extern BOOL NETrecvNet(NETQUEUE *queue, uint8_t *type); ///< recv a message from the net queues if possible. +extern BOOL NETrecvGame(NETQUEUE *queue, uint8_t *type); ///< recv a message from the game queues if possible. extern UBYTE NETsendFile(char *fileName, UDWORD player); // send file chunk. -extern UBYTE NETrecvFile(void); // recv file chunk +extern UBYTE NETrecvFile(NETQUEUE queue); // recv file chunk extern int NETclose(void); // close current game extern int NETshutdown(void); // leave the game in play. diff --git a/lib/netplay/netqueue.cpp b/lib/netplay/netqueue.cpp index 3874541b9..f402ee4dc 100644 --- a/lib/netplay/netqueue.cpp +++ b/lib/netplay/netqueue.cpp @@ -1,14 +1,12 @@ #include "netqueue.h" #include "lib/framework/frame.h" -#include #ifdef USE_ZLIB #include "zlib.h" #endif //USE_ZLIB -NetQueue multiQueues[MAX_PLAYERS]; - NetQueue::NetQueue(UsagePattern p) : deserialiseUnderflow(false) + , isCompressed(false) , readOffset(0) , readSuccessOffset(0) , netOffset(0) @@ -18,13 +16,16 @@ NetQueue::NetQueue(UsagePattern p) { switch (p) { + case Unused: canSerialise = false; canDeserialise = false; canWriteRaw = false; canReadRaw = false; canCompress = false; break; + case NetSend: canSerialise = true; canDeserialise = false; canWriteRaw = false; canReadRaw = true; canCompress = true; break; case NetReceive: canSerialise = false; canDeserialise = true; canWriteRaw = true; canReadRaw = false; canCompress = true; break; + case GameSend: canSerialise = true; canDeserialise = true; canWriteRaw = false; canReadRaw = true; canCompress = false; break; case GameReceive: canSerialise = false; canDeserialise = true; canWriteRaw = true; canReadRaw = false; canCompress = false; break; case GameSolo: canSerialise = true; canDeserialise = true; canWriteRaw = false; canReadRaw = false; canCompress = false; break; } - ASSERT(canSerialise == !canWriteRaw, "Can't insert both objects and raw data into the same NetQueue."); + ASSERT(!canSerialise || !canWriteRaw, "Can't insert both objects and raw data into the same NetQueue."); ASSERT(!canWriteRaw || canDeserialise, "No point being able to write data into the NetQueue if we can't deserialise it."); } @@ -133,6 +134,14 @@ void NetQueue::popRawData(size_t netLen) popOldData(); } +void NetQueue::endSerialiseLength() +{ + uint32_t len = data.size() - beginSerialiseOffset - 4; + data[beginSerialiseOffset ] = len>>24 & 0xFF; + data[beginSerialiseOffset+1] = len>>16 & 0xFF; + data[beginSerialiseOffset+2] = len>> 8 & 0xFF; + data[beginSerialiseOffset+3] = len & 0xFF; +} bool NetQueue::endDeserialise() { @@ -157,6 +166,29 @@ bool NetQueue::isDeserialiseError() const return deserialiseUnderflow; } +void NetQueue::serialiseLength() +{ + beginSerialiseOffset = data.size(); + + // Reserve room for length. + data.resize(data.size() + 4); +} + +bool NetQueue::deserialiseHaveLength() +{ + if (readOffset + 4 > data.size()) + { + return false; + } + uint32_t len = data[readOffset]<<24 | data[readOffset+1]<<16 | data[readOffset+2]<<8 | data[readOffset+3]; + return len < data.size() && readOffset + 4 <= data.size() - len; +} + +uint8_t NetQueue::deserialiseGetType() +{ + return readOffset + 5 > data.size() ? 0 : data[readOffset+4]; +} + void NetQueue::popOldData() { if (!canDeserialise) @@ -197,7 +229,7 @@ void NetQueue::deserialise(uint8_t &v) } // Deserialise. - if (readOffset >= data.size()) + if (readOffset + 1 > data.size()) { deserialiseUnderflow = true; return; // Not enough data. @@ -206,16 +238,22 @@ void NetQueue::deserialise(uint8_t &v) v = data[readOffset++]; } -#ifdef USE_ZLIB -void NetQueue::setCompression() +void NetQueue::setCompression(uint32_t compressionMask) { ASSERT(canCompress, "Wrong NetQueue type for setCompression."); - if (stream != NULL) - { - //debug(LOG_WARNING, "Already called setCompression on this NetQueue."); - return; // Been there, done that. - } +#ifdef USE_ZLIB + if (!isCompressed && (compressionMask & CompressionZlib) != 0) + { + setCompressionZlib(); + isCompressed = true; + } +#endif //USE_ZLIB +} + +#ifdef USE_ZLIB +void NetQueue::setCompressionZlib() +{ stream = new z_stream; stream->zalloc = NULL; stream->zfree = NULL; @@ -247,93 +285,6 @@ void NetQueue::setCompression() } #endif //USE_ZLIB -/////////////////// - -template -void queue(const Q &q, uint8_t &v) -{ - q.byte(v); -} - - -template -void queue(const Q &q, uint16_t &v) -{ - uint8_t b[2] = {v>>8, v}; - queue(q, b[0]); - queue(q, b[1]); - v = b[0]<<8 | b[1]; -} - -template -void queue(const Q &q, uint32_t &v) -{ - uint16_t b[2] = {v>>16, v}; - queue(q, b[0]); - queue(q, b[1]); - v = b[0]<<16 | b[1]; -} - -template -void queue(const Q &q, uint64_t &v) -{ - uint32_t b[2] = {v>>32, v}; - queue(q, b[0]); - queue(q, b[1]); - v = uint64_t(b[0])<<32 | b[1]; -} - -template -void queue(const Q &q, int8_t &v) -{ - uint8_t b = v; - queue(q, b); - v = b; - - STATIC_ASSERT(sizeof(b) == sizeof(v)); -} - -template -void queue(const Q &q, int16_t &v) -{ - uint16_t b = v; - queue(q, b); - v = b; - - STATIC_ASSERT(sizeof(b) == sizeof(v)); -} - -template -void queue(const Q &q, int32_t &v) -{ - uint32_t b = v; - queue(q, b); - v = b; - - STATIC_ASSERT(sizeof(b) == sizeof(v)); -} - -template -void queue(const Q &q, int64_t &v) -{ - uint64_t b = v; - queue(q, b); - v = b; - - STATIC_ASSERT(sizeof(b) == sizeof(v)); -} - -template -void queue(const Q &q, float &v) -{ - uint32_t b; - std::memcpy(&b, &v, sizeof(b)); - queue(q, b); - std::memcpy(&v, &b, sizeof(b)); - - STATIC_ASSERT(sizeof(b) == sizeof(v)); -} - #if 0 extern "C" void testNetQueue() { @@ -353,7 +304,7 @@ extern "C" void testNetQueue() } if (testString[i] == ' ') { - write.setCompression(); + write.setCompression(CompressionMask); } printf("%c", testString[i]); } @@ -384,7 +335,7 @@ extern "C" void testNetQueue() } if (result == ' ') { - read.setCompression(); + read.setCompression(CompressionMask); } printf("%c", result); } diff --git a/lib/netplay/netqueue.h b/lib/netplay/netqueue.h index 3c814e626..342a521e5 100644 --- a/lib/netplay/netqueue.h +++ b/lib/netplay/netqueue.h @@ -4,7 +4,16 @@ #include "lib/framework/types.h" // TODO Add zlib to build scripts and use it. -//#define USE_ZLIB +// TODO But first move it directly on top of the sockets, seems it didn't really belong here. NetQueue +// was originally intended to be just a stream of bytes, which would be synchronised among all players. +// It ended up being a stream of messages prefixed with message size. And thanks to the need for +// broadcasting, the message streams can get mixed together, which isn't good if the message streams are +// individually zlib-compressed. While it would be possible to enable compression if being careful which +// queues it's enabled on, the compression code doesn't belong here anymore. Leaving it here for now, +// since the compression code is tested, and works. At the time of writing, the compression code is the +// only part of the code which is currently known to work well. It should be moved to a CompressPipe +// class, or something similar. +//#don't define USE_ZLIB #ifdef __cplusplus #include @@ -26,6 +35,8 @@ class NetQueue public: enum UsagePattern { + Unused, ///< NetQueue is not used for anything. + NetSend, ///< For use with outgoing sockets. Will serialise and read raw data. NetReceive, ///< For use with incoming sockets. Will write raw data and deserialise. @@ -33,27 +44,38 @@ public: GameReceive, ///< For use as a game order queue. Will deserialise and write raw data. GameSolo ///< For use as a game order queue. Will serialise and deserialise. }; + enum Compression + { + CompressionZlib = 0x00000001, ///< Zlib compression. + // TODO? CompressionLzma = 0x00000002, ///< Lzma compression. + CompressionMask = 0x00000000 ///< All compression types we support. +#ifdef USE_ZLIB + | CompressionZlib +#endif //USE_ZLIB + }; class Writer { public: enum { Read, Write, Direction = Write }; - Writer(NetQueue &q) : queue(q) {} - void byte(uint8_t v) const { queue.serialise(v); } - NetQueue &queue; + Writer(NetQueue *q = NULL) : queue(q) {} + Writer(NetQueue &q) : queue(&q) {} + void byte(uint8_t v) const { queue->serialise(v); } + NetQueue *queue; }; class Reader { public: enum { Read, Write, Direction = Read }; - Reader(NetQueue &q) : queue(q) {} - void byte(uint8_t &v) const { queue.deserialise(v); } - NetQueue &queue; + Reader(NetQueue *q = NULL) : queue(q) {} + Reader(NetQueue &q) : queue(&q) {} + void byte(uint8_t &v) const { queue->deserialise(v); } + NetQueue *queue; }; - NetQueue(UsagePattern p = NetReceive); + NetQueue(UsagePattern p = Unused); ~NetQueue(); // Network related @@ -62,38 +84,58 @@ public: void popRawData(size_t netLen); ///< Pops the extracted data, so that future readRawData calls do not return that data. // Serialise/deserialise related. All game clients should deserialise all queues, including their own. - Writer beginSerialise() { return Writer(*this); } ///< No matching endSerialise. - Reader beginDeserialise() { return Reader(*this); } + void endSerialiseLength(); ///< Must call after serialiseLength, but not call otherwise. bool endDeserialise(); ///< Returns true if deserialise succeeded, data has been consumed. Returns false if deserialise failed, due to not enough data yet. bool isDeserialiseError() const; ///< Returns true if deserialise has failed. + void serialiseLength(); ///< Do not call readRawData or beginDeserialise before calling endSerialiseLength! Makes room for the length, which will actually be serialised there when calling endSerialise. + bool deserialiseHaveLength(); ///< Checks the length, and returns true iff that much data is available. Length will still be returned by deserialise. + uint8_t deserialiseGetType(); ///< Returns the byte immediately after the length. void serialise(uint8_t v); ///< Serialise a byte. void deserialise(uint8_t &v); ///< Deserialise a byte. -#ifdef USE_ZLIB - void setCompression(); ///< Enable compression. Should call after serialising or deserialising an appropriate message. -#endif //USE_ZLIB + void setCompression(uint32_t compressionMask); ///< Enable compression if possible. Should call after serialising or deserialising an appropriate message. private: +#ifdef USE_ZLIB + void setCompressionZlib(); ///< Enable zlib compression. +#endif //USE_ZLIB void popOldData(); ///< Pops any data that is no longer needed. + // Disable copy constructor and assignment operator. + NetQueue(const NetQueue &); + void operator =(const NetQueue &); + bool canSerialise; ///< True if we are the producer of data for this NetQueue. bool canDeserialise; ///< True if we are the producer of data for this NetQueue. bool canWriteRaw; ///< True if we will call getDataForNetwork. bool canReadRaw; ///< True if we will call getDataForNetwork. bool deserialiseUnderflow; ///< We ran out of data when deserialising. bool canCompress; ///< True if this is a NetQueue for a socket. + bool isCompressed; ///< True if we turned compression on already. unsigned readOffset; ///< Offset in data for reading. unsigned readSuccessOffset; ///< Offset in data for reading, when success was last called. unsigned netOffset; ///< Offset in data for writing to network. - std::vector data; ///< Decompressed serialised data. + unsigned beginSerialiseOffset; ///< Offset in data when serialiseLength was called. + std::vector data; ///< Decompressed serialised data. + std::vector compressedData; ///< Compressed data. #ifdef USE_ZLIB - std::vector compressedData; ///< Compressed data. - struct z_stream_s *stream; ///< Non-null iff we are using compression. + struct z_stream_s *stream; ///< Non-null iff we are using zlib compression. #endif //USE_ZLIB }; +class NetQueuePair +{ +public: + NetQueuePair() : send(NetQueue::NetSend), receive(NetQueue::NetReceive) {} + + NetQueue send; + NetQueue receive; +}; + extern "C" { +#else +#error There isn''t currently any C interface to this. #endif //__cplusplus #ifdef __cplusplus diff --git a/lib/netplay/nettypes.cpp b/lib/netplay/nettypes.cpp index 36094be2e..1a3c215d3 100644 --- a/lib/netplay/nettypes.cpp +++ b/lib/netplay/nettypes.cpp @@ -1,6 +1,6 @@ /* This file is part of Warzone 2100. - Copyright (C) 2007-2009 Warzone Resurrection Project + Copyright (C) 2007-2010 Warzone Resurrection Project Warzone 2100 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -32,233 +32,118 @@ #include "../framework/frame.h" #include "netplay.h" #include "nettypes.h" +#include "netqueue.h" +#include + + +static NetQueue *gameQueues[MAX_PLAYERS + 1] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}; // The game queues should be used, even in single-player. The +1 is for AIs that don't want to (TODO fix this) use their own queue. +static NetQueuePair *netQueues[MAX_CONNECTED_PLAYERS] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}; +static NetQueuePair *tmpQueues[MAX_TMP_SOCKETS] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}; +static NetQueue *broadcastQueue = NULL; +static NetQueue::Writer writer; +static NetQueue::Reader reader; +static int writeSocketIndex = -1; static PACKETDIR NetDir; static void NETsetPacketDir(PACKETDIR dir) { NetDir = dir; + + // Can't put STATIC_ASSERT in global scope, arbitrarily putting it here. + STATIC_ASSERT(MAX_PLAYERS == MAX_CONNECTED_PLAYERS); // Things might break if each connected player doesn't correspond to a player of the same index. } PACKETDIR NETgetPacketDir() { return NetDir; -} - -/* - * Begin & End functions - */ - -void NETbeginEncode(uint8_t type, uint8_t player) -{ - NETsetPacketDir(PACKET_ENCODE); - NetMsg.type = type; - NetMsg.size = 0; - NetMsg.status = true; - NetMsg.destination = player; - memset(&NetMsg.body, '\0', sizeof(NetMsg.body)); } -void NETbeginDecode(uint8_t type) +template +static void queue(const Q &q, uint8_t &v) { - NETsetPacketDir(PACKET_DECODE); - assert(type == NetMsg.type); - NetMsg.size = 0; - NetMsg.status = true; + q.byte(v); } -BOOL NETend(void) +template +static void queue(const Q &q, uint16_t &v) { - assert(NETgetPacketDir() != PACKET_INVALID); - - // If we are decoding just return true - if (NETgetPacketDir() == PACKET_DECODE) - { - return true; - } - - // If the packet is invalid or failed to compile - if (NETgetPacketDir() != PACKET_ENCODE || !NetMsg.status) - { - return false; - } - - // We have sent the packet, so make it invalid (to prevent re-sending) - NETsetPacketDir(PACKET_INVALID); - - // Send the packet, updating the send functions is on my todo list! - if (NetMsg.destination == NET_ALL_PLAYERS) - { - return NETbcast(&NetMsg); - } - else - { - return NETsend(&NetMsg, NetMsg.destination); - } + uint8_t b[2] = {v>>8, v}; + queue(q, b[0]); + queue(q, b[1]); + v = b[0]<<8 | b[1]; } -/* - * Primitive functions (ints and strings). Due to the lack of C++ and the fact - * that I hate macros this is a lot longer than it should be. - */ - -BOOL NETint8_t(int8_t *ip) +template +static void queue(const Q &q, uint32_t &v) { - int8_t *store = (int8_t *) &NetMsg.body[NetMsg.size]; - - // Make sure there is enough data/space left in the packet - if (sizeof(int8_t) + NetMsg.size > sizeof(NetMsg.body) || !NetMsg.status) - { - return NetMsg.status = false; - } - - // 8-bit (1 byte) integers need no endian-swapping! - if (NETgetPacketDir() == PACKET_ENCODE) - { - *store = *ip; - } - else if (NETgetPacketDir() == PACKET_DECODE) - { - *ip = *store; - } - - // Increment the size of the message - NetMsg.size += sizeof(int8_t); - - return true; + uint16_t b[2] = {v>>16, v}; + queue(q, b[0]); + queue(q, b[1]); + v = b[0]<<16 | b[1]; } -BOOL NETuint8_t(uint8_t *ip) +template +static void queue(const Q &q, uint64_t &v) { - uint8_t *store = (uint8_t *) &NetMsg.body[NetMsg.size]; - - // Make sure there is enough data/space left in the packet - if (sizeof(uint8_t) + NetMsg.size > sizeof(NetMsg.body) || !NetMsg.status) - { - return NetMsg.status = false; - } - - // 8-bit (1 byte) integers need no endian-swapping! - if (NETgetPacketDir() == PACKET_ENCODE) - { - *store = *ip; - } - else if (NETgetPacketDir() == PACKET_DECODE) - { - *ip = *store; - } - - // Increment the size of the message - NetMsg.size += sizeof(uint8_t); - - return true; + uint32_t b[2] = {v>>32, v}; + queue(q, b[0]); + queue(q, b[1]); + v = uint64_t(b[0])<<32 | b[1]; } -BOOL NETint16_t(int16_t *ip) +template +static void queue(const Q &q, char &v) { - int16_t *store = (int16_t *) &NetMsg.body[NetMsg.size]; + uint8_t b = v; + queue(q, b); + v = b; - // Make sure there is enough data/space left in the packet - if (sizeof(int16_t) + NetMsg.size > sizeof(NetMsg.body) || !NetMsg.status) - { - return NetMsg.status = false; - } - - // Convert the integer into the network byte order (big endian) - if (NETgetPacketDir() == PACKET_ENCODE) - { - *store = SDL_SwapBE16(*ip); - } - else if (NETgetPacketDir() == PACKET_DECODE) - { - *ip = SDL_SwapBE16(*store); - } - - // Increment the size of the message - NetMsg.size += sizeof(int16_t); - - return true; + STATIC_ASSERT(sizeof(b) == sizeof(v)); } -BOOL NETuint16_t(uint16_t *ip) +template +static void queue(const Q &q, int8_t &v) { - uint16_t *store = (uint16_t *) &NetMsg.body[NetMsg.size]; + uint8_t b = v; + queue(q, b); + v = b; - // Make sure there is enough data/space left in the packet - if (sizeof(uint16_t) + NetMsg.size > sizeof(NetMsg.body) || !NetMsg.status) - { - return NetMsg.status = false; - } - - // Convert the integer into the network byte order (big endian) - if (NETgetPacketDir() == PACKET_ENCODE) - { - *store = SDL_SwapBE16(*ip); - } - else if (NETgetPacketDir() == PACKET_DECODE) - { - *ip = SDL_SwapBE16(*store); - } - - // Increment the size of the message - NetMsg.size += sizeof(uint16_t); - - return true; + STATIC_ASSERT(sizeof(b) == sizeof(v)); } -BOOL NETint32_t(int32_t *ip) +template +static void queue(const Q &q, int16_t &v) { - int32_t *store = (int32_t *) &NetMsg.body[NetMsg.size]; + uint16_t b = v; + queue(q, b); + v = b; - // Make sure there is enough data/space left in the packet - if (sizeof(int32_t) + NetMsg.size > sizeof(NetMsg.body) || !NetMsg.status) - { - return NetMsg.status = false; - } - - // Convert the integer into the network byte order (big endian) - if (NETgetPacketDir() == PACKET_ENCODE) - { - *store = SDL_SwapBE32(*ip); - } - else if (NETgetPacketDir() == PACKET_DECODE) - { - *ip = SDL_SwapBE32(*store); - } - - // Increment the size of the message - NetMsg.size += sizeof(int32_t); - - return true; + STATIC_ASSERT(sizeof(b) == sizeof(v)); } -BOOL NETuint32_t(uint32_t *ip) +template +static void queue(const Q &q, int32_t &v) { - uint32_t *store = (uint32_t *) &NetMsg.body[NetMsg.size]; + uint32_t b = v; + queue(q, b); + v = b; - // Make sure there is enough data/space left in the packet - if (sizeof(uint32_t) + NetMsg.size > sizeof(NetMsg.body) || !NetMsg.status) - { - return NetMsg.status = false; - } - - // Convert the integer into the network byte order (big endian) - if (NETgetPacketDir() == PACKET_ENCODE) - { - *store = SDL_SwapBE32(*ip); - } - else if (NETgetPacketDir() == PACKET_DECODE) - { - *ip = SDL_SwapBE32(*store); - } - - // Increment the size of the message - NetMsg.size += sizeof(uint32_t); - - return true; + STATIC_ASSERT(sizeof(b) == sizeof(v)); } -BOOL NETfloat(float *fp) +template +static void queue(const Q &q, int64_t &v) +{ + uint64_t b = v; + queue(q, b); + v = b; + + STATIC_ASSERT(sizeof(b) == sizeof(v)); +} + +template +void queue(const Q &q, float &v) { /* * NB: Not portable. @@ -277,34 +162,283 @@ BOOL NETfloat(float *fp) // IEEE754 floating point numbers can be treated the same as 32-bit integers // with regards to endian conversion - STATIC_ASSERT(sizeof(float) == sizeof(int32_t)); + uint32_t b; + std::memcpy(&b, &v, sizeof(b)); + queue(q, b); + std::memcpy(&v, &b, sizeof(b)); - return NETint32_t((int32_t *) fp); + STATIC_ASSERT(sizeof(b) == sizeof(v)); } -BOOL NETbool(BOOL *bp) +template +static void queue(const Q &q, Vector3uw &v) { - // Bools are converted to uint8_ts - uint8_t tmp = (uint8_t) *bp; - NETuint8_t(&tmp); + queue(q, v.x); + queue(q, v.y); + queue(q, v.z); +} - // If we are decoding and managed to extract the value set it - if (NETgetPacketDir() == PACKET_DECODE && NetMsg.status) +// Queue selection functions + +static NetQueue *sendQueue(NETQUEUE queue) +{ + return queue.isPair ? &(*static_cast(queue.queue))->send : static_cast(queue.queue); +} + +static NetQueue *receiveQueue(NETQUEUE queue) +{ + return queue.isPair ? &(*static_cast(queue.queue))->receive : static_cast(queue.queue); +} + +static NetQueuePair *&pairQueue(NETQUEUE queue) +{ + ASSERT(queue.isPair, "Huh?"); + return *static_cast(queue.queue); +} + +NETQUEUE NETnetTmpQueue(unsigned tmpPlayer) +{ + NETQUEUE ret; + ASSERT(tmpPlayer < MAX_TMP_SOCKETS, "Huh?"); + NetQueuePair **queue = &tmpQueues[tmpPlayer]; + ret.queue = queue; + ret.isPair = true; + ret.index = tmpPlayer; + ret.queueType = QUEUE_TMP; + return ret; +} + +NETQUEUE NETnetQueue(unsigned player) +{ + NETQUEUE ret; + + if (player == NET_ALL_PLAYERS) { - *bp = (BOOL) tmp; + return NETbroadcastQueue(); } - return NetMsg.status; + ASSERT(player < MAX_CONNECTED_PLAYERS, "Huh?"); + NetQueuePair **queue = &netQueues[player]; + ret.queue = queue; + ret.isPair = true; + ret.index = player; + ret.queueType = QUEUE_NET; + return ret; +} + +NETQUEUE NETgameQueue(unsigned player) +{ + NETQUEUE ret; + ASSERT(player < MAX_CONNECTED_PLAYERS + 1, "Huh?"); // + 1 for AIs that don't use their own queue. + NetQueue *queue = gameQueues[player]; + ret.queue = queue; + ret.isPair = false; + ret.index = player; + ret.queueType = QUEUE_GAME; + return ret; +} + +NETQUEUE NETbroadcastQueue() +{ + NETQUEUE ret; + NetQueue *queue = broadcastQueue; + ret.queue = queue; + ret.isPair = false; + ret.index = NET_ALL_PLAYERS; + ret.queueType = QUEUE_BROADCAST; + return ret; +} + +void NETinsertRawData(NETQUEUE queue, uint8_t *data, size_t dataLen) +{ + receiveQueue(queue)->writeRawData(data, dataLen); +} + +BOOL NETisMessageReady(NETQUEUE queue) +{ + return receiveQueue(queue)->deserialiseHaveLength(); +} + +uint8_t NETmessageType(NETQUEUE queue) +{ + return receiveQueue(queue)->deserialiseGetType(); +} + +/* + * Begin & End functions + */ + +void NETinitQueue(NETQUEUE queue) +{ + if (queue.queueType == QUEUE_BROADCAST) + { + delete broadcastQueue; + broadcastQueue = new NetQueue(NetQueue::NetSend); + return; + } + else if (queue.queueType == QUEUE_GAME) + { + delete gameQueues[queue.index]; + gameQueues[queue.index] = new NetQueue(NetQueue::GameSolo); // TODO Should sometimes be NetQueue::GameSend or NetQueue::GameReceive. + return; + } + else + { + delete pairQueue(queue); + pairQueue(queue) = new NetQueuePair; + } +} + +void NETmoveQueue(NETQUEUE src, NETQUEUE dst) +{ + ASSERT(src.isPair, "Huh?"); + ASSERT(dst.isPair, "Huh?"); + delete pairQueue(dst); + pairQueue(dst) = NULL; + std::swap(pairQueue(src), pairQueue(dst)); +} + +void NETbeginEncode(NETQUEUE cqueue, uint8_t type) +{ + NETsetPacketDir(PACKET_ENCODE); + + writer = sendQueue(cqueue); + if (cqueue.queueType == QUEUE_NET || cqueue.queueType == QUEUE_BROADCAST) + { + writeSocketIndex = cqueue.index; + } + else + { + writeSocketIndex = -1; + } + + writer.queue->serialiseLength(); + queue(writer, type); +} + +void NETbeginDecode(NETQUEUE cqueue, uint8_t type) +{ + NETsetPacketDir(PACKET_DECODE); + + reader = receiveQueue(cqueue); + + uint32_t len; + uint8_t readType; + queue(reader, len); + queue(reader, readType); + assert(type == readType); +} + +BOOL NETend() +{ + assert(NETgetPacketDir() != PACKET_INVALID); + + // If we are encoding just return true + if (NETgetPacketDir() == PACKET_ENCODE) + { + writer.queue->endSerialiseLength(); + if (writeSocketIndex >= 0) + { + const uint8_t *data; + size_t dataLen; + NetQueue *queue = writeSocketIndex == NET_ALL_PLAYERS ? broadcastQueue : &netQueues[writeSocketIndex]->send; + + queue->readRawData(&data, &dataLen); + NETsend(writeSocketIndex, data, dataLen); + queue->popRawData(dataLen); + } + NETsetPacketDir(PACKET_INVALID); + return true; + } + + bool ret = reader.queue->endDeserialise(); + + // We have ended the deserialisation, so mark the direction invalid + NETsetPacketDir(PACKET_INVALID); + + return ret; +/* + // If the packet is invalid or failed to compile + if (NETgetPacketDir() != PACKET_ENCODE || !NetMsg.status) + { + return false; + } + + // Send the packet, updating the send functions is on my todo list! + if (NetMsg.destination == NET_ALL_PLAYERS) + { + return NETbcast(&NetMsg); + } + else + { + return NETsend(&NetMsg, NetMsg.destination); + } + */ +} + +template +static void queueAuto(T &v) +{ + if (NETgetPacketDir() == PACKET_ENCODE) + { + queue(writer, v); + } + else if (NETgetPacketDir() == PACKET_DECODE) + { + queue(reader, v); + } +} + +void NETint8_t(int8_t *ip) +{ + queueAuto(*ip); +} + +void NETuint8_t(uint8_t *ip) +{ + queueAuto(*ip); +} + +void NETint16_t(int16_t *ip) +{ + queueAuto(*ip); +} + +void NETuint16_t(uint16_t *ip) +{ + queueAuto(*ip); +} + +void NETint32_t(int32_t *ip) +{ + queueAuto(*ip); +} + +void NETuint32_t(uint32_t *ip) +{ + queueAuto(*ip); +} + +void NETfloat(float *fp) +{ + queueAuto(*fp); +} + +void NETbool(BOOL *bp) +{ + uint8_t i = !!*bp; + queueAuto(i); + *bp = !!i; } /* * NETnull should be used to either add 4 bytes of padding to a message, or to * discard 4 bytes of data from a message. */ -BOOL NETnull() +void NETnull() { uint32_t zero = 0; - return NETuint32_t(&zero); + NETuint32_t(&zero); } /** Sends or receives a string to or from the current network package. @@ -321,103 +455,65 @@ BOOL NETnull() * string being decoded, the resulting string (in \c str) will be * truncated. */ -BOOL NETstring(char *str, uint16_t maxlen) +void NETstring(char *str, uint16_t maxlen) { /* * Strings sent over the network are prefixed with their length, sent as an - * unsigned 16-bit integer. + * unsigned 16-bit integer, not including \0 termination. */ - // Work out the length of the string if we are encoding - uint16_t len = (NETgetPacketDir() == PACKET_ENCODE) ? strnlen1(str, maxlen) : 0; - char *store; + uint16_t len = NETgetPacketDir() == PACKET_ENCODE ? strnlen1(str, maxlen) - 1 : 0; + queueAuto(len); - // Add/fetch the length from the packet - NETuint16_t(&len); - - // Map store to the message buffer - store = (char *) &NetMsg.body[NetMsg.size]; - - // Make sure there is enough data/space left in the packet - if (len + NetMsg.size > sizeof(NetMsg.body) || !NetMsg.status) + // Truncate length if necessary + if (len > maxlen - 1) { - return NetMsg.status = false; + debug(LOG_ERROR, "NETstring: %s packet, length %u truncated at %u", NETgetPacketDir() == PACKET_ENCODE ? "Encoding" : "Decoding", len, maxlen); + len = maxlen - 1; } - if (NETgetPacketDir() == PACKET_ENCODE) + for (unsigned i = 0; i < len; ++i) { - memcpy(store, str, len); - } - else if (NETgetPacketDir() == PACKET_DECODE) - { - // Truncate length if necessary - if (len > maxlen) - { - debug(LOG_ERROR, "NETstring: Decoding packet type %d from %d, buffer size %u truncated at %u", - NetMsg.type, NetMsg.source, len, maxlen); - len = maxlen; - } - memcpy(str, store, len); - // Guarantee NUL-termination - str[len - 1] = '\0'; + queueAuto(str[i]); } - // Increment the size of the message - NetMsg.size += sizeof(len) + len; - - return true; + if (NETgetPacketDir() == PACKET_DECODE) + { + // NUL-terminate + str[len] = '\0'; + } } -BOOL NETbin(char *str, uint16_t maxlen) +void NETbin(uint8_t *str, uint16_t maxlen) { /* - * Strings sent over the network are prefixed with their length, sent as an + * Bins sent over the network are prefixed with their length, sent as an * unsigned 16-bit integer. */ - // Work out the length of the string if we are encoding - uint16_t len = (NETgetPacketDir() == PACKET_ENCODE) ? maxlen : 0; - char *store; + // Work out the length of the bin if we are encoding + uint16_t len = NETgetPacketDir() == PACKET_ENCODE ? maxlen : 0; + queueAuto(len); - // Add/fetch the length from the packet - NETuint16_t(&len); - - // Map store to the message buffer - store = (char *) &NetMsg.body[NetMsg.size]; - - // Make sure there is enough data/space left in the packet - if (len + NetMsg.size > sizeof(NetMsg.body) || !NetMsg.status) + // Truncate length if necessary + if (len > maxlen) { - return NetMsg.status = false; + debug(LOG_ERROR, "NETbin: Decoding packet, buffer size %u truncated at %u", len, maxlen); + len = maxlen; } - if (NETgetPacketDir() == PACKET_ENCODE) + for (unsigned i = 0; i < len; ++i) { - memcpy(store, str, len); - } - else if (NETgetPacketDir() == PACKET_DECODE) - { - // Truncate length if necessary - if (len > maxlen) - { - debug(LOG_ERROR, "NETbin: Decoding packet type %d from %d, buffer size %u truncated at %u", - NetMsg.type, NetMsg.source, len, maxlen); - len = maxlen; - } - memcpy(str, store, len); + queueAuto(str[i]); } - // Increment the size of the message - NetMsg.size += sizeof(len) + len; - - return true; + // Throw away length... + //maxlen = len; } -BOOL NETVector3uw(Vector3uw* vp) +void NETVector3uw(Vector3uw *vp) { - return (NETuint16_t(&vp->x) - && NETuint16_t(&vp->y) - && NETuint16_t(&vp->z)); + queueAuto(*vp); } typedef enum @@ -428,7 +524,7 @@ typedef enum static void NETcoder(PACKETDIR dir) { - static const char original[] = "THIS IS A TEST STRING"; +/* static const char original[] = "THIS IS A TEST STRING"; char str[sizeof(original)]; BOOL b = true; uint32_t u32 = 32; @@ -442,9 +538,9 @@ static void NETcoder(PACKETDIR dir) sstrcpy(str, original); if (dir == PACKET_ENCODE) - NETbeginEncode(0, 0); + NETbeginEncodeNet(0, 0); else - NETbeginDecode(0); + NETbeginDecodeNet(0, 0); NETbool(&b); assert(b == true); NETuint32_t(&u32); assert(u32 == 32); NETuint16_t(&u16); assert(u16 == 16); @@ -453,12 +549,12 @@ static void NETcoder(PACKETDIR dir) NETint16_t(&i16); assert(i16 == -16); NETint8_t(&i8); assert(i8 == -8); NETstring(str, sizeof(str)); assert(strncmp(str, original, sizeof(str) - 1) == 0); - NETenum(&te); assert(te == test_b); + NETenum(&te); assert(te == test_b);*/ } void NETtest() { - NETMSG cmp; + /*NETMSG cmp; memset(&cmp, 0, sizeof(cmp)); memset(&NetMsg, 0, sizeof(NetMsg)); @@ -466,10 +562,11 @@ void NETtest() memcpy(&cmp, &NetMsg, sizeof(cmp)); NETcoder(PACKET_DECODE); ASSERT(memcmp(&cmp, &NetMsg, sizeof(cmp)) == 0, "nettypes unit test failed"); - fprintf(stdout, "\tNETtypes self-test: PASSED\n"); + fprintf(stdout, "\tNETtypes self-test: PASSED\n");*/ + ASSERT(false, "nettypes test disabled, since it doesn't compile anymore."); } -int NETgetSource() +/*int NETgetSource() { return NetMsg.source; -} +}*/ diff --git a/lib/netplay/nettypes.h b/lib/netplay/nettypes.h index a37359b27..724710f53 100644 --- a/lib/netplay/nettypes.h +++ b/lib/netplay/nettypes.h @@ -40,20 +40,49 @@ typedef enum packetDirectionEnum PACKET_INVALID } PACKETDIR; -void NETbeginEncode(uint8_t type, uint8_t player); -void NETbeginDecode(uint8_t type); +typedef enum QueueType +{ + QUEUE_TMP, + QUEUE_NET, + QUEUE_GAME, + QUEUE_BROADCAST, +} QUEUETYPE; + +typedef struct _netqueue +{ + void *queue; ///< Is either a (NetQueuePair **) or a (NetQueue *). (Note different numbers of *.) + BOOL isPair; + uint8_t index; + uint8_t queueType; +} NETQUEUE; + +NETQUEUE NETnetTmpQueue(unsigned tmpPlayer); ///< One of the temp queues from before a client has joined the game. +NETQUEUE NETnetQueue(unsigned player); ///< The queue pair used for sending and receiving data directly from another client. +NETQUEUE NETgameQueue(unsigned player); ///< The game action queue. +NETQUEUE NETbroadcastQueue(void); ///< The queue for sending data directly to all clients, not just a specific one. + +void NETinsertRawData(NETQUEUE queue, uint8_t *data, size_t dataLen); /// Dump raw data from sockets and raw data sent via host here. +BOOL NETisMessageReady(NETQUEUE queue); +uint8_t NETmessageType(NETQUEUE queue); + +void NETinitQueue(NETQUEUE queue); +void NETmoveQueue(NETQUEUE src, NETQUEUE dst); + +void NETbeginEncode(NETQUEUE queue, uint8_t type); +void NETbeginDecode(NETQUEUE queue, uint8_t type); BOOL NETend(void); -BOOL NETint8_t(int8_t *ip); -BOOL NETuint8_t(uint8_t *ip); -BOOL NETint16_t(int16_t *ip); -BOOL NETuint16_t(uint16_t *ip); -BOOL NETint32_t(int32_t *ip); -BOOL NETuint32_t(uint32_t *ip); -BOOL NETfloat(float* fp); -BOOL NETbool(BOOL *bp); -BOOL NETnull(void); -BOOL NETstring(char *str, uint16_t maxlen); -BOOL NETbin(char *str, uint16_t maxlen); + +void NETint8_t(int8_t *ip); +void NETuint8_t(uint8_t *ip); +void NETint16_t(int16_t *ip); +void NETuint16_t(uint16_t *ip); +void NETint32_t(int32_t *ip); +void NETuint32_t(uint32_t *ip); +void NETfloat(float* fp); +void NETbool(BOOL *bp); +void NETnull(void); +void NETstring(char *str, uint16_t maxlen); +void NETbin(uint8_t *str, uint16_t maxlen); PACKETDIR NETgetPacketDir(void); @@ -91,13 +120,13 @@ do \ } while(0) #endif -BOOL NETVector3uw(Vector3uw* vp); +void NETVector3uw(Vector3uw* vp); /** * Get player who is the source of the current packet. * @see selectedPlayer */ -int NETgetSource(void); +//int NETgetSource(void); void NETtest(void); diff --git a/src/multibot.c b/src/multibot.c index 19176ef62..9e87e610e 100644 --- a/src/multibot.c +++ b/src/multibot.c @@ -73,7 +73,7 @@ BOOL sendHappyVtol(const DROID* psDroid) return false; } - NETbeginEncode(NET_VTOL, NET_ALL_PLAYERS); + NETbeginEncode(NETgameQueue(selectedPlayer), NET_VTOL); { uint8_t player = psDroid->player; uint32_t droid = psDroid->id; @@ -84,12 +84,12 @@ BOOL sendHappyVtol(const DROID* psDroid) return NETend(); } -BOOL recvHappyVtol() +BOOL recvHappyVtol(NETQUEUE queue) { DROID* pD; unsigned int i; - NETbeginDecode(NET_VTOL); + NETbeginDecode(queue, NET_VTOL); { uint8_t player; uint32_t droid; @@ -127,7 +127,7 @@ BOOL sendDroidSecondary(const DROID* psDroid, SECONDARY_ORDER sec, SECONDARY_STA if (!bMultiMessages) return true; - NETbeginEncode(NET_SECONDARY, NET_ALL_PLAYERS); + NETbeginEncode(NETgameQueue(selectedPlayer), NET_SECONDARY); { uint8_t player = psDroid->player; uint32_t droid = psDroid->id; @@ -145,7 +145,7 @@ BOOL sendDroidSecondary(const DROID* psDroid, SECONDARY_ORDER sec, SECONDARY_STA } // recv -BOOL recvDroidSecondary() +BOOL recvDroidSecondary(NETQUEUE queue) { DROID* psDroid; SECONDARY_ORDER sec = DSO_ATTACK_RANGE; @@ -153,7 +153,7 @@ BOOL recvDroidSecondary() uint32_t body; Vector3uw pos; - NETbeginDecode(NET_SECONDARY); + NETbeginDecode(queue, NET_SECONDARY); { uint8_t player; uint32_t droid; @@ -198,7 +198,7 @@ BOOL sendDroidSecondaryAll(const DROID* psDroid) if (!bMultiMessages) return true; - NETbeginEncode(NET_SECONDARY_ALL, NET_ALL_PLAYERS); + NETbeginEncode(NETgameQueue(selectedPlayer), NET_SECONDARY_ALL); { uint8_t player = psDroid->player; uint32_t droid = psDroid->id; @@ -211,11 +211,11 @@ BOOL sendDroidSecondaryAll(const DROID* psDroid) return NETend(); } -BOOL recvDroidSecondaryAll() +BOOL recvDroidSecondaryAll(NETQUEUE queue) { DROID* psDroid; - NETbeginDecode(NET_SECONDARY_ALL); + NETbeginDecode(queue, NET_SECONDARY_ALL); { uint8_t player; uint32_t droid, secOrder; @@ -249,7 +249,7 @@ BOOL sendDroidEmbark(const DROID* psDroid, const DROID* psTransporter) if (!bMultiMessages) return true; - NETbeginEncode(NET_DROIDEMBARK, NET_ALL_PLAYERS); + NETbeginEncode(NETgameQueue(selectedPlayer), NET_DROIDEMBARK); { uint8_t player = psDroid->player; uint32_t droidID = psDroid->id; @@ -266,13 +266,13 @@ BOOL sendDroidEmbark(const DROID* psDroid, const DROID* psTransporter) * * \sa sendDroidEmbark(),sendDroidDisEmbark(),recvDroidDisEmbark() */ -BOOL recvDroidEmbark() +BOOL recvDroidEmbark(NETQUEUE queue) { DROID* psDroid; DROID* psTransporterDroid; BOOL bDroidRemoved; - NETbeginDecode(NET_DROIDEMBARK); + NETbeginDecode(queue, NET_DROIDEMBARK); { uint8_t player; uint32_t droidID; @@ -336,7 +336,7 @@ BOOL sendDroidDisEmbark(const DROID* psDroid, const DROID* psTransporter) if (!bMultiMessages) return true; - NETbeginEncode(NET_DROIDDISEMBARK, NET_ALL_PLAYERS); + NETbeginEncode(NETgameQueue(selectedPlayer), NET_DROIDDISEMBARK); { uint8_t player = psDroid->player; uint32_t droidID = psDroid->id; @@ -355,12 +355,12 @@ BOOL sendDroidDisEmbark(const DROID* psDroid, const DROID* psTransporter) * * \sa sendDroidEmbark(),recvDroidEmbark(),sendDroidDisEmbark() */ -BOOL recvDroidDisEmbark() +BOOL recvDroidDisEmbark(NETQUEUE queue) { DROID *psFoundDroid = NULL, *psTransporterDroid = NULL; DROID *psCheckDroid = NULL; - NETbeginDecode(NET_DROIDDISEMBARK); + NETbeginDecode(queue, NET_DROIDDISEMBARK); { uint8_t player; uint32_t droidID; @@ -450,7 +450,7 @@ BOOL SendDroidMove(const DROID* psDroid, uint32_t x, uint32_t y, BOOL formation) return true; } - NETbeginEncode(NET_DROIDMOVE, NET_ALL_PLAYERS); + NETbeginEncode(NETgameQueue(selectedPlayer), NET_DROIDMOVE); { uint8_t player = psDroid->player; uint32_t droid = psDroid->id; @@ -465,13 +465,13 @@ BOOL SendDroidMove(const DROID* psDroid, uint32_t x, uint32_t y, BOOL formation) } // recv and updated droid position -BOOL recvDroidMove() +BOOL recvDroidMove(NETQUEUE queue) { DROID* psDroid; uint32_t x, y; BOOL formation; - NETbeginDecode(NET_DROIDMOVE); + NETbeginDecode(queue, NET_DROIDMOVE); { uint8_t player; uint32_t droid; @@ -487,14 +487,14 @@ BOOL recvDroidMove() if ((x == 0 && y == 0) || x > world_coord(mapWidth) || y > world_coord(mapHeight)) { /* Probably an invalid droid position */ - debug(LOG_ERROR, "Received an invalid droid position from %d, [%s : p%d]", NETgetSource(), + debug(LOG_ERROR, "Received an invalid droid position from %d, [%s : p%d]", queue.index, isHumanPlayer(player) ? "Human" : "AI", player); return false; } if (!IdToDroid(droid, player, &psDroid)) { debug(LOG_ERROR, "Packet from %d refers to non-existent droid %u, [%s : p%d]", - NETgetSource(), droid, isHumanPlayer(player) ? "Human" : "AI", player); + queue.index, droid, isHumanPlayer(player) ? "Human" : "AI", player); return false; } } @@ -537,7 +537,7 @@ BOOL SendDroid(const DROID_TEMPLATE* pTemplate, uint32_t x, uint32_t y, uint8_t } debug(LOG_SYNC, "Droid sent with id of %u", id); - NETbeginEncode(NET_DROID, NET_ALL_PLAYERS); + NETbeginEncode(NETgameQueue(selectedPlayer), NET_DROID); { Vector3uw pos = { x, y, 0 }; uint32_t templateID = pTemplate->multiPlayerID; @@ -556,7 +556,7 @@ BOOL SendDroid(const DROID_TEMPLATE* pTemplate, uint32_t x, uint32_t y, uint8_t // //////////////////////////////////////////////////////////////////////////// // receive droid creation information from other players -BOOL recvDroid() +BOOL recvDroid(NETQUEUE queue) { DROID_TEMPLATE* pT; DROID* psDroid; @@ -567,7 +567,7 @@ BOOL recvDroid() uint32_t templateID; uint32_t power; - NETbeginDecode(NET_DROID); + NETbeginDecode(queue, NET_DROID); { NETuint8_t(&player); NETuint32_t(&id); @@ -586,7 +586,7 @@ BOOL recvDroid() if ((pos.x == 0 && pos.y == 0) || pos.x > world_coord(mapWidth) || pos.y > world_coord(mapHeight)) { debug(LOG_ERROR, "Received bad droid position (%d, %d) from %d about p%d (%s)", (int)pos.x, (int)pos.y, - NETgetSource(), player, isHumanPlayer(player) ? "Human" : "AI"); + queue.index, player, isHumanPlayer(player) ? "Human" : "AI"); return false; } @@ -594,7 +594,7 @@ BOOL recvDroid() if (!pT) { debug(LOG_ERROR, "Packet from %d refers to non-existent template %u, [%s : p%d]", - NETgetSource(), templateID, isHumanPlayer(player) ? "Human" : "AI", player); + queue.index, templateID, isHumanPlayer(player) ? "Human" : "AI", player); return false; } @@ -616,7 +616,7 @@ BOOL recvDroid() } else { - debug(LOG_ERROR, "Packet from %d cannot create droid for p%d (%s)!", NETgetSource(), + debug(LOG_ERROR, "Packet from %d cannot create droid for p%d (%s)!", queue.index, player, isHumanPlayer(player) ? "Human" : "AI"); #ifdef DEBUG CONPRINTF(ConsoleString, (ConsoleString, "MULTIPLAYER: Couldn't build a remote droid, relying on checking to resync")); @@ -648,7 +648,7 @@ BOOL SendGroupOrderSelected(uint8_t player, uint32_t x, uint32_t y, const BASE_O if (!bMultiMessages) return true; - NETbeginEncode(NET_GROUPORDER, NET_ALL_PLAYERS); + NETbeginEncode(NETgameQueue(selectedPlayer), NET_GROUPORDER); { DROID_ORDER order = (altOrder?DORDER_UNKNOWN_ALT:DORDER_UNKNOWN); BOOL subType = (psObj) ? true : false, cmdOrder = false; @@ -722,7 +722,7 @@ BOOL SendGroupOrderGroup(const DROID_GROUP* psGroup, DROID_ORDER order, uint32_t if (!bMultiMessages) return true; - NETbeginEncode(NET_GROUPORDER, NET_ALL_PLAYERS); + NETbeginEncode(NETgameQueue(selectedPlayer), NET_GROUPORDER); { BOOL subType = (psObj) ? true : false, cmdOrder = false; DROID *psDroid; @@ -777,7 +777,7 @@ BOOL SendGroupOrderGroup(const DROID_GROUP* psGroup, DROID_ORDER order, uint32_t // //////////////////////////////////////////////////////////////////////////// // receive a group order. -BOOL recvGroupOrder() +BOOL recvGroupOrder(NETQUEUE queue) { DROID_ORDER order = DORDER_NONE; BOOL subType, cmdOrder; @@ -790,7 +790,7 @@ BOOL recvGroupOrder() uint32_t *droidBodies; Vector3uw *droidPositions; - NETbeginDecode(NET_GROUPORDER); + NETbeginDecode(queue, NET_GROUPORDER); { NETuint8_t(&player); // FYI: anything over MAX_PLAYERS means this is a ai player NETenum(&order); @@ -826,14 +826,7 @@ BOOL recvGroupOrder() for (i = 0; i < droidCount; ++i) { // Retrieve the id number for the current droid - if (!NETuint32_t(&droidIDs[i])) - { - // If somehow we fail assume the message got truncated prematurely - debug(LOG_SYNC, "Error retrieving droid ID number; while there are (supposed to be) still %u droids left for p%d", - (unsigned int)(droidCount - i), player); - NETend(); - return false; - } + NETuint32_t(&droidIDs[i]); // Get the body points of the droid NETuint32_t(&droidBodies[i]); @@ -842,12 +835,18 @@ BOOL recvGroupOrder() NETVector3uw(&droidPositions[i]); } } - NETend(); + if (!NETend()) + { + // If somehow we fail assume the message got truncated prematurely + debug(LOG_SYNC, "Error retrieving droid ID number; while there are (supposed to be) still %u droids left for p%d", + (unsigned int)droidCount, player); + return false; + } /* Check if the order is valid */ if (order != DORDER_UNKNOWN && order != DORDER_UNKNOWN_ALT && ((subType && !validOrderForObj(order)) || (!subType && !validOrderForLoc(order)))) { - debug(LOG_ERROR, "Invalid group order received from %d, [%s : p%d]", NETgetSource(), + debug(LOG_ERROR, "Invalid group order received from %d, [%s : p%d]", queue.index, isHumanPlayer(player) ? "Human" : "AI", player); return false; } @@ -863,7 +862,7 @@ BOOL recvGroupOrder() if (!IdToDroid(droidIDs[i], ANYPLAYER, &psDroid)) { debug(LOG_ERROR, "Packet from %d refers to non-existent droid %u, [%s : p%d]", - NETgetSource(), droidIDs[i], isHumanPlayer(player) ? "Human" : "AI", player); + queue.index, droidIDs[i], isHumanPlayer(player) ? "Human" : "AI", player); continue; // continue working on next droid; crossing fingers... } @@ -919,7 +918,7 @@ BOOL SendDroidInfo(const DROID* psDroid, DROID_ORDER order, uint32_t x, uint32_t return true; } - NETbeginEncode(NET_DROIDINFO, NET_ALL_PLAYERS); + NETbeginEncode(NETgameQueue(selectedPlayer), NET_DROIDINFO); { uint32_t droidId = psDroid->id; BOOL subType = (psObj) ? true : false; @@ -952,9 +951,9 @@ BOOL SendDroidInfo(const DROID* psDroid, DROID_ORDER order, uint32_t x, uint32_t // //////////////////////////////////////////////////////////////////////////// // receive droid information form other players. -BOOL recvDroidInfo() +BOOL recvDroidInfo(NETQUEUE queue) { - NETbeginDecode(NET_DROIDINFO); + NETbeginDecode(queue, NET_DROIDINFO); { uint32_t droidId; DROID* psDroid; @@ -968,7 +967,7 @@ BOOL recvDroidInfo() if (!IdToDroid(droidId, ANYPLAYER, &psDroid)) { debug(LOG_ERROR, "Packet from %d refers to non-existent droid %u, [%s : p%d]", - NETgetSource(), droidId, isHumanPlayer(player) ? "Human" : "AI", player); + queue.index, droidId, isHumanPlayer(player) ? "Human" : "AI", player); return false; } @@ -1101,7 +1100,7 @@ BOOL SendDestroyDroid(const DROID* psDroid) return true; } - NETbeginEncode(NET_DROIDDEST, NET_ALL_PLAYERS); + NETbeginEncode(NETgameQueue(selectedPlayer), NET_DROIDDEST); { uint32_t id = psDroid->id; @@ -1114,11 +1113,11 @@ BOOL SendDestroyDroid(const DROID* psDroid) // //////////////////////////////////////////////////////////////////////////// // Accept a droid which was destroyed on another machine -BOOL recvDestroyDroid() +BOOL recvDestroyDroid(NETQUEUE queue) { DROID* psDroid; - NETbeginDecode(NET_DROIDDEST); + NETbeginDecode(queue, NET_DROIDDEST); { uint32_t id; @@ -1127,7 +1126,7 @@ BOOL recvDestroyDroid() if (!IdToDroid(id, ANYPLAYER, &psDroid)) { debug(LOG_DEATH, "droid %d on request from player %d can't be found? Must be dead already?", - id, NETgetSource() ); + id, queue.index ); return false; } } @@ -1137,13 +1136,13 @@ BOOL recvDestroyDroid() if(!psDroid->died) { turnOffMultiMsg(true); - debug(LOG_DEATH, "Killing droid %d on request from player %d", psDroid->id, NETgetSource()); + debug(LOG_DEATH, "Killing droid %d on request from player %d", psDroid->id, queue.index); destroyDroid(psDroid); turnOffMultiMsg(false); } else { - debug(LOG_DEATH, "droid %d on request from player %d is dead already?", psDroid->id, NETgetSource()); + debug(LOG_DEATH, "droid %d on request from player %d is dead already?", psDroid->id, queue.index); } return true; diff --git a/src/multigifts.c b/src/multigifts.c index e3959587a..a13635484 100644 --- a/src/multigifts.c +++ b/src/multigifts.c @@ -65,13 +65,13 @@ static void giftResearch (uint8_t from, uint8_t to, BOOL send); /////////////////////////////////////////////////////////////////////////////// // gifts.. -BOOL recvGift(void) +BOOL recvGift(NETQUEUE queue) { uint8_t type, from, to; int audioTrack; uint32_t droidID; - NETbeginDecode(NET_GIFT); + NETbeginDecode(queue, NET_GIFT); NETuint8_t(&type); NETuint8_t(&from); NETuint8_t(&to); @@ -158,7 +158,7 @@ void giftRadar(uint8_t from, uint8_t to, BOOL send) { uint8_t subType = RADAR_GIFT; - NETbeginEncode(NET_GIFT, NET_ALL_PLAYERS); + NETbeginEncode(NETgameQueue(selectedPlayer), NET_GIFT); NETuint8_t(&subType); NETuint8_t(&from); NETuint8_t(&to); @@ -244,7 +244,7 @@ static void sendGiftDroids(uint8_t from, uint8_t to) } if (psD->selected) { - NETbeginEncode(NET_GIFT, NET_ALL_PLAYERS); + NETbeginEncode(NETgameQueue(selectedPlayer), NET_GIFT); NETuint8_t(&giftType); NETuint8_t(&from); NETuint8_t(&to); @@ -289,7 +289,7 @@ static void giftResearch(uint8_t from, uint8_t to, BOOL send) { uint8_t giftType = RESEARCH_GIFT; - NETbeginEncode(NET_GIFT, NET_ALL_PLAYERS); + NETbeginEncode(NETgameQueue(selectedPlayer), NET_GIFT); NETuint8_t(&giftType); NETuint8_t(&from); NETuint8_t(&to); @@ -327,7 +327,7 @@ void giftPower(uint8_t from, uint8_t to, BOOL send) { uint8_t giftType = POWER_GIFT; - NETbeginEncode(NET_GIFT, NET_ALL_PLAYERS); + NETbeginEncode(NETgameQueue(selectedPlayer), NET_GIFT); NETuint8_t(&giftType); NETuint8_t(&from); NETuint8_t(&to); @@ -470,7 +470,7 @@ void formAlliance(uint8_t p1, uint8_t p2, BOOL prop, BOOL allowAudio, BOOL allow void sendAlliance(uint8_t from, uint8_t to, uint8_t state, int32_t value) { - NETbeginEncode(NET_ALLIANCE, NET_ALL_PLAYERS); + NETbeginEncode(NETgameQueue(selectedPlayer), NET_ALLIANCE); NETuint8_t(&from); NETuint8_t(&to); NETuint8_t(&state); @@ -478,12 +478,12 @@ void sendAlliance(uint8_t from, uint8_t to, uint8_t state, int32_t value) NETend(); } -BOOL recvAlliance(BOOL allowAudio) +BOOL recvAlliance(NETQUEUE queue, BOOL allowAudio) { uint8_t to, from, state; int32_t value; - NETbeginDecode(NET_ALLIANCE); + NETbeginDecode(queue, NET_ALLIANCE); NETuint8_t(&from); NETuint8_t(&to); NETuint8_t(&state); @@ -546,7 +546,7 @@ void technologyGiveAway(const STRUCTURE *pS) pF->player = pS->player; } - NETbeginEncode(NET_ARTIFACTS, NET_ALL_PLAYERS); + NETbeginEncode(NETgameQueue(selectedPlayer), NET_ARTIFACTS); { /* Make sure that we don't have to violate the constness of pS. * Since the nettype functions aren't const correct when sending @@ -572,7 +572,7 @@ void technologyGiveAway(const STRUCTURE *pS) */ void sendMultiPlayerFeature(FEATURE_TYPE subType, uint32_t x, uint32_t y, uint32_t id) { - NETbeginEncode(NET_FEATURES, NET_ALL_PLAYERS); + NETbeginEncode(NETgameQueue(selectedPlayer), NET_FEATURES); { NETenum(&subType); NETuint32_t(&x); @@ -582,13 +582,13 @@ void sendMultiPlayerFeature(FEATURE_TYPE subType, uint32_t x, uint32_t y, uint32 NETend(); } -void recvMultiPlayerFeature() +void recvMultiPlayerFeature(NETQUEUE queue) { FEATURE_TYPE subType; uint32_t x, y, id; unsigned int i; - NETbeginDecode(NET_FEATURES); + NETbeginDecode(queue, NET_FEATURES); { NETenum(&subType); NETuint32_t(&x); @@ -637,7 +637,7 @@ void addMultiPlayerRandomArtifacts(uint8_t quantity, FEATURE_TYPE type) uint8_t player = ANYPLAYER; debug(LOG_FEATURE, "Sending %u artifact(s) type: (%s)", quantity, feature_names[type]); - NETbeginEncode(NET_ARTIFACTS, NET_ALL_PLAYERS); + NETbeginEncode(NETgameQueue(selectedPlayer), NET_ARTIFACTS); NETuint8_t(&quantity); NETenum(&type); @@ -702,7 +702,7 @@ BOOL addOilDrum(uint8_t count) // /////////////////////////////////////////////////////////////// // receive splattered artifacts -void recvMultiPlayerRandomArtifacts() +void recvMultiPlayerRandomArtifacts(NETQUEUE queue) { int count, i; uint8_t quantity, player; @@ -711,7 +711,7 @@ void recvMultiPlayerRandomArtifacts() FEATURE_TYPE type; FEATURE *pF; - NETbeginDecode(NET_ARTIFACTS); + NETbeginDecode(queue, NET_ARTIFACTS); NETuint8_t(&quantity); NETenum(&type); diff --git a/src/multigifts.h b/src/multigifts.h index 1e3f8e549..8dd393ae0 100644 --- a/src/multigifts.h +++ b/src/multigifts.h @@ -33,17 +33,17 @@ extern void requestAlliance (uint8_t from, uint8_t to, BOOL prop, BOOL allowAud extern void breakAlliance (uint8_t p1, uint8_t p2, BOOL prop, BOOL allowAudio); extern void formAlliance (uint8_t p1, uint8_t p2, BOOL prop, BOOL allowAudio, BOOL allowNotification); extern void sendAlliance (uint8_t from, uint8_t to, uint8_t state, int32_t value); -extern BOOL recvAlliance (BOOL allowAudio); +extern BOOL recvAlliance (NETQUEUE queue, BOOL allowAudio); // Was declared in multirecv.h, too. extern void createTeamAlliances (void); extern BOOL sendGift (uint8_t type, uint8_t to); -extern BOOL recvGift (void); +extern BOOL recvGift (NETQUEUE queue); extern void technologyGiveAway (const STRUCTURE* pS); -extern void recvMultiPlayerRandomArtifacts (void); +extern void recvMultiPlayerRandomArtifacts (NETQUEUE queue); extern void addMultiPlayerRandomArtifacts (uint8_t quantity, FEATURE_TYPE type); extern void processMultiPlayerArtifacts (void); -extern void recvMultiPlayerFeature(void); +extern void recvMultiPlayerFeature (NETQUEUE queue); extern void sendMultiPlayerFeature(FEATURE_TYPE type, uint32_t x, uint32_t y, uint32_t id); extern void giftArtifact (UDWORD owner,UDWORD x,UDWORD y); diff --git a/src/multiint.c b/src/multiint.c index 76381c702..6b02b4f21 100644 --- a/src/multiint.c +++ b/src/multiint.c @@ -88,6 +88,7 @@ #include "multirecv.h" #include "multimenu.h" #include "multilimit.h" +#include "multigifts.h" #include "warzoneconfig.h" @@ -1595,7 +1596,7 @@ static BOOL SendTeamRequest(UBYTE player, UBYTE chosenTeam) } else { - NETbeginEncode(NET_TEAMREQUEST, NET_HOST_ONLY); + NETbeginEncode(NETnetQueue(NET_HOST_ONLY), NET_TEAMREQUEST); NETuint8_t(&player); NETuint8_t(&chosenTeam); @@ -1606,7 +1607,7 @@ static BOOL SendTeamRequest(UBYTE player, UBYTE chosenTeam) return true; } -BOOL recvTeamRequest() +BOOL recvTeamRequest(NETQUEUE queue) { UBYTE player, team; @@ -1615,7 +1616,7 @@ BOOL recvTeamRequest() return true; } - NETbeginDecode(NET_TEAMREQUEST); + NETbeginDecode(queue, NET_TEAMREQUEST); NETuint8_t(&player); NETuint8_t(&team); NETend(); @@ -1623,7 +1624,7 @@ BOOL recvTeamRequest() if (player > MAX_PLAYERS || team > MAX_PLAYERS) { debug(LOG_ERROR, "Invalid NET_TEAMREQUEST from player %d: Tried to change player %d (team %d)", - NETgetSource(), (int)player, (int)team); + queue.index, (int)player, (int)team); return false; } @@ -1644,7 +1645,7 @@ static BOOL SendReadyRequest(UBYTE player, BOOL bReady) } else { - NETbeginEncode(NET_READY_REQUEST, NET_ALL_PLAYERS); + NETbeginEncode(NETbroadcastQueue(), NET_READY_REQUEST); NETuint8_t(&player); NETbool(&bReady); NETend(); @@ -1652,7 +1653,7 @@ static BOOL SendReadyRequest(UBYTE player, BOOL bReady) return true; } -BOOL recvReadyRequest() +BOOL recvReadyRequest(NETQUEUE queue) { UBYTE player; BOOL bReady; @@ -1662,7 +1663,7 @@ BOOL recvReadyRequest() return true; } - NETbeginDecode(NET_READY_REQUEST); + NETbeginDecode(queue, NET_READY_REQUEST); NETuint8_t(&player); NETbool(&bReady); NETend(); @@ -1670,7 +1671,7 @@ BOOL recvReadyRequest() if (player > MAX_PLAYERS) { debug(LOG_ERROR, "Invalid NET_READY_REQUEST from player %d: player id = %d", - NETgetSource(), (int)player); + queue.index, (int)player); return false; } @@ -1766,7 +1767,7 @@ static BOOL SendColourRequest(UBYTE player, UBYTE col) else { // clients tell the host which color they want - NETbeginEncode(NET_COLOURREQUEST, NET_HOST_ONLY); + NETbeginEncode(NETnetQueue(NET_HOST_ONLY), NET_COLOURREQUEST); NETuint8_t(&player); NETuint8_t(&col); NETend(); @@ -1784,7 +1785,7 @@ static BOOL SendPositionRequest(UBYTE player, UBYTE position) { debug(LOG_NET, "Requesting the host to change our position. From %d to %d", player, position); // clients tell the host which position they want - NETbeginEncode(NET_POSITIONREQUEST, NET_HOST_ONLY); + NETbeginEncode(NETnetQueue(NET_HOST_ONLY), NET_POSITIONREQUEST); NETuint8_t(&player); NETuint8_t(&position); NETend(); @@ -1792,7 +1793,7 @@ static BOOL SendPositionRequest(UBYTE player, UBYTE position) return true; } -BOOL recvColourRequest() +BOOL recvColourRequest(NETQUEUE queue) { UBYTE player, col; @@ -1801,7 +1802,7 @@ BOOL recvColourRequest() return true; } - NETbeginDecode(NET_COLOURREQUEST); + NETbeginDecode(queue, NET_COLOURREQUEST); NETuint8_t(&player); NETuint8_t(&col); NETend(); @@ -1809,7 +1810,7 @@ BOOL recvColourRequest() if (player > MAX_PLAYERS) { debug(LOG_ERROR, "Invalid NET_COLOURREQUEST from player %d: Tried to change player %d to colour %d", - NETgetSource(), (int)player, (int)col); + queue.index, (int)player, (int)col); return false; } @@ -1818,7 +1819,7 @@ BOOL recvColourRequest() return changeColour(player, col); } -BOOL recvPositionRequest() +BOOL recvPositionRequest(NETQUEUE queue) { UBYTE player, position; @@ -1827,7 +1828,7 @@ BOOL recvPositionRequest() return true; } - NETbeginDecode(NET_POSITIONREQUEST); + NETbeginDecode(queue, NET_POSITIONREQUEST); NETuint8_t(&player); NETuint8_t(&position); NETend(); @@ -1835,7 +1836,7 @@ BOOL recvPositionRequest() if (player > MAX_PLAYERS || position > MAX_PLAYERS) { debug(LOG_ERROR, "Invalid NET_POSITIONREQUEST from player %d: Tried to change player %d to %d", - NETgetSource(), (int)player, (int)position); + queue.index, (int)player, (int)position); return false; } @@ -2152,7 +2153,7 @@ UDWORD addPlayerBox(BOOL players) */ static void SendFireUp(void) { - NETbeginEncode(NET_FIREUP, NET_ALL_PLAYERS); + NETbeginEncode(NETbroadcastQueue(), NET_FIREUP); // no payload necessary NETend(); } @@ -2161,7 +2162,7 @@ static void SendFireUp(void) void kickPlayer(uint32_t player_id, const char *reason, LOBBY_ERROR_TYPES type) { // send a kick msg - NETbeginEncode(NET_KICK, NET_ALL_PLAYERS); + NETbeginEncode(NETbroadcastQueue(), NET_KICK); NETuint32_t(&player_id); NETstring( (char *) reason, MAX_KICK_REASON); NETenum(&type); @@ -2293,7 +2294,7 @@ static void stopJoining(void) { // annouce we are leaving... debug(LOG_NET, "Host is quitting game..."); - NETbeginEncode(NET_HOST_DROPPED, NET_ALL_PLAYERS); + NETbeginEncode(NETbroadcastQueue(), NET_HOST_DROPPED); NETend(); sendLeavingMsg(); // say goodbye NETclose(); // quit running game. @@ -2883,20 +2884,21 @@ void startMultiplayerGame(void) void frontendMultiMessages(void) { + NETQUEUE queue; uint8_t type; - while(NETrecv(&type)) + while (NETrecvNet(&queue, &type)) { // Copy the message to the global one used by the new NET API switch(type) { case NET_FILE_REQUESTED: - recvMapFileRequested(); + recvMapFileRequested(queue); break; case NET_FILE_PAYLOAD: widgSetButtonState(psWScreen, MULTIOP_MAP_BUT, 1); // turn preview button off - if (recvMapFileData()) + if (recvMapFileData(queue)) { widgSetButtonState(psWScreen, MULTIOP_MAP_BUT, 0); // turn it back on again } @@ -2907,7 +2909,7 @@ void frontendMultiMessages(void) uint32_t reason; uint32_t victim; - NETbeginDecode(NET_FILE_CANCELLED); + NETbeginDecode(queue, NET_FILE_CANCELLED); NETuint32_t(&victim); NETuint32_t(&reason); NETend(); @@ -2931,7 +2933,7 @@ void frontendMultiMessages(void) break; case NET_OPTIONS: // incoming options file. - recvOptions(); + recvOptions(queue); ingame.localOptionsReceived = true; if(titleMode == MULTIOPTION) @@ -2943,23 +2945,23 @@ void frontendMultiMessages(void) break; case NET_ALLIANCE: - recvAlliance(false); + recvAlliance(queue, false); break; case NET_COLOURREQUEST: - recvColourRequest(); + recvColourRequest(queue); break; case NET_POSITIONREQUEST: - recvPositionRequest(); + recvPositionRequest(queue); break; case NET_TEAMREQUEST: - recvTeamRequest(); + recvTeamRequest(queue); break; case NET_READY_REQUEST: - recvReadyRequest(); + recvReadyRequest(queue); // if hosting try to start the game if everyone is ready if(NetPlay.isHost && multiplayPlayersReady(false)) @@ -2969,7 +2971,7 @@ void frontendMultiMessages(void) break; case NET_PING: // diagnostic ping msg. - recvPing(); + recvPing(queue); break; case NET_PLAYER_DROPPED: // remote player got disconnected @@ -2979,7 +2981,7 @@ void frontendMultiMessages(void) resetReadyStatus(false); - NETbeginDecode(NET_PLAYER_DROPPED); + NETbeginDecode(queue, NET_PLAYER_DROPPED); { NETuint32_t(&player_id); NETbool(&host); @@ -3002,7 +3004,7 @@ void frontendMultiMessages(void) resetReadyStatus(false); - NETbeginDecode(NET_PLAYERRESPONDING); + NETbeginDecode(queue, NET_PLAYERRESPONDING); // the player that has just responded NETuint32_t(&player_id); NETend(); @@ -3037,7 +3039,7 @@ void frontendMultiMessages(void) char reason[MAX_KICK_REASON]; LOBBY_ERROR_TYPES KICK_TYPE = ERROR_NOERROR; - NETbeginDecode(NET_KICK); + NETbeginDecode(queue, NET_KICK); NETuint32_t(&player_id); NETstring( reason, MAX_KICK_REASON); NETenum(&KICK_TYPE); @@ -3060,7 +3062,7 @@ void frontendMultiMessages(void) break; } case NET_HOST_DROPPED: - NETbeginDecode(NET_HOST_DROPPED); + NETbeginDecode(queue, NET_HOST_DROPPED); NETend(); stopJoining(); debug(LOG_NET, "The host has quit!"); @@ -3070,7 +3072,7 @@ void frontendMultiMessages(void) case NET_TEXTMSG: // Chat message if(ingame.localOptionsReceived) { - recvTextMessage(); + recvTextMessage(queue); } break; } diff --git a/src/multijoin.c b/src/multijoin.c index 87dc63b1a..45d0e5820 100644 --- a/src/multijoin.c +++ b/src/multijoin.c @@ -278,7 +278,7 @@ bool sendDataCheck(void) int i = 0; uint32_t player = selectedPlayer; - NETbeginEncode(NET_DATA_CHECK, NET_HOST_ONLY); // only need to send to HOST + NETbeginEncode(NETnetQueue(NET_HOST_ONLY), NET_DATA_CHECK); // only need to send to HOST for(i = 0; i < DATA_MAXDATA; i++) { NETuint32_t(&DataHash[i]); @@ -289,13 +289,13 @@ bool sendDataCheck(void) return true; } -bool recvDataCheck(void) +bool recvDataCheck(NETQUEUE queue) { int i = 0; uint32_t player; uint32_t tempBuffer[DATA_MAXDATA] = {0}; - NETbeginDecode(NET_DATA_CHECK); + NETbeginDecode(queue, NET_DATA_CHECK); for(i = 0; i < DATA_MAXDATA; i++) { NETuint32_t(&tempBuffer[i]); diff --git a/src/multijoin.h b/src/multijoin.h index 4a5fe88ba..eac7611b6 100644 --- a/src/multijoin.h +++ b/src/multijoin.h @@ -46,7 +46,7 @@ typedef struct { extern DROIDSTORE *tempDroidList; extern void ShowMOTD(void); -extern bool recvDataCheck(void); +extern bool recvDataCheck(NETQUEUE queue); extern bool sendDataCheck(void); #ifdef __cplusplus diff --git a/src/multiopt.c b/src/multiopt.c index c57443f1f..4c40173a7 100644 --- a/src/multiopt.c +++ b/src/multiopt.c @@ -68,7 +68,7 @@ void sendOptions() { unsigned int i; - NETbeginEncode(NET_OPTIONS, NET_ALL_PLAYERS); + NETbeginEncode(NETbroadcastQueue(), NET_OPTIONS); // First send information about the game NETuint8_t(&game.type); @@ -137,11 +137,11 @@ static BOOL checkGameWdg(const char *nm) // //////////////////////////////////////////////////////////////////////////// // options for a game. (usually recvd in frontend) -void recvOptions() +void recvOptions(NETQUEUE queue) { unsigned int i; - NETbeginDecode(NET_OPTIONS); + NETbeginDecode(queue, NET_OPTIONS); // Get general information about the game NETuint8_t(&game.type); @@ -221,7 +221,7 @@ void recvOptions() debug(LOG_NET, "Map was not found, requesting map %s from host.", game.map); // Request the map from the host - NETbeginEncode(NET_FILE_REQUESTED, NET_HOST_ONLY); + NETbeginEncode(NETnetQueue(NET_HOST_ONLY), NET_FILE_REQUESTED); NETuint32_t(&player); NETend(); @@ -312,7 +312,7 @@ BOOL joinCampaign(UDWORD gameNumber, char *sPlayer) BOOL sendLeavingMsg(void) { debug(LOG_NET, "We are leaving 'nicely'"); - NETbeginEncode(NET_PLAYER_LEAVING, NET_ALL_PLAYERS); + NETbeginEncode(NETbroadcastQueue(), NET_PLAYER_LEAVING); { BOOL host = NetPlay.isHost; uint32_t id = selectedPlayer; @@ -518,6 +518,12 @@ static BOOL gameInit(void) { UDWORD player; + // Setup game queues. + for (player = 0; player < MAX_PLAYERS; ++player) + { + NETinitQueue(NETgameQueue(player)); + } + scriptInit(); // If this is from a savegame, stop here! @@ -575,7 +581,7 @@ void playerResponding(void) cameraToHome(selectedPlayer, false); // Tell the world we're here - NETbeginEncode(NET_PLAYERRESPONDING, NET_ALL_PLAYERS); + NETbeginEncode(NETbroadcastQueue(), NET_PLAYERRESPONDING); NETuint32_t(&selectedPlayer); NETend(); } diff --git a/src/multiplay.c b/src/multiplay.c index 09bba33be..dd61faa11 100644 --- a/src/multiplay.c +++ b/src/multiplay.c @@ -107,9 +107,9 @@ extern PLAYER_RESEARCH* asPlayerResList[MAX_PLAYERS]; // //////////////////////////////////////////////////////////////////////////// // Local Prototypes -static BOOL recvBeacon(void); -static BOOL recvDestroyTemplate(void); -static BOOL recvResearch(void); +static BOOL recvBeacon(NETQUEUE queue); +static BOOL recvDestroyTemplate(NETQUEUE queue); +static BOOL recvResearch(NETQUEUE queue); bool multiplayPlayersReady (bool bNotifyStatus); void startMultiplayerGame (void); @@ -582,9 +582,11 @@ Vector3i cameraToHome(UDWORD player,BOOL scroll) // Recv Messages. Get a message and dispatch to relevant function. BOOL recvMessage(void) { + NETQUEUE queue; uint8_t type; - while(NETrecv(&type)) // for all incoming messages. + // TODO Figure out which messages belong in the game queues, and which are net related. + while(NETrecvNet(&queue, &type) || NETrecvGame(&queue, &type)) // for all incoming messages. { // messages only in game. if(!ingame.localJoiningInProgress) @@ -592,72 +594,72 @@ BOOL recvMessage(void) switch(type) { case NET_DROID: // new droid of known type - recvDroid(); + recvDroid(queue); break; case NET_DROIDINFO: //droid update info - recvDroidInfo(); + recvDroidInfo(queue); break; case NET_DROIDDEST: // droid destroy - recvDestroyDroid(); + recvDestroyDroid(queue); break; case NET_DROIDMOVE: // move a droid to x,y command. - recvDroidMove(); + recvDroidMove(queue); break; case NET_GROUPORDER: // an order for more than 1 droid. - recvGroupOrder(); + recvGroupOrder(queue); break; case NET_CHECK_DROID: // droid damage and position checks - recvDroidCheck(); + recvDroidCheck(queue); break; case NET_CHECK_STRUCT: // structure damage checks. - recvStructureCheck(); + recvStructureCheck(queue); break; case NET_CHECK_POWER: // Power level syncing. - recvPowerCheck(); + recvPowerCheck(queue); break; case NET_TEXTMSG: // simple text message - recvTextMessage(); + recvTextMessage(queue); break; case NET_DATA_CHECK: - recvDataCheck(); + recvDataCheck(queue); break; case NET_AITEXTMSG: //multiplayer AI text message - recvTextMessageAI(); + recvTextMessageAI(queue); break; case NET_BEACONMSG: //beacon (blip) message - recvBeacon(); + recvBeacon(queue); break; case NET_BUILD: // a build order has been sent. - recvBuildStarted(); + recvBuildStarted(queue); break; case NET_BUILDFINISHED: // a building is complete - recvBuildFinished(); + recvBuildFinished(queue); break; case NET_STRUCTDEST: // structure destroy - recvDestroyStructure(); + recvDestroyStructure(queue); break; case NET_SECONDARY: // set a droids secondary order level. - recvDroidSecondary(); + recvDroidSecondary(queue); break; case NET_SECONDARY_ALL: // set a droids secondary order level. - recvDroidSecondaryAll(); + recvDroidSecondaryAll(queue); break; case NET_DROIDEMBARK: - recvDroidEmbark(); //droid has embarked on a Transporter + recvDroidEmbark(queue); //droid has embarked on a Transporter break; case NET_DROIDDISEMBARK: - recvDroidDisEmbark(); //droid has disembarked from a Transporter + recvDroidDisEmbark(queue); //droid has disembarked from a Transporter break; case NET_GIFT: // an alliance gift from one player to another. - recvGift(); + recvGift(queue); break; case NET_SCORESUBMIT: // a score update from another player [UNUSED] see NET_PLAYER_STATS break; case NET_VTOL: - recvHappyVtol(); + recvHappyVtol(queue); break; case NET_LASSAT: - recvLasSat(); + recvLasSat(queue); break; default: break; @@ -668,25 +670,25 @@ BOOL recvMessage(void) switch(type) { case NET_TEMPLATE: // new template - recvTemplate(); + recvTemplate(queue); break; case NET_TEMPLATEDEST: // template destroy - recvDestroyTemplate(); + recvDestroyTemplate(queue); break; case NET_FEATUREDEST: // feature destroy - recvDestroyFeature(); + recvDestroyFeature(queue); break; case NET_PING: // diagnostic ping msg. - recvPing(); + recvPing(queue); break; case NET_DEMOLISH: // structure demolished. - recvDemolishFinished(); + recvDemolishFinished(queue); break; case NET_RESEARCH: // some research has been done. - recvResearch(); + recvResearch(queue); break; case NET_OPTIONS: - recvOptions(); + recvOptions(queue); break; case NET_PLAYERRESPONDING: // remote player is now playing { @@ -694,7 +696,7 @@ BOOL recvMessage(void) resetReadyStatus(false); - NETbeginDecode(NET_PLAYERRESPONDING); + NETbeginDecode(queue, NET_PLAYERRESPONDING); // the player that has just responded NETuint32_t(&player_id); NETend(); @@ -709,16 +711,16 @@ BOOL recvMessage(void) } // FIXME: the next 4 cases might not belong here --check (we got two loops for this) case NET_COLOURREQUEST: - recvColourRequest(); + recvColourRequest(queue); break; case NET_POSITIONREQUEST: - recvPositionRequest(); + recvPositionRequest(queue); break; case NET_TEAMREQUEST: - recvTeamRequest(); + recvTeamRequest(queue); break; case NET_READY_REQUEST: - recvReadyRequest(); + recvReadyRequest(queue); // if hosting try to start the game if everyone is ready if(NetPlay.isHost && multiplayPlayersReady(false)) @@ -727,13 +729,13 @@ BOOL recvMessage(void) } break; case NET_ARTIFACTS: - recvMultiPlayerRandomArtifacts(); + recvMultiPlayerRandomArtifacts(queue); break; case NET_FEATURES: - recvMultiPlayerFeature(); + recvMultiPlayerFeature(queue); break; case NET_ALLIANCE: - recvAlliance(true); + recvAlliance(queue, true); break; case NET_KICK: { @@ -741,7 +743,7 @@ BOOL recvMessage(void) uint32_t player_id; char reason[MAX_KICK_REASON]; - NETbeginDecode(NET_KICK); + NETbeginDecode(queue, NET_KICK); NETuint32_t(&player_id); NETstring( reason, MAX_KICK_REASON); NETend(); @@ -761,10 +763,10 @@ BOOL recvMessage(void) debug(LOG_NET, "NET_FIREUP was received (frontend only?)"); break; case NET_RESEARCHSTATUS: - recvResearchStatus(); + recvResearchStatus(queue); break; case NET_PLAYER_STATS: - recvMultiStats(); + recvMultiStats(queue); break; default: break; @@ -783,7 +785,7 @@ BOOL SendResearch(uint8_t player, uint32_t index, bool trigger) PLAYER_RESEARCH *pPlayerRes; // Send the player that is researching the topic and the topic itself - NETbeginEncode(NET_RESEARCH, NET_ALL_PLAYERS); + NETbeginEncode(NETgameQueue(selectedPlayer), NET_RESEARCH); NETuint8_t(&player); NETuint32_t(&index); NETend(); @@ -816,7 +818,7 @@ BOOL SendResearch(uint8_t player, uint32_t index, bool trigger) } // recv a research topic that is now complete. -static BOOL recvResearch() +static BOOL recvResearch(NETQUEUE queue) { uint8_t player; uint32_t index; @@ -824,7 +826,7 @@ static BOOL recvResearch() PLAYER_RESEARCH *pPlayerRes; RESEARCH *pResearch; - NETbeginDecode(NET_RESEARCH); + NETbeginDecode(queue, NET_RESEARCH); NETuint8_t(&player); NETuint32_t(&index); NETend(); @@ -880,7 +882,7 @@ BOOL sendReseachStatus(STRUCTURE *psBuilding, uint32_t index, uint8_t player, BO return true; } - NETbeginEncode(NET_RESEARCHSTATUS, NET_ALL_PLAYERS); + NETbeginEncode(NETgameQueue(selectedPlayer), NET_RESEARCHSTATUS); NETuint8_t(&player); NETbool(&bStart); @@ -901,7 +903,7 @@ BOOL sendReseachStatus(STRUCTURE *psBuilding, uint32_t index, uint8_t player, BO return true; } -BOOL recvResearchStatus() +BOOL recvResearchStatus(NETQUEUE queue) { STRUCTURE *psBuilding; PLAYER_RESEARCH *pPlayerRes; @@ -911,7 +913,7 @@ BOOL recvResearchStatus() BOOL bStart; uint32_t index, structRef; - NETbeginDecode(NET_RESEARCHSTATUS); + NETbeginDecode(queue, NET_RESEARCHSTATUS); NETuint8_t(&player); NETbool(&bStart); NETuint32_t(&structRef); @@ -1099,7 +1101,7 @@ BOOL sendTextMessage(const char *pStr, BOOL all) if (all) //broadcast { - NETbeginEncode(NET_TEXTMSG, NET_ALL_PLAYERS); + NETbeginEncode(NETbroadcastQueue(), NET_TEXTMSG); NETuint32_t(&selectedPlayer); // who this msg is from NETstring(msg,MAX_CONSOLE_STRING_LENGTH); // the message to send NETend(); @@ -1112,7 +1114,7 @@ BOOL sendTextMessage(const char *pStr, BOOL all) { if (isHumanPlayer(i)) { - NETbeginEncode(NET_TEXTMSG, i); + NETbeginEncode(NETnetQueue(i), NET_TEXTMSG); NETuint32_t(&selectedPlayer); // who this msg is from NETstring(msg,MAX_CONSOLE_STRING_LENGTH); // the message to send NETend(); @@ -1132,7 +1134,7 @@ BOOL sendTextMessage(const char *pStr, BOOL all) { if (isHumanPlayer(i)) { - NETbeginEncode(NET_TEXTMSG, i); + NETbeginEncode(NETnetQueue(i), NET_TEXTMSG); NETuint32_t(&selectedPlayer); // who this msg is from NETstring(display, MAX_CONSOLE_STRING_LENGTH); // the message to send NETend(); @@ -1198,7 +1200,7 @@ BOOL sendAIMessage(char *pStr, UDWORD player, UDWORD to) } //send to the player who is hosting 'to' player (might be himself if human and not AI) - NETbeginEncode(NET_AITEXTMSG, sendPlayer); + NETbeginEncode(NETnetQueue(sendPlayer), NET_AITEXTMSG); NETuint32_t(&player); //save the actual sender //save the actual player that is to get this msg on the source machine (source can host many AIs) NETuint32_t(&to); //save the actual receiver (might not be the same as the one we are actually sending to, in case of AIs) @@ -1227,8 +1229,8 @@ BOOL sendBeacon(int32_t locX, int32_t locY, int32_t forPlayer, int32_t sender, c } // I assume this is correct, looks like it sends it to ONLY that person, and the routine - // kf_AddHelpBlip() itterates for each player it needs. - NETbeginEncode(NET_BEACONMSG, sendPlayer); // send to the player who is hosting 'to' player (might be himself if human and not AI) + // kf_AddHelpBlip() iterates for each player it needs. + NETbeginEncode(NETnetQueue(sendPlayer), NET_BEACONMSG); // send to the player who is hosting 'to' player (might be himself if human and not AI) NETint32_t(&sender); // save the actual sender // save the actual player that is to get this msg on the source machine (source can host many AIs) @@ -1258,7 +1260,7 @@ void displayAIMessage(char *pStr, SDWORD from, SDWORD to) } // Write a message to the console. -BOOL recvTextMessage() +BOOL recvTextMessage(NETQUEUE queue) { UDWORD playerIndex; char msg[MAX_CONSOLE_STRING_LENGTH]; @@ -1267,7 +1269,7 @@ BOOL recvTextMessage() memset(msg, 0x0, sizeof(msg)); memset(newmsg, 0x0, sizeof(newmsg)); - NETbeginDecode(NET_TEXTMSG); + NETbeginDecode(queue, NET_TEXTMSG); // Who this msg is from NETuint32_t(&playerIndex); // The message to send @@ -1309,13 +1311,13 @@ BOOL recvTextMessage() } //AI multiplayer message - received message from AI (from scripts) -BOOL recvTextMessageAI() +BOOL recvTextMessageAI(NETQUEUE queue) { UDWORD sender, receiver; char msg[MAX_CONSOLE_STRING_LENGTH]; char newmsg[MAX_CONSOLE_STRING_LENGTH]; - NETbeginDecode(NET_AITEXTMSG); + NETbeginDecode(queue, NET_AITEXTMSG); NETuint32_t(&sender); //in-game player index ('normal' one) NETuint32_t(&receiver); //in-game player index NETstring(newmsg,MAX_CONSOLE_STRING_LENGTH); @@ -1352,7 +1354,7 @@ BOOL sendTemplate(DROID_TEMPLATE *pTempl) ASSERT(pTempl != NULL, "sendTemplate: Old Pumpkin bug"); if (!pTempl) return true; /* hack */ - NETbeginEncode(NET_TEMPLATE, NET_ALL_PLAYERS); + NETbeginEncode(NETgameQueue(selectedPlayer), NET_TEMPLATE); NETuint8_t(&player); NETuint32_t(&pTempl->ref); NETstring(pTempl->aName, sizeof(pTempl->aName)); @@ -1381,14 +1383,14 @@ BOOL sendTemplate(DROID_TEMPLATE *pTempl) } // receive a template created by another player -BOOL recvTemplate() +BOOL recvTemplate(NETQUEUE queue) { uint8_t player; DROID_TEMPLATE *psTempl; DROID_TEMPLATE t, *pT = &t; int i; - NETbeginDecode(NET_TEMPLATE); + NETbeginDecode(queue, NET_TEMPLATE); NETuint8_t(&player); ASSERT(player < MAX_PLAYERS, "recvtemplate: invalid player size: %d", player); @@ -1447,7 +1449,7 @@ BOOL SendDestroyTemplate(DROID_TEMPLATE *t) { uint8_t player = selectedPlayer; - NETbeginEncode(NET_TEMPLATEDEST, NET_ALL_PLAYERS); + NETbeginEncode(NETgameQueue(selectedPlayer), NET_TEMPLATEDEST); NETuint8_t(&player); NETuint32_t(&t->multiPlayerID); NETend(); @@ -1456,13 +1458,13 @@ BOOL SendDestroyTemplate(DROID_TEMPLATE *t) } // acknowledge another player no longer has a template -static BOOL recvDestroyTemplate() +static BOOL recvDestroyTemplate(NETQUEUE queue) { uint8_t player; uint32_t templateID; DROID_TEMPLATE *psTempl, *psTempPrev = NULL; - NETbeginDecode(NET_TEMPLATEDEST); + NETbeginDecode(queue, NET_TEMPLATEDEST); NETuint8_t(&player); NETuint32_t(&templateID); NETend(); @@ -1506,18 +1508,18 @@ static BOOL recvDestroyTemplate() // send a destruct feature message. BOOL SendDestroyFeature(FEATURE *pF) { - NETbeginEncode(NET_FEATUREDEST, NET_ALL_PLAYERS); + NETbeginEncode(NETgameQueue(selectedPlayer), NET_FEATUREDEST); NETuint32_t(&pF->id); return NETend(); } // process a destroy feature msg. -BOOL recvDestroyFeature() +BOOL recvDestroyFeature(NETQUEUE queue) { FEATURE *pF; uint32_t id; - NETbeginDecode(NET_FEATUREDEST); + NETbeginDecode(queue, NET_FEATUREDEST); NETuint32_t(&id); NETend(); @@ -1539,7 +1541,7 @@ BOOL recvDestroyFeature() // //////////////////////////////////////////////////////////////////////////// // Network File packet processor. -BOOL recvMapFileRequested() +BOOL recvMapFileRequested(NETQUEUE queue) { char mapStr[256],mapName[256],fixedname[256]; uint32_t player; @@ -1554,7 +1556,7 @@ BOOL recvMapFileRequested() } // Check to see who wants the file - NETbeginDecode(NET_FILE_REQUESTED); + NETbeginDecode(queue, NET_FILE_REQUESTED); NETuint32_t(&player); NETend(); @@ -1599,7 +1601,7 @@ BOOL recvMapFileRequested() // NOTE: if we get here, then the game is basically over, The host can't send the file for whatever reason... // Which also means, that we can't continue. debug(LOG_NET, "***Host has a file issue, and is being forced to quit!***"); - NETbeginEncode(NET_HOST_DROPPED, NET_ALL_PLAYERS); + NETbeginEncode(NETbroadcastQueue(), NET_HOST_DROPPED); NETend(); abort(); } @@ -1640,9 +1642,9 @@ void sendMap(void) } // Another player is broadcasting a map, recv a chunk. Returns false if not yet done. -BOOL recvMapFileData() +BOOL recvMapFileData(NETQUEUE queue) { - mapDownloadProgress = NETrecvFile(); + mapDownloadProgress = NETrecvFile(queue); if (mapDownloadProgress == 100) { addConsoleMessage("MAP DOWNLOADED!",DEFAULT_JUSTIFY, SYSTEM_MESSAGE); @@ -1915,12 +1917,12 @@ BOOL msgStackFireTop(void) return true; } -static BOOL recvBeacon(void) +static BOOL recvBeacon(NETQUEUE queue) { int32_t sender, receiver,locX, locY; char msg[MAX_CONSOLE_STRING_LENGTH]; - NETbeginDecode(NET_BEACONMSG); + NETbeginDecode(queue, NET_BEACONMSG); NETint32_t(&sender); // the actual sender NETint32_t(&receiver); // the actual receiver (might not be the same as the one we are actually sending to, in case of AIs) NETint32_t(&locX); diff --git a/src/multirecv.h b/src/multirecv.h index 4f7b7afce..a001d94e7 100644 --- a/src/multirecv.h +++ b/src/multirecv.h @@ -32,43 +32,43 @@ extern "C" { #endif //__cplusplus -extern BOOL recvDroid (void); -extern BOOL recvDroidInfo (void); -extern BOOL recvDestroyDroid (void); -extern BOOL recvGroupOrder (void); -extern BOOL recvDroidMove (void); -extern BOOL recvDestroyStructure (void); -extern BOOL recvBuildStarted (void); -extern BOOL recvBuildFinished (void); -extern BOOL recvTemplate (void); -extern BOOL recvDestroyFeature (void); -extern BOOL recvDemolishFinished (void); -extern BOOL recvPing (void); -extern BOOL recvRequestDroid (void); -extern BOOL recvTextMessage (void); -extern BOOL recvDroidSecondary (void); -extern BOOL recvDroidSecondaryAll (void); -extern BOOL recvDroidEmbark (void); -extern BOOL recvDroidDisEmbark (void); -extern BOOL recvDroidCheck (void); -extern BOOL recvStructureCheck (void); -extern BOOL recvPowerCheck (void); -extern BOOL recvAlliance (BOOL allowAudio); -extern BOOL recvColourRequest (void); -extern BOOL recvPositionRequest (void); -extern void recvOptions (void); -extern void sendOptions (void); +extern BOOL recvDroid (NETQUEUE queue); +extern BOOL recvDroidInfo (NETQUEUE queue); +extern BOOL recvDestroyDroid (NETQUEUE queue); +extern BOOL recvGroupOrder (NETQUEUE queue); +extern BOOL recvDroidMove (NETQUEUE queue); +extern BOOL recvDestroyStructure (NETQUEUE queue); +extern BOOL recvBuildStarted (NETQUEUE queue); +extern BOOL recvBuildFinished (NETQUEUE queue); +extern BOOL recvTemplate (NETQUEUE queue); +extern BOOL recvDestroyFeature (NETQUEUE queue); +extern BOOL recvDemolishFinished (NETQUEUE queue); +extern BOOL recvPing (NETQUEUE queue); +extern BOOL recvRequestDroid (NETQUEUE queue); +extern BOOL recvTextMessage (NETQUEUE queue); +extern BOOL recvDroidSecondary (NETQUEUE queue); +extern BOOL recvDroidSecondaryAll (NETQUEUE queue); +extern BOOL recvDroidEmbark (NETQUEUE queue); +extern BOOL recvDroidDisEmbark (NETQUEUE queue); +extern BOOL recvDroidCheck (NETQUEUE queue); +extern BOOL recvStructureCheck (NETQUEUE queue); +extern BOOL recvPowerCheck (NETQUEUE queue); +//extern BOOL recvAlliance (NETQUEUE queue, BOOL allowAudio); // Was declared in multigifts.h, too. +extern BOOL recvColourRequest (NETQUEUE queue); +extern BOOL recvPositionRequest (NETQUEUE queue); +extern void recvOptions (NETQUEUE queue); +extern void sendOptions (void); -extern BOOL recvHappyVtol (void); -extern BOOL recvResearchStatus (void); -extern BOOL recvLasSat (void); -extern BOOL recvMapFileData (void); -extern BOOL recvMapFileRequested (void); +extern BOOL recvHappyVtol (NETQUEUE queue); +extern BOOL recvResearchStatus (NETQUEUE queue); +extern BOOL recvLasSat (NETQUEUE queue); +extern BOOL recvMapFileData (NETQUEUE queue); +extern BOOL recvMapFileRequested (NETQUEUE queue); -extern BOOL recvTextMessageAI (void); //AI multiplayer message -extern BOOL recvTeamRequest (void); -extern BOOL recvReadyRequest (void); +extern BOOL recvTextMessageAI (NETQUEUE queue); //AI multiplayer message +extern BOOL recvTeamRequest (NETQUEUE queue); +extern BOOL recvReadyRequest (NETQUEUE queue); #ifdef __cplusplus } diff --git a/src/multistat.c b/src/multistat.c index 0a5a09c1f..8e080a7c6 100644 --- a/src/multistat.c +++ b/src/multistat.c @@ -73,7 +73,7 @@ BOOL setMultiStats(SDWORD player, PLAYERSTATS plStats, BOOL bLocal) if (!bLocal) { // Now send it to all other players - NETbeginEncode(NET_PLAYER_STATS, NET_ALL_PLAYERS); + NETbeginEncode(NETbroadcastQueue(), NET_PLAYER_STATS); // Send the ID of the player's stats we're updating NETuint32_t(&playerIndex); @@ -93,11 +93,11 @@ BOOL setMultiStats(SDWORD player, PLAYERSTATS plStats, BOOL bLocal) return true; } -void recvMultiStats() +void recvMultiStats(NETQUEUE queue) { uint32_t playerIndex; - NETbeginDecode(NET_PLAYER_STATS); + NETbeginDecode(queue, NET_PLAYER_STATS); // Retrieve the ID number of the player for which we need to // update the stats NETuint32_t(&playerIndex); diff --git a/src/multistat.h b/src/multistat.h index ef6fbbdc3..f52f5db51 100644 --- a/src/multistat.h +++ b/src/multistat.h @@ -25,6 +25,8 @@ #ifndef __INCLUDED_SRC_MULTISTATS_H__ #define __INCLUDED_SRC_MULTISTATS_H__ +#include "lib/netplay/netplay.h" + #ifdef __cplusplus extern "C" { @@ -56,7 +58,7 @@ extern void updateMultiStatsWins (void); extern void updateMultiStatsLoses (void); extern void updateMultiStatsKills (BASE_OBJECT *psKilled,UDWORD player); -extern void recvMultiStats(void); +extern void recvMultiStats(NETQUEUE queue); #ifdef __cplusplus } diff --git a/src/multistruct.c b/src/multistruct.c index 5edd3c0ee..6030163e5 100644 --- a/src/multistruct.c +++ b/src/multistruct.c @@ -54,7 +54,7 @@ // INFORM others that a building has been started, and base plate should be put down. BOOL sendBuildStarted(STRUCTURE *psStruct, DROID *psDroid) { - NETbeginEncode(NET_BUILD, NET_ALL_PLAYERS); + NETbeginEncode(NETgameQueue(selectedPlayer), NET_BUILD); // Who is building it NETuint8_t(&psDroid->player); @@ -94,7 +94,7 @@ BOOL sendBuildStarted(STRUCTURE *psStruct, DROID *psDroid) // //////////////////////////////////////////////////////////////////////////// // put down a base plate and start droid building it! -BOOL recvBuildStarted() +BOOL recvBuildStarted(NETQUEUE queue) { STRUCTURE_STATS *psStats; DROID *psDroid; @@ -105,7 +105,7 @@ BOOL recvBuildStarted() int32_t order; uint32_t structRef, structId, targetId,droidID; - NETbeginDecode(NET_BUILD); + NETbeginDecode(queue, NET_BUILD); NETuint8_t(&player); NETuint32_t(&structRef); NETuint16_t(&x); @@ -177,7 +177,7 @@ BOOL SendBuildFinished(STRUCTURE *psStruct) uint8_t player = psStruct->player; ASSERT( player < MAX_PLAYERS, "invalid player %u", player); - NETbeginEncode(NET_BUILDFINISHED, NET_ALL_PLAYERS); + NETbeginEncode(NETgameQueue(selectedPlayer), NET_BUILDFINISHED); NETuint32_t(&power); // send how much power we got. NETuint32_t(&psStruct->id); // ID of building @@ -191,7 +191,7 @@ BOOL SendBuildFinished(STRUCTURE *psStruct) } // //////////////////////////////////////////////////////////////////////////// -BOOL recvBuildFinished() +BOOL recvBuildFinished(NETQUEUE queue) { uint32_t structId; STRUCTURE *psStruct; @@ -200,7 +200,7 @@ BOOL recvBuildFinished() uint8_t player; uint32_t power; - NETbeginDecode(NET_BUILDFINISHED); + NETbeginDecode(queue, NET_BUILDFINISHED); NETuint32_t(&power); // get the player's power level NETuint32_t(&structId); // get the struct id. NETuint32_t(&type); // Kind of building. @@ -278,7 +278,7 @@ BOOL recvBuildFinished() // demolish message. BOOL SendDemolishFinished(STRUCTURE *psStruct, DROID *psDroid) { - NETbeginEncode(NET_DEMOLISH, NET_ALL_PLAYERS); + NETbeginEncode(NETgameQueue(selectedPlayer), NET_DEMOLISH); // Send what is being demolish and who is doing it NETuint32_t(&psStruct->id); @@ -287,13 +287,13 @@ BOOL SendDemolishFinished(STRUCTURE *psStruct, DROID *psDroid) return NETend(); } -BOOL recvDemolishFinished() +BOOL recvDemolishFinished(NETQUEUE queue) { STRUCTURE *psStruct; DROID *psDroid; uint32_t structID, droidID; - NETbeginDecode(NET_DEMOLISH); + NETbeginDecode(queue, NET_DEMOLISH); NETuint32_t(&structID); NETuint32_t(&droidID); NETend(); @@ -325,7 +325,7 @@ BOOL recvDemolishFinished() BOOL SendDestroyStructure(STRUCTURE *s) { technologyGiveAway(s); - NETbeginEncode(NET_STRUCTDEST, NET_ALL_PLAYERS); + NETbeginEncode(NETgameQueue(selectedPlayer), NET_STRUCTDEST); // Struct to destroy NETuint32_t(&s->id); @@ -335,12 +335,12 @@ BOOL SendDestroyStructure(STRUCTURE *s) // //////////////////////////////////////////////////////////////////////////// // acknowledge the destruction of a structure, from another player. -BOOL recvDestroyStructure() +BOOL recvDestroyStructure(NETQUEUE queue) { uint32_t structID; STRUCTURE *psStruct; - NETbeginDecode(NET_STRUCTDEST); + NETbeginDecode(queue, NET_STRUCTDEST); NETuint32_t(&structID); NETend(); @@ -365,7 +365,7 @@ BOOL recvDestroyStructure() BOOL sendLasSat(UBYTE player, STRUCTURE *psStruct, BASE_OBJECT *psObj) { - NETbeginEncode(NET_LASSAT, NET_ALL_PLAYERS); + NETbeginEncode(NETgameQueue(selectedPlayer), NET_LASSAT); NETuint8_t(&player); NETuint32_t(&psStruct->id); @@ -376,14 +376,15 @@ BOOL sendLasSat(UBYTE player, STRUCTURE *psStruct, BASE_OBJECT *psObj) } // recv lassat info on the receiving end. -BOOL recvLasSat() +BOOL recvLasSat(NETQUEUE queue) { BASE_OBJECT *psObj; UBYTE player,targetplayer; STRUCTURE *psStruct; uint32_t id,targetid; - NETbeginDecode(NET_LASSAT); + // TODO Add some kind of checking, so that things don't get lasatted by bunkers. + NETbeginDecode(queue, NET_LASSAT); NETuint8_t(&player); NETuint32_t(&id); NETuint32_t(&targetid); diff --git a/src/multisync.c b/src/multisync.c index a0f429002..7fcc00267 100644 --- a/src/multisync.c +++ b/src/multisync.c @@ -258,7 +258,7 @@ BOOL ForceDroidSync(const DROID* droidToSend) debug(LOG_SYNC, "Force sync of droid %u from player %u", droidToSend->id, droidToSend->player); - NETbeginEncode(NET_CHECK_DROID, NET_ALL_PLAYERS); + NETbeginEncode(NETgameQueue(selectedPlayer), NET_CHECK_DROID); NETuint8_t(&count); packageCheck(droidToSend); return NETend(); @@ -286,7 +286,7 @@ static BOOL sendDroidCheck(void) lastSent = gameTime; - NETbeginEncode(NET_CHECK_DROID, NET_ALL_PLAYERS); + NETbeginEncode(NETgameQueue(selectedPlayer), NET_CHECK_DROID); // Allocate space for the list of droids to send ppD = alloca(sizeof(DROID *) * toSend); @@ -378,12 +378,12 @@ static void packageCheck(const DROID* pD) // //////////////////////////////////////////////////////////////////////////// // receive a check and update the local world state accordingly -BOOL recvDroidCheck() +BOOL recvDroidCheck(NETQUEUE queue) { uint8_t count; int i; - NETbeginDecode(NET_CHECK_DROID); + NETbeginDecode(queue, NET_CHECK_DROID); // Get the number of droids to expect NETuint8_t(&count); @@ -709,7 +709,7 @@ static BOOL sendStructureCheck(void) // Only send info about complete buildings if (pS && (pS->status == SS_BUILT)) { - NETbeginEncode(NET_CHECK_STRUCT, NET_ALL_PLAYERS); + NETbeginEncode(NETgameQueue(selectedPlayer), NET_CHECK_STRUCT); NETuint8_t(&pS->player); NETuint32_t(&pS->id); NETuint32_t(&pS->body); @@ -745,7 +745,7 @@ static BOOL sendStructureCheck(void) } // receive checking info about a structure and update local world state -BOOL recvStructureCheck() +BOOL recvStructureCheck(NETQUEUE queue) { STRUCTURE *pS; STRUCTURE_STATS *psStats; @@ -757,7 +757,7 @@ BOOL recvStructureCheck() uint16_t x, y, z; uint32_t ref, type; - NETbeginDecode(NET_CHECK_STRUCT); + NETbeginDecode(queue, NET_CHECK_STRUCT); NETuint8_t(&player); NETuint32_t(&ref); NETuint32_t(&body); @@ -934,18 +934,18 @@ static BOOL sendPowerCheck() lastsent = gameTime; - NETbeginEncode(NET_CHECK_POWER, NET_ALL_PLAYERS); + NETbeginEncode(NETgameQueue(selectedPlayer), NET_CHECK_POWER); NETuint8_t(&player); NETuint32_t(&power); return NETend(); } -BOOL recvPowerCheck() +BOOL recvPowerCheck(NETQUEUE queue) { uint8_t player; uint32_t power, power2; - NETbeginDecode(NET_CHECK_POWER); + NETbeginDecode(queue, NET_CHECK_POWER); NETuint8_t(&player); NETuint32_t(&power); NETend(); @@ -1098,7 +1098,7 @@ BOOL sendPing(void) } } - NETbeginEncode(NET_PING, NET_ALL_PLAYERS); + NETbeginEncode(NETbroadcastQueue(), NET_PING); NETuint8_t(&player); NETbool(&isNew); NETend(); @@ -1113,12 +1113,12 @@ BOOL sendPing(void) } // accept and process incoming ping messages. -BOOL recvPing() +BOOL recvPing(NETQUEUE queue) { BOOL isNew; uint8_t sender, us = selectedPlayer; - NETbeginDecode(NET_PING); + NETbeginDecode(queue, NET_PING); NETuint8_t(&sender); NETbool(&isNew); NETend(); @@ -1132,7 +1132,7 @@ BOOL recvPing() // If this is a new ping, respond to it if (isNew) { - NETbeginEncode(NET_PING, sender); + NETbeginEncode(NETnetQueue(sender), NET_PING); // We are responding to a new ping isNew = false; diff --git a/src/structure.c b/src/structure.c index 38b453718..af10e7a0a 100644 --- a/src/structure.c +++ b/src/structure.c @@ -6381,7 +6381,7 @@ BOOL electronicDamage(BASE_OBJECT *psTarget, UDWORD damage, UBYTE attackPlayer) { uint8_t giftType = DROID_GIFT, droid_count = 1; - NETbeginEncode(NET_GIFT, NET_ALL_PLAYERS); + NETbeginEncode(NETgameQueue(selectedPlayer), NET_GIFT); { // We need to distinguish between gift types NETuint8_t(&giftType);