/* ** Command & Conquer Generals(tm) ** Copyright 2025 Electronic Arts Inc. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . */ //////////////////////////////////////////////////////////////////////////////// // // // (c) 2001-2003 Electronic Arts Inc. // // // //////////////////////////////////////////////////////////////////////////////// #include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine #include "GameNetwork/NetworkUtil.h" Int MAX_FRAMES_AHEAD = 128; Int MIN_RUNAHEAD = 10; Int FRAME_DATA_LENGTH = (MAX_FRAMES_AHEAD+1)*2; Int FRAMES_TO_KEEP = (MAX_FRAMES_AHEAD/2) + 1; #ifdef DEBUG_LOGGING void dumpBufferToLog(const void *vBuf, Int len, const char *fname, Int line) { DEBUG_LOG(("======= dumpBufferToLog() %d bytes =======\n", len)); DEBUG_LOG(("Source: %s:%d\n", fname, line)); const char *buf = (const char *)vBuf; Int numLines = len / 8; if ((len % 8) != 0) { ++numLines; } for (Int dumpindex = 0; dumpindex < numLines; ++dumpindex) { Int offset = dumpindex*8; DEBUG_LOG(("\t%5.5d\t", offset)); Int dumpindex2; Int numBytesThisLine = min(8, len - offset); for (dumpindex2 = 0; dumpindex2 < numBytesThisLine; ++dumpindex2) { Int c = (buf[offset + dumpindex2] & 0xff); DEBUG_LOG(("%02X ", c)); } for (; dumpindex2 < 8; ++dumpindex2) { DEBUG_LOG((" ")); } DEBUG_LOG((" | ")); for (dumpindex2 = 0; dumpindex2 < numBytesThisLine; ++dumpindex2) { char c = buf[offset + dumpindex2]; DEBUG_LOG(("%c", (isprint(c)?c:'.'))); } DEBUG_LOG(("\n")); } DEBUG_LOG(("End of packet dump\n")); } #endif // DEBUG_LOGGING /** * ResolveIP turns a string ("games2.westwood.com", or "192.168.0.1") into * a 32-bit unsigned integer. */ UnsignedInt ResolveIP(AsciiString host) { struct hostent *hostStruct; struct in_addr *hostNode; if (host.getLength() == 0) { DEBUG_LOG(("ResolveIP(): Can't resolve NULL\n")); return 0; } // String such as "127.0.0.1" if (isdigit(host.getCharAt(0))) { return ( ntohl(inet_addr(host.str())) ); } // String such as "localhost" hostStruct = gethostbyname(host.str()); if (hostStruct == NULL) { DEBUG_LOG(("ResolveIP(): Can't resolve %s\n", host.str())); return 0; } hostNode = (struct in_addr *) hostStruct->h_addr; return ( ntohl(hostNode->s_addr) ); } /** * Returns the next network command ID. */ UnsignedShort GenerateNextCommandID() { static UnsignedShort commandID = 64000; ++commandID; return commandID; } /** * Returns true if this type of command requires a unique command ID. */ Bool DoesCommandRequireACommandID(NetCommandType type) { if ((type == NETCOMMANDTYPE_GAMECOMMAND) || (type == NETCOMMANDTYPE_FRAMEINFO) || (type == NETCOMMANDTYPE_PLAYERLEAVE) || (type == NETCOMMANDTYPE_DESTROYPLAYER) || (type == NETCOMMANDTYPE_RUNAHEADMETRICS) || (type == NETCOMMANDTYPE_RUNAHEAD) || (type == NETCOMMANDTYPE_CHAT) || (type == NETCOMMANDTYPE_DISCONNECTVOTE) || (type == NETCOMMANDTYPE_LOADCOMPLETE) || (type == NETCOMMANDTYPE_TIMEOUTSTART) || (type == NETCOMMANDTYPE_WRAPPER) || (type == NETCOMMANDTYPE_FILE) || (type == NETCOMMANDTYPE_FILEANNOUNCE) || (type == NETCOMMANDTYPE_FILEPROGRESS) || (type == NETCOMMANDTYPE_DISCONNECTPLAYER) || (type == NETCOMMANDTYPE_DISCONNECTFRAME) || (type == NETCOMMANDTYPE_DISCONNECTSCREENOFF) || (type == NETCOMMANDTYPE_FRAMERESENDREQUEST)) { return TRUE; } return FALSE; } /** * Returns true if this type of network command requires an ack. */ Bool CommandRequiresAck(NetCommandMsg *msg) { if ((msg->getNetCommandType() == NETCOMMANDTYPE_GAMECOMMAND) || (msg->getNetCommandType() == NETCOMMANDTYPE_FRAMEINFO) || (msg->getNetCommandType() == NETCOMMANDTYPE_PLAYERLEAVE) || (msg->getNetCommandType() == NETCOMMANDTYPE_DESTROYPLAYER) || (msg->getNetCommandType() == NETCOMMANDTYPE_RUNAHEADMETRICS) || (msg->getNetCommandType() == NETCOMMANDTYPE_RUNAHEAD) || (msg->getNetCommandType() == NETCOMMANDTYPE_CHAT) || (msg->getNetCommandType() == NETCOMMANDTYPE_DISCONNECTVOTE) || (msg->getNetCommandType() == NETCOMMANDTYPE_DISCONNECTPLAYER) || (msg->getNetCommandType() == NETCOMMANDTYPE_LOADCOMPLETE) || (msg->getNetCommandType() == NETCOMMANDTYPE_TIMEOUTSTART) || (msg->getNetCommandType() == NETCOMMANDTYPE_WRAPPER) || (msg->getNetCommandType() == NETCOMMANDTYPE_FILE) || (msg->getNetCommandType() == NETCOMMANDTYPE_FILEANNOUNCE) || (msg->getNetCommandType() == NETCOMMANDTYPE_FILEPROGRESS) || (msg->getNetCommandType() == NETCOMMANDTYPE_DISCONNECTPLAYER) || (msg->getNetCommandType() == NETCOMMANDTYPE_DISCONNECTFRAME) || (msg->getNetCommandType() == NETCOMMANDTYPE_DISCONNECTSCREENOFF) || (msg->getNetCommandType() == NETCOMMANDTYPE_FRAMERESENDREQUEST)) { return TRUE; } return FALSE; } Bool IsCommandSynchronized(NetCommandType type) { if ((type == NETCOMMANDTYPE_GAMECOMMAND) || (type == NETCOMMANDTYPE_FRAMEINFO) || (type == NETCOMMANDTYPE_PLAYERLEAVE) || (type == NETCOMMANDTYPE_DESTROYPLAYER) || (type == NETCOMMANDTYPE_RUNAHEAD)) { return TRUE; } return FALSE; } /** * Returns true if this type of network command requires the ack to be sent directly to the player * rather than going through the packet router. This should really only be used by commands * used on the disconnect screen. */ Bool CommandRequiresDirectSend(NetCommandMsg *msg) { if ((msg->getNetCommandType() == NETCOMMANDTYPE_DISCONNECTVOTE) || (msg->getNetCommandType() == NETCOMMANDTYPE_DISCONNECTPLAYER) || (msg->getNetCommandType() == NETCOMMANDTYPE_LOADCOMPLETE) || (msg->getNetCommandType() == NETCOMMANDTYPE_TIMEOUTSTART) || (msg->getNetCommandType() == NETCOMMANDTYPE_FILE) || (msg->getNetCommandType() == NETCOMMANDTYPE_FILEANNOUNCE) || (msg->getNetCommandType() == NETCOMMANDTYPE_FILEPROGRESS) || (msg->getNetCommandType() == NETCOMMANDTYPE_DISCONNECTFRAME) || (msg->getNetCommandType() == NETCOMMANDTYPE_DISCONNECTSCREENOFF) || (msg->getNetCommandType() == NETCOMMANDTYPE_FRAMERESENDREQUEST)) { return TRUE; } return FALSE; } AsciiString GetAsciiNetCommandType(NetCommandType type) { AsciiString s; if (type == NETCOMMANDTYPE_FRAMEINFO) { s.set("NETCOMMANDTYPE_FRAMEINFO"); } else if (type == NETCOMMANDTYPE_GAMECOMMAND) { s.set("NETCOMMANDTYPE_GAMECOMMAND"); } else if (type == NETCOMMANDTYPE_PLAYERLEAVE) { s.set("NETCOMMANDTYPE_PLAYERLEAVE"); } else if (type == NETCOMMANDTYPE_RUNAHEADMETRICS) { s.set("NETCOMMANDTYPE_RUNAHEADMETRICS"); } else if (type == NETCOMMANDTYPE_RUNAHEAD) { s.set("NETCOMMANDTYPE_RUNAHEAD"); } else if (type == NETCOMMANDTYPE_DESTROYPLAYER) { s.set("NETCOMMANDTYPE_DESTROYPLAYER"); } else if (type == NETCOMMANDTYPE_ACKBOTH) { s.set("NETCOMMANDTYPE_ACKBOTH"); } else if (type == NETCOMMANDTYPE_ACKSTAGE1) { s.set("NETCOMMANDTYPE_ACKSTAGE1"); } else if (type == NETCOMMANDTYPE_ACKSTAGE2) { s.set("NETCOMMANDTYPE_ACKSTAGE2"); } else if (type == NETCOMMANDTYPE_FRAMEINFO) { s.set("NETCOMMANDTYPE_FRAMEINFO"); } else if (type == NETCOMMANDTYPE_KEEPALIVE) { s.set("NETCOMMANDTYPE_KEEPALIVE"); } else if (type == NETCOMMANDTYPE_DISCONNECTCHAT) { s.set("NETCOMMANDTYPE_DISCONNECTCHAT"); } else if (type == NETCOMMANDTYPE_CHAT) { s.set("NETCOMMANDTYPE_CHAT"); } else if (type == NETCOMMANDTYPE_MANGLERQUERY) { s.set("NETCOMMANDTYPE_MANGLERQUERY"); } else if (type == NETCOMMANDTYPE_MANGLERRESPONSE) { s.set("NETCOMMANDTYPE_MANGLERRESPONSE"); } else if (type == NETCOMMANDTYPE_DISCONNECTKEEPALIVE) { s.set("NETCOMMANDTYPE_DISCONNECTKEEPALIVE"); } else if (type == NETCOMMANDTYPE_DISCONNECTPLAYER) { s.set("NETCOMMANDTYPE_DISCONNECTPLAYER"); } else if (type == NETCOMMANDTYPE_PACKETROUTERQUERY) { s.set("NETCOMMANDTYPE_PACKETROUTERQUERY"); } else if (type == NETCOMMANDTYPE_PACKETROUTERACK) { s.set("NETCOMMANDTYPE_PACKETROUTERACK"); } else if (type == NETCOMMANDTYPE_DISCONNECTVOTE) { s.set("NETCOMMANDTYPE_DISCONNECTVOTE"); } else if (type == NETCOMMANDTYPE_PROGRESS) { s.set("NETCOMMANDTYPE_PROGRESS"); } else if (type == NETCOMMANDTYPE_LOADCOMPLETE) { s.set("NETCOMMANDTYPE_LOADCOMPLETE"); } else if (type == NETCOMMANDTYPE_TIMEOUTSTART) { s.set("NETCOMMANDTYPE_TIMEOUTSTART"); } else if (type == NETCOMMANDTYPE_WRAPPER) { s.set("NETCOMMANDTYPE_WRAPPER"); } else if (type == NETCOMMANDTYPE_FILE) { s.set("NETCOMMANDTYPE_FILE"); } else if (type == NETCOMMANDTYPE_FILEANNOUNCE) { s.set("NETCOMMANDTYPE_FILEANNOUNCE"); } else if (type == NETCOMMANDTYPE_FILEPROGRESS) { s.set("NETCOMMANDTYPE_FILEPROGRESS"); } else if (type == NETCOMMANDTYPE_DISCONNECTFRAME) { s.set("NETCOMMANDTYPE_DISCONNECTFRAME"); } else if (type == NETCOMMANDTYPE_DISCONNECTSCREENOFF) { s.set("NETCOMMANDTYPE_DISCONNECTSCREENOFF"); } else if (type == NETCOMMANDTYPE_FRAMERESENDREQUEST) { s.set("NETCOMMANDTYPE_FRAMERESENDREQUEST"); } else { s.set("UNKNOWN"); } return s; }