From 5ae896395ca4e1d4b206253b75ef51d0dcc9dd19 Mon Sep 17 00:00:00 2001 From: Bobby Battista Date: Sun, 9 Nov 2025 14:14:25 -0500 Subject: [PATCH 1/4] refactor: unify GameNetwork and GameSpy code to Core (except GUIUtil) --- Core/GameEngine/CMakeLists.txt | 194 +- .../Include/GameNetwork/Connection.h | 0 .../Include/GameNetwork/ConnectionManager.h | 0 .../Include/GameNetwork/DisconnectManager.h | 0 .../Include/GameNetwork/DownloadManager.h | 0 .../Include/GameNetwork/FileTransfer.h | 0 .../Include/GameNetwork/FirewallHelper.h | 0 .../Include/GameNetwork/FrameData.h | 0 .../Include/GameNetwork/FrameDataManager.h | 0 .../Include/GameNetwork/FrameMetrics.h | 0 .../GameEngine/Include/GameNetwork/GameInfo.h | 0 .../Include/GameNetwork/GameMessageParser.h | 0 .../Include/GameNetwork/GameSpy/BuddyDefs.h | 0 .../Include/GameNetwork/GameSpy/BuddyThread.h | 0 .../Include/GameNetwork/GameSpy/GSConfig.h | 0 .../GameNetwork/GameSpy/GameResultsThread.h | 0 .../Include/GameNetwork/GameSpy/LadderDefs.h | 0 .../Include/GameNetwork/GameSpy/LobbyUtils.h | 0 .../GameNetwork/GameSpy/MainMenuUtils.h | 0 .../Include/GameNetwork/GameSpy/PeerDefs.h | 0 .../GameSpy/PeerDefsImplementation.h | 0 .../Include/GameNetwork/GameSpy/PeerThread.h | 0 .../GameSpy/PersistentStorageDefs.h | 0 .../GameSpy/PersistentStorageThread.h | 0 .../Include/GameNetwork/GameSpy/PingThread.h | 0 .../GameNetwork/GameSpy/StagingRoomGameInfo.h | 0 .../Include/GameNetwork/GameSpy/ThreadUtils.h | 0 .../Include/GameNetwork/GameSpyChat.h | 0 .../Include/GameNetwork/GameSpyGP.h | 0 .../Include/GameNetwork/GameSpyGameInfo.h | 0 .../Include/GameNetwork/GameSpyOverlay.h | 0 .../Include/GameNetwork/GameSpyThread.h | 0 .../Include/GameNetwork/IPEnumeration.h | 0 .../GameEngine/Include/GameNetwork/LANAPI.h | 0 .../Include/GameNetwork/LANAPICallbacks.h | 0 .../Include/GameNetwork/LANGameInfo.h | 0 .../Include/GameNetwork/LANPlayer.h | 0 .../GameEngine/Include/GameNetwork/NAT.h | 0 .../Include/GameNetwork/NetCommandList.h | 0 .../Include/GameNetwork/NetCommandMsg.h | 0 .../Include/GameNetwork/NetCommandRef.h | 0 .../GameNetwork/NetCommandWrapperList.h | 0 .../Include/GameNetwork/NetPacket.h | 0 .../Include/GameNetwork/NetworkDefs.h | 0 .../Include/GameNetwork/NetworkInterface.h | 0 .../Include/GameNetwork/RankPointValue.h | 0 .../Include/GameNetwork/Transport.h | 0 .../GameEngine/Include/GameNetwork/User.h | 0 .../GameNetwork/WOLBrowser/FEBDispatch.h | 0 .../GameNetwork/WOLBrowser/WebBrowser.h | 0 .../Include/GameNetwork/networkutil.h | 0 .../GameEngine/Include/GameNetwork/udp.h | 0 .../Source/GameNetwork/Connection.cpp | 0 .../Source/GameNetwork/ConnectionManager.cpp | 0 .../Source/GameNetwork/DisconnectManager.cpp | 0 .../Source/GameNetwork/DownloadManager.cpp | 0 .../Source/GameNetwork/FileTransfer.cpp | 0 .../Source/GameNetwork/FirewallHelper.cpp | 0 .../Source/GameNetwork/FrameData.cpp | 0 .../Source/GameNetwork/FrameDataManager.cpp | 0 .../Source/GameNetwork/FrameMetrics.cpp | 0 .../Source/GameNetwork/GameInfo.cpp | 0 .../Source/GameNetwork/GameMessageParser.cpp | 0 .../Source/GameNetwork/GameSpy/Chat.cpp | 0 .../Source/GameNetwork/GameSpy/GSConfig.cpp | 0 .../Source/GameNetwork/GameSpy/LadderDefs.cpp | 0 .../Source/GameNetwork/GameSpy/LobbyUtils.cpp | 0 .../GameNetwork/GameSpy/MainMenuUtils.cpp | 0 .../Source/GameNetwork/GameSpy/PeerDefs.cpp | 0 .../GameSpy/StagingRoomGameInfo.cpp | 0 .../GameSpy/Thread/BuddyThread.cpp | 0 .../GameSpy/Thread/GameResultsThread.cpp | 0 .../GameNetwork/GameSpy/Thread/PeerThread.cpp | 0 .../Thread/PersistentStorageThread.cpp | 0 .../GameNetwork/GameSpy/Thread/PingThread.cpp | 0 .../GameSpy/Thread/ThreadUtils.cpp | 0 .../Source/GameNetwork/GameSpyChat.cpp | 0 .../Source/GameNetwork/GameSpyGP.cpp | 0 .../Source/GameNetwork/GameSpyGameInfo.cpp | 0 .../Source/GameNetwork/GameSpyOverlay.cpp | 0 .../Source/GameNetwork/IPEnumeration.cpp | 0 .../GameEngine/Source/GameNetwork/LANAPI.cpp | 0 .../Source/GameNetwork/LANAPICallbacks.cpp | 0 .../Source/GameNetwork/LANAPIhandlers.cpp | 0 .../Source/GameNetwork/LANGameInfo.cpp | 0 .../GameEngine/Source/GameNetwork/NAT.cpp | 0 .../Source/GameNetwork/NetCommandList.cpp | 0 .../Source/GameNetwork/NetCommandMsg.cpp | 0 .../Source/GameNetwork/NetCommandRef.cpp | 0 .../GameNetwork/NetCommandWrapperList.cpp | 0 .../Source/GameNetwork/NetMessageStream.cpp | 0 .../Source/GameNetwork/NetPacket.cpp | 0 .../GameEngine/Source/GameNetwork/Network.cpp | 0 .../Source/GameNetwork/NetworkUtil.cpp | 0 .../Source/GameNetwork/Transport.cpp | 0 .../GameEngine/Source/GameNetwork/User.cpp | 0 .../GameNetwork/WOLBrowser/WebBrowser.cpp | 0 .../GameEngine/Source/GameNetwork/udp.cpp | 0 Generals/Code/GameEngine/CMakeLists.txt | 194 +- .../Include/GameNetwork/Connection.h | 101 - .../Include/GameNetwork/ConnectionManager.h | 216 - .../Include/GameNetwork/DisconnectManager.h | 125 - .../Include/GameNetwork/DownloadManager.h | 93 - .../Include/GameNetwork/FileTransfer.h | 48 - .../Include/GameNetwork/FirewallHelper.h | 307 - .../Include/GameNetwork/FrameData.h | 63 - .../Include/GameNetwork/FrameDataManager.h | 61 - .../Include/GameNetwork/FrameMetrics.h | 69 - .../GameEngine/Include/GameNetwork/GameInfo.h | 305 - .../Include/GameNetwork/GameMessageParser.h | 104 - .../Include/GameNetwork/GameSpy/BuddyDefs.h | 32 - .../Include/GameNetwork/GameSpy/BuddyThread.h | 171 - .../Include/GameNetwork/GameSpy/GSConfig.h | 77 - .../GameNetwork/GameSpy/GameResultsThread.h | 75 - .../Include/GameNetwork/GameSpy/LadderDefs.h | 83 - .../Include/GameNetwork/GameSpy/LobbyUtils.h | 55 - .../GameNetwork/GameSpy/MainMenuUtils.h | 65 - .../Include/GameNetwork/GameSpy/PeerDefs.h | 297 - .../GameSpy/PeerDefsImplementation.h | 177 - .../Include/GameNetwork/GameSpy/PeerThread.h | 386 -- .../GameSpy/PersistentStorageDefs.h | 42 - .../GameSpy/PersistentStorageThread.h | 181 - .../Include/GameNetwork/GameSpy/PingThread.h | 77 - .../GameNetwork/GameSpy/StagingRoomGameInfo.h | 156 - .../Include/GameNetwork/GameSpy/ThreadUtils.h | 32 - .../Include/GameNetwork/GameSpyChat.h | 55 - .../Include/GameNetwork/GameSpyGP.h | 42 - .../Include/GameNetwork/GameSpyGameInfo.h | 92 - .../Include/GameNetwork/GameSpyOverlay.h | 65 - .../Include/GameNetwork/GameSpyThread.h | 62 - .../Include/GameNetwork/IPEnumeration.h | 77 - .../GameEngine/Include/GameNetwork/LANAPI.h | 412 -- .../Include/GameNetwork/LANAPICallbacks.h | 83 - .../Include/GameNetwork/LANGameInfo.h | 179 - .../Include/GameNetwork/LANPlayer.h | 63 - .../Code/GameEngine/Include/GameNetwork/NAT.h | 157 - .../Include/GameNetwork/NetCommandList.h | 68 - .../Include/GameNetwork/NetCommandMsg.h | 516 -- .../Include/GameNetwork/NetCommandRef.h | 146 - .../GameNetwork/NetCommandWrapperList.h | 78 - .../Include/GameNetwork/NetPacket.h | 234 - .../Include/GameNetwork/NetworkDefs.h | 210 - .../Include/GameNetwork/NetworkInterface.h | 136 - .../Include/GameNetwork/RankPointValue.h | 100 - .../Include/GameNetwork/Transport.h | 100 - .../GameEngine/Include/GameNetwork/User.h | 57 - .../GameNetwork/WOLBrowser/FEBDispatch.h | 103 - .../GameNetwork/WOLBrowser/WebBrowser.h | 124 - .../Include/GameNetwork/networkutil.h | 54 - .../Code/GameEngine/Include/GameNetwork/udp.h | 125 - .../Source/GameNetwork/Connection.cpp | 415 -- .../Source/GameNetwork/ConnectionManager.cpp | 2416 ------- .../Source/GameNetwork/DisconnectManager.cpp | 808 --- .../Source/GameNetwork/DownloadManager.cpp | 224 - .../Source/GameNetwork/FileTransfer.cpp | 283 - .../Source/GameNetwork/FirewallHelper.cpp | 1574 ----- .../Source/GameNetwork/FrameData.cpp | 203 - .../Source/GameNetwork/FrameDataManager.cpp | 203 - .../Source/GameNetwork/FrameMetrics.cpp | 141 - .../Source/GameNetwork/GameInfo.cpp | 1649 ----- .../Source/GameNetwork/GameMessageParser.cpp | 101 - .../Source/GameNetwork/GameSpy/Chat.cpp | 351 - .../Source/GameNetwork/GameSpy/GSConfig.cpp | 482 -- .../Source/GameNetwork/GameSpy/LadderDefs.cpp | 525 -- .../Source/GameNetwork/GameSpy/LobbyUtils.cpp | 939 --- .../GameNetwork/GameSpy/MainMenuUtils.cpp | 885 --- .../Source/GameNetwork/GameSpy/PeerDefs.cpp | 920 --- .../GameSpy/StagingRoomGameInfo.cpp | 886 --- .../GameSpy/Thread/BuddyThread.cpp | 683 -- .../GameSpy/Thread/GameResultsThread.cpp | 392 -- .../GameNetwork/GameSpy/Thread/PeerThread.cpp | 2999 --------- .../Thread/PersistentStorageThread.cpp | 1488 ---- .../GameNetwork/GameSpy/Thread/PingThread.cpp | 573 -- .../GameSpy/Thread/ThreadUtils.cpp | 81 - .../Source/GameNetwork/GameSpyChat.cpp | 455 -- .../Source/GameNetwork/GameSpyGP.cpp | 162 - .../Source/GameNetwork/GameSpyGameInfo.cpp | 751 --- .../Source/GameNetwork/GameSpyOverlay.cpp | 333 - .../Source/GameNetwork/IPEnumeration.cpp | 196 - .../GameEngine/Source/GameNetwork/LANAPI.cpp | 1283 ---- .../Source/GameNetwork/LANAPICallbacks.cpp | 737 -- .../Source/GameNetwork/LANAPIhandlers.cpp | 661 -- .../Source/GameNetwork/LANGameInfo.cpp | 320 - .../GameEngine/Source/GameNetwork/NAT.cpp | 1294 ---- .../Source/GameNetwork/NetCommandList.cpp | 455 -- .../Source/GameNetwork/NetCommandMsg.cpp | 1066 --- .../Source/GameNetwork/NetCommandRef.cpp | 71 - .../GameNetwork/NetCommandWrapperList.cpp | 229 - .../Source/GameNetwork/NetMessageStream.cpp | 227 - .../Source/GameNetwork/NetPacket.cpp | 5964 ----------------- .../GameEngine/Source/GameNetwork/Network.cpp | 1056 --- .../Source/GameNetwork/NetworkUtil.cpp | 275 - .../Source/GameNetwork/Transport.cpp | 504 -- .../GameEngine/Source/GameNetwork/User.cpp | 74 - .../GameNetwork/WOLBrowser/WebBrowser.cpp | 310 - .../GameEngine/Source/GameNetwork/udp.cpp | 534 -- GeneralsMD/Code/GameEngine/CMakeLists.txt | 194 +- scripts/cpp/unify_move_files.py | 144 +- 198 files changed, 397 insertions(+), 43243 deletions(-) rename {GeneralsMD/Code => Core}/GameEngine/Include/GameNetwork/Connection.h (100%) rename {GeneralsMD/Code => Core}/GameEngine/Include/GameNetwork/ConnectionManager.h (100%) rename {GeneralsMD/Code => Core}/GameEngine/Include/GameNetwork/DisconnectManager.h (100%) rename {GeneralsMD/Code => Core}/GameEngine/Include/GameNetwork/DownloadManager.h (100%) rename {GeneralsMD/Code => Core}/GameEngine/Include/GameNetwork/FileTransfer.h (100%) rename {GeneralsMD/Code => Core}/GameEngine/Include/GameNetwork/FirewallHelper.h (100%) rename {GeneralsMD/Code => Core}/GameEngine/Include/GameNetwork/FrameData.h (100%) rename {GeneralsMD/Code => Core}/GameEngine/Include/GameNetwork/FrameDataManager.h (100%) rename {GeneralsMD/Code => Core}/GameEngine/Include/GameNetwork/FrameMetrics.h (100%) rename {GeneralsMD/Code => Core}/GameEngine/Include/GameNetwork/GameInfo.h (100%) rename {GeneralsMD/Code => Core}/GameEngine/Include/GameNetwork/GameMessageParser.h (100%) rename {GeneralsMD/Code => Core}/GameEngine/Include/GameNetwork/GameSpy/BuddyDefs.h (100%) rename {GeneralsMD/Code => Core}/GameEngine/Include/GameNetwork/GameSpy/BuddyThread.h (100%) rename {GeneralsMD/Code => Core}/GameEngine/Include/GameNetwork/GameSpy/GSConfig.h (100%) rename {GeneralsMD/Code => Core}/GameEngine/Include/GameNetwork/GameSpy/GameResultsThread.h (100%) rename {GeneralsMD/Code => Core}/GameEngine/Include/GameNetwork/GameSpy/LadderDefs.h (100%) rename {GeneralsMD/Code => Core}/GameEngine/Include/GameNetwork/GameSpy/LobbyUtils.h (100%) rename {GeneralsMD/Code => Core}/GameEngine/Include/GameNetwork/GameSpy/MainMenuUtils.h (100%) rename {GeneralsMD/Code => Core}/GameEngine/Include/GameNetwork/GameSpy/PeerDefs.h (100%) rename {GeneralsMD/Code => Core}/GameEngine/Include/GameNetwork/GameSpy/PeerDefsImplementation.h (100%) rename {GeneralsMD/Code => Core}/GameEngine/Include/GameNetwork/GameSpy/PeerThread.h (100%) rename {GeneralsMD/Code => Core}/GameEngine/Include/GameNetwork/GameSpy/PersistentStorageDefs.h (100%) rename {GeneralsMD/Code => Core}/GameEngine/Include/GameNetwork/GameSpy/PersistentStorageThread.h (100%) rename {GeneralsMD/Code => Core}/GameEngine/Include/GameNetwork/GameSpy/PingThread.h (100%) rename {GeneralsMD/Code => Core}/GameEngine/Include/GameNetwork/GameSpy/StagingRoomGameInfo.h (100%) rename {GeneralsMD/Code => Core}/GameEngine/Include/GameNetwork/GameSpy/ThreadUtils.h (100%) rename {GeneralsMD/Code => Core}/GameEngine/Include/GameNetwork/GameSpyChat.h (100%) rename {GeneralsMD/Code => Core}/GameEngine/Include/GameNetwork/GameSpyGP.h (100%) rename {GeneralsMD/Code => Core}/GameEngine/Include/GameNetwork/GameSpyGameInfo.h (100%) rename {GeneralsMD/Code => Core}/GameEngine/Include/GameNetwork/GameSpyOverlay.h (100%) rename {GeneralsMD/Code => Core}/GameEngine/Include/GameNetwork/GameSpyThread.h (100%) rename {GeneralsMD/Code => Core}/GameEngine/Include/GameNetwork/IPEnumeration.h (100%) rename {GeneralsMD/Code => Core}/GameEngine/Include/GameNetwork/LANAPI.h (100%) rename {GeneralsMD/Code => Core}/GameEngine/Include/GameNetwork/LANAPICallbacks.h (100%) rename {GeneralsMD/Code => Core}/GameEngine/Include/GameNetwork/LANGameInfo.h (100%) rename {GeneralsMD/Code => Core}/GameEngine/Include/GameNetwork/LANPlayer.h (100%) rename {GeneralsMD/Code => Core}/GameEngine/Include/GameNetwork/NAT.h (100%) rename {GeneralsMD/Code => Core}/GameEngine/Include/GameNetwork/NetCommandList.h (100%) rename {GeneralsMD/Code => Core}/GameEngine/Include/GameNetwork/NetCommandMsg.h (100%) rename {GeneralsMD/Code => Core}/GameEngine/Include/GameNetwork/NetCommandRef.h (100%) rename {GeneralsMD/Code => Core}/GameEngine/Include/GameNetwork/NetCommandWrapperList.h (100%) rename {GeneralsMD/Code => Core}/GameEngine/Include/GameNetwork/NetPacket.h (100%) rename {GeneralsMD/Code => Core}/GameEngine/Include/GameNetwork/NetworkDefs.h (100%) rename {GeneralsMD/Code => Core}/GameEngine/Include/GameNetwork/NetworkInterface.h (100%) rename {GeneralsMD/Code => Core}/GameEngine/Include/GameNetwork/RankPointValue.h (100%) rename {GeneralsMD/Code => Core}/GameEngine/Include/GameNetwork/Transport.h (100%) rename {GeneralsMD/Code => Core}/GameEngine/Include/GameNetwork/User.h (100%) rename {GeneralsMD/Code => Core}/GameEngine/Include/GameNetwork/WOLBrowser/FEBDispatch.h (100%) rename {GeneralsMD/Code => Core}/GameEngine/Include/GameNetwork/WOLBrowser/WebBrowser.h (100%) rename {GeneralsMD/Code => Core}/GameEngine/Include/GameNetwork/networkutil.h (100%) rename {GeneralsMD/Code => Core}/GameEngine/Include/GameNetwork/udp.h (100%) rename {GeneralsMD/Code => Core}/GameEngine/Source/GameNetwork/Connection.cpp (100%) rename {GeneralsMD/Code => Core}/GameEngine/Source/GameNetwork/ConnectionManager.cpp (100%) rename {GeneralsMD/Code => Core}/GameEngine/Source/GameNetwork/DisconnectManager.cpp (100%) rename {GeneralsMD/Code => Core}/GameEngine/Source/GameNetwork/DownloadManager.cpp (100%) rename {GeneralsMD/Code => Core}/GameEngine/Source/GameNetwork/FileTransfer.cpp (100%) rename {GeneralsMD/Code => Core}/GameEngine/Source/GameNetwork/FirewallHelper.cpp (100%) rename {GeneralsMD/Code => Core}/GameEngine/Source/GameNetwork/FrameData.cpp (100%) rename {GeneralsMD/Code => Core}/GameEngine/Source/GameNetwork/FrameDataManager.cpp (100%) rename {GeneralsMD/Code => Core}/GameEngine/Source/GameNetwork/FrameMetrics.cpp (100%) rename {GeneralsMD/Code => Core}/GameEngine/Source/GameNetwork/GameInfo.cpp (100%) rename {GeneralsMD/Code => Core}/GameEngine/Source/GameNetwork/GameMessageParser.cpp (100%) rename {GeneralsMD/Code => Core}/GameEngine/Source/GameNetwork/GameSpy/Chat.cpp (100%) rename {GeneralsMD/Code => Core}/GameEngine/Source/GameNetwork/GameSpy/GSConfig.cpp (100%) rename {GeneralsMD/Code => Core}/GameEngine/Source/GameNetwork/GameSpy/LadderDefs.cpp (100%) rename {GeneralsMD/Code => Core}/GameEngine/Source/GameNetwork/GameSpy/LobbyUtils.cpp (100%) rename {GeneralsMD/Code => Core}/GameEngine/Source/GameNetwork/GameSpy/MainMenuUtils.cpp (100%) rename {GeneralsMD/Code => Core}/GameEngine/Source/GameNetwork/GameSpy/PeerDefs.cpp (100%) rename {GeneralsMD/Code => Core}/GameEngine/Source/GameNetwork/GameSpy/StagingRoomGameInfo.cpp (100%) rename {GeneralsMD/Code => Core}/GameEngine/Source/GameNetwork/GameSpy/Thread/BuddyThread.cpp (100%) rename {GeneralsMD/Code => Core}/GameEngine/Source/GameNetwork/GameSpy/Thread/GameResultsThread.cpp (100%) rename {GeneralsMD/Code => Core}/GameEngine/Source/GameNetwork/GameSpy/Thread/PeerThread.cpp (100%) rename {GeneralsMD/Code => Core}/GameEngine/Source/GameNetwork/GameSpy/Thread/PersistentStorageThread.cpp (100%) rename {GeneralsMD/Code => Core}/GameEngine/Source/GameNetwork/GameSpy/Thread/PingThread.cpp (100%) rename {GeneralsMD/Code => Core}/GameEngine/Source/GameNetwork/GameSpy/Thread/ThreadUtils.cpp (100%) rename {GeneralsMD/Code => Core}/GameEngine/Source/GameNetwork/GameSpyChat.cpp (100%) rename {GeneralsMD/Code => Core}/GameEngine/Source/GameNetwork/GameSpyGP.cpp (100%) rename {GeneralsMD/Code => Core}/GameEngine/Source/GameNetwork/GameSpyGameInfo.cpp (100%) rename {GeneralsMD/Code => Core}/GameEngine/Source/GameNetwork/GameSpyOverlay.cpp (100%) rename {GeneralsMD/Code => Core}/GameEngine/Source/GameNetwork/IPEnumeration.cpp (100%) rename {GeneralsMD/Code => Core}/GameEngine/Source/GameNetwork/LANAPI.cpp (100%) rename {GeneralsMD/Code => Core}/GameEngine/Source/GameNetwork/LANAPICallbacks.cpp (100%) rename {GeneralsMD/Code => Core}/GameEngine/Source/GameNetwork/LANAPIhandlers.cpp (100%) rename {GeneralsMD/Code => Core}/GameEngine/Source/GameNetwork/LANGameInfo.cpp (100%) rename {GeneralsMD/Code => Core}/GameEngine/Source/GameNetwork/NAT.cpp (100%) rename {GeneralsMD/Code => Core}/GameEngine/Source/GameNetwork/NetCommandList.cpp (100%) rename {GeneralsMD/Code => Core}/GameEngine/Source/GameNetwork/NetCommandMsg.cpp (100%) rename {GeneralsMD/Code => Core}/GameEngine/Source/GameNetwork/NetCommandRef.cpp (100%) rename {GeneralsMD/Code => Core}/GameEngine/Source/GameNetwork/NetCommandWrapperList.cpp (100%) rename {GeneralsMD/Code => Core}/GameEngine/Source/GameNetwork/NetMessageStream.cpp (100%) rename {GeneralsMD/Code => Core}/GameEngine/Source/GameNetwork/NetPacket.cpp (100%) rename {GeneralsMD/Code => Core}/GameEngine/Source/GameNetwork/Network.cpp (100%) rename {GeneralsMD/Code => Core}/GameEngine/Source/GameNetwork/NetworkUtil.cpp (100%) rename {GeneralsMD/Code => Core}/GameEngine/Source/GameNetwork/Transport.cpp (100%) rename {GeneralsMD/Code => Core}/GameEngine/Source/GameNetwork/User.cpp (100%) rename {GeneralsMD/Code => Core}/GameEngine/Source/GameNetwork/WOLBrowser/WebBrowser.cpp (100%) rename {GeneralsMD/Code => Core}/GameEngine/Source/GameNetwork/udp.cpp (100%) delete mode 100644 Generals/Code/GameEngine/Include/GameNetwork/Connection.h delete mode 100644 Generals/Code/GameEngine/Include/GameNetwork/ConnectionManager.h delete mode 100644 Generals/Code/GameEngine/Include/GameNetwork/DisconnectManager.h delete mode 100644 Generals/Code/GameEngine/Include/GameNetwork/DownloadManager.h delete mode 100644 Generals/Code/GameEngine/Include/GameNetwork/FileTransfer.h delete mode 100644 Generals/Code/GameEngine/Include/GameNetwork/FirewallHelper.h delete mode 100644 Generals/Code/GameEngine/Include/GameNetwork/FrameData.h delete mode 100644 Generals/Code/GameEngine/Include/GameNetwork/FrameDataManager.h delete mode 100644 Generals/Code/GameEngine/Include/GameNetwork/FrameMetrics.h delete mode 100644 Generals/Code/GameEngine/Include/GameNetwork/GameInfo.h delete mode 100644 Generals/Code/GameEngine/Include/GameNetwork/GameMessageParser.h delete mode 100644 Generals/Code/GameEngine/Include/GameNetwork/GameSpy/BuddyDefs.h delete mode 100644 Generals/Code/GameEngine/Include/GameNetwork/GameSpy/BuddyThread.h delete mode 100644 Generals/Code/GameEngine/Include/GameNetwork/GameSpy/GSConfig.h delete mode 100644 Generals/Code/GameEngine/Include/GameNetwork/GameSpy/GameResultsThread.h delete mode 100644 Generals/Code/GameEngine/Include/GameNetwork/GameSpy/LadderDefs.h delete mode 100644 Generals/Code/GameEngine/Include/GameNetwork/GameSpy/LobbyUtils.h delete mode 100644 Generals/Code/GameEngine/Include/GameNetwork/GameSpy/MainMenuUtils.h delete mode 100644 Generals/Code/GameEngine/Include/GameNetwork/GameSpy/PeerDefs.h delete mode 100644 Generals/Code/GameEngine/Include/GameNetwork/GameSpy/PeerDefsImplementation.h delete mode 100644 Generals/Code/GameEngine/Include/GameNetwork/GameSpy/PeerThread.h delete mode 100644 Generals/Code/GameEngine/Include/GameNetwork/GameSpy/PersistentStorageDefs.h delete mode 100644 Generals/Code/GameEngine/Include/GameNetwork/GameSpy/PersistentStorageThread.h delete mode 100644 Generals/Code/GameEngine/Include/GameNetwork/GameSpy/PingThread.h delete mode 100644 Generals/Code/GameEngine/Include/GameNetwork/GameSpy/StagingRoomGameInfo.h delete mode 100644 Generals/Code/GameEngine/Include/GameNetwork/GameSpy/ThreadUtils.h delete mode 100644 Generals/Code/GameEngine/Include/GameNetwork/GameSpyChat.h delete mode 100644 Generals/Code/GameEngine/Include/GameNetwork/GameSpyGP.h delete mode 100644 Generals/Code/GameEngine/Include/GameNetwork/GameSpyGameInfo.h delete mode 100644 Generals/Code/GameEngine/Include/GameNetwork/GameSpyOverlay.h delete mode 100644 Generals/Code/GameEngine/Include/GameNetwork/GameSpyThread.h delete mode 100644 Generals/Code/GameEngine/Include/GameNetwork/IPEnumeration.h delete mode 100644 Generals/Code/GameEngine/Include/GameNetwork/LANAPI.h delete mode 100644 Generals/Code/GameEngine/Include/GameNetwork/LANAPICallbacks.h delete mode 100644 Generals/Code/GameEngine/Include/GameNetwork/LANGameInfo.h delete mode 100644 Generals/Code/GameEngine/Include/GameNetwork/LANPlayer.h delete mode 100644 Generals/Code/GameEngine/Include/GameNetwork/NAT.h delete mode 100644 Generals/Code/GameEngine/Include/GameNetwork/NetCommandList.h delete mode 100644 Generals/Code/GameEngine/Include/GameNetwork/NetCommandMsg.h delete mode 100644 Generals/Code/GameEngine/Include/GameNetwork/NetCommandRef.h delete mode 100644 Generals/Code/GameEngine/Include/GameNetwork/NetCommandWrapperList.h delete mode 100644 Generals/Code/GameEngine/Include/GameNetwork/NetPacket.h delete mode 100644 Generals/Code/GameEngine/Include/GameNetwork/NetworkDefs.h delete mode 100644 Generals/Code/GameEngine/Include/GameNetwork/NetworkInterface.h delete mode 100644 Generals/Code/GameEngine/Include/GameNetwork/RankPointValue.h delete mode 100644 Generals/Code/GameEngine/Include/GameNetwork/Transport.h delete mode 100644 Generals/Code/GameEngine/Include/GameNetwork/User.h delete mode 100644 Generals/Code/GameEngine/Include/GameNetwork/WOLBrowser/FEBDispatch.h delete mode 100644 Generals/Code/GameEngine/Include/GameNetwork/WOLBrowser/WebBrowser.h delete mode 100644 Generals/Code/GameEngine/Include/GameNetwork/networkutil.h delete mode 100644 Generals/Code/GameEngine/Include/GameNetwork/udp.h delete mode 100644 Generals/Code/GameEngine/Source/GameNetwork/Connection.cpp delete mode 100644 Generals/Code/GameEngine/Source/GameNetwork/ConnectionManager.cpp delete mode 100644 Generals/Code/GameEngine/Source/GameNetwork/DisconnectManager.cpp delete mode 100644 Generals/Code/GameEngine/Source/GameNetwork/DownloadManager.cpp delete mode 100644 Generals/Code/GameEngine/Source/GameNetwork/FileTransfer.cpp delete mode 100644 Generals/Code/GameEngine/Source/GameNetwork/FirewallHelper.cpp delete mode 100644 Generals/Code/GameEngine/Source/GameNetwork/FrameData.cpp delete mode 100644 Generals/Code/GameEngine/Source/GameNetwork/FrameDataManager.cpp delete mode 100644 Generals/Code/GameEngine/Source/GameNetwork/FrameMetrics.cpp delete mode 100644 Generals/Code/GameEngine/Source/GameNetwork/GameInfo.cpp delete mode 100644 Generals/Code/GameEngine/Source/GameNetwork/GameMessageParser.cpp delete mode 100644 Generals/Code/GameEngine/Source/GameNetwork/GameSpy/Chat.cpp delete mode 100644 Generals/Code/GameEngine/Source/GameNetwork/GameSpy/GSConfig.cpp delete mode 100644 Generals/Code/GameEngine/Source/GameNetwork/GameSpy/LadderDefs.cpp delete mode 100644 Generals/Code/GameEngine/Source/GameNetwork/GameSpy/LobbyUtils.cpp delete mode 100644 Generals/Code/GameEngine/Source/GameNetwork/GameSpy/MainMenuUtils.cpp delete mode 100644 Generals/Code/GameEngine/Source/GameNetwork/GameSpy/PeerDefs.cpp delete mode 100644 Generals/Code/GameEngine/Source/GameNetwork/GameSpy/StagingRoomGameInfo.cpp delete mode 100644 Generals/Code/GameEngine/Source/GameNetwork/GameSpy/Thread/BuddyThread.cpp delete mode 100644 Generals/Code/GameEngine/Source/GameNetwork/GameSpy/Thread/GameResultsThread.cpp delete mode 100644 Generals/Code/GameEngine/Source/GameNetwork/GameSpy/Thread/PeerThread.cpp delete mode 100644 Generals/Code/GameEngine/Source/GameNetwork/GameSpy/Thread/PersistentStorageThread.cpp delete mode 100644 Generals/Code/GameEngine/Source/GameNetwork/GameSpy/Thread/PingThread.cpp delete mode 100644 Generals/Code/GameEngine/Source/GameNetwork/GameSpy/Thread/ThreadUtils.cpp delete mode 100644 Generals/Code/GameEngine/Source/GameNetwork/GameSpyChat.cpp delete mode 100644 Generals/Code/GameEngine/Source/GameNetwork/GameSpyGP.cpp delete mode 100644 Generals/Code/GameEngine/Source/GameNetwork/GameSpyGameInfo.cpp delete mode 100644 Generals/Code/GameEngine/Source/GameNetwork/GameSpyOverlay.cpp delete mode 100644 Generals/Code/GameEngine/Source/GameNetwork/IPEnumeration.cpp delete mode 100644 Generals/Code/GameEngine/Source/GameNetwork/LANAPI.cpp delete mode 100644 Generals/Code/GameEngine/Source/GameNetwork/LANAPICallbacks.cpp delete mode 100644 Generals/Code/GameEngine/Source/GameNetwork/LANAPIhandlers.cpp delete mode 100644 Generals/Code/GameEngine/Source/GameNetwork/LANGameInfo.cpp delete mode 100644 Generals/Code/GameEngine/Source/GameNetwork/NAT.cpp delete mode 100644 Generals/Code/GameEngine/Source/GameNetwork/NetCommandList.cpp delete mode 100644 Generals/Code/GameEngine/Source/GameNetwork/NetCommandMsg.cpp delete mode 100644 Generals/Code/GameEngine/Source/GameNetwork/NetCommandRef.cpp delete mode 100644 Generals/Code/GameEngine/Source/GameNetwork/NetCommandWrapperList.cpp delete mode 100644 Generals/Code/GameEngine/Source/GameNetwork/NetMessageStream.cpp delete mode 100644 Generals/Code/GameEngine/Source/GameNetwork/NetPacket.cpp delete mode 100644 Generals/Code/GameEngine/Source/GameNetwork/Network.cpp delete mode 100644 Generals/Code/GameEngine/Source/GameNetwork/NetworkUtil.cpp delete mode 100644 Generals/Code/GameEngine/Source/GameNetwork/Transport.cpp delete mode 100644 Generals/Code/GameEngine/Source/GameNetwork/User.cpp delete mode 100644 Generals/Code/GameEngine/Source/GameNetwork/WOLBrowser/WebBrowser.cpp delete mode 100644 Generals/Code/GameEngine/Source/GameNetwork/udp.cpp diff --git a/Core/GameEngine/CMakeLists.txt b/Core/GameEngine/CMakeLists.txt index 0a58dfc431..fbeaaeffd2 100644 --- a/Core/GameEngine/CMakeLists.txt +++ b/Core/GameEngine/CMakeLists.txt @@ -501,58 +501,58 @@ set(GAMEENGINE_SRC # Include/GameLogic/WeaponSetFlags.h # Include/GameLogic/WeaponSetType.h # Include/GameLogic/WeaponStatus.h -# Include/GameNetwork/Connection.h -# Include/GameNetwork/ConnectionManager.h -# Include/GameNetwork/DisconnectManager.h -# Include/GameNetwork/DownloadManager.h -# Include/GameNetwork/FileTransfer.h -# Include/GameNetwork/FirewallHelper.h -# Include/GameNetwork/FrameData.h -# Include/GameNetwork/FrameDataManager.h -# Include/GameNetwork/FrameMetrics.h -# Include/GameNetwork/GameInfo.h -# Include/GameNetwork/GameMessageParser.h -# Include/GameNetwork/GameSpy/BuddyDefs.h -# Include/GameNetwork/GameSpy/BuddyThread.h -# Include/GameNetwork/GameSpy/GameResultsThread.h -# Include/GameNetwork/GameSpy/GSConfig.h -# Include/GameNetwork/GameSpy/LadderDefs.h -# Include/GameNetwork/GameSpy/LobbyUtils.h -# Include/GameNetwork/GameSpy/MainMenuUtils.h -# Include/GameNetwork/GameSpy/PeerDefs.h -# Include/GameNetwork/GameSpy/PeerDefsImplementation.h -# Include/GameNetwork/GameSpy/PeerThread.h -# Include/GameNetwork/GameSpy/PersistentStorageDefs.h -# Include/GameNetwork/GameSpy/PersistentStorageThread.h -# Include/GameNetwork/GameSpy/PingThread.h -# Include/GameNetwork/GameSpy/StagingRoomGameInfo.h -# Include/GameNetwork/GameSpy/ThreadUtils.h -# Include/GameNetwork/GameSpyChat.h -# Include/GameNetwork/GameSpyGameInfo.h -# Include/GameNetwork/GameSpyGP.h -# Include/GameNetwork/GameSpyOverlay.h -# Include/GameNetwork/GameSpyThread.h + Include/GameNetwork/Connection.h + Include/GameNetwork/ConnectionManager.h + Include/GameNetwork/DisconnectManager.h + Include/GameNetwork/DownloadManager.h + Include/GameNetwork/FileTransfer.h + Include/GameNetwork/FirewallHelper.h + Include/GameNetwork/FrameData.h + Include/GameNetwork/FrameDataManager.h + Include/GameNetwork/FrameMetrics.h + Include/GameNetwork/GameInfo.h + Include/GameNetwork/GameMessageParser.h + Include/GameNetwork/GameSpy/BuddyDefs.h + Include/GameNetwork/GameSpy/BuddyThread.h + Include/GameNetwork/GameSpy/GameResultsThread.h + Include/GameNetwork/GameSpy/GSConfig.h + Include/GameNetwork/GameSpy/LadderDefs.h + Include/GameNetwork/GameSpy/LobbyUtils.h + Include/GameNetwork/GameSpy/MainMenuUtils.h + Include/GameNetwork/GameSpy/PeerDefs.h + Include/GameNetwork/GameSpy/PeerDefsImplementation.h + Include/GameNetwork/GameSpy/PeerThread.h + Include/GameNetwork/GameSpy/PersistentStorageDefs.h + Include/GameNetwork/GameSpy/PersistentStorageThread.h + Include/GameNetwork/GameSpy/PingThread.h + Include/GameNetwork/GameSpy/StagingRoomGameInfo.h + Include/GameNetwork/GameSpy/ThreadUtils.h + Include/GameNetwork/GameSpyChat.h + Include/GameNetwork/GameSpyGameInfo.h + Include/GameNetwork/GameSpyGP.h + Include/GameNetwork/GameSpyOverlay.h + Include/GameNetwork/GameSpyThread.h # Include/GameNetwork/GUIUtil.h -# Include/GameNetwork/IPEnumeration.h -# Include/GameNetwork/LANAPI.h -# Include/GameNetwork/LANAPICallbacks.h -# Include/GameNetwork/LANGameInfo.h -# Include/GameNetwork/LANPlayer.h -# Include/GameNetwork/NAT.h -# Include/GameNetwork/NetCommandList.h -# Include/GameNetwork/NetCommandMsg.h -# Include/GameNetwork/NetCommandRef.h -# Include/GameNetwork/NetCommandWrapperList.h -# Include/GameNetwork/NetPacket.h -# Include/GameNetwork/NetworkDefs.h -# Include/GameNetwork/NetworkInterface.h -# Include/GameNetwork/networkutil.h -# Include/GameNetwork/RankPointValue.h -# Include/GameNetwork/Transport.h -# Include/GameNetwork/udp.h -# Include/GameNetwork/User.h -# Include/GameNetwork/WOLBrowser/FEBDispatch.h -# Include/GameNetwork/WOLBrowser/WebBrowser.h + Include/GameNetwork/IPEnumeration.h + Include/GameNetwork/LANAPI.h + Include/GameNetwork/LANAPICallbacks.h + Include/GameNetwork/LANGameInfo.h + Include/GameNetwork/LANPlayer.h + Include/GameNetwork/NAT.h + Include/GameNetwork/NetCommandList.h + Include/GameNetwork/NetCommandMsg.h + Include/GameNetwork/NetCommandRef.h + Include/GameNetwork/NetCommandWrapperList.h + Include/GameNetwork/NetPacket.h + Include/GameNetwork/NetworkDefs.h + Include/GameNetwork/NetworkInterface.h + Include/GameNetwork/networkutil.h + Include/GameNetwork/RankPointValue.h + Include/GameNetwork/Transport.h + Include/GameNetwork/udp.h + Include/GameNetwork/User.h + Include/GameNetwork/WOLBrowser/FEBDispatch.h + Include/GameNetwork/WOLBrowser/WebBrowser.h # Include/Precompiled/PreRTS.h Source/Common/Audio/AudioEventRTS.cpp Source/Common/Audio/AudioRequest.cpp @@ -1091,53 +1091,53 @@ set(GAMEENGINE_SRC # Source/GameLogic/System/GameLogic.cpp # Source/GameLogic/System/GameLogicDispatch.cpp # Source/GameLogic/System/RankInfo.cpp -# Source/GameNetwork/Connection.cpp -# Source/GameNetwork/ConnectionManager.cpp -# Source/GameNetwork/DisconnectManager.cpp -# Source/GameNetwork/DownloadManager.cpp -# Source/GameNetwork/FileTransfer.cpp -# Source/GameNetwork/FirewallHelper.cpp -# Source/GameNetwork/FrameData.cpp -# Source/GameNetwork/FrameDataManager.cpp -# Source/GameNetwork/FrameMetrics.cpp -# Source/GameNetwork/GameInfo.cpp -# Source/GameNetwork/GameMessageParser.cpp - #Source/GameNetwork/GameSpyChat.cpp # unused - #Source/GameNetwork/GameSpyGameInfo.cpp # unused - #Source/GameNetwork/GameSpyGP.cpp # unused -# Source/GameNetwork/GameSpy/Chat.cpp -# Source/GameNetwork/GameSpy/GSConfig.cpp -# Source/GameNetwork/GameSpy/LadderDefs.cpp -# Source/GameNetwork/GameSpy/LobbyUtils.cpp -# Source/GameNetwork/GameSpy/MainMenuUtils.cpp -# Source/GameNetwork/GameSpy/PeerDefs.cpp -# Source/GameNetwork/GameSpy/StagingRoomGameInfo.cpp -# Source/GameNetwork/GameSpy/Thread/BuddyThread.cpp -# Source/GameNetwork/GameSpy/Thread/GameResultsThread.cpp -# Source/GameNetwork/GameSpy/Thread/PeerThread.cpp -# Source/GameNetwork/GameSpy/Thread/PersistentStorageThread.cpp -# Source/GameNetwork/GameSpy/Thread/PingThread.cpp -# Source/GameNetwork/GameSpy/Thread/ThreadUtils.cpp -# Source/GameNetwork/GameSpyOverlay.cpp + Source/GameNetwork/Connection.cpp + Source/GameNetwork/ConnectionManager.cpp + Source/GameNetwork/DisconnectManager.cpp + Source/GameNetwork/DownloadManager.cpp + Source/GameNetwork/FileTransfer.cpp + Source/GameNetwork/FirewallHelper.cpp + Source/GameNetwork/FrameData.cpp + Source/GameNetwork/FrameDataManager.cpp + Source/GameNetwork/FrameMetrics.cpp + Source/GameNetwork/GameInfo.cpp + Source/GameNetwork/GameMessageParser.cpp + Source/GameNetwork/GameSpyChat.cpp # unused + Source/GameNetwork/GameSpyGameInfo.cpp # unused + Source/GameNetwork/GameSpyGP.cpp # unused + Source/GameNetwork/GameSpy/Chat.cpp + Source/GameNetwork/GameSpy/GSConfig.cpp + Source/GameNetwork/GameSpy/LadderDefs.cpp + Source/GameNetwork/GameSpy/LobbyUtils.cpp + Source/GameNetwork/GameSpy/MainMenuUtils.cpp + Source/GameNetwork/GameSpy/PeerDefs.cpp + Source/GameNetwork/GameSpy/StagingRoomGameInfo.cpp + Source/GameNetwork/GameSpy/Thread/BuddyThread.cpp + Source/GameNetwork/GameSpy/Thread/GameResultsThread.cpp + Source/GameNetwork/GameSpy/Thread/PeerThread.cpp + Source/GameNetwork/GameSpy/Thread/PersistentStorageThread.cpp + Source/GameNetwork/GameSpy/Thread/PingThread.cpp + Source/GameNetwork/GameSpy/Thread/ThreadUtils.cpp + Source/GameNetwork/GameSpyOverlay.cpp # Source/GameNetwork/GUIUtil.cpp -# Source/GameNetwork/IPEnumeration.cpp -# Source/GameNetwork/LANAPI.cpp -# Source/GameNetwork/LANAPICallbacks.cpp -# Source/GameNetwork/LANAPIhandlers.cpp -# Source/GameNetwork/LANGameInfo.cpp -# Source/GameNetwork/NAT.cpp -# Source/GameNetwork/NetCommandList.cpp -# Source/GameNetwork/NetCommandMsg.cpp -# Source/GameNetwork/NetCommandRef.cpp -# Source/GameNetwork/NetCommandWrapperList.cpp -# Source/GameNetwork/NetMessageStream.cpp -# Source/GameNetwork/NetPacket.cpp -# Source/GameNetwork/Network.cpp -# Source/GameNetwork/NetworkUtil.cpp -# Source/GameNetwork/Transport.cpp -# Source/GameNetwork/udp.cpp -# Source/GameNetwork/User.cpp -# Source/GameNetwork/WOLBrowser/WebBrowser.cpp + Source/GameNetwork/IPEnumeration.cpp + Source/GameNetwork/LANAPI.cpp + Source/GameNetwork/LANAPICallbacks.cpp + Source/GameNetwork/LANAPIhandlers.cpp + Source/GameNetwork/LANGameInfo.cpp + Source/GameNetwork/NAT.cpp + Source/GameNetwork/NetCommandList.cpp + Source/GameNetwork/NetCommandMsg.cpp + Source/GameNetwork/NetCommandRef.cpp + Source/GameNetwork/NetCommandWrapperList.cpp + Source/GameNetwork/NetMessageStream.cpp + Source/GameNetwork/NetPacket.cpp + Source/GameNetwork/Network.cpp + Source/GameNetwork/NetworkUtil.cpp + Source/GameNetwork/Transport.cpp + Source/GameNetwork/udp.cpp + Source/GameNetwork/User.cpp + Source/GameNetwork/WOLBrowser/WebBrowser.cpp # Source/Precompiled/PreRTS.cpp ) diff --git a/GeneralsMD/Code/GameEngine/Include/GameNetwork/Connection.h b/Core/GameEngine/Include/GameNetwork/Connection.h similarity index 100% rename from GeneralsMD/Code/GameEngine/Include/GameNetwork/Connection.h rename to Core/GameEngine/Include/GameNetwork/Connection.h diff --git a/GeneralsMD/Code/GameEngine/Include/GameNetwork/ConnectionManager.h b/Core/GameEngine/Include/GameNetwork/ConnectionManager.h similarity index 100% rename from GeneralsMD/Code/GameEngine/Include/GameNetwork/ConnectionManager.h rename to Core/GameEngine/Include/GameNetwork/ConnectionManager.h diff --git a/GeneralsMD/Code/GameEngine/Include/GameNetwork/DisconnectManager.h b/Core/GameEngine/Include/GameNetwork/DisconnectManager.h similarity index 100% rename from GeneralsMD/Code/GameEngine/Include/GameNetwork/DisconnectManager.h rename to Core/GameEngine/Include/GameNetwork/DisconnectManager.h diff --git a/GeneralsMD/Code/GameEngine/Include/GameNetwork/DownloadManager.h b/Core/GameEngine/Include/GameNetwork/DownloadManager.h similarity index 100% rename from GeneralsMD/Code/GameEngine/Include/GameNetwork/DownloadManager.h rename to Core/GameEngine/Include/GameNetwork/DownloadManager.h diff --git a/GeneralsMD/Code/GameEngine/Include/GameNetwork/FileTransfer.h b/Core/GameEngine/Include/GameNetwork/FileTransfer.h similarity index 100% rename from GeneralsMD/Code/GameEngine/Include/GameNetwork/FileTransfer.h rename to Core/GameEngine/Include/GameNetwork/FileTransfer.h diff --git a/GeneralsMD/Code/GameEngine/Include/GameNetwork/FirewallHelper.h b/Core/GameEngine/Include/GameNetwork/FirewallHelper.h similarity index 100% rename from GeneralsMD/Code/GameEngine/Include/GameNetwork/FirewallHelper.h rename to Core/GameEngine/Include/GameNetwork/FirewallHelper.h diff --git a/GeneralsMD/Code/GameEngine/Include/GameNetwork/FrameData.h b/Core/GameEngine/Include/GameNetwork/FrameData.h similarity index 100% rename from GeneralsMD/Code/GameEngine/Include/GameNetwork/FrameData.h rename to Core/GameEngine/Include/GameNetwork/FrameData.h diff --git a/GeneralsMD/Code/GameEngine/Include/GameNetwork/FrameDataManager.h b/Core/GameEngine/Include/GameNetwork/FrameDataManager.h similarity index 100% rename from GeneralsMD/Code/GameEngine/Include/GameNetwork/FrameDataManager.h rename to Core/GameEngine/Include/GameNetwork/FrameDataManager.h diff --git a/GeneralsMD/Code/GameEngine/Include/GameNetwork/FrameMetrics.h b/Core/GameEngine/Include/GameNetwork/FrameMetrics.h similarity index 100% rename from GeneralsMD/Code/GameEngine/Include/GameNetwork/FrameMetrics.h rename to Core/GameEngine/Include/GameNetwork/FrameMetrics.h diff --git a/GeneralsMD/Code/GameEngine/Include/GameNetwork/GameInfo.h b/Core/GameEngine/Include/GameNetwork/GameInfo.h similarity index 100% rename from GeneralsMD/Code/GameEngine/Include/GameNetwork/GameInfo.h rename to Core/GameEngine/Include/GameNetwork/GameInfo.h diff --git a/GeneralsMD/Code/GameEngine/Include/GameNetwork/GameMessageParser.h b/Core/GameEngine/Include/GameNetwork/GameMessageParser.h similarity index 100% rename from GeneralsMD/Code/GameEngine/Include/GameNetwork/GameMessageParser.h rename to Core/GameEngine/Include/GameNetwork/GameMessageParser.h diff --git a/GeneralsMD/Code/GameEngine/Include/GameNetwork/GameSpy/BuddyDefs.h b/Core/GameEngine/Include/GameNetwork/GameSpy/BuddyDefs.h similarity index 100% rename from GeneralsMD/Code/GameEngine/Include/GameNetwork/GameSpy/BuddyDefs.h rename to Core/GameEngine/Include/GameNetwork/GameSpy/BuddyDefs.h diff --git a/GeneralsMD/Code/GameEngine/Include/GameNetwork/GameSpy/BuddyThread.h b/Core/GameEngine/Include/GameNetwork/GameSpy/BuddyThread.h similarity index 100% rename from GeneralsMD/Code/GameEngine/Include/GameNetwork/GameSpy/BuddyThread.h rename to Core/GameEngine/Include/GameNetwork/GameSpy/BuddyThread.h diff --git a/GeneralsMD/Code/GameEngine/Include/GameNetwork/GameSpy/GSConfig.h b/Core/GameEngine/Include/GameNetwork/GameSpy/GSConfig.h similarity index 100% rename from GeneralsMD/Code/GameEngine/Include/GameNetwork/GameSpy/GSConfig.h rename to Core/GameEngine/Include/GameNetwork/GameSpy/GSConfig.h diff --git a/GeneralsMD/Code/GameEngine/Include/GameNetwork/GameSpy/GameResultsThread.h b/Core/GameEngine/Include/GameNetwork/GameSpy/GameResultsThread.h similarity index 100% rename from GeneralsMD/Code/GameEngine/Include/GameNetwork/GameSpy/GameResultsThread.h rename to Core/GameEngine/Include/GameNetwork/GameSpy/GameResultsThread.h diff --git a/GeneralsMD/Code/GameEngine/Include/GameNetwork/GameSpy/LadderDefs.h b/Core/GameEngine/Include/GameNetwork/GameSpy/LadderDefs.h similarity index 100% rename from GeneralsMD/Code/GameEngine/Include/GameNetwork/GameSpy/LadderDefs.h rename to Core/GameEngine/Include/GameNetwork/GameSpy/LadderDefs.h diff --git a/GeneralsMD/Code/GameEngine/Include/GameNetwork/GameSpy/LobbyUtils.h b/Core/GameEngine/Include/GameNetwork/GameSpy/LobbyUtils.h similarity index 100% rename from GeneralsMD/Code/GameEngine/Include/GameNetwork/GameSpy/LobbyUtils.h rename to Core/GameEngine/Include/GameNetwork/GameSpy/LobbyUtils.h diff --git a/GeneralsMD/Code/GameEngine/Include/GameNetwork/GameSpy/MainMenuUtils.h b/Core/GameEngine/Include/GameNetwork/GameSpy/MainMenuUtils.h similarity index 100% rename from GeneralsMD/Code/GameEngine/Include/GameNetwork/GameSpy/MainMenuUtils.h rename to Core/GameEngine/Include/GameNetwork/GameSpy/MainMenuUtils.h diff --git a/GeneralsMD/Code/GameEngine/Include/GameNetwork/GameSpy/PeerDefs.h b/Core/GameEngine/Include/GameNetwork/GameSpy/PeerDefs.h similarity index 100% rename from GeneralsMD/Code/GameEngine/Include/GameNetwork/GameSpy/PeerDefs.h rename to Core/GameEngine/Include/GameNetwork/GameSpy/PeerDefs.h diff --git a/GeneralsMD/Code/GameEngine/Include/GameNetwork/GameSpy/PeerDefsImplementation.h b/Core/GameEngine/Include/GameNetwork/GameSpy/PeerDefsImplementation.h similarity index 100% rename from GeneralsMD/Code/GameEngine/Include/GameNetwork/GameSpy/PeerDefsImplementation.h rename to Core/GameEngine/Include/GameNetwork/GameSpy/PeerDefsImplementation.h diff --git a/GeneralsMD/Code/GameEngine/Include/GameNetwork/GameSpy/PeerThread.h b/Core/GameEngine/Include/GameNetwork/GameSpy/PeerThread.h similarity index 100% rename from GeneralsMD/Code/GameEngine/Include/GameNetwork/GameSpy/PeerThread.h rename to Core/GameEngine/Include/GameNetwork/GameSpy/PeerThread.h diff --git a/GeneralsMD/Code/GameEngine/Include/GameNetwork/GameSpy/PersistentStorageDefs.h b/Core/GameEngine/Include/GameNetwork/GameSpy/PersistentStorageDefs.h similarity index 100% rename from GeneralsMD/Code/GameEngine/Include/GameNetwork/GameSpy/PersistentStorageDefs.h rename to Core/GameEngine/Include/GameNetwork/GameSpy/PersistentStorageDefs.h diff --git a/GeneralsMD/Code/GameEngine/Include/GameNetwork/GameSpy/PersistentStorageThread.h b/Core/GameEngine/Include/GameNetwork/GameSpy/PersistentStorageThread.h similarity index 100% rename from GeneralsMD/Code/GameEngine/Include/GameNetwork/GameSpy/PersistentStorageThread.h rename to Core/GameEngine/Include/GameNetwork/GameSpy/PersistentStorageThread.h diff --git a/GeneralsMD/Code/GameEngine/Include/GameNetwork/GameSpy/PingThread.h b/Core/GameEngine/Include/GameNetwork/GameSpy/PingThread.h similarity index 100% rename from GeneralsMD/Code/GameEngine/Include/GameNetwork/GameSpy/PingThread.h rename to Core/GameEngine/Include/GameNetwork/GameSpy/PingThread.h diff --git a/GeneralsMD/Code/GameEngine/Include/GameNetwork/GameSpy/StagingRoomGameInfo.h b/Core/GameEngine/Include/GameNetwork/GameSpy/StagingRoomGameInfo.h similarity index 100% rename from GeneralsMD/Code/GameEngine/Include/GameNetwork/GameSpy/StagingRoomGameInfo.h rename to Core/GameEngine/Include/GameNetwork/GameSpy/StagingRoomGameInfo.h diff --git a/GeneralsMD/Code/GameEngine/Include/GameNetwork/GameSpy/ThreadUtils.h b/Core/GameEngine/Include/GameNetwork/GameSpy/ThreadUtils.h similarity index 100% rename from GeneralsMD/Code/GameEngine/Include/GameNetwork/GameSpy/ThreadUtils.h rename to Core/GameEngine/Include/GameNetwork/GameSpy/ThreadUtils.h diff --git a/GeneralsMD/Code/GameEngine/Include/GameNetwork/GameSpyChat.h b/Core/GameEngine/Include/GameNetwork/GameSpyChat.h similarity index 100% rename from GeneralsMD/Code/GameEngine/Include/GameNetwork/GameSpyChat.h rename to Core/GameEngine/Include/GameNetwork/GameSpyChat.h diff --git a/GeneralsMD/Code/GameEngine/Include/GameNetwork/GameSpyGP.h b/Core/GameEngine/Include/GameNetwork/GameSpyGP.h similarity index 100% rename from GeneralsMD/Code/GameEngine/Include/GameNetwork/GameSpyGP.h rename to Core/GameEngine/Include/GameNetwork/GameSpyGP.h diff --git a/GeneralsMD/Code/GameEngine/Include/GameNetwork/GameSpyGameInfo.h b/Core/GameEngine/Include/GameNetwork/GameSpyGameInfo.h similarity index 100% rename from GeneralsMD/Code/GameEngine/Include/GameNetwork/GameSpyGameInfo.h rename to Core/GameEngine/Include/GameNetwork/GameSpyGameInfo.h diff --git a/GeneralsMD/Code/GameEngine/Include/GameNetwork/GameSpyOverlay.h b/Core/GameEngine/Include/GameNetwork/GameSpyOverlay.h similarity index 100% rename from GeneralsMD/Code/GameEngine/Include/GameNetwork/GameSpyOverlay.h rename to Core/GameEngine/Include/GameNetwork/GameSpyOverlay.h diff --git a/GeneralsMD/Code/GameEngine/Include/GameNetwork/GameSpyThread.h b/Core/GameEngine/Include/GameNetwork/GameSpyThread.h similarity index 100% rename from GeneralsMD/Code/GameEngine/Include/GameNetwork/GameSpyThread.h rename to Core/GameEngine/Include/GameNetwork/GameSpyThread.h diff --git a/GeneralsMD/Code/GameEngine/Include/GameNetwork/IPEnumeration.h b/Core/GameEngine/Include/GameNetwork/IPEnumeration.h similarity index 100% rename from GeneralsMD/Code/GameEngine/Include/GameNetwork/IPEnumeration.h rename to Core/GameEngine/Include/GameNetwork/IPEnumeration.h diff --git a/GeneralsMD/Code/GameEngine/Include/GameNetwork/LANAPI.h b/Core/GameEngine/Include/GameNetwork/LANAPI.h similarity index 100% rename from GeneralsMD/Code/GameEngine/Include/GameNetwork/LANAPI.h rename to Core/GameEngine/Include/GameNetwork/LANAPI.h diff --git a/GeneralsMD/Code/GameEngine/Include/GameNetwork/LANAPICallbacks.h b/Core/GameEngine/Include/GameNetwork/LANAPICallbacks.h similarity index 100% rename from GeneralsMD/Code/GameEngine/Include/GameNetwork/LANAPICallbacks.h rename to Core/GameEngine/Include/GameNetwork/LANAPICallbacks.h diff --git a/GeneralsMD/Code/GameEngine/Include/GameNetwork/LANGameInfo.h b/Core/GameEngine/Include/GameNetwork/LANGameInfo.h similarity index 100% rename from GeneralsMD/Code/GameEngine/Include/GameNetwork/LANGameInfo.h rename to Core/GameEngine/Include/GameNetwork/LANGameInfo.h diff --git a/GeneralsMD/Code/GameEngine/Include/GameNetwork/LANPlayer.h b/Core/GameEngine/Include/GameNetwork/LANPlayer.h similarity index 100% rename from GeneralsMD/Code/GameEngine/Include/GameNetwork/LANPlayer.h rename to Core/GameEngine/Include/GameNetwork/LANPlayer.h diff --git a/GeneralsMD/Code/GameEngine/Include/GameNetwork/NAT.h b/Core/GameEngine/Include/GameNetwork/NAT.h similarity index 100% rename from GeneralsMD/Code/GameEngine/Include/GameNetwork/NAT.h rename to Core/GameEngine/Include/GameNetwork/NAT.h diff --git a/GeneralsMD/Code/GameEngine/Include/GameNetwork/NetCommandList.h b/Core/GameEngine/Include/GameNetwork/NetCommandList.h similarity index 100% rename from GeneralsMD/Code/GameEngine/Include/GameNetwork/NetCommandList.h rename to Core/GameEngine/Include/GameNetwork/NetCommandList.h diff --git a/GeneralsMD/Code/GameEngine/Include/GameNetwork/NetCommandMsg.h b/Core/GameEngine/Include/GameNetwork/NetCommandMsg.h similarity index 100% rename from GeneralsMD/Code/GameEngine/Include/GameNetwork/NetCommandMsg.h rename to Core/GameEngine/Include/GameNetwork/NetCommandMsg.h diff --git a/GeneralsMD/Code/GameEngine/Include/GameNetwork/NetCommandRef.h b/Core/GameEngine/Include/GameNetwork/NetCommandRef.h similarity index 100% rename from GeneralsMD/Code/GameEngine/Include/GameNetwork/NetCommandRef.h rename to Core/GameEngine/Include/GameNetwork/NetCommandRef.h diff --git a/GeneralsMD/Code/GameEngine/Include/GameNetwork/NetCommandWrapperList.h b/Core/GameEngine/Include/GameNetwork/NetCommandWrapperList.h similarity index 100% rename from GeneralsMD/Code/GameEngine/Include/GameNetwork/NetCommandWrapperList.h rename to Core/GameEngine/Include/GameNetwork/NetCommandWrapperList.h diff --git a/GeneralsMD/Code/GameEngine/Include/GameNetwork/NetPacket.h b/Core/GameEngine/Include/GameNetwork/NetPacket.h similarity index 100% rename from GeneralsMD/Code/GameEngine/Include/GameNetwork/NetPacket.h rename to Core/GameEngine/Include/GameNetwork/NetPacket.h diff --git a/GeneralsMD/Code/GameEngine/Include/GameNetwork/NetworkDefs.h b/Core/GameEngine/Include/GameNetwork/NetworkDefs.h similarity index 100% rename from GeneralsMD/Code/GameEngine/Include/GameNetwork/NetworkDefs.h rename to Core/GameEngine/Include/GameNetwork/NetworkDefs.h diff --git a/GeneralsMD/Code/GameEngine/Include/GameNetwork/NetworkInterface.h b/Core/GameEngine/Include/GameNetwork/NetworkInterface.h similarity index 100% rename from GeneralsMD/Code/GameEngine/Include/GameNetwork/NetworkInterface.h rename to Core/GameEngine/Include/GameNetwork/NetworkInterface.h diff --git a/GeneralsMD/Code/GameEngine/Include/GameNetwork/RankPointValue.h b/Core/GameEngine/Include/GameNetwork/RankPointValue.h similarity index 100% rename from GeneralsMD/Code/GameEngine/Include/GameNetwork/RankPointValue.h rename to Core/GameEngine/Include/GameNetwork/RankPointValue.h diff --git a/GeneralsMD/Code/GameEngine/Include/GameNetwork/Transport.h b/Core/GameEngine/Include/GameNetwork/Transport.h similarity index 100% rename from GeneralsMD/Code/GameEngine/Include/GameNetwork/Transport.h rename to Core/GameEngine/Include/GameNetwork/Transport.h diff --git a/GeneralsMD/Code/GameEngine/Include/GameNetwork/User.h b/Core/GameEngine/Include/GameNetwork/User.h similarity index 100% rename from GeneralsMD/Code/GameEngine/Include/GameNetwork/User.h rename to Core/GameEngine/Include/GameNetwork/User.h diff --git a/GeneralsMD/Code/GameEngine/Include/GameNetwork/WOLBrowser/FEBDispatch.h b/Core/GameEngine/Include/GameNetwork/WOLBrowser/FEBDispatch.h similarity index 100% rename from GeneralsMD/Code/GameEngine/Include/GameNetwork/WOLBrowser/FEBDispatch.h rename to Core/GameEngine/Include/GameNetwork/WOLBrowser/FEBDispatch.h diff --git a/GeneralsMD/Code/GameEngine/Include/GameNetwork/WOLBrowser/WebBrowser.h b/Core/GameEngine/Include/GameNetwork/WOLBrowser/WebBrowser.h similarity index 100% rename from GeneralsMD/Code/GameEngine/Include/GameNetwork/WOLBrowser/WebBrowser.h rename to Core/GameEngine/Include/GameNetwork/WOLBrowser/WebBrowser.h diff --git a/GeneralsMD/Code/GameEngine/Include/GameNetwork/networkutil.h b/Core/GameEngine/Include/GameNetwork/networkutil.h similarity index 100% rename from GeneralsMD/Code/GameEngine/Include/GameNetwork/networkutil.h rename to Core/GameEngine/Include/GameNetwork/networkutil.h diff --git a/GeneralsMD/Code/GameEngine/Include/GameNetwork/udp.h b/Core/GameEngine/Include/GameNetwork/udp.h similarity index 100% rename from GeneralsMD/Code/GameEngine/Include/GameNetwork/udp.h rename to Core/GameEngine/Include/GameNetwork/udp.h diff --git a/GeneralsMD/Code/GameEngine/Source/GameNetwork/Connection.cpp b/Core/GameEngine/Source/GameNetwork/Connection.cpp similarity index 100% rename from GeneralsMD/Code/GameEngine/Source/GameNetwork/Connection.cpp rename to Core/GameEngine/Source/GameNetwork/Connection.cpp diff --git a/GeneralsMD/Code/GameEngine/Source/GameNetwork/ConnectionManager.cpp b/Core/GameEngine/Source/GameNetwork/ConnectionManager.cpp similarity index 100% rename from GeneralsMD/Code/GameEngine/Source/GameNetwork/ConnectionManager.cpp rename to Core/GameEngine/Source/GameNetwork/ConnectionManager.cpp diff --git a/GeneralsMD/Code/GameEngine/Source/GameNetwork/DisconnectManager.cpp b/Core/GameEngine/Source/GameNetwork/DisconnectManager.cpp similarity index 100% rename from GeneralsMD/Code/GameEngine/Source/GameNetwork/DisconnectManager.cpp rename to Core/GameEngine/Source/GameNetwork/DisconnectManager.cpp diff --git a/GeneralsMD/Code/GameEngine/Source/GameNetwork/DownloadManager.cpp b/Core/GameEngine/Source/GameNetwork/DownloadManager.cpp similarity index 100% rename from GeneralsMD/Code/GameEngine/Source/GameNetwork/DownloadManager.cpp rename to Core/GameEngine/Source/GameNetwork/DownloadManager.cpp diff --git a/GeneralsMD/Code/GameEngine/Source/GameNetwork/FileTransfer.cpp b/Core/GameEngine/Source/GameNetwork/FileTransfer.cpp similarity index 100% rename from GeneralsMD/Code/GameEngine/Source/GameNetwork/FileTransfer.cpp rename to Core/GameEngine/Source/GameNetwork/FileTransfer.cpp diff --git a/GeneralsMD/Code/GameEngine/Source/GameNetwork/FirewallHelper.cpp b/Core/GameEngine/Source/GameNetwork/FirewallHelper.cpp similarity index 100% rename from GeneralsMD/Code/GameEngine/Source/GameNetwork/FirewallHelper.cpp rename to Core/GameEngine/Source/GameNetwork/FirewallHelper.cpp diff --git a/GeneralsMD/Code/GameEngine/Source/GameNetwork/FrameData.cpp b/Core/GameEngine/Source/GameNetwork/FrameData.cpp similarity index 100% rename from GeneralsMD/Code/GameEngine/Source/GameNetwork/FrameData.cpp rename to Core/GameEngine/Source/GameNetwork/FrameData.cpp diff --git a/GeneralsMD/Code/GameEngine/Source/GameNetwork/FrameDataManager.cpp b/Core/GameEngine/Source/GameNetwork/FrameDataManager.cpp similarity index 100% rename from GeneralsMD/Code/GameEngine/Source/GameNetwork/FrameDataManager.cpp rename to Core/GameEngine/Source/GameNetwork/FrameDataManager.cpp diff --git a/GeneralsMD/Code/GameEngine/Source/GameNetwork/FrameMetrics.cpp b/Core/GameEngine/Source/GameNetwork/FrameMetrics.cpp similarity index 100% rename from GeneralsMD/Code/GameEngine/Source/GameNetwork/FrameMetrics.cpp rename to Core/GameEngine/Source/GameNetwork/FrameMetrics.cpp diff --git a/GeneralsMD/Code/GameEngine/Source/GameNetwork/GameInfo.cpp b/Core/GameEngine/Source/GameNetwork/GameInfo.cpp similarity index 100% rename from GeneralsMD/Code/GameEngine/Source/GameNetwork/GameInfo.cpp rename to Core/GameEngine/Source/GameNetwork/GameInfo.cpp diff --git a/GeneralsMD/Code/GameEngine/Source/GameNetwork/GameMessageParser.cpp b/Core/GameEngine/Source/GameNetwork/GameMessageParser.cpp similarity index 100% rename from GeneralsMD/Code/GameEngine/Source/GameNetwork/GameMessageParser.cpp rename to Core/GameEngine/Source/GameNetwork/GameMessageParser.cpp diff --git a/GeneralsMD/Code/GameEngine/Source/GameNetwork/GameSpy/Chat.cpp b/Core/GameEngine/Source/GameNetwork/GameSpy/Chat.cpp similarity index 100% rename from GeneralsMD/Code/GameEngine/Source/GameNetwork/GameSpy/Chat.cpp rename to Core/GameEngine/Source/GameNetwork/GameSpy/Chat.cpp diff --git a/GeneralsMD/Code/GameEngine/Source/GameNetwork/GameSpy/GSConfig.cpp b/Core/GameEngine/Source/GameNetwork/GameSpy/GSConfig.cpp similarity index 100% rename from GeneralsMD/Code/GameEngine/Source/GameNetwork/GameSpy/GSConfig.cpp rename to Core/GameEngine/Source/GameNetwork/GameSpy/GSConfig.cpp diff --git a/GeneralsMD/Code/GameEngine/Source/GameNetwork/GameSpy/LadderDefs.cpp b/Core/GameEngine/Source/GameNetwork/GameSpy/LadderDefs.cpp similarity index 100% rename from GeneralsMD/Code/GameEngine/Source/GameNetwork/GameSpy/LadderDefs.cpp rename to Core/GameEngine/Source/GameNetwork/GameSpy/LadderDefs.cpp diff --git a/GeneralsMD/Code/GameEngine/Source/GameNetwork/GameSpy/LobbyUtils.cpp b/Core/GameEngine/Source/GameNetwork/GameSpy/LobbyUtils.cpp similarity index 100% rename from GeneralsMD/Code/GameEngine/Source/GameNetwork/GameSpy/LobbyUtils.cpp rename to Core/GameEngine/Source/GameNetwork/GameSpy/LobbyUtils.cpp diff --git a/GeneralsMD/Code/GameEngine/Source/GameNetwork/GameSpy/MainMenuUtils.cpp b/Core/GameEngine/Source/GameNetwork/GameSpy/MainMenuUtils.cpp similarity index 100% rename from GeneralsMD/Code/GameEngine/Source/GameNetwork/GameSpy/MainMenuUtils.cpp rename to Core/GameEngine/Source/GameNetwork/GameSpy/MainMenuUtils.cpp diff --git a/GeneralsMD/Code/GameEngine/Source/GameNetwork/GameSpy/PeerDefs.cpp b/Core/GameEngine/Source/GameNetwork/GameSpy/PeerDefs.cpp similarity index 100% rename from GeneralsMD/Code/GameEngine/Source/GameNetwork/GameSpy/PeerDefs.cpp rename to Core/GameEngine/Source/GameNetwork/GameSpy/PeerDefs.cpp diff --git a/GeneralsMD/Code/GameEngine/Source/GameNetwork/GameSpy/StagingRoomGameInfo.cpp b/Core/GameEngine/Source/GameNetwork/GameSpy/StagingRoomGameInfo.cpp similarity index 100% rename from GeneralsMD/Code/GameEngine/Source/GameNetwork/GameSpy/StagingRoomGameInfo.cpp rename to Core/GameEngine/Source/GameNetwork/GameSpy/StagingRoomGameInfo.cpp diff --git a/GeneralsMD/Code/GameEngine/Source/GameNetwork/GameSpy/Thread/BuddyThread.cpp b/Core/GameEngine/Source/GameNetwork/GameSpy/Thread/BuddyThread.cpp similarity index 100% rename from GeneralsMD/Code/GameEngine/Source/GameNetwork/GameSpy/Thread/BuddyThread.cpp rename to Core/GameEngine/Source/GameNetwork/GameSpy/Thread/BuddyThread.cpp diff --git a/GeneralsMD/Code/GameEngine/Source/GameNetwork/GameSpy/Thread/GameResultsThread.cpp b/Core/GameEngine/Source/GameNetwork/GameSpy/Thread/GameResultsThread.cpp similarity index 100% rename from GeneralsMD/Code/GameEngine/Source/GameNetwork/GameSpy/Thread/GameResultsThread.cpp rename to Core/GameEngine/Source/GameNetwork/GameSpy/Thread/GameResultsThread.cpp diff --git a/GeneralsMD/Code/GameEngine/Source/GameNetwork/GameSpy/Thread/PeerThread.cpp b/Core/GameEngine/Source/GameNetwork/GameSpy/Thread/PeerThread.cpp similarity index 100% rename from GeneralsMD/Code/GameEngine/Source/GameNetwork/GameSpy/Thread/PeerThread.cpp rename to Core/GameEngine/Source/GameNetwork/GameSpy/Thread/PeerThread.cpp diff --git a/GeneralsMD/Code/GameEngine/Source/GameNetwork/GameSpy/Thread/PersistentStorageThread.cpp b/Core/GameEngine/Source/GameNetwork/GameSpy/Thread/PersistentStorageThread.cpp similarity index 100% rename from GeneralsMD/Code/GameEngine/Source/GameNetwork/GameSpy/Thread/PersistentStorageThread.cpp rename to Core/GameEngine/Source/GameNetwork/GameSpy/Thread/PersistentStorageThread.cpp diff --git a/GeneralsMD/Code/GameEngine/Source/GameNetwork/GameSpy/Thread/PingThread.cpp b/Core/GameEngine/Source/GameNetwork/GameSpy/Thread/PingThread.cpp similarity index 100% rename from GeneralsMD/Code/GameEngine/Source/GameNetwork/GameSpy/Thread/PingThread.cpp rename to Core/GameEngine/Source/GameNetwork/GameSpy/Thread/PingThread.cpp diff --git a/GeneralsMD/Code/GameEngine/Source/GameNetwork/GameSpy/Thread/ThreadUtils.cpp b/Core/GameEngine/Source/GameNetwork/GameSpy/Thread/ThreadUtils.cpp similarity index 100% rename from GeneralsMD/Code/GameEngine/Source/GameNetwork/GameSpy/Thread/ThreadUtils.cpp rename to Core/GameEngine/Source/GameNetwork/GameSpy/Thread/ThreadUtils.cpp diff --git a/GeneralsMD/Code/GameEngine/Source/GameNetwork/GameSpyChat.cpp b/Core/GameEngine/Source/GameNetwork/GameSpyChat.cpp similarity index 100% rename from GeneralsMD/Code/GameEngine/Source/GameNetwork/GameSpyChat.cpp rename to Core/GameEngine/Source/GameNetwork/GameSpyChat.cpp diff --git a/GeneralsMD/Code/GameEngine/Source/GameNetwork/GameSpyGP.cpp b/Core/GameEngine/Source/GameNetwork/GameSpyGP.cpp similarity index 100% rename from GeneralsMD/Code/GameEngine/Source/GameNetwork/GameSpyGP.cpp rename to Core/GameEngine/Source/GameNetwork/GameSpyGP.cpp diff --git a/GeneralsMD/Code/GameEngine/Source/GameNetwork/GameSpyGameInfo.cpp b/Core/GameEngine/Source/GameNetwork/GameSpyGameInfo.cpp similarity index 100% rename from GeneralsMD/Code/GameEngine/Source/GameNetwork/GameSpyGameInfo.cpp rename to Core/GameEngine/Source/GameNetwork/GameSpyGameInfo.cpp diff --git a/GeneralsMD/Code/GameEngine/Source/GameNetwork/GameSpyOverlay.cpp b/Core/GameEngine/Source/GameNetwork/GameSpyOverlay.cpp similarity index 100% rename from GeneralsMD/Code/GameEngine/Source/GameNetwork/GameSpyOverlay.cpp rename to Core/GameEngine/Source/GameNetwork/GameSpyOverlay.cpp diff --git a/GeneralsMD/Code/GameEngine/Source/GameNetwork/IPEnumeration.cpp b/Core/GameEngine/Source/GameNetwork/IPEnumeration.cpp similarity index 100% rename from GeneralsMD/Code/GameEngine/Source/GameNetwork/IPEnumeration.cpp rename to Core/GameEngine/Source/GameNetwork/IPEnumeration.cpp diff --git a/GeneralsMD/Code/GameEngine/Source/GameNetwork/LANAPI.cpp b/Core/GameEngine/Source/GameNetwork/LANAPI.cpp similarity index 100% rename from GeneralsMD/Code/GameEngine/Source/GameNetwork/LANAPI.cpp rename to Core/GameEngine/Source/GameNetwork/LANAPI.cpp diff --git a/GeneralsMD/Code/GameEngine/Source/GameNetwork/LANAPICallbacks.cpp b/Core/GameEngine/Source/GameNetwork/LANAPICallbacks.cpp similarity index 100% rename from GeneralsMD/Code/GameEngine/Source/GameNetwork/LANAPICallbacks.cpp rename to Core/GameEngine/Source/GameNetwork/LANAPICallbacks.cpp diff --git a/GeneralsMD/Code/GameEngine/Source/GameNetwork/LANAPIhandlers.cpp b/Core/GameEngine/Source/GameNetwork/LANAPIhandlers.cpp similarity index 100% rename from GeneralsMD/Code/GameEngine/Source/GameNetwork/LANAPIhandlers.cpp rename to Core/GameEngine/Source/GameNetwork/LANAPIhandlers.cpp diff --git a/GeneralsMD/Code/GameEngine/Source/GameNetwork/LANGameInfo.cpp b/Core/GameEngine/Source/GameNetwork/LANGameInfo.cpp similarity index 100% rename from GeneralsMD/Code/GameEngine/Source/GameNetwork/LANGameInfo.cpp rename to Core/GameEngine/Source/GameNetwork/LANGameInfo.cpp diff --git a/GeneralsMD/Code/GameEngine/Source/GameNetwork/NAT.cpp b/Core/GameEngine/Source/GameNetwork/NAT.cpp similarity index 100% rename from GeneralsMD/Code/GameEngine/Source/GameNetwork/NAT.cpp rename to Core/GameEngine/Source/GameNetwork/NAT.cpp diff --git a/GeneralsMD/Code/GameEngine/Source/GameNetwork/NetCommandList.cpp b/Core/GameEngine/Source/GameNetwork/NetCommandList.cpp similarity index 100% rename from GeneralsMD/Code/GameEngine/Source/GameNetwork/NetCommandList.cpp rename to Core/GameEngine/Source/GameNetwork/NetCommandList.cpp diff --git a/GeneralsMD/Code/GameEngine/Source/GameNetwork/NetCommandMsg.cpp b/Core/GameEngine/Source/GameNetwork/NetCommandMsg.cpp similarity index 100% rename from GeneralsMD/Code/GameEngine/Source/GameNetwork/NetCommandMsg.cpp rename to Core/GameEngine/Source/GameNetwork/NetCommandMsg.cpp diff --git a/GeneralsMD/Code/GameEngine/Source/GameNetwork/NetCommandRef.cpp b/Core/GameEngine/Source/GameNetwork/NetCommandRef.cpp similarity index 100% rename from GeneralsMD/Code/GameEngine/Source/GameNetwork/NetCommandRef.cpp rename to Core/GameEngine/Source/GameNetwork/NetCommandRef.cpp diff --git a/GeneralsMD/Code/GameEngine/Source/GameNetwork/NetCommandWrapperList.cpp b/Core/GameEngine/Source/GameNetwork/NetCommandWrapperList.cpp similarity index 100% rename from GeneralsMD/Code/GameEngine/Source/GameNetwork/NetCommandWrapperList.cpp rename to Core/GameEngine/Source/GameNetwork/NetCommandWrapperList.cpp diff --git a/GeneralsMD/Code/GameEngine/Source/GameNetwork/NetMessageStream.cpp b/Core/GameEngine/Source/GameNetwork/NetMessageStream.cpp similarity index 100% rename from GeneralsMD/Code/GameEngine/Source/GameNetwork/NetMessageStream.cpp rename to Core/GameEngine/Source/GameNetwork/NetMessageStream.cpp diff --git a/GeneralsMD/Code/GameEngine/Source/GameNetwork/NetPacket.cpp b/Core/GameEngine/Source/GameNetwork/NetPacket.cpp similarity index 100% rename from GeneralsMD/Code/GameEngine/Source/GameNetwork/NetPacket.cpp rename to Core/GameEngine/Source/GameNetwork/NetPacket.cpp diff --git a/GeneralsMD/Code/GameEngine/Source/GameNetwork/Network.cpp b/Core/GameEngine/Source/GameNetwork/Network.cpp similarity index 100% rename from GeneralsMD/Code/GameEngine/Source/GameNetwork/Network.cpp rename to Core/GameEngine/Source/GameNetwork/Network.cpp diff --git a/GeneralsMD/Code/GameEngine/Source/GameNetwork/NetworkUtil.cpp b/Core/GameEngine/Source/GameNetwork/NetworkUtil.cpp similarity index 100% rename from GeneralsMD/Code/GameEngine/Source/GameNetwork/NetworkUtil.cpp rename to Core/GameEngine/Source/GameNetwork/NetworkUtil.cpp diff --git a/GeneralsMD/Code/GameEngine/Source/GameNetwork/Transport.cpp b/Core/GameEngine/Source/GameNetwork/Transport.cpp similarity index 100% rename from GeneralsMD/Code/GameEngine/Source/GameNetwork/Transport.cpp rename to Core/GameEngine/Source/GameNetwork/Transport.cpp diff --git a/GeneralsMD/Code/GameEngine/Source/GameNetwork/User.cpp b/Core/GameEngine/Source/GameNetwork/User.cpp similarity index 100% rename from GeneralsMD/Code/GameEngine/Source/GameNetwork/User.cpp rename to Core/GameEngine/Source/GameNetwork/User.cpp diff --git a/GeneralsMD/Code/GameEngine/Source/GameNetwork/WOLBrowser/WebBrowser.cpp b/Core/GameEngine/Source/GameNetwork/WOLBrowser/WebBrowser.cpp similarity index 100% rename from GeneralsMD/Code/GameEngine/Source/GameNetwork/WOLBrowser/WebBrowser.cpp rename to Core/GameEngine/Source/GameNetwork/WOLBrowser/WebBrowser.cpp diff --git a/GeneralsMD/Code/GameEngine/Source/GameNetwork/udp.cpp b/Core/GameEngine/Source/GameNetwork/udp.cpp similarity index 100% rename from GeneralsMD/Code/GameEngine/Source/GameNetwork/udp.cpp rename to Core/GameEngine/Source/GameNetwork/udp.cpp diff --git a/Generals/Code/GameEngine/CMakeLists.txt b/Generals/Code/GameEngine/CMakeLists.txt index 64236aa60d..cd24fd95c9 100644 --- a/Generals/Code/GameEngine/CMakeLists.txt +++ b/Generals/Code/GameEngine/CMakeLists.txt @@ -457,60 +457,60 @@ set(GAMEENGINE_SRC Include/GameLogic/WeaponSetFlags.h Include/GameLogic/WeaponSetType.h Include/GameLogic/WeaponStatus.h - Include/GameNetwork/Connection.h - Include/GameNetwork/ConnectionManager.h - Include/GameNetwork/DisconnectManager.h - Include/GameNetwork/DownloadManager.h - Include/GameNetwork/FileTransfer.h - Include/GameNetwork/FirewallHelper.h - Include/GameNetwork/FrameData.h - Include/GameNetwork/FrameDataManager.h - Include/GameNetwork/FrameMetrics.h - Include/GameNetwork/GameInfo.h - Include/GameNetwork/GameMessageParser.h +# Include/GameNetwork/Connection.h +# Include/GameNetwork/ConnectionManager.h +# Include/GameNetwork/DisconnectManager.h +# Include/GameNetwork/DownloadManager.h +# Include/GameNetwork/FileTransfer.h +# Include/GameNetwork/FirewallHelper.h +# Include/GameNetwork/FrameData.h +# Include/GameNetwork/FrameDataManager.h +# Include/GameNetwork/FrameMetrics.h +# Include/GameNetwork/GameInfo.h +# Include/GameNetwork/GameMessageParser.h Include/GameNetwork/GameSpy.h - Include/GameNetwork/GameSpy/BuddyDefs.h - Include/GameNetwork/GameSpy/BuddyThread.h - Include/GameNetwork/GameSpy/GameResultsThread.h - Include/GameNetwork/GameSpy/GSConfig.h - Include/GameNetwork/GameSpy/LadderDefs.h - Include/GameNetwork/GameSpy/LobbyUtils.h - Include/GameNetwork/GameSpy/MainMenuUtils.h - Include/GameNetwork/GameSpy/PeerDefs.h - Include/GameNetwork/GameSpy/PeerDefsImplementation.h - Include/GameNetwork/GameSpy/PeerThread.h - Include/GameNetwork/GameSpy/PersistentStorageDefs.h - Include/GameNetwork/GameSpy/PersistentStorageThread.h - Include/GameNetwork/GameSpy/PingThread.h - Include/GameNetwork/GameSpy/StagingRoomGameInfo.h - Include/GameNetwork/GameSpy/ThreadUtils.h - Include/GameNetwork/GameSpyChat.h - Include/GameNetwork/GameSpyGameInfo.h - Include/GameNetwork/GameSpyGP.h - Include/GameNetwork/GameSpyOverlay.h +# Include/GameNetwork/GameSpy/BuddyDefs.h +# Include/GameNetwork/GameSpy/BuddyThread.h +# Include/GameNetwork/GameSpy/GameResultsThread.h +# Include/GameNetwork/GameSpy/GSConfig.h +# Include/GameNetwork/GameSpy/LadderDefs.h +# Include/GameNetwork/GameSpy/LobbyUtils.h +# Include/GameNetwork/GameSpy/MainMenuUtils.h +# Include/GameNetwork/GameSpy/PeerDefs.h +# Include/GameNetwork/GameSpy/PeerDefsImplementation.h +# Include/GameNetwork/GameSpy/PeerThread.h +# Include/GameNetwork/GameSpy/PersistentStorageDefs.h +# Include/GameNetwork/GameSpy/PersistentStorageThread.h +# Include/GameNetwork/GameSpy/PingThread.h +# Include/GameNetwork/GameSpy/StagingRoomGameInfo.h +# Include/GameNetwork/GameSpy/ThreadUtils.h +# Include/GameNetwork/GameSpyChat.h +# Include/GameNetwork/GameSpyGameInfo.h +# Include/GameNetwork/GameSpyGP.h +# Include/GameNetwork/GameSpyOverlay.h Include/GameNetwork/GameSpyPersistentStorage.h - Include/GameNetwork/GameSpyThread.h +# Include/GameNetwork/GameSpyThread.h Include/GameNetwork/GUIUtil.h - Include/GameNetwork/IPEnumeration.h - Include/GameNetwork/LANAPI.h - Include/GameNetwork/LANAPICallbacks.h - Include/GameNetwork/LANGameInfo.h - Include/GameNetwork/LANPlayer.h - Include/GameNetwork/NAT.h - Include/GameNetwork/NetCommandList.h - Include/GameNetwork/NetCommandMsg.h - Include/GameNetwork/NetCommandRef.h - Include/GameNetwork/NetCommandWrapperList.h - Include/GameNetwork/NetPacket.h - Include/GameNetwork/NetworkDefs.h - Include/GameNetwork/NetworkInterface.h - Include/GameNetwork/networkutil.h - Include/GameNetwork/RankPointValue.h - Include/GameNetwork/Transport.h - Include/GameNetwork/udp.h - Include/GameNetwork/User.h - Include/GameNetwork/WOLBrowser/FEBDispatch.h - Include/GameNetwork/WOLBrowser/WebBrowser.h +# Include/GameNetwork/IPEnumeration.h +# Include/GameNetwork/LANAPI.h +# Include/GameNetwork/LANAPICallbacks.h +# Include/GameNetwork/LANGameInfo.h +# Include/GameNetwork/LANPlayer.h +# Include/GameNetwork/NAT.h +# Include/GameNetwork/NetCommandList.h +# Include/GameNetwork/NetCommandMsg.h +# Include/GameNetwork/NetCommandRef.h +# Include/GameNetwork/NetCommandWrapperList.h +# Include/GameNetwork/NetPacket.h +# Include/GameNetwork/NetworkDefs.h +# Include/GameNetwork/NetworkInterface.h +# Include/GameNetwork/networkutil.h +# Include/GameNetwork/RankPointValue.h +# Include/GameNetwork/Transport.h +# Include/GameNetwork/udp.h +# Include/GameNetwork/User.h +# Include/GameNetwork/WOLBrowser/FEBDispatch.h +# Include/GameNetwork/WOLBrowser/WebBrowser.h Include/Precompiled/PreRTS.h # Source/Common/Audio/AudioEventRTS.cpp # Source/Common/Audio/AudioRequest.cpp @@ -1005,55 +1005,55 @@ set(GAMEENGINE_SRC Source/GameLogic/System/GameLogic.cpp Source/GameLogic/System/GameLogicDispatch.cpp Source/GameLogic/System/RankInfo.cpp - Source/GameNetwork/Connection.cpp - Source/GameNetwork/ConnectionManager.cpp - Source/GameNetwork/DisconnectManager.cpp - Source/GameNetwork/DownloadManager.cpp - Source/GameNetwork/FileTransfer.cpp - Source/GameNetwork/FirewallHelper.cpp - Source/GameNetwork/FrameData.cpp - Source/GameNetwork/FrameDataManager.cpp - Source/GameNetwork/FrameMetrics.cpp - Source/GameNetwork/GameInfo.cpp - Source/GameNetwork/GameMessageParser.cpp +# Source/GameNetwork/Connection.cpp +# Source/GameNetwork/ConnectionManager.cpp +# Source/GameNetwork/DisconnectManager.cpp +# Source/GameNetwork/DownloadManager.cpp +# Source/GameNetwork/FileTransfer.cpp +# Source/GameNetwork/FirewallHelper.cpp +# Source/GameNetwork/FrameData.cpp +# Source/GameNetwork/FrameDataManager.cpp +# Source/GameNetwork/FrameMetrics.cpp +# Source/GameNetwork/GameInfo.cpp +# Source/GameNetwork/GameMessageParser.cpp #Source/GameNetwork/GameSpy.cpp - #Source/GameNetwork/GameSpyChat.cpp - #Source/GameNetwork/GameSpyGameInfo.cpp - #Source/GameNetwork/GameSpyGP.cpp +# #Source/GameNetwork/GameSpyChat.cpp +# #Source/GameNetwork/GameSpyGameInfo.cpp +# #Source/GameNetwork/GameSpyGP.cpp #Source/GameNetwork/GameSpyPersistentStorage.cpp - Source/GameNetwork/GameSpy/Chat.cpp - Source/GameNetwork/GameSpy/GSConfig.cpp - Source/GameNetwork/GameSpy/LadderDefs.cpp - Source/GameNetwork/GameSpy/LobbyUtils.cpp - Source/GameNetwork/GameSpy/MainMenuUtils.cpp - Source/GameNetwork/GameSpy/PeerDefs.cpp - Source/GameNetwork/GameSpy/StagingRoomGameInfo.cpp - Source/GameNetwork/GameSpy/Thread/BuddyThread.cpp - Source/GameNetwork/GameSpy/Thread/GameResultsThread.cpp - Source/GameNetwork/GameSpy/Thread/PeerThread.cpp - Source/GameNetwork/GameSpy/Thread/PersistentStorageThread.cpp - Source/GameNetwork/GameSpy/Thread/PingThread.cpp - Source/GameNetwork/GameSpy/Thread/ThreadUtils.cpp - Source/GameNetwork/GameSpyOverlay.cpp +# Source/GameNetwork/GameSpy/Chat.cpp +# Source/GameNetwork/GameSpy/GSConfig.cpp +# Source/GameNetwork/GameSpy/LadderDefs.cpp +# Source/GameNetwork/GameSpy/LobbyUtils.cpp +# Source/GameNetwork/GameSpy/MainMenuUtils.cpp +# Source/GameNetwork/GameSpy/PeerDefs.cpp +# Source/GameNetwork/GameSpy/StagingRoomGameInfo.cpp +# Source/GameNetwork/GameSpy/Thread/BuddyThread.cpp +# Source/GameNetwork/GameSpy/Thread/GameResultsThread.cpp +# Source/GameNetwork/GameSpy/Thread/PeerThread.cpp +# Source/GameNetwork/GameSpy/Thread/PersistentStorageThread.cpp +# Source/GameNetwork/GameSpy/Thread/PingThread.cpp +# Source/GameNetwork/GameSpy/Thread/ThreadUtils.cpp +# Source/GameNetwork/GameSpyOverlay.cpp Source/GameNetwork/GUIUtil.cpp - Source/GameNetwork/IPEnumeration.cpp - Source/GameNetwork/LANAPI.cpp - Source/GameNetwork/LANAPICallbacks.cpp - Source/GameNetwork/LANAPIhandlers.cpp - Source/GameNetwork/LANGameInfo.cpp - Source/GameNetwork/NAT.cpp - Source/GameNetwork/NetCommandList.cpp - Source/GameNetwork/NetCommandMsg.cpp - Source/GameNetwork/NetCommandRef.cpp - Source/GameNetwork/NetCommandWrapperList.cpp - Source/GameNetwork/NetMessageStream.cpp - Source/GameNetwork/NetPacket.cpp - Source/GameNetwork/Network.cpp - Source/GameNetwork/NetworkUtil.cpp - Source/GameNetwork/Transport.cpp - Source/GameNetwork/udp.cpp - Source/GameNetwork/User.cpp - Source/GameNetwork/WOLBrowser/WebBrowser.cpp +# Source/GameNetwork/IPEnumeration.cpp +# Source/GameNetwork/LANAPI.cpp +# Source/GameNetwork/LANAPICallbacks.cpp +# Source/GameNetwork/LANAPIhandlers.cpp +# Source/GameNetwork/LANGameInfo.cpp +# Source/GameNetwork/NAT.cpp +# Source/GameNetwork/NetCommandList.cpp +# Source/GameNetwork/NetCommandMsg.cpp +# Source/GameNetwork/NetCommandRef.cpp +# Source/GameNetwork/NetCommandWrapperList.cpp +# Source/GameNetwork/NetMessageStream.cpp +# Source/GameNetwork/NetPacket.cpp +# Source/GameNetwork/Network.cpp +# Source/GameNetwork/NetworkUtil.cpp +# Source/GameNetwork/Transport.cpp +# Source/GameNetwork/udp.cpp +# Source/GameNetwork/User.cpp +# Source/GameNetwork/WOLBrowser/WebBrowser.cpp Source/Precompiled/PreRTS.cpp ) diff --git a/Generals/Code/GameEngine/Include/GameNetwork/Connection.h b/Generals/Code/GameEngine/Include/GameNetwork/Connection.h deleted file mode 100644 index 1cd335e367..0000000000 --- a/Generals/Code/GameEngine/Include/GameNetwork/Connection.h +++ /dev/null @@ -1,101 +0,0 @@ -/* -** 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 . -*/ - -/** - * The Connection class handles queues for individual players, one connection per player. - * Connections are identified by their names (m_name). This should accomodate changing IPs - * in the face of modem disconnects, NAT irregularities, etc. - * Messages can be guaranteed or non-guaranteed, sequenced or not. - * - * - * So how this works is this: - * The connection contains the incoming and outgoing commands to and from the player this - * connection object represents. The incoming packets are separated into the different frames - * of execution. This is done for efficiency reasons since we will be keeping track of commands - * that are to be executed on many different frames, and they will need to be retrieved by the - * connection manager on a per-frame basis. We don't really care what frame the outgoing - * commands are executed on as they all need to be sent out right away to ensure that the commands - * get to their destination in time. - */ - -#pragma once - -#include "GameNetwork/NetCommandList.h" -#include "GameNetwork/User.h" -#include "GameNetwork/Transport.h" -#include "GameNetwork/NetPacket.h" - -#define CONNECTION_LATENCY_HISTORY_LENGTH 200 - -class Connection : public MemoryPoolObject -{ - MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE(Connection, "Connection") -public: - Connection(); - //~Connection(); - - void update(); - void init(); - void reset(); - - UnsignedInt doSend(); - void doRecv(); - - Bool allCommandsReady(UnsignedInt frame); - Bool isQueueEmpty(); - void attachTransport(Transport *transport); - void setUser(User *user); - User *getUser(); - void setFrameGrouping(time_t frameGrouping); - - void sendNetCommandMsg(NetCommandMsg *msg, UnsignedByte relay); - - // These two processAck calls do the same thing, just take different types of ACK commands. - NetCommandRef * processAck(NetAckBothCommandMsg *msg); - NetCommandRef * processAck(NetAckStage1CommandMsg *msg); - NetCommandRef * processAck(NetCommandMsg *msg); - NetCommandRef * processAck(UnsignedShort commandID, UnsignedByte originalPlayerID); - - void clearCommandsExceptFrom( Int playerIndex ); - - void setQuitting( void ); - Bool isQuitting( void ) { return m_isQuitting; } - -#if defined(RTS_DEBUG) - void debugPrintCommands(); -#endif - -protected: - void doRetryMetrics(); - - Bool m_isQuitting; - UnsignedInt m_quitTime; - - Transport *m_transport; - User *m_user; - - NetCommandList *m_netCommandList; - time_t m_retryTime; ///< The time between sending retry packets for this connection. Time is in milliseconds. - Real m_averageLatency; ///< The average time between sending a command and receiving an ACK. - Real m_latencies[CONNECTION_LATENCY_HISTORY_LENGTH]; ///< List of the last 100 latencies. - - time_t m_frameGrouping; ///< The minimum time between packet sends. - time_t m_lastTimeSent; ///< The time of the last packet send. - Int m_numRetries; ///< The number of retries for the last second. - time_t m_retryMetricsTime; ///< The start time of the current retry metrics thing. -}; diff --git a/Generals/Code/GameEngine/Include/GameNetwork/ConnectionManager.h b/Generals/Code/GameEngine/Include/GameNetwork/ConnectionManager.h deleted file mode 100644 index 8588a3350b..0000000000 --- a/Generals/Code/GameEngine/Include/GameNetwork/ConnectionManager.h +++ /dev/null @@ -1,216 +0,0 @@ -/* -** 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. // -// // -//////////////////////////////////////////////////////////////////////////////// - -/** - * The connection manager maintains a collection of Connections to each player. Messages are queued up - * from here, as well as removed through here. - */ - -#pragma once - -#include "GameNetwork/Connection.h" -#include "GameNetwork/NetCommandList.h" -#include "GameNetwork/Transport.h" -#include "GameNetwork/FrameDataManager.h" -#include "GameNetwork/FrameMetrics.h" -#include "GameNetwork/NetworkDefs.h" -#include "GameNetwork/DisconnectManager.h" - -class GameInfo; -class NetCommandWrapperList; - -typedef std::map FileCommandMap; -typedef std::map FileMaskMap; -typedef std::map FileProgressMap; - -class ConnectionManager -{ -public: - ConnectionManager(); - ~ConnectionManager(); - - virtual void init(); ///< Initialize this instance. - virtual void reset(); ///< Take this instance back to the initial state. - virtual void update(Bool isInGame); ///< Service the Connections being managed by this instance. - - // End SubsystemInterface functions - - void updateRunAhead(Int oldRunAhead, Int frameRate, Bool didSelfSlug, Int nextExecutionFrame); ///< Update the run ahead value. If we are the current packet router, issue the command. - - void attachTransport(Transport *transport); - - void parseUserList(const GameInfo *game); - void sendChat(UnicodeString text, Int playerMask, UnsignedInt executionFrame); - void sendDisconnectChat(UnicodeString text); - void sendLocalCommand(NetCommandMsg *msg, UnsignedByte relay = 0xff); ///< Send command to the players specified in the relay, goes through packet router. - void sendLocalCommandDirect(NetCommandMsg *msg, UnsignedByte relay); ///< Send command directly to the players specified, doesn't go through packet router. - void sendLocalGameMessage(GameMessage *msg, UnsignedInt frame); - void sendCommand(NetCommandMsg *msg); - Bool allCommandsReady(UnsignedInt frame, Bool justTesting = FALSE); - void handleAllCommandsReady(void); - NetCommandList *getFrameCommandList(UnsignedInt frame); -// void AddConnection(User *user, UnsignedInt slot); - void determineRouterFallbackPlan(); - void zeroFrames(UnsignedInt startingFrame, UnsignedInt numFrames); - void destroyGameMessages(); -// void createConnections(UnsignedInt numberOfPlayers, UnsignedInt localSlot); - void setLocalAddress(UnsignedInt ip, UnsignedInt port); - void initTransport(); - void processFrameTick(UnsignedInt frame); - void handleLocalPlayerLeaving(UnsignedInt frame); - - void sendFile(AsciiString path, UnsignedByte playerMask, UnsignedShort commandID); - UnsignedShort sendFileAnnounce(AsciiString path, UnsignedByte playerMask); - Int getFileTransferProgress(Int playerID, AsciiString path); - Bool areAllQueuesEmpty(void); - - UnsignedInt getLocalPlayerID(); - UnicodeString getPlayerName(Int playerNum); - Int getNumPlayers(); - - UnsignedInt getPacketRouterFallbackSlot(Int packetRouterNumber); ///< Returns the slot of the given packet router number in the fallback plan. - UnsignedInt getPacketRouterSlot(); ///< Returns the current packet router's slot. - PlayerLeaveCode disconnectPlayer(Int slot); ///< Disconnect this player immediately. This should only be called by the disconnect manager. - void disconnectLocalPlayer(); ///< Does whatever is necessary to get TheNetwork to realize that it should be leaving the game now. - void quitGame(); ///< Disconnect from the game RIGHT NOW!! Tell everyone else we are disconnecting. - - void voteForPlayerDisconnect(Int slot); ///< Register a vote for a player to be disconnected. - - void resendPendingCommands(); ///< Resend the pending commands to the packet router. - - void setFrameGrouping(time_t frameGrouping); ///< Set the number of frames that are grouped together into packets. - - PlayerLeaveCode processPlayerLeave(NetPlayerLeaveCommandMsg *msg); - Bool canILeave(); ///< Returns true if the local player is allowed to leave. - - // Bandwidth metrics - Real getIncomingBytesPerSecond( void ); - Real getIncomingPacketsPerSecond( void ); - Real getOutgoingBytesPerSecond( void ); - Real getOutgoingPacketsPerSecond( void ); - Real getUnknownBytesPerSecond( void ); - Real getUnknownPacketsPerSecond( void ); - UnsignedInt getPacketArrivalCushion( void ); - - UnsignedInt getMinimumCushion(); - - void flushConnections(); - - void processChat(NetChatCommandMsg *msg); // this actually needs to be public because it is frame-synchronized - - void updateLoadProgress( Int progress ); - void loadProgressComplete( void ); - void sendTimeOutGameStart( void ); - - Bool isPacketRouter( void ); - - Bool isPlayerConnected( Int playerID ); - - void notifyOthersOfCurrentFrame(Int frame); - void sendFrameDataToPlayer(UnsignedInt playerID, UnsignedInt startingFrame); - void sendSingleFrameToPlayer(UnsignedInt playerID, UnsignedInt frame); - void notifyOthersOfNewFrame(UnsignedInt frame); - - UnsignedInt getNextPacketRouterSlot(UnsignedInt playerID); ///< returns the packet router player that comes after the given player. - - Int getAverageFPS( void ); - Int getSlotAverageFPS(Int slot); - -#if defined(RTS_DEBUG) - void debugPrintConnectionCommands(); -#endif - - // For disconnect blame assignment - UnsignedInt getPingFrame(); - Int getPingsSent(); - Int getPingsRecieved(); - -private: - void doRelay(); - void doKeepAlive(); - void sendRemoteCommand(NetCommandRef *msg); - void ackCommand(NetCommandRef *ref, UnsignedInt localSlot); - - Bool processNetCommand(NetCommandRef *ref); - void processAckStage1(NetCommandMsg *msg); - void processAckStage2(NetCommandMsg *msg); - void processAck(NetCommandMsg *msg); - void processFrameInfo(NetFrameCommandMsg *msg); - void processRunAheadMetrics(NetRunAheadMetricsCommandMsg *msg); - void processDisconnectChat(NetDisconnectChatCommandMsg *msg); - void processProgress( NetProgressCommandMsg *msg ); - void processLoadComplete( NetCommandMsg *msg ); - void processTimeOutGameStart( NetCommandMsg *msg ); - void processWrapper(NetCommandRef *ref); - void processFrameResendRequest(NetFrameResendRequestCommandMsg *msg); - - void processFile(NetFileCommandMsg *ref); - void processFileAnnounce(NetFileAnnounceCommandMsg *ref); - void processFileProgress(NetFileProgressCommandMsg *ref); - - // void doPerFrameMetrics(UnsignedInt frame); - void getMinimumFps(Int &minFps, Int &minFpsPlayer); ///< Returns the smallest FPS in the m_fpsAverages list. - Real getMaximumLatency(); ///< Returns the highest average latency between players. - - void requestFrameDataResend(Int playerID, UnsignedInt frame); ///< request of this player that he send the specified frame's data. - - // The connections are set up like the slot list. The connection corresponding to the local - // player's position in the slot list will be NULL. Connections corresponding to slots that - // do not have a player will also be NULL. - Connection *m_connections[MAX_SLOTS]; - - Transport *m_transport; - UnsignedInt m_localSlot; - UnsignedInt m_packetRouterSlot; - UnsignedInt m_packetRouterFallback[MAX_SLOTS]; - UnsignedInt m_localAddr; - UnsignedInt m_localPort; - User* m_localUser; - - DisconnectManager *m_disconnectManager; ///< Controls the disconnect dialog. - - FrameDataManager *m_frameData[MAX_SLOTS]; - - NetCommandList *m_pendingCommands; - NetCommandList *m_relayedCommands; - - FrameMetrics m_frameMetrics; - - NetCommandWrapperList *m_netCommandWrapperList; - - // These variables are used to keep track of the other players' average fps and latency. - // yup. - Real m_latencyAverages[MAX_SLOTS]; - Int m_fpsAverages[MAX_SLOTS]; - Int m_minFpsPlayer; - Int m_minFps; - UnsignedInt m_smallestPacketArrivalCushion; - Bool m_didSelfSlug; - - // ----------------------------------------------------------------------------- - FileCommandMap s_fileCommandMap; - FileMaskMap s_fileRecipientMaskMap; - FileProgressMap s_fileProgressMap[MAX_SLOTS]; - // ----------------------------------------------------------------------------- -}; diff --git a/Generals/Code/GameEngine/Include/GameNetwork/DisconnectManager.h b/Generals/Code/GameEngine/Include/GameNetwork/DisconnectManager.h deleted file mode 100644 index 0448566d88..0000000000 --- a/Generals/Code/GameEngine/Include/GameNetwork/DisconnectManager.h +++ /dev/null @@ -1,125 +0,0 @@ -/* -** 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. // -// // -//////////////////////////////////////////////////////////////////////////////// - -#pragma once - -#include "GameNetwork/NetCommandRef.h" -#include "Lib/BaseType.h" -//#include "GameNetwork/ConnectionManager.h" - -enum DisconnectStateType CPP_11(: Int) { - DISCONNECTSTATETYPE_SCREENON, - DISCONNECTSTATETYPE_SCREENOFF -// DISCONNECTSTATETYPE_WAITINGFORPACKETROUTER -}; - -class ConnectionManager; - -struct DisconnectVoteStruct { - Bool vote; - UnsignedInt frame; -}; - -class DisconnectManager -{ -public: - DisconnectManager(); - virtual ~DisconnectManager(); - - void init(); - void update(ConnectionManager *conMgr); - - void processDisconnectCommand(NetCommandRef *ref, ConnectionManager *conMgr); - void allCommandsReady(UnsignedInt frame, ConnectionManager *conMgr, Bool waitForPacketRouter = TRUE); - void nextFrame(UnsignedInt frame, ConnectionManager *conMgr); - Bool allowedToContinue(); ///< Allow the next frame to go through? - void playerHasAdvancedAFrame(Int slot, UnsignedInt frame); ///< this player has advanced to that frame. - - void voteForPlayerDisconnect(Int slot, ConnectionManager *conMgr); - - // For disconnect blame assignment - UnsignedInt getPingFrame(); - Int getPingsSent(); - Int getPingsRecieved(); - -protected: - void sendKeepAlive(ConnectionManager *conMgr); - void populateDisconnectScreen(ConnectionManager *conMgr); - Int translatedSlotPosition(Int slot, Int localSlot); - Int untranslatedSlotPosition(Int slot, Int localSlot); - void resetPlayerTimeouts(ConnectionManager *conMgr); - void resetPlayerTimeout(Int slot); - void resetPacketRouterTimeout(); - void updateDisconnectStatus(ConnectionManager *conMgr); - void disconnectPlayer(Int slot, ConnectionManager *conMgr); - void sendDisconnectCommand(Int slot, ConnectionManager *conMgr); - void sendVoteCommand(Int slot, ConnectionManager *conMgr); - void updateWaitForPacketRouter(ConnectionManager *conMgr); - void recalculatePacketRouterIndex(ConnectionManager *conMgr); - Bool allOnSameFrame(ConnectionManager *conMgr); ///< returns true if all players are stuck on the same frame. - Bool isLocalPlayerNextPacketRouter(ConnectionManager *conMgr); ///< returns true if the local player is next in line to be the packet router with all the players that have timed out being taken out of the picture. - Bool hasPlayerTimedOut(Int slot); ///< returns true if this player has timed out. - void sendPlayerDestruct(Int slot, ConnectionManager *conMgr); ///< send a destruct player network message. - Bool isPlayerVotedOut(Int slot, ConnectionManager *conMgr); ///< returns true if this player has been voted out. - Bool isPlayerInGame(Int slot, ConnectionManager *conMgr); ///< returns true if the player has neither timed out or been voted out. - UnsignedInt getMaxDisconnectFrame(); ///< returns the highest frame that people have got to. - Int countVotesForPlayer(Int slot); ///< return the number of disconnect votes a player has. - void resetPlayersVotes(Int playerID, UnsignedInt frame, ConnectionManager *conMgr); ///< reset the votes for this player. - - void turnOnScreen(ConnectionManager *conMgr); ///< This gets called when the disconnect screen is first turned on. - - void processDisconnectKeepAlive(NetCommandMsg *msg, ConnectionManager *conMgr); - void processDisconnectPlayer(NetCommandMsg *msg, ConnectionManager *conMgr); - void processPacketRouterQuery(NetCommandMsg *msg, ConnectionManager *conMgr); - void processPacketRouterAck(NetCommandMsg *msg, ConnectionManager *conMgr); - void processDisconnectVote(NetCommandMsg *msg, ConnectionManager *conMgr); - void processDisconnectFrame(NetCommandMsg *msg, ConnectionManager *conMgr); - void processDisconnectScreenOff(NetCommandMsg *msg, ConnectionManager *conMgr); - - void applyDisconnectVote(Int slot, UnsignedInt frame, Int castingSlot, ConnectionManager *conMgr); - - UnsignedInt m_lastFrame; - time_t m_lastFrameTime; - DisconnectStateType m_disconnectState; - - UnsignedInt m_packetRouterFallback[MAX_SLOTS]; - UnsignedInt m_currentPacketRouterIndex; - - time_t m_lastKeepAliveSendTime; - - time_t m_playerTimeouts[MAX_SLOTS - 1]; - time_t m_packetRouterTimeout; - - DisconnectVoteStruct m_playerVotes[MAX_SLOTS][MAX_SLOTS]; -// Bool m_myVotes[MAX_SLOTS - 1]; - - UnsignedInt m_disconnectFrames[MAX_SLOTS]; - Bool m_disconnectFramesReceived[MAX_SLOTS]; - Bool m_haveNotifiedOtherPlayersOfCurrentFrame; - - time_t m_timeOfDisconnectScreenOn; - Int m_pingsSent; - Int m_pingsRecieved; - UnsignedInt m_pingFrame; -}; diff --git a/Generals/Code/GameEngine/Include/GameNetwork/DownloadManager.h b/Generals/Code/GameEngine/Include/GameNetwork/DownloadManager.h deleted file mode 100644 index 25dc35b13b..0000000000 --- a/Generals/Code/GameEngine/Include/GameNetwork/DownloadManager.h +++ /dev/null @@ -1,93 +0,0 @@ -/* -** 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. // -// // -//////////////////////////////////////////////////////////////////////////////// - -// FILE: DownloadManager.h ////////////////////////////////////////////////////// -// Generals download class definitions -// Author: Matthew D. Campbell, July 2002 - -#pragma once - -#include "WWDownload/downloaddefs.h" -#include "WWDownload/Download.h" - -class CDownload; -class QueuedDownload -{ -public: - AsciiString server; - AsciiString userName; - AsciiString password; - AsciiString file; - AsciiString localFile; - AsciiString regKey; - Bool tryResume; -}; - -///////////////////////////////////////////////////////////////////////////// -// DownloadManager - -class DownloadManager : public IDownload -{ -public: - DownloadManager(); - virtual ~DownloadManager(); - -public: - void init( void ); - HRESULT update( void ); - void reset( void ); - - virtual HRESULT OnError( Int error ); - virtual HRESULT OnEnd(); - virtual HRESULT OnQueryResume(); - virtual HRESULT OnProgressUpdate( Int bytesread, Int totalsize, Int timetaken, Int timeleft ); - virtual HRESULT OnStatusUpdate( Int status ); - - virtual HRESULT downloadFile( AsciiString server, AsciiString username, AsciiString password, AsciiString file, AsciiString localfile, AsciiString regkey, Bool tryResume ); - AsciiString getLastLocalFile( void ); - - Bool isDone( void ) { return m_sawEnd || m_wasError; } - Bool isOk( void ) { return m_sawEnd; } - Bool wasError( void ) { return m_wasError; } - - UnicodeString getStatusString( void ) { return m_statusString; } - UnicodeString getErrorString( void ) { return m_errorString; } - - void queueFileForDownload( AsciiString server, AsciiString username, AsciiString password, AsciiString file, AsciiString localfile, AsciiString regkey, Bool tryResume ); - Bool isFileQueuedForDownload( void ) { return !m_queuedDownloads.empty(); } - HRESULT downloadNextQueuedFile( void ); - -private: - Bool m_winsockInit; - CDownload *m_download; - Bool m_wasError; - Bool m_sawEnd; - UnicodeString m_errorString; - UnicodeString m_statusString; - -protected: - std::list m_queuedDownloads; -}; - -extern DownloadManager *TheDownloadManager; diff --git a/Generals/Code/GameEngine/Include/GameNetwork/FileTransfer.h b/Generals/Code/GameEngine/Include/GameNetwork/FileTransfer.h deleted file mode 100644 index e1ca2d1e27..0000000000 --- a/Generals/Code/GameEngine/Include/GameNetwork/FileTransfer.h +++ /dev/null @@ -1,48 +0,0 @@ -/* -** 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. // -// // -//////////////////////////////////////////////////////////////////////////////// - -/////////////////////////////////////////////////////////////////////////////////////// -// FILE: FileTransfer.h -// Author: Matthew D. Campbell, December 2002 -// Description: File Transfer wrapper using TheNetwork -/////////////////////////////////////////////////////////////////////////////////////// - -#pragma once - -class GameInfo; - -// Convenience functions -AsciiString GetBasePathFromPath( AsciiString path ); -AsciiString GetFileFromPath( AsciiString path ); -AsciiString GetExtensionFromFile( AsciiString fname ); -AsciiString GetBaseFileFromFile( AsciiString fname ); -AsciiString GetPreviewFromMap( AsciiString path ); -AsciiString GetINIFromMap( AsciiString path ); -AsciiString GetStrFileFromMap( AsciiString path ); -AsciiString GetSoloINIFromMap( AsciiString path ); -AsciiString GetAssetUsageFromMap( AsciiString path ); -AsciiString GetReadmeFromMap( AsciiString path ); - -// The meat of file (map) transfers -Bool DoAnyMapTransfers(GameInfo *game); diff --git a/Generals/Code/GameEngine/Include/GameNetwork/FirewallHelper.h b/Generals/Code/GameEngine/Include/GameNetwork/FirewallHelper.h deleted file mode 100644 index 70a9cfcab2..0000000000 --- a/Generals/Code/GameEngine/Include/GameNetwork/FirewallHelper.h +++ /dev/null @@ -1,307 +0,0 @@ -/* -** 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. // -// // -//////////////////////////////////////////////////////////////////////////////// - - -/*********************************************************************************************** - *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S *** - *********************************************************************************************** - * * - * Project Name : Command & Conquer * - * * - * $Archive:: /RedAlert2/NAT.cpp $* - * * - * $Author:: Steve_t $* - * * - * $Modtime:: 3/15/01 12:00PM $* - * * - * $Revision:: 1 $* - * * - * * - *---------------------------------------------------------------------------------------------* - * * - * * - *---------------------------------------------------------------------------------------------* - * * - * Functions: * - * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - -#pragma once - -class UDP; - -#define NUM_TEST_PORTS 4 -#define MAX_SPARE_SOCKETS 8 - -/* -** -** Class to help in dealing with firewalls. -** -** -** -*/ - -struct SpareSocketStruct { - UDP *udp; - UnsignedShort port; -}; - -enum FirewallDetectionState CPP_11(: Int) { - DETECTIONSTATE_IDLE, - DETECTIONSTATE_BEGIN, - DETECTIONSTATE_TEST1, - DETECTIONSTATE_TEST2, - DETECTIONSTATE_TEST3, - DETECTIONSTATE_TEST3_WAITFORRESPONSES, - DETECTIONSTATE_TEST4_1, - DETECTIONSTATE_TEST4_2, - DETECTIONSTATE_TEST5, - DETECTIONSTATE_DONE -}; - -#pragma pack(push, 1) - -// size = 16 bytes -struct ManglerData { - unsigned int CRC; - unsigned short magic; - unsigned short PacketID; - unsigned short MyMangledPortNumber; - unsigned short OriginalPortNumber; - unsigned char MyMangledAddress[4]; - unsigned char NetCommandType; - unsigned char BlitzMe; - unsigned short Padding; -}; - -// size = TransportMessageHeader + ManglerData + 10 bytes = 26 bytes -struct ManglerMessage { - ManglerData data; - int length; - unsigned int ip; - unsigned short port; -}; - -#pragma pack(pop) - -static const Int MAX_NUM_MANGLERS = 4; -static const UnsignedShort MANGLER_PORT = 4321; - -class FirewallHelperClass { - - public: - - /* - ** Enumeration of firewall behaviors we can detect. - ** - ** It is assumed that all port mangling firewalls change the mangled source port in response to - ** an application source port change. - */ - typedef enum tFirewallBehaviorType { - - FIREWALL_MIN = 0, - - /* - ** Just used as an initialiser. - */ - FIREWALL_TYPE_UNKNOWN = 0, - - /* - ** This is a simple, non-port translating firewall, or there is no firewall at all. - */ - FIREWALL_TYPE_SIMPLE = 1, - - /* - ** This is a firewall/NAT with port mangling but it's pretty dumb - it uses the same mangled - ** source port regardless of the destination address. - */ - FIREWALL_TYPE_DUMB_MANGLING = 2, - - /* - ** This is a smarter firewall/NAT with port mangling that uses different mangled source ports - ** for different destination IPs. - */ - FIREWALL_TYPE_SMART_MANGLING = 4, - - /* - ** This is a firewall that exhibits the bug as seen in the Netgear firewalls. A previously good - ** source port mapping will change in response to unsolicited traffic from a known IP. - */ - FIREWALL_TYPE_NETGEAR_BUG = 8, - - /* - ** This firewall has a simple absolute offset port allocation scheme. - */ - FIREWALL_TYPE_SIMPLE_PORT_ALLOCATION = 16, - - /* - ** This firewall has a relative offset port allocation scheme. For these firewalls, we have to - ** subtract the actual source port from the mangled source port to discover the allocation scheme. - ** The mangled port number is based in part on the original source port number. - */ - FIREWALL_TYPE_RELATIVE_PORT_ALLOCATION = 32, - - /* - ** This firewall mangles source ports differently depending on the destination port. - */ - FIREWALL_TYPE_DESTINATION_PORT_DELTA = 64, - - FIREWALL_MAX = 128 - - } FirewallBehaviorType; - - - - FirewallHelperClass(void); - virtual ~FirewallHelperClass(void); - Bool detectFirewall(void); - UnsignedShort getRawFirewallBehavior(void) {return((UnsignedShort)m_behavior);} - Short getSourcePortAllocationDelta(void); - Int getFirewallHardness(FirewallBehaviorType behavior); - Int getFirewallRetries(FirewallBehaviorType behavior); - void setSourcePortPoolStart(Int port) {m_sourcePortPool = port;}; - Int getSourcePortPool(void) {return(m_sourcePortPool);}; - void readFirewallBehavior(void); - void reset(void); - Bool behaviorDetectionUpdate(void); - - FirewallBehaviorType getFirewallBehavior(void); - void writeFirewallBehavior(void); - - void flagNeedToRefresh(Bool flag); - - static void getManglerName(Int manglerIndex, Char *nameBuf); - Bool sendToManglerFromPort(UnsignedInt address, UnsignedShort port, UnsignedShort packetID, Bool blitzme = FALSE); - UnsignedShort getManglerResponse(UnsignedShort packetID, Int time = 0); - Bool openSpareSocket(UnsignedShort port); - void closeSpareSocket(UnsignedShort port); - void closeAllSpareSockets(); - UnsignedShort getNextTemporarySourcePort(Int skip); - - Bool detectionBeginUpdate(void); - Bool detectionTest1Update(void); - Bool detectionTest2Update(void); - Bool detectionTest3Update(void); - Bool detectionTest3WaitForResponsesUpdate(void); - Bool detectionTest4Stage1Update(void); - Bool detectionTest4Stage2Update(void); - Bool detectionTest5Update(void); - - - /* - ** Behavior query functions. - */ - inline Bool isNAT(void) { - if (m_behavior == FIREWALL_TYPE_UNKNOWN || (m_behavior & FIREWALL_TYPE_SIMPLE) != 0) { - return(FALSE); - } - return(TRUE); - }; - - inline Bool isNAT(FirewallBehaviorType behavior) { - if (behavior == FIREWALL_TYPE_UNKNOWN || (behavior & FIREWALL_TYPE_SIMPLE) != 0) { - return(FALSE); - } - return(TRUE); - }; - - inline Bool isNetgear(FirewallBehaviorType behavior) { - if ((behavior & FIREWALL_TYPE_NETGEAR_BUG) != 0) { - return(TRUE); - } - return(FALSE); - }; - - inline Bool isNetgear(void) { - if ((m_behavior & FIREWALL_TYPE_NETGEAR_BUG) != 0) { - return(TRUE); - } - return(FALSE); - }; - - - - private: - - Int getNATPortAllocationScheme(Int numPorts, UnsignedShort *originalPorts, UnsignedShort *mangledPorts, Bool &relativeDelta, Bool &looksGood); - void detectFirewallBehavior(/*Bool &canRecord*/); - Bool getReferencePort(void); - - SpareSocketStruct * findSpareSocketByPort(UnsignedShort port); - ManglerMessage * findEmptyMessage(); - - void byteAdjust(ManglerData *data); - - /* - ** How does our firewall behave? - */ - FirewallBehaviorType m_behavior; - - /* - ** How did the firewall behave the last time we ran the game. - */ - FirewallBehaviorType m_lastBehavior; - - /* - ** What is the delta in our firewalls NAT port allocation scheme. - */ - Int m_sourcePortAllocationDelta; - - /* - ** What was the delta the last time we ran? - */ - Int m_lastSourcePortAllocationDelta; - - /* - ** Source ports used only to discover port allocation patterns. - ** Needs to be static so that previous communications with the manglers - ** don't affect the current one. - */ - static Int m_sourcePortPool; - - /* - ** Spare sockets used for detecting mangling and such. - */ - SpareSocketStruct m_spareSockets[MAX_SPARE_SOCKETS]; - - UnsignedInt m_manglers[MAX_NUM_MANGLERS]; - Int m_numManglers; - - UnsignedShort m_sparePorts[MAX_SPARE_SOCKETS]; - UnsignedShort m_mangledPorts[MAX_SPARE_SOCKETS]; - UnsignedShort m_packetID; - - ManglerMessage m_messages[MAX_SPARE_SOCKETS]; - - FirewallDetectionState m_currentState; - time_t m_timeoutStart; - time_t m_timeoutLength; - - Int m_numResponses; - Int m_currentTry; -}; - - - -extern FirewallHelperClass *TheFirewallHelper; -FirewallHelperClass * createFirewallHelper(); diff --git a/Generals/Code/GameEngine/Include/GameNetwork/FrameData.h b/Generals/Code/GameEngine/Include/GameNetwork/FrameData.h deleted file mode 100644 index 51e0428e91..0000000000 --- a/Generals/Code/GameEngine/Include/GameNetwork/FrameData.h +++ /dev/null @@ -1,63 +0,0 @@ -/* -** 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. // -// // -//////////////////////////////////////////////////////////////////////////////// - -#pragma once - -#include "Lib/BaseType.h" -#include "GameNetwork/NetCommandList.h" - -enum FrameDataReturnType CPP_11(: Int) { - FRAMEDATA_NOTREADY, - FRAMEDATA_RESEND, - FRAMEDATA_READY -}; - -class FrameData { -public: - FrameData(); - ~FrameData(); - - void init(); - void reset(); - void update(); - - UnsignedInt getFrame(); - void setFrame(UnsignedInt frame); - FrameDataReturnType allCommandsReady(Bool debugSpewage); - NetCommandList * getCommandList(); - void setFrameCommandCount(UnsignedInt totalCommandCount); - UnsignedInt getFrameCommandCount(); - void addCommand(NetCommandMsg *msg); - UnsignedInt getCommandCount(); - void zeroFrame(); - void destroyGameMessages(); - -protected: - UnsignedInt m_frame; - UnsignedInt m_frameCommandCount; - UnsignedInt m_commandCount; - NetCommandList *m_commandList; - UnsignedInt m_lastFailedCC; - UnsignedInt m_lastFailedFrameCC; -}; diff --git a/Generals/Code/GameEngine/Include/GameNetwork/FrameDataManager.h b/Generals/Code/GameEngine/Include/GameNetwork/FrameDataManager.h deleted file mode 100644 index 2069b49673..0000000000 --- a/Generals/Code/GameEngine/Include/GameNetwork/FrameDataManager.h +++ /dev/null @@ -1,61 +0,0 @@ -/* -** 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. // -// // -//////////////////////////////////////////////////////////////////////////////// - -#pragma once - -#include "GameNetwork/NetworkDefs.h" -#include "GameNetwork/FrameData.h" - -class FrameDataManager : public MemoryPoolObject -{ - MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE(FrameDataManager, "FrameDataManager") -public: - FrameDataManager(Bool isLocal); - //virtual ~FrameDataManager(); - - void init(); - void reset(); - void update(); - - void addNetCommandMsg(NetCommandMsg *msg); - void setIsLocal(Bool isLocal); - FrameDataReturnType allCommandsReady(UnsignedInt frame, Bool debugSpewage); - NetCommandList * getFrameCommandList(UnsignedInt frame); - UnsignedInt getCommandCount(UnsignedInt frame); - void setFrameCommandCount(UnsignedInt frame, UnsignedInt commandCount); - UnsignedInt getFrameCommandCount(UnsignedInt frame); - void zeroFrames(UnsignedInt startingFrame, UnsignedInt numFrames); - void destroyGameMessages(); - void resetFrame(UnsignedInt frame, Bool isAdvancing = TRUE); - void setQuitFrame(UnsignedInt frame); - UnsignedInt getQuitFrame(); - Bool getIsQuitting(); - -protected: - FrameData *m_frameData; - Bool m_isLocal; - - Bool m_isQuitting; - UnsignedInt m_quitFrame; -}; diff --git a/Generals/Code/GameEngine/Include/GameNetwork/FrameMetrics.h b/Generals/Code/GameEngine/Include/GameNetwork/FrameMetrics.h deleted file mode 100644 index 7661f3a16e..0000000000 --- a/Generals/Code/GameEngine/Include/GameNetwork/FrameMetrics.h +++ /dev/null @@ -1,69 +0,0 @@ -/* -** 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. // -// // -//////////////////////////////////////////////////////////////////////////////// - -/** FrameMetrics.h */ - -#pragma once - -#include "Lib/BaseType.h" -#include "GameNetwork/NetworkDefs.h" - -class FrameMetrics { -public: - FrameMetrics(); - virtual ~FrameMetrics(); - - void init(); - void reset(); - - void doPerFrameMetrics(UnsignedInt frame); - void processLatencyResponse(UnsignedInt frame); - void addCushion(Int cushion); - - Real getAverageLatency(); - Int getAverageFPS(); - Int getMinimumCushion(); - -protected: - // These are used for keeping track of parameters to the run ahead equation. - // frames per second history variables. - Real *m_fpsList; ///< A record of how many game logic frames per second there were for the last 60 seconds. - time_t m_lastFpsTimeThing; ///< The time when the last fps entry started being recorded. - Int m_fpsListIndex; ///< Index into the array of the current fps list entry being measured. - Real m_averageFps; ///< The current average logic fps, computed just like m_averageLatency below but with the fps numbers. - - // round trip time to packet router variables. - // The lists are indexed off the frame number of the frame info packet they are associated with. - // The index used should be the frame number mod the array length. - Real *m_latencyList; ///< A record of the round trip latencies of the frame info packets to the packet router. Values in seconds. - time_t *m_pendingLatencies; ///< The latencies of frame info packets that are "in the air." - Real m_averageLatency; ///< The current average latency, this is used to save calculation time. - ///< When a new latency value is received, the old one is subtracted out and the new - ///< one is added in. - - // packet arrival cushion variables. - // Keeps track of the cushion for the incoming commands. - UnsignedInt m_cushionIndex; ///< The next index to use for the cushion list. - Int m_minimumCushion; ///< The average cushion for the history. -}; diff --git a/Generals/Code/GameEngine/Include/GameNetwork/GameInfo.h b/Generals/Code/GameEngine/Include/GameNetwork/GameInfo.h deleted file mode 100644 index 21aab5bc52..0000000000 --- a/Generals/Code/GameEngine/Include/GameNetwork/GameInfo.h +++ /dev/null @@ -1,305 +0,0 @@ -/* -** 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. // -// // -//////////////////////////////////////////////////////////////////////////////// - -// FILE: GameInfo.h ////////////////////////////////////////////////////// -// Generals game setup information -// Author: Matthew D. Campbell, December 2001 - -#pragma once - -#include "Common/Snapshot.h" -#include "Common/Money.h" -#include "GameNetwork/NetworkDefs.h" -#include "GameNetwork/FirewallHelper.h" - -enum SlotState CPP_11(: Int) -{ - SLOT_OPEN, - SLOT_CLOSED, - SLOT_EASY_AI, - SLOT_MED_AI, - SLOT_BRUTAL_AI, - SLOT_PLAYER -}; - -enum -{ - PLAYERTEMPLATE_RANDOM = -1, - PLAYERTEMPLATE_OBSERVER = -2, - PLAYERTEMPLATE_MIN = PLAYERTEMPLATE_OBSERVER -}; - -/** - * GameSlot class - maintains information about the contents of a - * game slot. This persists throughout the game. - */ -class GameSlot -{ -public: - GameSlot(); - virtual void reset(); - - void setAccept( void ) { m_isAccepted = true; } ///< Accept the current options - void unAccept( void ); ///< Unaccept (options changed, etc) - Bool isAccepted( void ) const { return m_isAccepted; } ///< Non-human slots are always accepted - - void setMapAvailability( Bool hasMap ); ///< Set whether the slot has the map - Bool hasMap( void ) const { return m_hasMap; } ///< Non-human slots always have the map - - void setState( SlotState state, - UnicodeString name = UnicodeString::TheEmptyString, - UnsignedInt IP = 0); ///< Set the slot's state (human, AI, open, etc) - SlotState getState( void ) const { return m_state; } ///< Get the slot state - - void setColor( Int color ) { m_color = color; } - Int getColor( void ) const { return m_color; } - - void setStartPos( Int startPos ) { m_startPos = startPos; } - Int getStartPos( void ) const { return m_startPos; } - - void setPlayerTemplate( Int playerTemplate ) - { m_playerTemplate = playerTemplate; - if (playerTemplate <= PLAYERTEMPLATE_MIN) - m_startPos = -1; - } - Int getPlayerTemplate( void ) const { return m_playerTemplate; } - - void setTeamNumber( Int teamNumber ) { m_teamNumber = teamNumber; } - Int getTeamNumber( void ) const { return m_teamNumber; } - - inline void setName( UnicodeString name ) { m_name = name; } - inline UnicodeString getName( void ) const { return m_name; } - - inline void setIP( UnsignedInt IP ) { m_IP = IP; } - inline UnsignedInt getIP( void ) const { return m_IP; } - - inline void setPort( UnsignedShort port ) { m_port = port; } - inline UnsignedShort getPort( void ) const { return m_port; } - - inline void setNATBehavior( FirewallHelperClass::FirewallBehaviorType NATBehavior) { m_NATBehavior = NATBehavior; } - inline FirewallHelperClass::FirewallBehaviorType getNATBehavior() const { return m_NATBehavior; } - - void saveOffOriginalInfo( void ); - inline Int getOriginalPlayerTemplate( void ) const { return m_origPlayerTemplate; } - inline Int getOriginalColor( void ) const { return m_origColor; } - inline Int getOriginalStartPos( void ) const { return m_origStartPos; } - Int getApparentPlayerTemplate( void ) const; - Int getApparentColor( void ) const; - Int getApparentStartPos( void ) const; - UnicodeString getApparentPlayerTemplateDisplayName( void ) const; - - // Various tests - Bool isHuman( void ) const; ///< Is this slot occupied by a human player? - Bool isOccupied( void ) const; ///< Is this slot occupied (by a human or an AI)? - Bool isAI( void ) const; ///< Is this slot occupied by an AI? - Bool isPlayer( AsciiString userName ) const; ///< Does this slot contain the given user? - Bool isPlayer( UnicodeString userName ) const; ///< Does this slot contain the given user? - Bool isPlayer( UnsignedInt ip ) const; ///< Is this slot at this IP? - Bool isOpen( void ) const; - - void setLastFrameInGame( UnsignedInt frame ) { m_lastFrameInGame = frame; } - void markAsDisconnected( void ) { m_disconnected = TRUE; } - UnsignedInt lastFrameInGame( void ) const { return m_lastFrameInGame; } - Bool disconnected( void ) const { return isHuman() && m_disconnected; } - - void mute( Bool isMuted ) { m_isMuted = isMuted; } - Bool isMuted( void ) const { return m_isMuted; } -protected: - SlotState m_state; - Bool m_isAccepted; - Bool m_hasMap; - Bool m_isMuted; - Int m_color; ///< color, or -1 for random - Int m_startPos; ///< start position, or -1 for random - Int m_playerTemplate; ///< PlayerTemplate - Int m_teamNumber; ///< alliance, -1 for none - Int m_origColor; ///< color, or -1 for random - Int m_origStartPos; ///< start position, or -1 for random - Int m_origPlayerTemplate; ///< PlayerTemplate - UnicodeString m_name; ///< Only valid for human players - UnsignedInt m_IP; ///< Only valid for human players in LAN/WOL - UnsignedShort m_port; ///< Only valid for human players in LAN/WOL - FirewallHelperClass::FirewallBehaviorType m_NATBehavior; ///< The NAT behavior for this slot's player. - UnsignedInt m_lastFrameInGame; // only valid for human players - Bool m_disconnected; // only valid for human players -}; - -/** - * GameInfo class - maintains information about the game setup and - * the contents of its slot list hroughout the game. - */ -class GameInfo -{ -public: - GameInfo(); - - void init( void ); - virtual void reset( void ); - - void clearSlotList( void ); - - Int getNumPlayers( void ) const; ///< How many players (human and AI) are in the game? - Int getNumNonObserverPlayers( void ) const; ///< How many non-observer players (human and AI) are in the game? - Int getMaxPlayers( void ) const; ///< How many players (human and AI) can be in the game? - - void enterGame( void ); ///< Mark us as having entered the game - void leaveGame( void ); ///< Mark us as having left the game - virtual void startGame( Int gameID ); ///< Mark our game as started, and record the game ID - void endGame( void ); ///< Mark us as out of game - inline Int getGameID( void ) const; ///< Get the game ID of the current game or the last one if we're not in game - - inline void setInGame( void ); ///< set the m_inGame flag - inline Bool isInGame( void ) const; ///< Are we (in game or in game setup)? As opposed to chatting, matching, etc - inline Bool isGameInProgress( void ) const; ///< Is the game in progress? - inline void setGameInProgress( Bool inProgress ); ///< Set whether the game is in progress or not. - void setSlot( Int slotNum, GameSlot slotInfo ); ///< Set the slot state (human, open, AI, etc) - GameSlot* getSlot( Int slotNum ); ///< Get the slot - const GameSlot* getConstSlot( Int slotNum ) const; ///< Get the slot - virtual Bool amIHost( void ) const; ///< Convenience function - is the local player the game host? - virtual Int getLocalSlotNum( void ) const; ///< Get the local slot number, or -1 if we're not present - Int getSlotNum( AsciiString userName ) const; ///< Get the slot number corresponding to a specific user, or -1 if he's not present - - // Game options - void setMap( AsciiString mapName ); ///< Set the map to play on - void setMapCRC( UnsignedInt mapCRC ); ///< Set the map CRC - void setMapSize( UnsignedInt mapSize ); ///< Set the map size - void setMapContentsMask( Int mask ); ///< Set the map contents mask (1=map,2=preview,4=map.ini) - inline AsciiString getMap( void ) const; ///< Get the game map - inline UnsignedInt getMapCRC( void ) const; ///< Get the map CRC - inline UnsignedInt getMapSize( void ) const; ///< Get the map size - inline Int getMapContentsMask( void ) const; ///< Get the map contents mask - void setSeed( Int seed ); ///< Set the random seed for the game - inline Int getSeed( void ) const; ///< Get the game seed - inline Int getUseStats( void ) const; ///< Does this game count towards gamespy stats? - inline void setUseStats( Int useStats ); - - inline UnsignedShort getSuperweaponRestriction( void ) const; ///< Get any optional limits on superweapons - void setSuperweaponRestriction( UnsignedShort restriction ); ///< Set the optional limits on superweapons - inline const Money & getStartingCash(void) const; - void setStartingCash( const Money & startingCash ); - - void setSlotPointer( Int index, GameSlot *slot ); ///< Set the slot info pointer - - void setLocalIP( UnsignedInt ip ) { m_localIP =ip; } ///< Set the local IP - UnsignedInt getLocalIP( void ) const { return m_localIP; } ///< Get the local IP - - Bool isColorTaken(Int colorIdx, Int slotToIgnore = -1 ) const; - Bool isStartPositionTaken(Int positionIdx, Int slotToIgnore = -1 ) const; - - virtual void resetAccepted(void); ///< Reset the accepted flag on all players - virtual void resetStartSpots(void); ///< reset the start spots for the new map. - virtual void adjustSlotsForMap(void); ///< adjusts the slots to open and closed depending on the players in the game and the number of players the map can hold. - - virtual void closeOpenSlots(void); ///< close all slots that are currently unoccupied. - - // CRC checking hack - void setCRCInterval( Int val ) { m_crcInterval = (val<100)?val:100; } - inline Int getCRCInterval( void ) const { return m_crcInterval; } - - Bool haveWeSurrendered(void) { return m_surrendered; } - void markAsSurrendered(void) { m_surrendered = TRUE; } - - Bool isSkirmish(void); // TRUE if 1 human & 1+ AI are present && !isSandbox() - Bool isMultiPlayer(void); // TRUE if 2+ human are present - Bool isSandbox(void); // TRUE if everybody is on the same team - - Bool isPlayerPreorder(Int index); - void markPlayerAsPreorder(Int index); - - inline Bool oldFactionsOnly(void) const; - inline void setOldFactionsOnly( Bool oldFactionsOnly ); - -protected: - Int m_preorderMask; - Int m_crcInterval; - Bool m_inGame; - Bool m_inProgress; - Bool m_surrendered; - Int m_gameID; - GameSlot *m_slot[MAX_SLOTS]; - - UnsignedInt m_localIP; - - // Game options - AsciiString m_mapName; - UnsignedInt m_mapCRC; - UnsignedInt m_mapSize; - Int m_mapMask; - Int m_seed; - Int m_useStats; - Money m_startingCash; - UnsignedShort m_superweaponRestriction; - Bool m_oldFactionsOnly; // Only USA, China, GLA -- not USA Air Force General, GLA Toxic General, et al -}; - -extern GameInfo *TheGameInfo; - -// Inline functions -Int GameInfo::getGameID( void ) const { return m_gameID; } -AsciiString GameInfo::getMap( void ) const { return m_mapName; } -UnsignedInt GameInfo::getMapCRC( void ) const { return m_mapCRC; } -UnsignedInt GameInfo::getMapSize( void ) const { return m_mapSize; } -Int GameInfo::getMapContentsMask( void ) const { return m_mapMask; } -Int GameInfo::getSeed( void ) const { return m_seed; } -Bool GameInfo::isInGame( void ) const { return m_inGame; } -void GameInfo::setInGame( void ) { m_inGame = true; } -Bool GameInfo::isGameInProgress( void ) const { return m_inProgress; } -void GameInfo::setGameInProgress( Bool inProgress ) { m_inProgress = inProgress; } -Int GameInfo::getUseStats( void ) const { return m_useStats; } -void GameInfo::setUseStats( Int useStats ) { m_useStats = useStats; } -const Money&GameInfo::getStartingCash( void ) const { return m_startingCash; } -UnsignedShort GameInfo::getSuperweaponRestriction( void ) const { return m_superweaponRestriction; } -Bool GameInfo::oldFactionsOnly(void) const { return m_oldFactionsOnly; } -void GameInfo::setOldFactionsOnly( Bool oldFactionsOnly ) { m_oldFactionsOnly = oldFactionsOnly; } - -AsciiString GameInfoToAsciiString( const GameInfo *game ); -Bool ParseAsciiStringToGameInfo( GameInfo *game, AsciiString options ); - - -/** - * The SkirmishGameInfo class holds information about the skirmish game and - * the contents of its slot list. - */ - -class SkirmishGameInfo : public GameInfo, public Snapshot -{ -private: - GameSlot m_skirmishSlot[MAX_SLOTS]; - -protected: - // snapshot methods - virtual void crc( Xfer *xfer ); - virtual void xfer( Xfer *xfer ); - virtual void loadPostProcess( void ); - -public: - SkirmishGameInfo() - { - for (Int i = 0; i< MAX_SLOTS; ++i) - setSlotPointer(i, &m_skirmishSlot[i]); - } -}; - -extern SkirmishGameInfo *TheSkirmishGameInfo; -extern SkirmishGameInfo *TheChallengeGameInfo; diff --git a/Generals/Code/GameEngine/Include/GameNetwork/GameMessageParser.h b/Generals/Code/GameEngine/Include/GameNetwork/GameMessageParser.h deleted file mode 100644 index 25783f2740..0000000000 --- a/Generals/Code/GameEngine/Include/GameNetwork/GameMessageParser.h +++ /dev/null @@ -1,104 +0,0 @@ -/* -** 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. // -// // -//////////////////////////////////////////////////////////////////////////////// - -#pragma once - -#include "Common/MessageStream.h" -#include "Common/GameMemory.h" - -//---------------------------------------------------------------------------- -class GameMessageParserArgumentType : public MemoryPoolObject -{ - MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE(GameMessageParserArgumentType, "GameMessageParserArgumentType") -public: - GameMessageParserArgumentType(GameMessageArgumentDataType type, Int argCount); - //virtual ~GameMessageParserArgumentType(); - - GameMessageParserArgumentType *getNext(); - void setNext(GameMessageParserArgumentType *next); - Int getArgCount(); - GameMessageArgumentDataType getType(); - -protected: - GameMessageParserArgumentType* m_next; - GameMessageArgumentDataType m_type; - Int m_argCount; -}; - -//---------------------------------------------------------------------------- -inline GameMessageParserArgumentType * GameMessageParserArgumentType::getNext() -{ - return m_next; -} - -//---------------------------------------------------------------------------- -inline void GameMessageParserArgumentType::setNext(GameMessageParserArgumentType *next) -{ - m_next = next; -} - -//---------------------------------------------------------------------------- -inline GameMessageArgumentDataType GameMessageParserArgumentType::getType() -{ - return m_type; -} - -//---------------------------------------------------------------------------- -inline Int GameMessageParserArgumentType::getArgCount() -{ - return m_argCount; -} - -//---------------------------------------------------------------------------- -//---------------------------------------------------------------------------- -//---------------------------------------------------------------------------- -class GameMessageParser : public MemoryPoolObject -{ - MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE(GameMessageParser, "GameMessageParser") -public: - GameMessageParser(); - GameMessageParser(GameMessage *msg); - //virtual ~GameMessageParser(); - - GameMessageParserArgumentType *getFirstArgumentType(); - void addArgType(GameMessageArgumentDataType type, Int argCount); - Int getNumTypes(); - -protected: - GameMessageParserArgumentType *m_first, *m_last; - Int m_argTypeCount; -}; - -//---------------------------------------------------------------------------- -inline GameMessageParserArgumentType * GameMessageParser::getFirstArgumentType() -{ - return m_first; -} - -//---------------------------------------------------------------------------- -inline Int GameMessageParser::getNumTypes() -{ - return m_argTypeCount; -} - diff --git a/Generals/Code/GameEngine/Include/GameNetwork/GameSpy/BuddyDefs.h b/Generals/Code/GameEngine/Include/GameNetwork/GameSpy/BuddyDefs.h deleted file mode 100644 index d9cd0fe2ed..0000000000 --- a/Generals/Code/GameEngine/Include/GameNetwork/GameSpy/BuddyDefs.h +++ /dev/null @@ -1,32 +0,0 @@ -/* -** 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. // -// // -//////////////////////////////////////////////////////////////////////////////// - -// FILE: BuddyDefs.h ////////////////////////////////////////////////////// -// Generals GameSpy Buddy (GP) definitions -// Author: Matthew D. Campbell, July 2002 - -#pragma once - -void HandleBuddyResponses(void); -void PopulateOldBuddyMessages(void); diff --git a/Generals/Code/GameEngine/Include/GameNetwork/GameSpy/BuddyThread.h b/Generals/Code/GameEngine/Include/GameNetwork/GameSpy/BuddyThread.h deleted file mode 100644 index 1aea93930b..0000000000 --- a/Generals/Code/GameEngine/Include/GameNetwork/GameSpy/BuddyThread.h +++ /dev/null @@ -1,171 +0,0 @@ -/* -** 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. // -// // -//////////////////////////////////////////////////////////////////////////////// - -// FILE: BuddyThread.h ////////////////////////////////////////////////////// -// Generals GameSpy BuddyList thread class interface -// Author: Matthew D. Campbell, June 2002 - -#pragma once - -#include "gamespy/gp/gp.h" - -#define MAX_BUDDY_CHAT_LEN 128 - -// this class encapsulates a request for the buddy thread -class BuddyRequest -{ -public: - enum - { - BUDDYREQUEST_LOGIN, // attempt to login - BUDDYREQUEST_RELOGIN, // log in after being disconnected - BUDDYREQUEST_LOGOUT, // log out if connected - BUDDYREQUEST_MESSAGE, - BUDDYREQUEST_LOGINNEW, // attempt to create a new nick and login - //BUDDYREQUEST_DELETELOGIN, - BUDDYREQUEST_ADDBUDDY, // add someone to your buddy list - BUDDYREQUEST_DELBUDDY, // delete someone from your buddy list - BUDDYREQUEST_OKADD, // allow someone to add you to their buddy list - BUDDYREQUEST_DENYADD, // don't allow someone to add you to their buddy list - BUDDYREQUEST_SETSTATUS, // Set our status - BUDDYREQUEST_DELETEACCT, // Delete our account - } buddyRequestType; - - union - { - struct - { - GPProfile recipient; - WideChar text[MAX_BUDDY_CHAT_LEN]; - } message; - - struct - { - char nick[GP_NICK_LEN]; - char email[GP_EMAIL_LEN]; - char password[GP_PASSWORD_LEN]; - Bool hasFirewall; - } login; - - struct - { - GPProfile id; - WideChar text[MAX_BUDDY_CHAT_LEN]; - } addbuddy; - - struct - { - GPProfile id; - } profile; - - struct - { - GPEnum status; - char statusString[GP_STATUS_STRING_LEN]; - char locationString[GP_LOCATION_STRING_LEN]; - } status; - - } arg; -}; - -//------------------------------------------------------------------------- - -// this class encapsulates an action the buddy thread wants from the UI -class BuddyResponse -{ -public: - enum - { - BUDDYRESPONSE_LOGIN, - BUDDYRESPONSE_DISCONNECT, - BUDDYRESPONSE_MESSAGE, - BUDDYRESPONSE_REQUEST, - BUDDYRESPONSE_STATUS, - } buddyResponseType; - - GPProfile profile; - GPResult result; - - union - { - struct - { - UnsignedInt date; - char nick[GP_NICK_LEN]; - WideChar text[MAX_BUDDY_CHAT_LEN]; - } message; - - struct - { - char nick[GP_NICK_LEN]; - char email[GP_EMAIL_LEN]; - char countrycode[GP_COUNTRYCODE_LEN]; - WideChar text[GP_REASON_LEN]; - } request; - - struct - { - //GPResult result; - GPErrorCode errorCode; - char errorString[MAX_BUDDY_CHAT_LEN]; - GPEnum fatal; - } error; - - struct - { - char nick[GP_NICK_LEN]; - char email[GP_EMAIL_LEN]; - char countrycode[GP_COUNTRYCODE_LEN]; - char location[GP_LOCATION_STRING_LEN]; - GPEnum status; - char statusString[GP_STATUS_STRING_LEN]; - } status; - } arg; -}; - -//------------------------------------------------------------------------- - -// this is the actual message queue used to pass messages between threads -class GameSpyBuddyMessageQueueInterface -{ -public: - virtual ~GameSpyBuddyMessageQueueInterface() {} - virtual void startThread( void ) = 0; - virtual void endThread( void ) = 0; - virtual Bool isThreadRunning( void ) = 0; - virtual Bool isConnected( void ) = 0; - virtual Bool isConnecting( void ) = 0; - - virtual void addRequest( const BuddyRequest& req ) = 0; - virtual Bool getRequest( BuddyRequest& req ) = 0; - - virtual void addResponse( const BuddyResponse& resp ) = 0; - virtual Bool getResponse( BuddyResponse& resp ) = 0; - - virtual GPProfile getLocalProfileID( void ) = 0; - - static GameSpyBuddyMessageQueueInterface* createNewMessageQueue( void ); -}; - -extern GameSpyBuddyMessageQueueInterface *TheGameSpyBuddyMessageQueue; diff --git a/Generals/Code/GameEngine/Include/GameNetwork/GameSpy/GSConfig.h b/Generals/Code/GameEngine/Include/GameNetwork/GameSpy/GSConfig.h deleted file mode 100644 index b16659e775..0000000000 --- a/Generals/Code/GameEngine/Include/GameNetwork/GameSpy/GSConfig.h +++ /dev/null @@ -1,77 +0,0 @@ -/* -** 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. // -// // -//////////////////////////////////////////////////////////////////////////////// - -// FILE: GSConfig.h /////////////////////////////////////////////////////////// -// Author: Matthew D. Campbell, Sept 2002 -// Description: GameSpy online config -/////////////////////////////////////////////////////////////////////////////// - -#pragma once - -#include "Common/AsciiString.h" -#include "Common/STLTypedefs.h" - -class GameSpyConfigInterface -{ -public: - virtual ~GameSpyConfigInterface() {} - - // Pings - virtual std::list getPingServers(void) = 0; - virtual Int getNumPingRepetitions(void) = 0; - virtual Int getPingTimeoutInMs(void) = 0; - virtual Int getPingCutoffGood( void ) = 0; - virtual Int getPingCutoffBad( void ) = 0; - - // QM - virtual std::list getQMMaps(void) = 0; - virtual Int getQMBotID(void) = 0; - virtual Int getQMChannel(void) = 0; - virtual void setQMChannel(Int channel) = 0; - - // Player Info - virtual Int getPointsForRank(Int rank) = 0; - virtual Bool isPlayerVIP(Int id) = 0; - - // mangler Info - virtual Bool getManglerLocation(Int index, AsciiString& host, UnsignedShort& port) = 0; - - // Ladder / Any other external parsing - virtual AsciiString getLeftoverConfig(void) = 0; - - // NAT Timeouts - virtual Int getTimeBetweenRetries() = 0; - virtual Int getMaxManglerRetries() = 0; - virtual time_t getRetryInterval() = 0; - virtual time_t getKeepaliveInterval() = 0; - virtual time_t getPortTimeout() = 0; - virtual time_t getRoundTimeout() = 0; - - // Custom match - virtual Bool restrictGamesToLobby() = 0; - - static GameSpyConfigInterface* create(AsciiString config); -}; - -extern GameSpyConfigInterface *TheGameSpyConfig; diff --git a/Generals/Code/GameEngine/Include/GameNetwork/GameSpy/GameResultsThread.h b/Generals/Code/GameEngine/Include/GameNetwork/GameSpy/GameResultsThread.h deleted file mode 100644 index b9cc6af3b2..0000000000 --- a/Generals/Code/GameEngine/Include/GameNetwork/GameSpy/GameResultsThread.h +++ /dev/null @@ -1,75 +0,0 @@ -/* -** 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. // -// // -//////////////////////////////////////////////////////////////////////////////// - -// FILE: GameResultsThread.h ////////////////////////////////////////////////////// -// Generals game results thread class interface -// Author: Matthew D. Campbell, August 2002 - -#pragma once - -#include "Common/SubsystemInterface.h" - -// this class encapsulates a request for the thread -class GameResultsRequest -{ -public: - std::string hostname; - UnsignedShort port; - std::string results; -}; - -//------------------------------------------------------------------------- - -// this class encapsulates a response from the thread -class GameResultsResponse -{ -public: - std::string hostname; - UnsignedShort port; - Bool sentOk; -}; - -//------------------------------------------------------------------------- - -// this is the actual message queue used to pass messages between threads -class GameResultsInterface : public SubsystemInterface -{ -public: - virtual ~GameResultsInterface() {} - virtual void startThreads( void ) = 0; - virtual void endThreads( void ) = 0; - virtual Bool areThreadsRunning( void ) = 0; - - virtual void addRequest( const GameResultsRequest& req ) = 0; - virtual Bool getRequest( GameResultsRequest& resp ) = 0; - - virtual void addResponse( const GameResultsResponse& resp ) = 0; - virtual Bool getResponse( GameResultsResponse& resp ) = 0; - - static GameResultsInterface* createNewGameResultsInterface( void ); - - virtual Bool areGameResultsBeingSent( void ) = 0; -}; - -extern GameResultsInterface *TheGameResultsQueue; diff --git a/Generals/Code/GameEngine/Include/GameNetwork/GameSpy/LadderDefs.h b/Generals/Code/GameEngine/Include/GameNetwork/GameSpy/LadderDefs.h deleted file mode 100644 index c9944902c9..0000000000 --- a/Generals/Code/GameEngine/Include/GameNetwork/GameSpy/LadderDefs.h +++ /dev/null @@ -1,83 +0,0 @@ -/* -** 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. // -// // -//////////////////////////////////////////////////////////////////////////////// - -// FILE: LadderDefs.h ////////////////////////////////////////////////////// -// Generals ladder definitions -// Author: Matthew D. Campbell, August 2002 - -#pragma once - -#include "Common/UnicodeString.h" -#include "Common/AsciiString.h" -#include "Common/STLTypedefs.h" - -class GameWindow; - -class LadderInfo -{ -public: - LadderInfo(); - UnicodeString name; - UnicodeString description; - UnicodeString location; - Int playersPerTeam; - Int minWins; - Int maxWins; - Bool randomMaps; - Bool randomFactions; - Bool validQM; - Bool validCustom; - std::list validMaps; - std::list validFactions; - AsciiString cryptedPassword; - AsciiString address; - UnsignedShort port; - AsciiString homepageURL; - Bool submitReplay; // with game results - Int index; -}; - -typedef std::list LadderInfoList; - -class LadderList -{ -public: - LadderList(); - ~LadderList(); - - const LadderInfo* findLadder( const AsciiString& addr, UnsignedShort port ); - const LadderInfo* findLadderByIndex( Int index ); // doesn't look in local ladders - const LadderInfoList* getLocalLadders( void ); - const LadderInfoList* getSpecialLadders( void ); - const LadderInfoList* getStandardLadders( void ); - -private: - void loadLocalLadders( void ); - void checkLadder( AsciiString fname, Int index ); - LadderInfoList m_localLadders; - LadderInfoList m_specialLadders; - LadderInfoList m_standardLadders; -}; - -extern LadderList *TheLadderList; diff --git a/Generals/Code/GameEngine/Include/GameNetwork/GameSpy/LobbyUtils.h b/Generals/Code/GameEngine/Include/GameNetwork/GameSpy/LobbyUtils.h deleted file mode 100644 index 805b46dede..0000000000 --- a/Generals/Code/GameEngine/Include/GameNetwork/GameSpy/LobbyUtils.h +++ /dev/null @@ -1,55 +0,0 @@ -/* -** 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. // -// // -//////////////////////////////////////////////////////////////////////////////// - -// FILE: LobbyUtils.h ////////////////////////////////////////////////////// -// Generals lobby utils -// Author: Matthew D. Campbell, Sept 2002 - -#pragma once - -class GameWindow; - -GameWindow *GetGameListBox( void ); -GameWindow *GetGameInfoListBox( void ); -NameKeyType GetGameListBoxID( void ); -NameKeyType GetGameInfoListBoxID( void ); -void GrabWindowInfo( void ); -void ReleaseWindowInfo( void ); -void RefreshGameInfoListBox( GameWindow *mainWin, GameWindow *win ); -void RefreshGameListBoxes( void ); -void ToggleGameListType( void ); - -void playerTemplateComboBoxTooltip(GameWindow *wndComboBox, WinInstanceData *instData, UnsignedInt mouse); -void playerTemplateListBoxTooltip(GameWindow *wndListBox, WinInstanceData *instData, UnsignedInt mouse); - -enum GameSortType CPP_11(: Int) -{ - GAMESORT_ALPHA_ASCENDING = 0, - GAMESORT_ALPHA_DESCENDING, - GAMESORT_PING_ASCENDING, - GAMESORT_PING_DESCENDING, -}; - -Bool HandleSortButton( NameKeyType sortButton ); -void PopulateLobbyPlayerListbox(void); diff --git a/Generals/Code/GameEngine/Include/GameNetwork/GameSpy/MainMenuUtils.h b/Generals/Code/GameEngine/Include/GameNetwork/GameSpy/MainMenuUtils.h deleted file mode 100644 index 84a75eac45..0000000000 --- a/Generals/Code/GameEngine/Include/GameNetwork/GameSpy/MainMenuUtils.h +++ /dev/null @@ -1,65 +0,0 @@ -/* -** 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. // -// // -//////////////////////////////////////////////////////////////////////////////// - -// FILE: MainMenuUtils.h ////////////////////////////////////////////////////// -// Author: Matthew D. Campbell, Sept 2002 -// Description: GameSpy version check, patch download, etc utils -/////////////////////////////////////////////////////////////////////////////// - -#pragma once - -void HTTPThinkWrapper( void ); -void StopAsyncDNSCheck( void ); -void StartPatchCheck( void ); -void CancelPatchCheckCallback( void ); -void StartDownloadingPatches( void ); -void HandleCanceledDownload( Bool resetDropDown = TRUE ); - -#if RTS_GENERALS -enum OverallStatsPeriod CPP_11(: Int) -{ - STATS_TODAY = 0, - STATS_YESTERDAY, - STATS_ALLTIME, - STATS_LASTWEEK, - STATS_MAX -}; - -struct OverallStats -{ - OverallStats(); - Int wins[STATS_MAX]; - Int losses[STATS_MAX]; -}; -#endif - -void CheckOverallStats( void ); -#if RTS_GENERALS -void HandleOverallStats( const OverallStats& USA, const OverallStats& China, const OverallStats& GLA ); -#else -void HandleOverallStats( const char* szHTTPStats, unsigned len ); -#endif - -void CheckNumPlayersOnline( void ); -void HandleNumPlayersOnline( Int numPlayersOnline ); diff --git a/Generals/Code/GameEngine/Include/GameNetwork/GameSpy/PeerDefs.h b/Generals/Code/GameEngine/Include/GameNetwork/GameSpy/PeerDefs.h deleted file mode 100644 index 5ed37aa8f7..0000000000 --- a/Generals/Code/GameEngine/Include/GameNetwork/GameSpy/PeerDefs.h +++ /dev/null @@ -1,297 +0,0 @@ -/* -** 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. // -// // -//////////////////////////////////////////////////////////////////////////////// - -// FILE: PeerDefs.h ////////////////////////////////////////////////////// -// Generals GameSpy Peer (chat) definitions -// Author: Matthew D. Campbell, June 2002 - -#pragma once - -#include "gamespy/peer/peer.h" -#include "gamespy/gp/gp.h" - -#include "GameClient/Color.h" -#include "Common/STLTypedefs.h" -#include "GameNetwork/GameSpy/StagingRoomGameInfo.h" - -class GameWindow; -class PSPlayerStats; - -typedef std::set IgnoreList; -typedef std::map SavedIgnoreMap; - -enum RCItemType CPP_11(: Int) -{ - ITEM_BUDDY, - ITEM_REQUEST, - ITEM_NONBUDDY, - ITEM_NONE, -}; - -class GameSpyRCMenuData -{ -public: - AsciiString m_nick; - GPProfile m_id; - RCItemType m_itemType; -}; - -class BuddyInfo -{ -public: - GPProfile m_id; - AsciiString m_name; - AsciiString m_email; - AsciiString m_countryCode; - GPEnum m_status; - UnicodeString m_statusString; - UnicodeString m_locationString; -}; -typedef std::map BuddyInfoMap; - -class BuddyMessage -{ -public: - UnsignedInt m_timestamp; - GPProfile m_senderID; - AsciiString m_senderNick; - GPProfile m_recipientID; - AsciiString m_recipientNick; - UnicodeString m_message; -}; -typedef std::list BuddyMessageList; - -class GameSpyGroupRoom -{ -public: - GameSpyGroupRoom() { m_name = AsciiString::TheEmptyString; m_translatedName = UnicodeString::TheEmptyString; m_groupID = m_numWaiting = m_maxWaiting = m_numGames = m_numPlaying = 0; } - AsciiString m_name; - UnicodeString m_translatedName; - Int m_groupID; - Int m_numWaiting; - Int m_maxWaiting; - Int m_numGames; - Int m_numPlaying; -}; -typedef std::map GroupRoomMap; - -class Transport; -class NAT; - -typedef std::map StagingRoomMap; - -class PlayerInfo -{ -public: - PlayerInfo() { m_name = m_locale = AsciiString::TheEmptyString; m_wins = m_losses = m_rankPoints = m_side = m_preorder = m_profileID = m_flags = 0; } - AsciiString m_name; - AsciiString m_locale; - Int m_wins; - Int m_losses; - Int m_profileID; - Int m_flags; - Int m_rankPoints; - Int m_side; - Int m_preorder; - Bool isIgnored( void ); -}; -struct AsciiComparator -{ - bool operator()(AsciiString s1, AsciiString s2) const; -}; - - -typedef std::map PlayerInfoMap; - -enum GameSpyColors CPP_11(: Int) { - GSCOLOR_DEFAULT = 0, - GSCOLOR_CURRENTROOM, - GSCOLOR_ROOM, - GSCOLOR_GAME, - GSCOLOR_GAME_FULL, - GSCOLOR_GAME_CRCMISMATCH, - GSCOLOR_PLAYER_NORMAL, - GSCOLOR_PLAYER_OWNER, - GSCOLOR_PLAYER_BUDDY, - GSCOLOR_PLAYER_SELF, - GSCOLOR_PLAYER_IGNORED, - GSCOLOR_CHAT_NORMAL, - GSCOLOR_CHAT_EMOTE, - GSCOLOR_CHAT_OWNER, - GSCOLOR_CHAT_OWNER_EMOTE, - GSCOLOR_CHAT_PRIVATE, - GSCOLOR_CHAT_PRIVATE_EMOTE, - GSCOLOR_CHAT_PRIVATE_OWNER, - GSCOLOR_CHAT_PRIVATE_OWNER_EMOTE, - GSCOLOR_CHAT_BUDDY, - GSCOLOR_CHAT_SELF, - GSCOLOR_ACCEPT_TRUE, - GSCOLOR_ACCEPT_FALSE, - GSCOLOR_MAP_SELECTED, - GSCOLOR_MAP_UNSELECTED, - GSCOLOR_MOTD, - GSCOLOR_MOTD_HEADING, - GSCOLOR_MAX -}; - -extern Color GameSpyColor[GSCOLOR_MAX]; - -enum GameSpyBuddyStatus CPP_11(: Int) { - BUDDY_OFFLINE, - BUDDY_ONLINE, - BUDDY_LOBBY, - BUDDY_STAGING, - BUDDY_LOADING, - BUDDY_PLAYING, - BUDDY_MATCHING, -}; - -// --------------------------------------------------- -// this class holds info used in the main thread -class GameSpyInfoInterface -{ -public: - virtual ~GameSpyInfoInterface() {}; - virtual void reset( void ) {}; - virtual void clearGroupRoomList( void ) = 0; - virtual GroupRoomMap* getGroupRoomList( void ) = 0; - virtual void addGroupRoom( GameSpyGroupRoom room ) = 0; - virtual Bool gotGroupRoomList( void ) = 0; - virtual void joinGroupRoom( Int groupID ) = 0; - virtual void leaveGroupRoom( void ) = 0; - virtual void joinBestGroupRoom( void ) = 0; - virtual void setCurrentGroupRoom( Int groupID ) = 0; - virtual Int getCurrentGroupRoom( void ) = 0; - virtual void updatePlayerInfo( PlayerInfo pi, AsciiString oldNick = AsciiString::TheEmptyString ) = 0; - virtual void playerLeftGroupRoom( AsciiString nick ) = 0; - virtual PlayerInfoMap* getPlayerInfoMap( void ) = 0; - - virtual BuddyInfoMap* getBuddyMap( void ) = 0; - virtual BuddyInfoMap* getBuddyRequestMap( void ) = 0; - virtual BuddyMessageList* getBuddyMessages( void ) = 0; - virtual Bool isBuddy( Int id ) = 0; - - virtual void setLocalName( AsciiString name ) = 0; - virtual AsciiString getLocalName( void ) = 0; - virtual void setLocalProfileID( Int profileID ) = 0; - virtual Int getLocalProfileID( void ) = 0; - virtual AsciiString getLocalEmail( void ) = 0; - virtual void setLocalEmail( AsciiString email ) = 0; - virtual AsciiString getLocalPassword( void ) = 0; - virtual void setLocalPassword( AsciiString passwd ) = 0; - virtual void setLocalBaseName( AsciiString name ) = 0; - virtual AsciiString getLocalBaseName( void ) = 0; - - virtual void setCachedLocalPlayerStats( PSPlayerStats stats ) = 0; - virtual PSPlayerStats getCachedLocalPlayerStats( void ) = 0; - - virtual void clearStagingRoomList( void ) = 0; - virtual StagingRoomMap* getStagingRoomList( void ) = 0; - virtual GameSpyStagingRoom* findStagingRoomByID( Int id ) = 0; - virtual void addStagingRoom( GameSpyStagingRoom room ) = 0; - virtual void updateStagingRoom( GameSpyStagingRoom room ) = 0; - virtual void removeStagingRoom( GameSpyStagingRoom room ) = 0; - virtual Bool hasStagingRoomListChanged( void ) = 0; - virtual void leaveStagingRoom( void ) = 0; - virtual void markAsStagingRoomHost( void ) = 0; - virtual void markAsStagingRoomJoiner( Int game ) = 0; - virtual void sawFullGameList( void ) = 0; - - virtual Bool amIHost( void ) = 0; - virtual GameSpyStagingRoom* getCurrentStagingRoom( void ) = 0; - virtual void setGameOptions( void ) = 0; - virtual Int getCurrentStagingRoomID( void ) = 0; - - virtual void setDisallowAsianText( Bool val ) = 0; - virtual void setDisallowNonAsianText( Bool val ) = 0; - virtual Bool getDisallowAsianText( void ) = 0; - virtual Bool getDisallowNonAsianText(void ) = 0; - - // chat - virtual void registerTextWindow( GameWindow *win ) = 0; - virtual void unregisterTextWindow( GameWindow *win ) = 0; - virtual Int addText( UnicodeString message, Color c, GameWindow *win ) = 0; - virtual void addChat( PlayerInfo p, UnicodeString msg, Bool isPublic, Bool isAction, GameWindow *win ) = 0; - virtual void addChat( AsciiString nick, Int profileID, UnicodeString msg, Bool isPublic, Bool isAction, GameWindow *win ) = 0; - virtual Bool sendChat( UnicodeString message, Bool isAction, GameWindow *playerListbox ) = 0; - - virtual void setMOTD( const AsciiString& motd ) = 0; - virtual const AsciiString& getMOTD( void ) = 0; - - virtual void setConfig( const AsciiString& config ) = 0; - virtual const AsciiString& getConfig( void ) = 0; - - virtual void setPingString( const AsciiString& ping ) = 0; - virtual const AsciiString& getPingString( void ) = 0; - virtual Int getPingValue( const AsciiString& otherPing ) = 0; - - static GameSpyInfoInterface* createNewGameSpyInfoInterface( void ); - - virtual void addToSavedIgnoreList( Int profileID, AsciiString nick ) = 0; - virtual void removeFromSavedIgnoreList( Int profileID ) = 0; - virtual Bool isSavedIgnored( Int profileID ) = 0; - virtual SavedIgnoreMap returnSavedIgnoreList( void ) = 0; - virtual void loadSavedIgnoreList( void ) = 0; - - virtual IgnoreList returnIgnoreList( void ) = 0; - virtual void addToIgnoreList( AsciiString nick ) = 0; - virtual void removeFromIgnoreList( AsciiString nick ) = 0; - virtual Bool isIgnored( AsciiString nick ) = 0; - - virtual void setLocalIPs(UnsignedInt internalIP, UnsignedInt externalIP) = 0; - virtual UnsignedInt getInternalIP(void) = 0; - virtual UnsignedInt getExternalIP(void) = 0; - - virtual Bool isDisconnectedAfterGameStart(Int *reason) const = 0; - virtual void markAsDisconnectedAfterGameStart(Int reason) = 0; - - virtual Bool didPlayerPreorder( Int profileID ) const = 0; - virtual void markPlayerAsPreorder( Int profileID ) = 0; - - virtual void setMaxMessagesPerUpdate( Int num ) = 0; - virtual Int getMaxMessagesPerUpdate( void ) = 0; - - virtual Int getAdditionalDisconnects( void ) = 0; - virtual void clearAdditionalDisconnects( void ) = 0; - virtual void readAdditionalDisconnects( void ) = 0; - virtual void updateAdditionalGameSpyDisconnections(Int count) = 0; -}; - -extern GameSpyInfoInterface *TheGameSpyInfo; - -void WOLDisplayGameOptions( void ); -void WOLDisplaySlotList( void ); -Bool GetLocalChatConnectionAddress(AsciiString serverName, UnsignedShort serverPort, UnsignedInt& localIP); -void SetLobbyAttemptHostJoin(Bool start); -void SendStatsToOtherPlayers(const GameInfo *game); - -class PSPlayerStats; -void GetAdditionalDisconnectsFromUserFile(PSPlayerStats *stats); -extern Int GetAdditionalDisconnectsFromUserFile(Int playerID); - -//------------------------------------------------------------------------- -// These functions set up the globals and threads neccessary for our GameSpy impl. - -void SetUpGameSpy( const char *motdBuffer, const char *configBuffer ); -void TearDownGameSpy( void ); diff --git a/Generals/Code/GameEngine/Include/GameNetwork/GameSpy/PeerDefsImplementation.h b/Generals/Code/GameEngine/Include/GameNetwork/GameSpy/PeerDefsImplementation.h deleted file mode 100644 index 05a61af37d..0000000000 --- a/Generals/Code/GameEngine/Include/GameNetwork/GameSpy/PeerDefsImplementation.h +++ /dev/null @@ -1,177 +0,0 @@ -/* -** 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. // -// // -//////////////////////////////////////////////////////////////////////////////// - -// FILE: PeerDefsImplementation.h ////////////////////////////////////////////////////// -// Generals GameSpy Peer (chat) implementation definitions -// Author: Matthew D. Campbell, Sept 2002 - -#pragma once - -#include "GameNetwork/GameSpy/PeerDefs.h" -#include "GameNetwork/GameSpy/PersistentStorageThread.h" - - -class GameSpyInfo : public GameSpyInfoInterface -{ -public: - GameSpyInfo(); - virtual ~GameSpyInfo(); - virtual void reset( void ); - virtual void clearGroupRoomList( void ) { m_groupRooms.clear(); m_gotGroupRoomList = false; } - virtual GroupRoomMap* getGroupRoomList( void ) { return &m_groupRooms; } - virtual void addGroupRoom( GameSpyGroupRoom room ); - virtual Bool gotGroupRoomList( void ) { return m_gotGroupRoomList; } - virtual void joinGroupRoom( Int groupID ); - virtual void leaveGroupRoom( void ); - virtual void joinBestGroupRoom( void ); - virtual void setCurrentGroupRoom( Int groupID ) { m_currentGroupRoomID = groupID; m_playerInfoMap.clear(); } - virtual Int getCurrentGroupRoom( void ) { return m_currentGroupRoomID; } - virtual void updatePlayerInfo( PlayerInfo pi, AsciiString oldNick = AsciiString::TheEmptyString ); - virtual void playerLeftGroupRoom( AsciiString nick ); - virtual PlayerInfoMap* getPlayerInfoMap( void ) { return &m_playerInfoMap; } - - virtual void setLocalName( AsciiString name ) { m_localName = name; } - virtual AsciiString getLocalName( void ) { return m_localName; } - virtual void setLocalProfileID( Int profileID ) { m_localProfileID = profileID; } - virtual Int getLocalProfileID( void ) { return m_localProfileID; } - virtual AsciiString getLocalEmail( void ) { return m_localEmail; } - virtual void setLocalEmail( AsciiString email ) { m_localEmail = email; } - virtual AsciiString getLocalPassword( void ){ return m_localPasswd; } - virtual void setLocalPassword( AsciiString passwd ) { m_localPasswd = passwd; } - virtual void setLocalBaseName( AsciiString name ) { m_localBaseName = name; } - virtual AsciiString getLocalBaseName( void ){ return m_localBaseName; } - virtual void setCachedLocalPlayerStats( PSPlayerStats stats ) {m_cachedLocalPlayerStats = stats; } - virtual PSPlayerStats getCachedLocalPlayerStats( void ){ return m_cachedLocalPlayerStats; } - - virtual BuddyInfoMap* getBuddyMap( void ) { return &m_buddyMap; } - virtual BuddyInfoMap* getBuddyRequestMap( void ) { return &m_buddyRequestMap; } - virtual BuddyMessageList* getBuddyMessages( void ) { return &m_buddyMessages; } - virtual Bool isBuddy( Int id ); - - virtual void clearStagingRoomList( void ); - virtual StagingRoomMap* getStagingRoomList( void ) { return &m_stagingRooms; } - virtual GameSpyStagingRoom* findStagingRoomByID( Int id ); - virtual void addStagingRoom( GameSpyStagingRoom room ); - virtual void updateStagingRoom( GameSpyStagingRoom room ); - virtual void removeStagingRoom( GameSpyStagingRoom room ); - virtual Bool hasStagingRoomListChanged( void ); - virtual void leaveStagingRoom( void ); - virtual void markAsStagingRoomHost( void ); - virtual void markAsStagingRoomJoiner( Int game ); - virtual Int getCurrentStagingRoomID( void ) { return m_localStagingRoomID; } - - virtual void sawFullGameList( void ) { m_sawFullGameList = TRUE; } - - virtual void setDisallowAsianText( Bool val ); - virtual void setDisallowNonAsianText( Bool val ); - virtual Bool getDisallowAsianText( void ); - virtual Bool getDisallowNonAsianText(void ); - // chat - virtual void registerTextWindow( GameWindow *win ); - virtual void unregisterTextWindow( GameWindow *win ); - virtual Int addText( UnicodeString message, Color c, GameWindow *win ); - virtual void addChat( PlayerInfo p, UnicodeString msg, Bool isPublic, Bool isAction, GameWindow *win ); - virtual void addChat( AsciiString nick, Int profileID, UnicodeString msg, Bool isPublic, Bool isAction, GameWindow *win ); - virtual Bool sendChat( UnicodeString message, Bool isAction, GameWindow *playerListbox ); - - virtual void setMOTD( const AsciiString& motd ); - virtual const AsciiString& getMOTD( void ); - virtual void setConfig( const AsciiString& config ); - virtual const AsciiString& getConfig( void ); - - virtual void setPingString( const AsciiString& ping ) { m_pingString = ping; } - virtual const AsciiString& getPingString( void ) { return m_pingString; } - virtual Int getPingValue( const AsciiString& otherPing ); - - virtual Bool amIHost( void ); - virtual GameSpyStagingRoom* getCurrentStagingRoom( void ); - virtual void setGameOptions( void ); - - virtual void addToIgnoreList( AsciiString nick ); - virtual void removeFromIgnoreList( AsciiString nick ); - virtual Bool isIgnored( AsciiString nick ); - virtual IgnoreList returnIgnoreList( void ); - - virtual void loadSavedIgnoreList( void ); - virtual SavedIgnoreMap returnSavedIgnoreList( void ); - virtual void addToSavedIgnoreList( Int profileID, AsciiString nick); - virtual void removeFromSavedIgnoreList( Int profileID ); - virtual Bool isSavedIgnored( Int profileID ); - virtual void setLocalIPs(UnsignedInt internalIP, UnsignedInt externalIP); - virtual UnsignedInt getInternalIP(void) { return m_internalIP; } - virtual UnsignedInt getExternalIP(void) { return m_externalIP; } - - virtual Bool isDisconnectedAfterGameStart(Int *reason) const { if (reason) *reason = m_disconReason; return m_isDisconAfterGameStart; } - virtual void markAsDisconnectedAfterGameStart(Int reason) { m_isDisconAfterGameStart = TRUE; m_disconReason = reason; } - - virtual Bool didPlayerPreorder( Int profileID ) const; - virtual void markPlayerAsPreorder( Int profileID ); - - virtual void setMaxMessagesPerUpdate( Int num ); - virtual Int getMaxMessagesPerUpdate( void ); - - virtual Int getAdditionalDisconnects( void ); - virtual void clearAdditionalDisconnects( void ); - virtual void readAdditionalDisconnects( void ); - virtual void updateAdditionalGameSpyDisconnections(Int count); -private: - Bool m_sawFullGameList; - Bool m_isDisconAfterGameStart; - Int m_disconReason; - AsciiString m_rawMotd; - AsciiString m_rawConfig; - AsciiString m_pingString; - GroupRoomMap m_groupRooms; - StagingRoomMap m_stagingRooms; - Bool m_stagingRoomsDirty; - BuddyInfoMap m_buddyMap; - BuddyInfoMap m_buddyRequestMap; - PlayerInfoMap m_playerInfoMap; - BuddyMessageList m_buddyMessages; - Int m_currentGroupRoomID; - Bool m_gotGroupRoomList; - AsciiString m_localName; - Int m_localProfileID; - AsciiString m_localPasswd; - AsciiString m_localEmail; - AsciiString m_localBaseName; - PSPlayerStats m_cachedLocalPlayerStats; - Bool m_disallowAsainText; - Bool m_disallowNonAsianText; - UnsignedInt m_internalIP, m_externalIP; - Int m_maxMessagesPerUpdate; - - Int m_joinedStagingRoom; // if we join a staging room, this holds its ID (0 otherwise) - Bool m_isHosting; // if we host, this is true, and - GameSpyStagingRoom m_localStagingRoom; // this holds the GameInfo for it. - Int m_localStagingRoomID; - - IgnoreList m_ignoreList; - SavedIgnoreMap m_savedIgnoreMap; - - std::set m_textWindows; - - std::set m_preorderPlayers; - Int m_additionalDisconnects; -}; diff --git a/Generals/Code/GameEngine/Include/GameNetwork/GameSpy/PeerThread.h b/Generals/Code/GameEngine/Include/GameNetwork/GameSpy/PeerThread.h deleted file mode 100644 index d2df592081..0000000000 --- a/Generals/Code/GameEngine/Include/GameNetwork/GameSpy/PeerThread.h +++ /dev/null @@ -1,386 +0,0 @@ -/* -** 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. // -// // -//////////////////////////////////////////////////////////////////////////////// - -// FILE: PeerThread.h ////////////////////////////////////////////////////// -// Generals GameSpy Peer-to-peer chat thread class interface -// Author: Matthew D. Campbell, June 2002 - -#pragma once - -#include "gamespy/peer/peer.h" -#include "GameNetwork/NetworkDefs.h" - -enum SerialAuthResult CPP_11(: Int) -{ - SERIAL_NONEXISTENT, - SERIAL_AUTHFAILED, - SERIAL_BANNED, - SERIAL_OK -}; - -// this class encapsulates a request for the peer thread -class PeerRequest -{ -public: - enum - { - PEERREQUEST_LOGIN, // attempt to login - PEERREQUEST_LOGOUT, // log out if connected - PEERREQUEST_MESSAGEPLAYER, - PEERREQUEST_MESSAGEROOM, - PEERREQUEST_JOINGROUPROOM, - PEERREQUEST_LEAVEGROUPROOM, - PEERREQUEST_STARTGAMELIST, - PEERREQUEST_STOPGAMELIST, - PEERREQUEST_CREATESTAGINGROOM, - PEERREQUEST_SETGAMEOPTIONS, - PEERREQUEST_JOINSTAGINGROOM, - PEERREQUEST_LEAVESTAGINGROOM, - PEERREQUEST_UTMPLAYER, - PEERREQUEST_UTMROOM, - PEERREQUEST_STARTGAME, - PEERREQUEST_STARTQUICKMATCH, - PEERREQUEST_WIDENQUICKMATCHSEARCH, - PEERREQUEST_STOPQUICKMATCH, - PEERREQUEST_PUSHSTATS, - PEERREQUEST_GETEXTENDEDSTAGINGROOMINFO, - PEERREQUEST_MAX - } peerRequestType; - - std::string nick; // only used by login, but must be outside the union b/c of copy constructor - std::wstring text; // can't be in a union - std::string password; - std::string email; - std::string id; - - // gameopts - std::string options; // full string for UTMs - std::string ladderIP; - std::string hostPingStr; - std::string gameOptsMapName; - std::string gameOptsPlayerNames[MAX_SLOTS]; - - std::vector qmMaps; - - union - { - struct - { - Int profileID; - } login; - - struct - { - Int id; - } groupRoom; - - struct - { - Bool restrictGameList; - } gameList; - - struct - { - Bool isAction; - } message; - - struct - { - Int id; - } stagingRoom; - - struct - { - UnsignedInt exeCRC; - UnsignedInt iniCRC; - UnsignedInt gameVersion; - Bool allowObservers; - Bool useStats; - UnsignedShort ladPort; - UnsignedInt ladPassCRC; - Bool restrictGameList; - } stagingRoomCreation; - - struct - { - Int wins[MAX_SLOTS]; - Int losses[MAX_SLOTS]; - Int profileID[MAX_SLOTS]; - Int faction[MAX_SLOTS]; - Int color[MAX_SLOTS]; - Int numPlayers; - Int maxPlayers; - Int numObservers; - } gameOptions; - - struct - { - Bool isStagingRoom; - } UTM; - - struct - { - Int minPointPercentage, maxPointPercentage, points; - Int widenTime; - Int ladderID; - UnsignedInt ladderPassCRC; - Int maxPing; - Int maxDiscons, discons; - char pings[17]; // 8 servers (0-ff), 1 NULL - Int numPlayers; - Int botID; - Int roomID; - Int side; - Int color; - Int NAT; - UnsignedInt exeCRC; - UnsignedInt iniCRC; - } QM; - - struct - { - Int locale; - Int wins; - Int losses; - Int rankPoints; - Int side; - Bool preorder; - } statsToPush; - - }; -}; - -//------------------------------------------------------------------------- - -enum DisconnectReason CPP_11(: Int) -{ - DISCONNECT_NICKTAKEN = 1, - DISCONNECT_BADNICK, - DISCONNECT_LOSTCON, - DISCONNECT_COULDNOTCONNECT, - DISCONNECT_GP_LOGIN_TIMEOUT, - DISCONNECT_GP_LOGIN_BAD_NICK, - DISCONNECT_GP_LOGIN_BAD_EMAIL, - DISCONNECT_GP_LOGIN_BAD_PASSWORD, - DISCONNECT_GP_LOGIN_BAD_PROFILE, - DISCONNECT_GP_LOGIN_PROFILE_DELETED, - DISCONNECT_GP_LOGIN_CONNECTION_FAILED, - DISCONNECT_GP_LOGIN_SERVER_AUTH_FAILED, - DISCONNECT_SERIAL_INVALID, - DISCONNECT_SERIAL_NOT_PRESENT, - DISCONNECT_SERIAL_BANNED, - DISCONNECT_GP_NEWUSER_BAD_NICK, - DISCONNECT_GP_NEWUSER_BAD_PASSWORD, - DISCONNECT_GP_NEWPROFILE_BAD_NICK, - DISCONNECT_GP_NEWPROFILE_BAD_OLD_NICK, -}; - -enum QMStatus CPP_11(: Int) -{ - QM_IDLE, - QM_JOININGQMCHANNEL, - QM_LOOKINGFORBOT, - QM_SENTINFO, - QM_WORKING, - QM_POOLSIZE, - QM_WIDENINGSEARCH, - QM_MATCHED, - QM_INCHANNEL, - QM_NEGOTIATINGFIREWALLS, - QM_STARTINGGAME, - QM_COULDNOTFINDBOT, - QM_COULDNOTFINDCHANNEL, - QM_COULDNOTNEGOTIATEFIREWALLS, - QM_STOPPED, -}; - -// this class encapsulates an action the peer thread wants from the UI -class PeerResponse -{ -public: - enum - { - PEERRESPONSE_LOGIN, - PEERRESPONSE_DISCONNECT, - PEERRESPONSE_MESSAGE, - PEERRESPONSE_GROUPROOM, - PEERRESPONSE_STAGINGROOM, - PEERRESPONSE_STAGINGROOMLISTCOMPLETE, - PEERRESPONSE_STAGINGROOMPLAYERINFO, - PEERRESPONSE_JOINGROUPROOM, - PEERRESPONSE_CREATESTAGINGROOM, - PEERRESPONSE_JOINSTAGINGROOM, - PEERRESPONSE_PLAYERJOIN, - PEERRESPONSE_PLAYERLEFT, - PEERRESPONSE_PLAYERCHANGEDNICK, - PEERRESPONSE_PLAYERINFO, - PEERRESPONSE_PLAYERCHANGEDFLAGS, - PEERRESPONSE_ROOMUTM, - PEERRESPONSE_PLAYERUTM, - PEERRESPONSE_QUICKMATCHSTATUS, - PEERRESPONSE_GAMESTART, - PEERRESPONSE_FAILEDTOHOST, - PEERRESPONSE_MAX - } peerResponseType; - - std::string groupRoomName; // can't be in union - - std::string nick; // can't be in a union - std::string oldNick; // can't be in a union - std::wstring text; // can't be in a union - std::string locale; // can't be in a union - - std::string stagingServerGameOptions; // full string from UTMs - - // game opts sent with PEERRESPONSE_STAGINGROOM - std::wstring stagingServerName; - std::string stagingServerPingString; - std::string stagingServerLadderIP; - std::string stagingRoomMapName; - - // game opts sent with PEERRESPONSE_STAGINGROOMPLAYERINFO - std::string stagingRoomPlayerNames[MAX_SLOTS]; - - std::string command; - std::string commandOptions; - - union - { - struct - { - DisconnectReason reason; - } discon; - - struct - { - Int id; - Int numWaiting; - Int maxWaiting; - Int numGames; - Int numPlaying; - } groupRoom; - - struct - { - Int id; - Bool ok; - } joinGroupRoom; - - struct - { - Int result; - } createStagingRoom; - - struct - { - Int id; - Bool ok; - Bool isHostPresent; - Int result; // for failures - } joinStagingRoom; - - struct - { - Bool isPrivate; - Bool isAction; - Int profileID; - } message; - - struct - { - Int profileID; - Int wins; - Int losses; - RoomType roomType; - Int flags; - UnsignedInt IP; - Int rankPoints; - Int side; - Int preorder; - UnsignedInt internalIP; // for us, on connection - UnsignedInt externalIP; // for us, on connection - } player; - - struct - { - Int id; - Int action; - Bool isStaging; - Bool requiresPassword; - Bool allowObservers; - Bool useStats; - UnsignedInt version; - UnsignedInt exeCRC; - UnsignedInt iniCRC; - UnsignedShort ladderPort; - Int wins[MAX_SLOTS]; - Int losses[MAX_SLOTS]; - Int profileID[MAX_SLOTS]; - Int faction[MAX_SLOTS]; - Int color[MAX_SLOTS]; - Int numPlayers; - Int numObservers; - Int maxPlayers; - Int percentComplete; - } stagingRoom; - - struct - { - QMStatus status; - Int poolSize; - Int mapIdx; // when matched - Int seed; // when matched - UnsignedInt IP[MAX_SLOTS]; // when matched - Int side[MAX_SLOTS]; // when matched - Int color[MAX_SLOTS]; // when matched - Int nat[MAX_SLOTS]; - } qmStatus; - }; -}; - -//------------------------------------------------------------------------- - -// this is the actual message queue used to pass messages between threads -class GameSpyPeerMessageQueueInterface -{ -public: - virtual ~GameSpyPeerMessageQueueInterface() {} - virtual void startThread( void ) = 0; - virtual void endThread( void ) = 0; - virtual Bool isThreadRunning( void ) = 0; - virtual Bool isConnected( void ) = 0; - virtual Bool isConnecting( void ) = 0; - - virtual void addRequest( const PeerRequest& req ) = 0; - virtual Bool getRequest( PeerRequest& req ) = 0; - - virtual void addResponse( const PeerResponse& resp ) = 0; - virtual Bool getResponse( PeerResponse& resp ) = 0; - - virtual SerialAuthResult getSerialAuthResult( void ) = 0; - - static GameSpyPeerMessageQueueInterface* createNewMessageQueue( void ); -}; - -extern GameSpyPeerMessageQueueInterface *TheGameSpyPeerMessageQueue; diff --git a/Generals/Code/GameEngine/Include/GameNetwork/GameSpy/PersistentStorageDefs.h b/Generals/Code/GameEngine/Include/GameNetwork/GameSpy/PersistentStorageDefs.h deleted file mode 100644 index 62d84b887a..0000000000 --- a/Generals/Code/GameEngine/Include/GameNetwork/GameSpy/PersistentStorageDefs.h +++ /dev/null @@ -1,42 +0,0 @@ -/* -** 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. // -// // -//////////////////////////////////////////////////////////////////////////////// - -// FILE: PersistentStorageDefs.h ////////////////////////////////////////////////////// -// Generals GameSpy Persistent Storage definitions -// Author: Matthew D. Campbell, July 2002 - -#pragma once - -enum LocaleType CPP_11(: Int) -{ - LOC_UNKNOWN = 0, - LOC_MIN = 1, - LOC_MAX = 37 -}; - -void HandlePersistentStorageResponses(void); -void UpdateLocalPlayerStats(void); - -void SetLookAtPlayer( Int id, AsciiString nick ); -void PopulatePlayerInfoWindows( AsciiString parentWindowName ); diff --git a/Generals/Code/GameEngine/Include/GameNetwork/GameSpy/PersistentStorageThread.h b/Generals/Code/GameEngine/Include/GameNetwork/GameSpy/PersistentStorageThread.h deleted file mode 100644 index 7832c036f8..0000000000 --- a/Generals/Code/GameEngine/Include/GameNetwork/GameSpy/PersistentStorageThread.h +++ /dev/null @@ -1,181 +0,0 @@ -/* -** 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. // -// // -//////////////////////////////////////////////////////////////////////////////// - -// FILE: PersistentStorageThread.h ////////////////////////////////////////////////////// -// Generals GameSpy Persistent Storage thread class interface -// Author: Matthew D. Campbell, July 2002 - -#pragma once - -#include "gamespy/gstats/gpersist.h" - -#define MAX_BUDDY_CHAT_LEN 128 - -typedef std::map PerGeneralMap; -// this structure holds all info on a player that is stored online -class PSPlayerStats -{ -public: - PSPlayerStats( void ); - PSPlayerStats( const PSPlayerStats& other ); - void reset(void); - - Int id; - PerGeneralMap wins; - PerGeneralMap losses; - PerGeneralMap games; //first: playerTemplate #, second: #games played (see also gamesAsRandom) - PerGeneralMap duration; - PerGeneralMap unitsKilled; - PerGeneralMap unitsLost; - PerGeneralMap unitsBuilt; - PerGeneralMap buildingsKilled; - PerGeneralMap buildingsLost; - PerGeneralMap buildingsBuilt; - PerGeneralMap earnings; - PerGeneralMap techCaptured; - PerGeneralMap discons; - PerGeneralMap desyncs; - PerGeneralMap surrenders; - PerGeneralMap gamesOf2p; - PerGeneralMap gamesOf3p; - PerGeneralMap gamesOf4p; - PerGeneralMap gamesOf5p; - PerGeneralMap gamesOf6p; - PerGeneralMap gamesOf7p; - PerGeneralMap gamesOf8p; - PerGeneralMap customGames; - PerGeneralMap QMGames; - Int locale; - Int gamesAsRandom; - std::string options; - std::string systemSpec; - Real lastFPS; - Int lastGeneral; - Int gamesInRowWithLastGeneral; - Int challengeMedals; - Int battleHonors; - Int QMwinsInARow; - Int maxQMwinsInARow; - - Int winsInARow; - Int maxWinsInARow; - Int lossesInARow; - Int maxLossesInARow; - Int disconsInARow; - Int maxDisconsInARow; - Int desyncsInARow; - Int maxDesyncsInARow; - - Int builtParticleCannon; - Int builtNuke; - Int builtSCUD; - - Int lastLadderPort; - std::string lastLadderHost; - - void incorporate( const PSPlayerStats& other ); -}; - -// this class encapsulates a request for the thread -class PSRequest -{ -public: - PSRequest(); - enum - { - PSREQUEST_READPLAYERSTATS, // read stats for a player - PSREQUEST_UPDATEPLAYERSTATS, // update stats on the server - PSREQUEST_UPDATEPLAYERLOCALE, // update locale on the server - PSREQUEST_READCDKEYSTATS, // read stats for a cdkey - PSREQUEST_SENDGAMERESTOGAMESPY, // report game results to GameSpy - PSREQUEST_MAX - } requestType; - - // player stats for the *PLAYERSTATS - PSPlayerStats player; - - // cdkey for READCDKEYSTATS; - std::string cdkey; - - // our info for UPDATEPLAYERSTATS - std::string nick; - std::string password; - std::string email; - Bool addDiscon; - Bool addDesync; - Int lastHouse; - - // for GameRes - std::string results; -}; - -//------------------------------------------------------------------------- - -// this class encapsulates a response from the thread -class PSResponse -{ -public: - enum - { - PSRESPONSE_PLAYERSTATS, - PSRESPONSE_COULDNOTCONNECT, - PSRESPONSE_PREORDER, - PSRESPONSE_MAX - } responseType; - - // player stats for the *PLAYERSTATS - PSPlayerStats player; - - // preorder flag - Bool preorder; -}; - -//------------------------------------------------------------------------- - -// this is the actual message queue used to pass messages between threads -class GameSpyPSMessageQueueInterface -{ -public: - virtual ~GameSpyPSMessageQueueInterface() {} - virtual void startThread( void ) = 0; - virtual void endThread( void ) = 0; - virtual Bool isThreadRunning( void ) = 0; - - virtual void addRequest( const PSRequest& req ) = 0; - virtual Bool getRequest( PSRequest& req ) = 0; - - virtual void addResponse( const PSResponse& resp ) = 0; - virtual Bool getResponse( PSResponse& resp ) = 0; - - // called from the main thread - virtual void trackPlayerStats( PSPlayerStats stats ) = 0; - virtual PSPlayerStats findPlayerStatsByID( Int id ) = 0; - - static GameSpyPSMessageQueueInterface* createNewMessageQueue( void ); - - static std::string formatPlayerKVPairs( PSPlayerStats stats ); - static PSPlayerStats parsePlayerKVPairs( std::string kvPairs ); -}; - -extern GameSpyPSMessageQueueInterface *TheGameSpyPSMessageQueue; diff --git a/Generals/Code/GameEngine/Include/GameNetwork/GameSpy/PingThread.h b/Generals/Code/GameEngine/Include/GameNetwork/GameSpy/PingThread.h deleted file mode 100644 index aab2e51609..0000000000 --- a/Generals/Code/GameEngine/Include/GameNetwork/GameSpy/PingThread.h +++ /dev/null @@ -1,77 +0,0 @@ -/* -** 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. // -// // -//////////////////////////////////////////////////////////////////////////////// - -// FILE: PingThread.h ////////////////////////////////////////////////////// -// Generals ping thread class interface -// Author: Matthew D. Campbell, August 2002 -// Note: adapted from WOLAPI - -#pragma once - -// this class encapsulates a request for the thread -class PingRequest -{ -public: - std::string hostname; - Int repetitions; - Int timeout; -}; - -//------------------------------------------------------------------------- - -// this class encapsulates a response from the thread -class PingResponse -{ -public: - std::string hostname; - Int avgPing; - Int repetitions; -}; - -//------------------------------------------------------------------------- - -// this is the actual message queue used to pass messages between threads -class PingerInterface -{ -public: - virtual ~PingerInterface() {} - virtual void startThreads( void ) = 0; - virtual void endThreads( void ) = 0; - virtual Bool areThreadsRunning( void ) = 0; - - virtual void addRequest( const PingRequest& req ) = 0; - virtual Bool getRequest( PingRequest& resp ) = 0; - - virtual void addResponse( const PingResponse& resp ) = 0; - virtual Bool getResponse( PingResponse& resp ) = 0; - - static PingerInterface* createNewPingerInterface( void ); - - virtual Bool arePingsInProgress( void ) = 0; - virtual Int getPing( AsciiString hostname ) = 0; - virtual void clearPingMap( void ) = 0; - virtual AsciiString getPingString( Int timeout ) = 0; -}; - -extern PingerInterface *ThePinger; diff --git a/Generals/Code/GameEngine/Include/GameNetwork/GameSpy/StagingRoomGameInfo.h b/Generals/Code/GameEngine/Include/GameNetwork/GameSpy/StagingRoomGameInfo.h deleted file mode 100644 index 5f7572a343..0000000000 --- a/Generals/Code/GameEngine/Include/GameNetwork/GameSpy/StagingRoomGameInfo.h +++ /dev/null @@ -1,156 +0,0 @@ -/* -** 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. // -// // -//////////////////////////////////////////////////////////////////////////////// - -// FILE: StagingRoomGameInfo.h ////////////////////////////////////////////////////// -// Generals GameSpy GameInfo -// Author: Matthew D. Campbell, Sept 2002 - -#pragma once - -#include "GameNetwork/GameInfo.h" -#include "GameNetwork/Transport.h" - -class GameSpyGameSlot : public GameSlot -{ -public: - GameSpyGameSlot(); - Int getProfileID( void ) const { return m_profileID; } - void setProfileID( Int id ) { m_profileID = id; } - AsciiString getLoginName( void ) const { return m_gameSpyLogin; } - void setLoginName( AsciiString name ) { m_gameSpyLogin = name; } - AsciiString getLocale( void ) const { return m_gameSpyLocale; } - void setLocale( AsciiString name ) { m_gameSpyLocale = name; } - Int getWins( void ) const { return m_wins; } - Int getLosses( void ) const { return m_losses; } - void setWins( Int wins ) { m_wins = wins; } - void setLosses( Int losses ) { m_losses = losses; } - - Int getSlotRankPoints( void ) const { return m_rankPoints; } - Int getFavoriteSide( void ) const { return m_favoriteSide; } - void setSlotRankPoints( Int val ) { m_rankPoints = val; } - void setFavoriteSide( Int val ) { m_favoriteSide = val; } - - void setPingString( AsciiString pingStr ); - inline AsciiString getPingString( void ) const { return m_pingStr; } - inline Int getPingAsInt( void ) const { return m_pingInt; } - -protected: - Int m_profileID; - AsciiString m_gameSpyLogin; - AsciiString m_gameSpyLocale; - - AsciiString m_pingStr; - Int m_pingInt; - Int m_wins, m_losses; - Int m_rankPoints, m_favoriteSide; -}; - -/** - * GameSpyStagingRoom class - maintains information about the GameSpy game and - * the contents of its slot list throughout the game. - */ -class GameSpyStagingRoom : public GameInfo -{ -private: - GameSpyGameSlot m_GameSpySlot[MAX_SLOTS]; ///< The GameSpy Games Slot List - UnicodeString m_gameName; - Int m_id; - Transport *m_transport; - AsciiString m_localName; - Bool m_requiresPassword; - Bool m_allowObservers; - UnsignedInt m_version; - UnsignedInt m_exeCRC; - UnsignedInt m_iniCRC; - Bool m_isQM; - - AsciiString m_ladderIP; - AsciiString m_pingStr; - Int m_pingInt; - UnsignedShort m_ladderPort; - - Int m_reportedNumPlayers; - Int m_reportedMaxPlayers; - Int m_reportedNumObservers; - -public: - GameSpyStagingRoom(); - virtual void reset( void ); - - void cleanUpSlotPointers(void); - inline void setID(Int id) { m_id = id; } - inline Int getID( void ) const { return m_id; } - - inline void setHasPassword(Bool val) { m_requiresPassword = val; } - inline Bool getHasPassword(void) const { return m_requiresPassword; } - inline void setAllowObservers(Bool val) { m_allowObservers = val; } - inline Bool getAllowObservers(void) const { return m_allowObservers; } - - inline void setVersion(UnsignedInt val) { m_version = val; } - inline UnsignedInt getVersion(void) const { return m_version; } - inline void setExeCRC(UnsignedInt val) { m_exeCRC = val; } - inline UnsignedInt getExeCRC(void) const { return m_exeCRC; } - inline void setIniCRC(UnsignedInt val) { m_iniCRC = val; } - inline UnsignedInt getIniCRC(void) const { return m_iniCRC; } - - inline void setReportedNumPlayers(Int val) { m_reportedNumPlayers = val; } - inline Int getReportedNumPlayers(void) const { return m_reportedNumPlayers; } - - inline void setReportedMaxPlayers(Int val) { m_reportedMaxPlayers = val; } - inline Int getReportedMaxPlayers(void) const { return m_reportedMaxPlayers; } - - inline void setReportedNumObservers(Int val) { m_reportedNumObservers = val; } - inline Int getReportedNumObservers(void) const { return m_reportedNumObservers; } - - inline void setLadderIP( AsciiString ladderIP ) { m_ladderIP = ladderIP; } - inline AsciiString getLadderIP( void ) const { return m_ladderIP; } - inline void setLadderPort( UnsignedShort ladderPort ) { m_ladderPort = ladderPort; } - inline UnsignedShort getLadderPort( void ) const { return m_ladderPort; } - void setPingString( AsciiString pingStr ); - inline AsciiString getPingString( void ) const { return m_pingStr; } - inline Int getPingAsInt( void ) const { return m_pingInt; } - - virtual Bool amIHost( void ) const; ///< Convenience function - is the local player the game host? - - GameSpyGameSlot *getGameSpySlot( Int index ); - - AsciiString generateGameSpyGameResultsPacket( void ); - AsciiString generateLadderGameResultsPacket( void ); - void markGameAsQM( void ) { m_isQM = TRUE; } - Bool isQMGame( void ) { return m_isQM; } - - virtual void init(void); - virtual void resetAccepted(void); ///< Reset the accepted flag on all players - - virtual void startGame(Int gameID); ///< Mark our game as started and record the game ID. - void launchGame( void ); ///< NAT negotiation has finished - really start - virtual Int getLocalSlotNum( void ) const; ///< Get the local slot number, or -1 if we're not present - - inline void setGameName( UnicodeString name ) { m_gameName = name; } - inline UnicodeString getGameName( void ) const { return m_gameName; } - - inline void setLocalName( AsciiString name ) { m_localName = name; } -}; - -extern GameSpyStagingRoom *TheGameSpyGame; diff --git a/Generals/Code/GameEngine/Include/GameNetwork/GameSpy/ThreadUtils.h b/Generals/Code/GameEngine/Include/GameNetwork/GameSpy/ThreadUtils.h deleted file mode 100644 index ace441eaf0..0000000000 --- a/Generals/Code/GameEngine/Include/GameNetwork/GameSpy/ThreadUtils.h +++ /dev/null @@ -1,32 +0,0 @@ -/* -** 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. // -// // -//////////////////////////////////////////////////////////////////////////////// - -// FILE: ThreadUtils.h ////////////////////////////////////////////////////// -// Generals GameSpy thread utils -// Author: Matthew D. Campbell, July 2002 - -#pragma once - -std::wstring MultiByteToWideCharSingleLine( const char *orig ); -std::string WideCharStringToMultiByte( const WideChar *orig ); diff --git a/Generals/Code/GameEngine/Include/GameNetwork/GameSpyChat.h b/Generals/Code/GameEngine/Include/GameNetwork/GameSpyChat.h deleted file mode 100644 index 4b56c34b8e..0000000000 --- a/Generals/Code/GameEngine/Include/GameNetwork/GameSpyChat.h +++ /dev/null @@ -1,55 +0,0 @@ -/* -** 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. // -// // -//////////////////////////////////////////////////////////////////////////////// - -// FILE: GameSpyChat.h ////////////////////////////////////////////////////// -// Generals GameSpy Chat -// Author: Matthew D. Campbell, February 2002 - -#pragma once - -#include "gamespy/peer/peer.h" - -class GameWindow; -class WindowLayout; - -Bool GameSpySendChat(UnicodeString message, Bool isEmote, GameWindow *playerListbox = NULL); -void GameSpyAddText( UnicodeString message, GameSpyColors color = GSCOLOR_DEFAULT ); - -extern GameWindow *progressTextWindow; ///< Text box on the progress screen -extern GameWindow *quickmatchTextWindow; ///< Text box on the quickmatch screen -extern GameWindow *quickmatchTextWindow; ///< Text box on the quickmatch screen -extern GameWindow *listboxLobbyChat; ///< Chat box on the custom lobby screen -extern GameWindow *listboxLobbyPlayers; ///< Player box on the custom lobby screen -extern GameWindow *listboxLobbyGames; ///< Game box on the custom lobby screen -extern GameWindow *listboxLobbyChatChannels; ///< Chat channel box on the custom lobby screen -extern GameWindow *listboxGameSetupChat; ///< Chat box on the custom game setup screen -extern WindowLayout *WOLMapSelectLayout; ///< Map selection overlay - -void RoomMessageCallback(PEER peer, RoomType roomType, - const char * nick, const char * message, - MessageType messageType, void * param); ///< Called when a message arrives in a room. - -void PlayerMessageCallback(PEER peer, const char * nick, - const char * message, MessageType messageType, - void * param); ///< Called when a private message is received from another player. diff --git a/Generals/Code/GameEngine/Include/GameNetwork/GameSpyGP.h b/Generals/Code/GameEngine/Include/GameNetwork/GameSpyGP.h deleted file mode 100644 index df001959ed..0000000000 --- a/Generals/Code/GameEngine/Include/GameNetwork/GameSpyGP.h +++ /dev/null @@ -1,42 +0,0 @@ -/* -** 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. // -// // -//////////////////////////////////////////////////////////////////////////////// - -// FILE: GameSpyGP.h ////////////////////////////////////////////////////// -// Generals GameSpy GP (Buddy) -// Author: Matthew D. Campbell, March 2002 - -#pragma once - -#include "gamespy/gp/gp.h" - -void GPRecvBuddyRequestCallback(GPConnection * connection, GPRecvBuddyRequestArg * arg, void * param); -void GPRecvBuddyMessageCallback(GPConnection * pconnection, GPRecvBuddyMessageArg * arg, void * param); -void GPRecvBuddyStatusCallback(GPConnection * connection, GPRecvBuddyStatusArg * arg, void * param); -void GPErrorCallback(GPConnection * pconnection, GPErrorArg * arg, void * param); -void GPConnectCallback(GPConnection * pconnection, GPConnectResponseArg * arg, void * param); -void GameSpyUpdateBuddyOverlay(void); - -extern GPConnection *TheGPConnection; - -Bool IsGameSpyBuddy(GPProfile id); diff --git a/Generals/Code/GameEngine/Include/GameNetwork/GameSpyGameInfo.h b/Generals/Code/GameEngine/Include/GameNetwork/GameSpyGameInfo.h deleted file mode 100644 index daba3ca64f..0000000000 --- a/Generals/Code/GameEngine/Include/GameNetwork/GameSpyGameInfo.h +++ /dev/null @@ -1,92 +0,0 @@ -/* -** 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. // -// // -//////////////////////////////////////////////////////////////////////////////// - -// FILE: GameSpyGameInfo.h ////////////////////////////////////////////////////// -// Generals GameSpy game setup information -// Author: Matthew D. Campbell, February 2002 - -#pragma once - -#error this file is obsolete -#include "gamespy/peer/peer.h" - -#include "GameNetwork/GameInfo.h" - -class Transport; -class NAT; - -class GameSpyGameSlot : public GameSlot -{ -public: - GameSpyGameSlot(); - Int getProfileID( void ) { return m_profileID; } - void setProfileID( Int id ) { m_profileID = id; } - AsciiString getLoginName( void ) { return m_gameSpyLogin; } - void setLoginName( AsciiString name ) { m_gameSpyLogin = name; } - AsciiString getLocale( void ) { return m_gameSpyLocale; } - void setLocale( AsciiString name ) { m_gameSpyLocale = name; } -protected: - Int m_profileID; - AsciiString m_gameSpyLogin; - AsciiString m_gameSpyLocale; -}; - -/** - * GameSpyGameInfo class - maintains information about the GameSpy game and - * the contents of its slot list throughout the game. - */ -class GameSpyGameInfo : public GameInfo -{ -private: - GameSpyGameSlot m_GameSpySlot[MAX_SLOTS]; ///< The GameSpy Games Slot List - SBServer m_server; - Bool m_hasBeenQueried; - Transport *m_transport; - Bool m_isQM; - -public: - GameSpyGameInfo(); - - inline void setServer(SBServer server) { m_server = server; } - inline SBServer getServer( void ) { return m_server; } - - AsciiString generateGameResultsPacket( void ); - - virtual void init(void); - virtual void resetAccepted(void); ///< Reset the accepted flag on all players - - void markGameAsQM( void ) { m_isQM = TRUE; } - virtual void startGame(Int gameID); ///< Mark our game as started and record the game ID. - virtual Int getLocalSlotNum( void ) const; ///< Get the local slot number, or -1 if we're not present - - void gotGOACall( void ); ///< Mark the game info as having been queried -}; - -extern GameSpyGameInfo *TheGameSpyGame; - -void WOLDisplayGameOptions( void ); -void WOLDisplaySlotList( void ); -void GameSpyStartGame( void ); -void GameSpyLaunchGame( void ); -Bool GetLocalChatConnectionAddress(AsciiString serverName, UnsignedShort serverPort, UnsignedInt& localIP); diff --git a/Generals/Code/GameEngine/Include/GameNetwork/GameSpyOverlay.h b/Generals/Code/GameEngine/Include/GameNetwork/GameSpyOverlay.h deleted file mode 100644 index e56f238c1c..0000000000 --- a/Generals/Code/GameEngine/Include/GameNetwork/GameSpyOverlay.h +++ /dev/null @@ -1,65 +0,0 @@ -/* -** 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. // -// // -//////////////////////////////////////////////////////////////////////////////// - -// FILE: GamespyOverlay.h ////////////////////////////////////////////////////// -// Generals GameSpy overlay screens -// Author: Matthew D. Campbell, March 2002 - -#pragma once - -#include "Common/NameKeyGenerator.h" -#include "GameClient/WindowLayout.h" -#include "GameClient/Gadget.h" -#include "GameClient/Shell.h" -#include "GameClient/KeyDefs.h" -#include "GameClient/GameWindowManager.h" - -void ClearGSMessageBoxes( void ); ///< Tear down any GS message boxes (e.g. in case we have a new one to put up) -void GSMessageBoxOk(UnicodeString titleString,UnicodeString bodyString, GameWinMsgBoxFunc okFunc = NULL); ///< Display a Message box with Ok button and track it -void GSMessageBoxOkCancel(UnicodeString title, UnicodeString message, GameWinMsgBoxFunc okFunc, GameWinMsgBoxFunc cancelFunc); ///< Display a Message box with Ok/Cancel buttons and track it -void GSMessageBoxYesNo(UnicodeString title, UnicodeString message, GameWinMsgBoxFunc yesFunc, GameWinMsgBoxFunc noFunc); ///< Display a Message box with Yes/No buttons and track it -void RaiseGSMessageBox( void ); ///< Bring GS message box to the foreground (if we transition screens while a message box is up) - -enum GSOverlayType CPP_11(: Int) -{ - GSOVERLAY_PLAYERINFO, - GSOVERLAY_MAPSELECT, - GSOVERLAY_BUDDY, - GSOVERLAY_PAGE, - GSOVERLAY_GAMEOPTIONS, - GSOVERLAY_GAMEPASSWORD, - GSOVERLAY_LADDERSELECT, - GSOVERLAY_LOCALESELECT, - GSOVERLAY_OPTIONS, - GSOVERLAY_MAX -}; - -void GameSpyOpenOverlay( GSOverlayType ); -void GameSpyCloseOverlay( GSOverlayType ); -void GameSpyCloseAllOverlays( void ); -Bool GameSpyIsOverlayOpen( GSOverlayType ); -void GameSpyToggleOverlay( GSOverlayType ); -void GameSpyUpdateOverlays( void ); -void ReOpenPlayerInfo( void ); -void CheckReOpenPlayerInfo(void ); diff --git a/Generals/Code/GameEngine/Include/GameNetwork/GameSpyThread.h b/Generals/Code/GameEngine/Include/GameNetwork/GameSpyThread.h deleted file mode 100644 index 03046f692a..0000000000 --- a/Generals/Code/GameEngine/Include/GameNetwork/GameSpyThread.h +++ /dev/null @@ -1,62 +0,0 @@ -/* -** 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. // -// // -//////////////////////////////////////////////////////////////////////////////// - -// FILE: GameSpyThread.h ////////////////////////////////////////////////////// -// Generals GameSpy thread class -// Author: Matthew D. Campbell, March 2002 - -#pragma once - -#include "mutex.h" -#include "thread.h" - -class GameSpyThreadClass : public ThreadClass -{ - -public: - GameSpyThreadClass::GameSpyThreadClass() : ThreadClass() { m_doLogin = false; m_readStats = false; m_updateWins = false; m_updateLosses = false; m_updateLocale = false; m_showLocaleSelect = false; m_nextShellScreen.clear(); } - void queueLogin(AsciiString nick, AsciiString pass, AsciiString email) { m_nick = nick; m_pass = pass; m_email = email; m_doLogin = true; } - void queueReadPersistentStatsFromServer( void ) { m_readStats = true; } - void queueUpdateLocale( AsciiString locale ) { m_locale = locale; m_updateLocale = true; } - void queueUpdateWins ( AsciiString wins ) { m_wins = wins; m_updateWins = true; } - void queueUpdateLosses( AsciiString losses ) { m_losses = losses; m_updateLosses = true; } - - void Thread_Function(); - - AsciiString getNextShellScreen( void ); - Bool showLocaleSelect( void ); - - void setNextShellScreen( AsciiString nextShellScreen ); - void setShowLocaleSelect( Bool val ); - -private: - AsciiString m_nick, m_pass, m_email; - Bool m_doLogin, m_readStats, m_updateWins, m_updateLosses, m_updateLocale; - AsciiString m_locale, m_wins, m_losses; - AsciiString m_nextShellScreen; - Bool m_showLocaleSelect; -}; - -extern GameSpyThreadClass *TheGameSpyThread; -extern MutexClass TheGameSpyMutex; diff --git a/Generals/Code/GameEngine/Include/GameNetwork/IPEnumeration.h b/Generals/Code/GameEngine/Include/GameNetwork/IPEnumeration.h deleted file mode 100644 index cef08e33aa..0000000000 --- a/Generals/Code/GameEngine/Include/GameNetwork/IPEnumeration.h +++ /dev/null @@ -1,77 +0,0 @@ -/* -** 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. // -// // -//////////////////////////////////////////////////////////////////////////////// - -// IPEnumeration.h /////////////////////////////////////////////////////////////// -// Class for enumerating IP addresses -// Author: Matthew D. Campbell, October 2001 - -#pragma once - -#include "GameNetwork/Transport.h" - -/** - * IP wrapper class. - */ -class EnumeratedIP : public MemoryPoolObject -{ - MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE(EnumeratedIP, "EnumeratedIP") -public: - EnumeratedIP() { m_IPstring = ""; m_next = NULL; m_IP = 0; } - - // Access functions - inline AsciiString getIPstring( void ) { return m_IPstring; } - inline void setIPstring( AsciiString name ) { m_IPstring = name; } - inline UnsignedInt getIP( void ) { return m_IP; } - inline void setIP( UnsignedInt IP ) { m_IP = IP; } - inline EnumeratedIP *getNext( void ) { return m_next; } - inline void setNext( EnumeratedIP *next ) { m_next = next; } - -protected: - AsciiString m_IPstring; - UnsignedInt m_IP; - EnumeratedIP *m_next; -}; -EMPTY_DTOR(EnumeratedIP) - - -/** - * The IPEnumeration class is used to obtain a list of IP addresses on the - * local machine. - */ -class IPEnumeration -{ -public: - - IPEnumeration(); - ~IPEnumeration(); - - EnumeratedIP * getAddresses( void ); ///< Return a linked list of local IP addresses - AsciiString getMachineName( void ); ///< Return the Network Neighborhood machine name - -protected: - void addNewIP( UnsignedByte a, UnsignedByte b, UnsignedByte c, UnsignedByte d ); - - EnumeratedIP *m_IPlist; - Bool m_isWinsockInitialized; -}; diff --git a/Generals/Code/GameEngine/Include/GameNetwork/LANAPI.h b/Generals/Code/GameEngine/Include/GameNetwork/LANAPI.h deleted file mode 100644 index 48d04a2991..0000000000 --- a/Generals/Code/GameEngine/Include/GameNetwork/LANAPI.h +++ /dev/null @@ -1,412 +0,0 @@ -/* -** 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. // -// // -//////////////////////////////////////////////////////////////////////////////// - -// LANAPI.h /////////////////////////////////////////////////////////////// -// LANAPI singleton class - defines interface to LAN broadcast communications -// Author: Matthew D. Campbell, October 2001 - -#pragma once - -#include "GameNetwork/Transport.h" -#include "GameNetwork/NetworkInterface.h" -#include "GameNetwork/NetworkDefs.h" -#include "GameNetwork/LANPlayer.h" -#include "GameNetwork/LANGameInfo.h" - -//static const Int g_lanPlayerNameLength = 20; -static const Int g_lanPlayerNameLength = 12; // reduced length because of game option length -//static const Int g_lanLoginNameLength = 16; -//static const Int g_lanHostNameLength = 16; -static const Int g_lanLoginNameLength = 1; -static const Int g_lanHostNameLength = 1; -//static const Int g_lanGameNameLength = 32; -static const Int g_lanGameNameLength = 16; // reduced length because of game option length -static const Int g_lanGameNameReservedLength = 16; // save N wchars for ID info -static const Int g_lanMaxChatLength = 100; -static const Int m_lanMaxOptionsLength = MAX_PACKET_SIZE - ( 8 + (g_lanGameNameLength+1)*2 + 4 + (g_lanPlayerNameLength+1)*2 - + (g_lanLoginNameLength+1) + (g_lanHostNameLength+1) ); -static const Int g_maxSerialLength = 23; // including the trailing '\0' - -struct LANMessage; - -/** - * The LANAPI class is used to instantiate a singleton which - * implements the interface to all LAN broadcast communications. - */ -class LANAPIInterface : public SubsystemInterface -{ -public: - - virtual ~LANAPIInterface() { }; - - virtual void init( void ) = 0; ///< Initialize or re-initialize the instance - virtual void reset( void ) = 0; ///< reset the logic system - virtual void update( void ) = 0; ///< update the world - - virtual void setIsActive(Bool isActive ) = 0; ///< Tell TheLAN whether or not the app is active. - - // Possible types of chat messages - enum ChatType - { - LANCHAT_NORMAL = 0, - LANCHAT_EMOTE, - LANCHAT_SYSTEM, - }; - - // Request functions generate network traffic - virtual void RequestLocations( void ) = 0; ///< Request everybody to respond with where they are - virtual void RequestGameJoin( LANGameInfo *game, UnsignedInt ip = 0 ) = 0; ///< Request to join a game - virtual void RequestGameJoinDirectConnect( UnsignedInt ipaddress ) = 0; ///< Request to join a game at an IP address - virtual void RequestGameLeave( void ) = 0; ///< Tell everyone we're leaving - virtual void RequestAccept( void ) = 0; ///< Indicate we're OK with the game options - virtual void RequestHasMap( void ) = 0; ///< Send our map status - virtual void RequestChat( UnicodeString message, ChatType format ) = 0; ///< Send a chat message - virtual void RequestGameStart( void ) = 0; ///< Tell everyone the game is starting - virtual void RequestGameStartTimer( Int seconds ) = 0; - virtual void RequestGameOptions( AsciiString gameOptions, Bool isPublic, UnsignedInt ip = 0 ) = 0; ///< Change the game options - virtual void RequestGameCreate( UnicodeString gameName, Bool isDirectConnect ) = 0; ///< Try to host a game - virtual void RequestGameAnnounce( void ) = 0; ///< Sound out current game info if host -// virtual void RequestSlotList( void ) = 0; ///< Pump out the Slot info. - virtual void RequestSetName( UnicodeString newName ) = 0; ///< Pick a new name - virtual void RequestLobbyLeave( Bool forced ) = 0; ///< Announce that we're leaving the lobby - virtual void ResetGameStartTimer( void ) = 0; - - // Possible result codes passed to On functions - enum ReturnType - { - RET_OK, // Any function - RET_TIMEOUT, // OnGameJoin/Leave/Start, etc - RET_GAME_FULL, // OnGameJoin - RET_DUPLICATE_NAME, // OnGameJoin - RET_CRC_MISMATCH, // OnGameJoin - RET_SERIAL_DUPE, // OnGameJoin - RET_GAME_STARTED, // OnGameJoin - RET_GAME_EXISTS, // OnGameCreate - RET_GAME_GONE, // OnGameJoin - RET_BUSY, // OnGameCreate/Join/etc if another action is in progress - RET_UNKNOWN, // Default message for oddity - }; - UnicodeString getErrorStringFromReturnType( ReturnType ret ); - - // On functions are (generally) the result of network traffic - virtual void OnGameList( LANGameInfo *gameList ) = 0; ///< List of games - virtual void OnPlayerList( LANPlayer *playerList ) = 0; ///< List of players in the Lobby - virtual void OnGameJoin( ReturnType ret, LANGameInfo *theGame ) = 0; ///< Did we get in the game? - virtual void OnPlayerJoin( Int slot, UnicodeString playerName ) = 0; ///< Someone else joined our game (host only; joiners get a slotlist) - virtual void OnHostLeave( void ) = 0; ///< Host left the game - virtual void OnPlayerLeave( UnicodeString player ) = 0; ///< Someone left the game - virtual void OnAccept( UnsignedInt playerIP, Bool status ) = 0; ///< Someone's accept status changed - virtual void OnHasMap( UnsignedInt playerIP, Bool status ) = 0; ///< Someone's map status changed - virtual void OnChat( UnicodeString player, UnsignedInt ip, - UnicodeString message, ChatType format ) = 0; ///< Chat message from someone - virtual void OnGameStart( void ) = 0; ///< The game is starting - virtual void OnGameStartTimer( Int seconds ) = 0; - virtual void OnGameOptions( UnsignedInt playerIP, Int playerSlot, AsciiString options ) = 0; ///< Someone sent game options - virtual void OnGameCreate( ReturnType ret ) = 0; ///< Your game is created -// virtual void OnSlotList( ReturnType ret, LANGameInfo *theGame ) = 0; ///< Slotlist for a game in setup - virtual void OnNameChange( UnsignedInt IP, UnicodeString newName ) = 0; ///< Someone has morphed - - // Misc utility functions - virtual LANGameInfo * LookupGame( UnicodeString gameName ) = 0; ///< return a pointer to a game we know about - virtual LANGameInfo * LookupGameByListOffset( Int offset ) = 0; ///< return a pointer to a game we know about - virtual Bool SetLocalIP( UnsignedInt localIP ) = 0; ///< For multiple NIC machines - virtual void SetLocalIP( AsciiString localIP ) = 0; ///< For multiple NIC machines - virtual Bool AmIHost( void ) = 0; ///< Am I hosting a game? - virtual inline UnicodeString GetMyName( void ) = 0; ///< What's my name? - virtual inline LANGameInfo *GetMyGame( void ) = 0; ///< What's my Game? - virtual void fillInLANMessage( LANMessage *msg ) = 0; ///< Fill in default params - virtual void checkMOTD( void ) = 0; -}; - - -/** - * The LANAPI class is used to instantiate a singleton which - * implements the interface to all LAN broadcast communications. - */ -class LANAPI : public LANAPIInterface -{ -public: - - LANAPI(); - virtual ~LANAPI(); - - virtual void init( void ); ///< Initialize or re-initialize the instance - virtual void reset( void ); ///< reset the logic system - virtual void update( void ); ///< update the world - - virtual void setIsActive(Bool isActive); ///< tell TheLAN whether or not - - // Request functions generate network traffic - virtual void RequestLocations( void ); ///< Request everybody to respond with where they are - virtual void RequestGameJoin( LANGameInfo *game, UnsignedInt ip = 0 ); ///< Request to join a game - virtual void RequestGameJoinDirectConnect( UnsignedInt ipaddress ); ///< Request to join a game at an IP address - virtual void RequestGameLeave( void ); ///< Tell everyone we're leaving - virtual void RequestAccept( void ); ///< Indicate we're OK with the game options - virtual void RequestHasMap( void ); ///< Send our map status - virtual void RequestChat( UnicodeString message, ChatType format ); ///< Send a chat message - virtual void RequestGameStart( void ); ///< Tell everyone the game is starting - virtual void RequestGameStartTimer( Int seconds ); - virtual void RequestGameOptions( AsciiString gameOptions, Bool isPublic, UnsignedInt ip = 0 ); ///< Change the game options - virtual void RequestGameCreate( UnicodeString gameName, Bool isDirectConnect ); ///< Try to host a game - virtual void RequestGameAnnounce( void ); ///< Send out game info if host - virtual void RequestSetName( UnicodeString newName ); ///< Pick a new name -// virtual void RequestSlotList( void ); ///< Pump out the Slot info. - virtual void RequestLobbyLeave( Bool forced ); ///< Announce that we're leaving the lobby - virtual void ResetGameStartTimer( void ); - - // On functions are (generally) the result of network traffic - virtual void OnGameList( LANGameInfo *gameList ); ///< List of games - virtual void OnPlayerList( LANPlayer *playerList ); ///< List of players in the Lobby - virtual void OnGameJoin( ReturnType ret, LANGameInfo *theGame ); ///< Did we get in the game? - virtual void OnPlayerJoin( Int slot, UnicodeString playerName ); ///< Someone else joined our game (host only; joiners get a slotlist) - virtual void OnHostLeave( void ); ///< Host left the game - virtual void OnPlayerLeave( UnicodeString player ); ///< Someone left the game - virtual void OnAccept( UnsignedInt playerIP, Bool status ); ///< Someone's accept status changed - virtual void OnHasMap( UnsignedInt playerIP, Bool status ); ///< Someone's map status changed - virtual void OnChat( UnicodeString player, UnsignedInt ip, - UnicodeString message, ChatType format ); ///< Chat message from someone - virtual void OnGameStart( void ); ///< The game is starting - virtual void OnGameStartTimer( Int seconds ); - virtual void OnGameOptions( UnsignedInt playerIP, Int playerSlot, AsciiString options ); ///< Someone sent game options - virtual void OnGameCreate( ReturnType ret ); ///< Your game is created - //virtual void OnSlotList( ReturnType ret, LANGameInfo *theGame ); ///< Slotlist for a game in setup - virtual void OnNameChange( UnsignedInt IP, UnicodeString newName ); ///< Someone has morphed - virtual void OnInActive( UnsignedInt IP ); ///< Someone has alt-tabbed out. - - - // Misc utility functions - virtual LANGameInfo * LookupGame( UnicodeString gameName ); ///< return a pointer to a game we know about - virtual LANGameInfo * LookupGameByListOffset( Int offset ); ///< return a pointer to a game we know about - virtual LANPlayer * LookupPlayer( UnsignedInt playerIP ); ///< return a pointer to a player we know about - virtual Bool SetLocalIP( UnsignedInt localIP ); ///< For multiple NIC machines - virtual void SetLocalIP( AsciiString localIP ); ///< For multiple NIC machines - virtual Bool AmIHost( void ); ///< Am I hosting a game? - virtual inline UnicodeString GetMyName( void ) { return m_name; } ///< What's my name? - virtual inline LANGameInfo* GetMyGame( void ) { return m_currentGame; } ///< What's my Game? - virtual inline UnsignedInt GetLocalIP( void ) { return m_localIP; } ///< What's my IP? - virtual void fillInLANMessage( LANMessage *msg ); ///< Fill in default params - virtual void checkMOTD( void ); -protected: - - enum PendingActionType - { - ACT_NONE = 0, - ACT_JOIN, - ACT_JOINDIRECTCONNECT, - ACT_LEAVE, - }; - - static const UnsignedInt s_resendDelta; // in ms - -protected: - LANPlayer * m_lobbyPlayers; ///< List of players in the lobby - LANGameInfo * m_games; ///< List of games - UnicodeString m_name; ///< Who do we think we are? - AsciiString m_userName; ///< login name - AsciiString m_hostName; ///< machine name - UnsignedInt m_gameStartTime; - Int m_gameStartSeconds; - - PendingActionType m_pendingAction; ///< What action are we performing? - UnsignedInt m_expiration; ///< When should we give up on our action? - UnsignedInt m_actionTimeout; - UnsignedInt m_directConnectRemoteIP;///< The IP address of the game we are direct connecting to. - - // Resend timer --------------------------------------------------------------------------- - UnsignedInt m_lastResendTime; // in ms - - Bool m_isInLANMenu; ///< true while we are in a LAN menu (lobby, game options, direct connect) - Bool m_inLobby; ///< Are we in the lobby (not in a game)? - LANGameInfo * m_currentGame; ///< Pointer to game (setup screen) we are currently in (NULL for lobby) - //LANGameInfo *m_currentGameInfo; ///< Pointer to game setup info we are currently in. - - UnsignedInt m_localIP; - Transport* m_transport; - - UnsignedInt m_broadcastAddr; - - UnsignedInt m_lastUpdate; - AsciiString m_lastGameopt; /// @todo: hack for demo - remove this - - Bool m_isActive; ///< is the game currently active? - -protected: - void sendMessage(LANMessage *msg, UnsignedInt ip = 0); // Convenience function - void removePlayer(LANPlayer *player); - void removeGame(LANGameInfo *game); - void addPlayer(LANPlayer *player); - void addGame(LANGameInfo *game); - AsciiString createSlotString( void ); - - // Functions to handle incoming messages ----------------------------------- - void handleRequestLocations( LANMessage *msg, UnsignedInt senderIP ); - void handleGameAnnounce( LANMessage *msg, UnsignedInt senderIP ); - void handleLobbyAnnounce( LANMessage *msg, UnsignedInt senderIP ); - void handleRequestGameInfo( LANMessage *msg, UnsignedInt senderIP ); - void handleRequestJoin( LANMessage *msg, UnsignedInt senderIP ); - void handleJoinAccept( LANMessage *msg, UnsignedInt senderIP ); - void handleJoinDeny( LANMessage *msg, UnsignedInt senderIP ); - void handleRequestGameLeave( LANMessage *msg, UnsignedInt senderIP ); - void handleRequestLobbyLeave( LANMessage *msg, UnsignedInt senderIP ); - void handleSetAccept( LANMessage *msg, UnsignedInt senderIP ); - void handleHasMap( LANMessage *msg, UnsignedInt senderIP ); - void handleChat( LANMessage *msg, UnsignedInt senderIP ); - void handleGameStart( LANMessage *msg, UnsignedInt senderIP ); - void handleGameStartTimer( LANMessage *msg, UnsignedInt senderIP ); - void handleGameOptions( LANMessage *msg, UnsignedInt senderIP ); - void handleInActive( LANMessage *msg, UnsignedInt senderIP ); - -}; - - - -/** - * LAN message class - */ -#pragma pack(push, 1) -struct LANMessage -{ - enum Type ///< What kind of message are we? - { - // Locating everybody - MSG_REQUEST_LOCATIONS, ///< Hey, where is everybody? - MSG_GAME_ANNOUNCE, ///< Here I am, and here's my game info! - MSG_LOBBY_ANNOUNCE, ///< Hey, I'm in the lobby! - - // Joining games - MSG_REQUEST_JOIN, ///< Let me in! Let me in! - MSG_JOIN_ACCEPT, ///< Okay, you can join. - MSG_JOIN_DENY, ///< Go away! We don't want any! - - // Leaving games - MSG_REQUEST_GAME_LEAVE, ///< I want to leave the game - MSG_REQUEST_LOBBY_LEAVE,///< I'm leaving the lobby - - // Game options, chat, etc - MSG_SET_ACCEPT, ///< I'm cool with everything as is. - MSG_MAP_AVAILABILITY, ///< I do (not) have the map. - MSG_CHAT, ///< Just spouting my mouth off. - MSG_GAME_START, ///< Hold on; we're starting! - MSG_GAME_START_TIMER, ///< The game will start in N seconds - MSG_GAME_OPTIONS, ///< Here's some info about the game. - MSG_INACTIVE, ///< I've alt-tabbed out. Unaccept me cause I'm a poo-flinging monkey. - - MSG_REQUEST_GAME_INFO, ///< For direct connect, get the game info from a specific IP Address - } messageType; - - WideChar name[g_lanPlayerNameLength+1]; ///< My name, for convenience - char userName[g_lanLoginNameLength+1]; ///< login name, for convenience - char hostName[g_lanHostNameLength+1]; ///< machine name, for convenience - - // No additional data is required for REQUEST_LOCATIONS, LOBBY_ANNOUNCE, - // REQUEST_LOBBY_LEAVE, GAME_START. - union - { - // StartTimer is sent with GAME_START_TIMER - struct - { - Int seconds; - } StartTimer; - - // GameJoined is sent with REQUEST_GAME_LEAVE - struct - { - WideChar gameName[g_lanGameNameLength+1]; - } GameToLeave; - - // GameInfo if sent with GAME_ANNOUNCE - struct - { - WideChar gameName[g_lanGameNameLength+1]; - Bool inProgress; - char options[m_lanMaxOptionsLength+1]; - Bool isDirectConnect; - } GameInfo; - - // PlayerInfo is sent with REQUEST_GAME_INFO for direct connect games. - struct - { - UnsignedInt ip; - WideChar playerName[g_lanPlayerNameLength+1]; - } PlayerInfo; - - // GameToJoin is sent with REQUEST_JOIN - struct - { - UnsignedInt gameIP; - UnsignedInt exeCRC; - UnsignedInt iniCRC; - char serial[g_maxSerialLength]; - } GameToJoin; - - // GameJoined is sent with JOIN_ACCEPT - struct - { - WideChar gameName[g_lanGameNameLength+1]; - UnsignedInt gameIP; - UnsignedInt playerIP; - Int slotPosition; - } GameJoined; - - // GameNotJoined is sent with JOIN_DENY - struct - { - WideChar gameName[g_lanGameNameLength+1]; - UnsignedInt gameIP; - UnsignedInt playerIP; - LANAPIInterface::ReturnType reason; - } GameNotJoined; - - // Accept is sent with SET_ACCEPT - struct - { - WideChar gameName[g_lanGameNameLength+1]; - Bool isAccepted; - } Accept; - - // Accept is sent with MAP_AVAILABILITY - struct - { - WideChar gameName[g_lanGameNameLength+1]; - UnsignedInt mapCRC; // to make sure we're talking about the same map - Bool hasMap; - } MapStatus; - - // Chat is sent with CHAT - struct - { - WideChar gameName[g_lanGameNameLength+1]; - LANAPIInterface::ChatType chatType; - WideChar message[g_lanMaxChatLength+1]; - } Chat; - - // GameOptions is sent with GAME_OPTIONS - struct - { - char options[m_lanMaxOptionsLength+1]; - } GameOptions; - - }; -}; -#pragma pack(pop) diff --git a/Generals/Code/GameEngine/Include/GameNetwork/LANAPICallbacks.h b/Generals/Code/GameEngine/Include/GameNetwork/LANAPICallbacks.h deleted file mode 100644 index 48d5ee28a8..0000000000 --- a/Generals/Code/GameEngine/Include/GameNetwork/LANAPICallbacks.h +++ /dev/null @@ -1,83 +0,0 @@ -/* -** 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. // -// // -//////////////////////////////////////////////////////////////////////////////// - -/////////////////////////////////////////////////////////////////////////////////////// -// FILE: LANAPICallbacks.h -// Author: Chris Huybregts, October 2001 -// Description: LAN API Callbacks header -/////////////////////////////////////////////////////////////////////////////////////// - -#pragma once - -#include "Common/NameKeyGenerator.h" -#include "GameClient/Shell.h" -#include "GameClient/GadgetListBox.h" -#include "GameClient/GadgetTextEntry.h" -#include "GameNetwork/LANAPI.h" - - -// LAN API Singleton ---------------------------------------------------------------------- -extern LANAPI *TheLAN; - -//external declarations of the Gadgets the callbacks can use -// LanLobby -extern NameKeyType listboxChatWindowID; -extern GameWindow *listboxChatWindow; -extern GameWindow *listboxPlayers; -extern NameKeyType listboxGamesID; -extern GameWindow *listboxGames; -//LanGame Options screen -extern NameKeyType listboxChatWindowLanGameID; -extern GameWindow *listboxChatWindowLanGame; -extern WindowLayout *mapSelectLayout; -// ScoreScreen -extern NameKeyType listboxChatWindowScoreScreenID; -extern GameWindow *listboxChatWindowScoreScreen; - - -//Colors used for the chat dialogs -extern const Color playerColor; -extern const Color gameColor; -extern const Color gameInProgressColor; -extern const Color chatNormalColor; -extern const Color chatActionColor; -extern const Color chatLocalNormalColor; -extern const Color chatLocalActionColor; -extern const Color chatSystemColor; -extern const Color chatSystemColor; -extern const Color acceptTrueColor; -extern const Color acceptFalseColor; - - -void lanUpdateSlotList( void ); -void updateGameOptions( void ); -void setLANPlayerTooltip(LANPlayer* player); - -//Enum is used for the utility function so other windows do not need -//to know about controls on LanGameOptions window. -enum PostToLanGameType CPP_11(: Int){ SEND_GAME_OPTS = 0, - MAP_BACK, - POST_TO_LAN_GAME_TYPE_COUNT }; -//the utility function mentioned above -void PostToLanGameOptions(PostToLanGameType post); diff --git a/Generals/Code/GameEngine/Include/GameNetwork/LANGameInfo.h b/Generals/Code/GameEngine/Include/GameNetwork/LANGameInfo.h deleted file mode 100644 index 69504d50bb..0000000000 --- a/Generals/Code/GameEngine/Include/GameNetwork/LANGameInfo.h +++ /dev/null @@ -1,179 +0,0 @@ -/* -** 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. // -// // -//////////////////////////////////////////////////////////////////////////////// - -// FILE: LANGameInfo.h ////////////////////////////////////////////////////// -// Generals LAN game setup information -// Author: Matthew D. Campbell, December 2001 - -#pragma once - -#include "GameNetwork/GameInfo.h" -#include "GameNetwork/LANPlayer.h" - -class GameWindow; - -/** - * LANGameSlot class - maintains information about the contents of a - * game slot. This persists throughout the game. - */ -class LANGameSlot : public GameSlot -{ -public: - LANGameSlot(); - - LANPlayer *getUser( void ); ///< Get the User structure associated with the slot (NULL for non-humans) - - // Various tests - Bool isUser( LANPlayer *user ); ///< Does this slot contain the given user? Based off user->name - Bool isUser( UnicodeString userName ); ///< Does this slot contain the given user? - Bool isLocalPlayer( void ) const; ///< Is this slot me? - inline void setLogin( UnicodeString name ) { m_user.setLogin(name); } - inline void setLogin( AsciiString name ) { m_user.setLogin(name); } - inline void setHost( UnicodeString name ) { m_user.setHost(name); } - inline void setHost( AsciiString name ) { m_user.setHost(name); } - inline void setSerial( AsciiString serial ) { m_serial = serial; } - inline AsciiString getSerial( void ) { return m_serial; } - - inline void setLastHeard( UnsignedInt t ) { m_lastHeard = t; } - inline UnsignedInt getLastHeard( void ) { return m_lastHeard; } - - //LANGameSlot& operator=(const LANGameSlot& src); - -private: - - LANPlayer m_user; ///< filled in for each getUser() call - AsciiString m_serial; - - UnsignedInt m_lastHeard; -}; - -/** - * LANGameInfo class - maintains information about the LAN game and - * the contents of its slot list hroughout the game. - */ -class LANGameInfo : public GameInfo -{ -private: - LANGameSlot m_LANSlot[MAX_SLOTS]; ///< The Lan Games Slot List - -public: - LANGameInfo(); - void setSlot( Int slotNum, LANGameSlot slotInfo ); ///< Set the slot state (human, open, AI, etc) - LANGameSlot* getLANSlot( Int slotNum ); ///< Get the slot - const LANGameSlot* getConstLANSlot( Int slotNum ) const; ///< Get the slot - virtual Int getLocalSlotNum( void ) const; ///< Get the local slot number, or -1 if we're not present - Int getSlotNum( UnicodeString userName ); ///< Get the slot number corresponding to a specific user, or -1 if he's not present - - inline UnsignedInt getLastHeard( void ) { return m_lastHeard; } - inline void setLastHeard( UnsignedInt lastHeard ) { m_lastHeard = lastHeard; } - inline LANGameInfo *getNext( void ) { return m_next; } - inline void setNext( LANGameInfo *next ) { m_next = next; } - - // Game options - void setMap( AsciiString mapName ); ///< Set the map to play on - void setSeed( Int seed ); ///< Set the random seed for the game - - inline void setName( UnicodeString name ) { m_gameName = name; } ///< Set the Name of the Game - inline UnicodeString getName( void ) { return m_gameName; } ///< Get the Name of the Game - - // Convinience functions that interface with the LANPlayer held in the slot list - virtual void resetAccepted(void); ///< Reset the accepted flag on all players - Bool amIHost( void ); ///< Convenience function - is the local player the game host? - - /// Get the IP of selected player or return 0 - inline UnsignedInt getIP( int who ) - { - return m_LANSlot[who].getIP(); - } - - /// Set the IP of the Selected Player - inline void setIP( int who, UnsignedInt IP ) - { - m_LANSlot[who].setIP(IP); - } - - /// set whether or not this is a direct connect game or not. - inline void setIsDirectConnect(Bool isDirectConnect) - { - m_isDirectConnect = isDirectConnect; - } - - /// returns whether or not this is a direct connect game or not. - inline Bool getIsDirectConnect() - { - return m_isDirectConnect; - } - - /// Set the Player Name - inline void setPlayerName( int who, UnicodeString name ) - { - m_LANSlot[who].setName(name); - } - - /// Return the Player name or TheEmptyString - inline UnicodeString getPlayerName(int who) - { - return m_LANSlot[who].getName(); - } - - /// Return the time the player was heard from last, or 0 - inline UnsignedInt getPlayerLastHeard( int who ) - { - if (m_LANSlot[who].isHuman()) - return m_LANSlot[who].getLastHeard(); - return 0; - } - - /// Set the last time we heard from the player - inline void setPlayerLastHeard( int who, UnsignedInt lastHeard ) - { - DEBUG_LOG(("LANGameInfo::setPlayerLastHeard - changing player %d last heard from %d to %d", who, getPlayerLastHeard(who), lastHeard)); - if (m_LANSlot[who].isHuman()) - m_LANSlot[who].setLastHeard(lastHeard); - } - - /// Return the hosts IP or 0 - UnsignedInt getHostIP(void) - { - if (m_LANSlot[0].isHuman()) - return m_LANSlot[0].getIP(); - return 0; - } - - -private: - LANGameInfo *m_next; ///< Pointer for linked list - UnsignedInt m_lastHeard; ///< The last time we heard from this game (for timeout purposes) - UnicodeString m_gameName; ///< Game name. @todo: are game names based off of host player names? - Bool m_isDirectConnect; ///< Is this game a direct connect game, or a LAN game? -}; - -void LANDisplayGameList( GameWindow *gameListbox, LANGameInfo *gameList ); ///< Displays the list of games in a listbox, preserving selections -void LANEnableStartButton(Bool enabled); - -void LANDisplaySlotList( void ); ///< Displays the slot list according to TheLANGameInfo -void LANDisplayGameOptions( void ); ///< Displays the game options according to TheLANGameInfo - -AsciiString GenerateGameOptionsString( void ); -Bool ParseGameOptionsString(LANGameInfo *game, AsciiString options); diff --git a/Generals/Code/GameEngine/Include/GameNetwork/LANPlayer.h b/Generals/Code/GameEngine/Include/GameNetwork/LANPlayer.h deleted file mode 100644 index e87f3880b6..0000000000 --- a/Generals/Code/GameEngine/Include/GameNetwork/LANPlayer.h +++ /dev/null @@ -1,63 +0,0 @@ -/* -** 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. // -// // -//////////////////////////////////////////////////////////////////////////////// - -// LANPlayer.h /////////////////////////////////////////////////////////////// -// LAN Player Class used for both the LANAPI and LANGameInfo -// Author: Matthew D. Campbell, October 2001 (Pulled out of LANAPI.h by CLH on 12/21/01 - -#pragma once - -/** - * LAN player class. This is for players sitting in the lobby. Players are - * uniquely identified by their IP addresses. - */ -class LANPlayer -{ -public: - LANPlayer() { m_name = m_login = m_host = L""; m_lastHeard = 0; m_next = NULL; m_IP = 0; } - - // Access functions - inline UnicodeString getName( void ) { return m_name; } - inline void setName( UnicodeString name ) { m_name = name; } - inline UnicodeString getLogin( void ) { return m_login; } - inline void setLogin( UnicodeString name ) { m_login = name; } - inline void setLogin( AsciiString name ) { m_login.translate(name); } - inline UnicodeString getHost( void ) { return m_host; } - inline void setHost( UnicodeString name ) { m_host = name; } - inline void setHost( AsciiString name ) { m_host.translate(name); } - inline UnsignedInt getLastHeard( void ) { return m_lastHeard; } - inline void setLastHeard( UnsignedInt lastHeard ) { m_lastHeard = lastHeard; } - inline LANPlayer *getNext( void ) { return m_next; } - inline void setNext( LANPlayer *next ) { m_next = next; } - inline UnsignedInt getIP( void ) { return m_IP; } - inline void setIP( UnsignedInt IP ) { m_IP = IP; } - -protected: - UnicodeString m_name; ///< Player name - UnicodeString m_login; ///< login name - UnicodeString m_host; ///< machine name - UnsignedInt m_lastHeard; ///< The last time we heard from this player (for timeout purposes) - LANPlayer *m_next; ///< Linked list pointer - UnsignedInt m_IP; ///< Player's IP -}; diff --git a/Generals/Code/GameEngine/Include/GameNetwork/NAT.h b/Generals/Code/GameEngine/Include/GameNetwork/NAT.h deleted file mode 100644 index 499b84d6ff..0000000000 --- a/Generals/Code/GameEngine/Include/GameNetwork/NAT.h +++ /dev/null @@ -1,157 +0,0 @@ -/* -** 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. // -// // -//////////////////////////////////////////////////////////////////////////////// - -// FILE: NAT.h ///////////////////////////////////////////////////////////////////////////////// -// Author: Bryan Cleveland April 2002 -// Desc: Resolves NAT'd IPs and port numbers for the other players in a game. -/////////////////////////////////////////////////////////////////////////////////////////////////// - -#pragma once - -#include "Lib/BaseType.h" -#include "GameNetwork/NetworkInterface.h" -#include "GameNetwork/FirewallHelper.h" - -class Transport; -class GameSlot; - -enum NATStateType CPP_11(: Int) { - NATSTATE_IDLE, - NATSTATE_DOCONNECTIONPATHS, - NATSTATE_WAITFORSTATS, - NATSTATE_DONE, - NATSTATE_FAILED -}; - -enum NATConnectionState CPP_11(: Int) { - NATCONNECTIONSTATE_NOSTATE, - NATCONNECTIONSTATE_WAITINGTOBEGIN, -// NATCONNECTIONSTATE_NETGEARDELAY, - NATCONNECTIONSTATE_WAITINGFORMANGLERRESPONSE, - NATCONNECTIONSTATE_WAITINGFORMANGLEDPORT, - NATCONNECTIONSTATE_WAITINGFORRESPONSE, - NATCONNECTIONSTATE_DONE, - NATCONNECTIONSTATE_FAILED -}; - -struct ConnectionNodeType { - FirewallHelperClass::tFirewallBehaviorType m_behavior; ///< the NAT/Firewall behavior of this node. - UnsignedInt m_slotIndex; ///< the player list index of this node. -}; - -class NAT { -public: - NAT(); - virtual ~NAT(); - - NATStateType update(); - - void attachSlotList(GameSlot **slotList, Int localSlot, UnsignedInt localIP); - void establishConnectionPaths(); - - Int getSlotPort(Int slot); - Transport * getTransport(); ///< return the newly created Transport layer that has all the connections and whatnot. - - // Notification messages from GameSpy - void processGlobalMessage(Int slotNum, const char *options); - -protected: - NATConnectionState connectionUpdate(); ///< the update function for the connections. - void sendMangledSourcePort(); ///< starts the process to get the next mangled source port. - void processManglerResponse(UnsignedShort mangledPort); - - Bool allConnectionsDoneThisRound(); - Bool allConnectionsDone(); - - void generatePortNumbers(GameSlot **slotList, Int localSlot); ///< generate all of the slots' port numbers to be used. - - void doThisConnectionRound(); ///< compute who will connect with who for this round. - void setConnectionState(Int nodeNumber, NATConnectionState state); ///< central point for changing a connection's state. - void sendAProbe(UnsignedInt ip, UnsignedShort port, Int fromNode); ///< send a "PROBE" packet to this IP and port. - void notifyTargetOfProbe(GameSlot *targetSlot); - void notifyUsersOfConnectionDone(Int nodeIndex); - void notifyUsersOfConnectionFailed(Int nodeIndex); - void sendMangledPortNumberToTarget(UnsignedShort mangledPort, GameSlot *targetSlot); - - void probed(Int nodeNumber); - void gotMangledPort(Int nodeNumber, UnsignedShort mangledPort); - void gotInternalAddress(Int nodeNumber, UnsignedInt address); - void connectionComplete(Int slotIndex); - void connectionFailed(Int slotIndex); - - Transport *m_transport; - GameSlot **m_slotList; - NATStateType m_NATState; - Int m_localNodeNumber; ///< The node number of the local player. - Int m_targetNodeNumber; ///< The node number of the player we are connecting to this round. - UnsignedInt m_localIP; ///< The IP of the local computer. - UnsignedInt m_numNodes; ///< The number of players we have to connect together. - UnsignedInt m_connectionRound; ///< The "round" of connections we are currently on. - - Int m_numRetries; - Int m_maxNumRetriesAllowed; - - UnsignedShort m_packetID; - UnsignedShort m_spareSocketPort; - time_t m_manglerRetryTime; - Int m_manglerRetries; - UnsignedShort m_previousSourcePort; - - Bool m_beenProbed; ///< have I been notified that I've been probed this round? - - UnsignedInt m_manglerAddress; - - time_t m_timeTillNextSend; ///< The number of milliseconds till we send to the other guy's port again. - NATConnectionState m_connectionStates[MAX_SLOTS]; ///< connection states for this round for all the nodes. - - ConnectionNodeType m_connectionNodes[MAX_SLOTS]; ///< info regarding the nodes that are being connected. - - UnsignedShort m_sourcePorts[MAX_SLOTS]; ///< the source ports that the other players communicate to us on. - - Bool m_myConnections[MAX_SLOTS]; ///< keeps track of all the nodes I've connected to. For keepalive. - time_t m_nextKeepaliveTime; ///< the next time we will send out our keepalive packets. - - static Int m_connectionPairs[MAX_SLOTS-1][MAX_SLOTS-1][MAX_SLOTS]; - Int m_connectionPairIndex; - - UnsignedShort m_startingPortNumber; ///< the starting port number for this game. The slots all get port numbers with their port numbers based on this number. - ///< this is done so that games that are played right after each other with the same players in the same - ///< slot order will not use the old source port allocation scheme in case their NAT - ///< hasn't timed out that connection. - - time_t m_nextPortSendTime; ///< Last time we sent our mangled port number to our target this round. - - time_t m_timeoutTime; ///< the time at which we will time out waiting for the other player's port number. - time_t m_roundTimeout; ///< the time at which we will time out this connection round. - - static Int m_timeBetweenRetries; // 1 second between retries sounds good to me. - static time_t m_manglerRetryTimeInterval; // sounds good to me. - static Int m_maxAllowedManglerRetries; // works for me. - static time_t m_keepaliveInterval; // 15 seconds between keepalive packets seems good. - static time_t m_timeToWaitForPort; // wait for ten seconds for the other player's port number. - static time_t m_timeForRoundTimeout; // wait for at most ten seconds for each connection round to finish. - -}; - -extern NAT *TheNAT; diff --git a/Generals/Code/GameEngine/Include/GameNetwork/NetCommandList.h b/Generals/Code/GameEngine/Include/GameNetwork/NetCommandList.h deleted file mode 100644 index 2497f904fd..0000000000 --- a/Generals/Code/GameEngine/Include/GameNetwork/NetCommandList.h +++ /dev/null @@ -1,68 +0,0 @@ -/* -** 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. // -// // -//////////////////////////////////////////////////////////////////////////////// - -#pragma once - -#include "Common/GameMemory.h" -#include "GameNetwork/NetCommandRef.h" - -/** - * The NetCommandList is a ordered linked list of NetCommandRef objects. - * The list is ordered based on the command id, player id, and command type. - * It is ordered in this way to aid in constructing the packets efficiently. - * The list keeps track of the last message inserted in order to accommodate - * adding commands in order more efficiently since that is whats going to be - * done most of the time. If the new message doesn't go after the last message - * inserted, then the list will be traversed linearly until the proper spot is - * found. We can get away with this inefficient method since these occurances - * will be rare. Also, the list is not expected to ever have more than 30 or so - * commands on it at a time. Five commands would probably be a normal amount. - */ - -class NetCommandList : public MemoryPoolObject -{ - MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE(NetCommandList, "NetCommandList") -public: - NetCommandList(); - //virtual ~NetCommandList(); - - void init(); ///< Initialize the list - void reset(); ///< Reset the list to the initial state. - NetCommandRef * addMessage(NetCommandMsg *cmdMsg); ///< Add message to the list in its properly ordered place. - Bool isEqualCommandMsg(NetCommandMsg *msg1, NetCommandMsg *msg2); - NetCommandRef * getFirstMessage(); ///< Get the first message on the list. - NetCommandRef * findMessage(NetCommandMsg *msg); ///< Find and return a reference to the given message if one exists. - NetCommandRef * findMessage(UnsignedShort commandID, UnsignedByte playerID); ///< Find and return a reference to the - ///< message given the player id and the command id. - ///< This will only check against messages of types that require - ///< a command id. - void removeMessage(NetCommandRef *msg); ///< Remove the given message from the list. - void appendList(NetCommandList *list); ///< Append the given list to the end of this list. - Int length(); ///< Returns the number of nodes in this list. This is inefficient and is meant to be a debug tool. - -protected: - NetCommandRef *m_first; ///< Head of the list. - NetCommandRef *m_last; ///< Tail of the list. - NetCommandRef *m_lastMessageInserted; ///< The last message that was inserted to this list. -}; diff --git a/Generals/Code/GameEngine/Include/GameNetwork/NetCommandMsg.h b/Generals/Code/GameEngine/Include/GameNetwork/NetCommandMsg.h deleted file mode 100644 index 4c585bb355..0000000000 --- a/Generals/Code/GameEngine/Include/GameNetwork/NetCommandMsg.h +++ /dev/null @@ -1,516 +0,0 @@ -/* -** 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. // -// // -//////////////////////////////////////////////////////////////////////////////// - -//------------------------------------------------------------------------------------ -// The CommandMsg class is a linked-list wrapper around GameMessage objects that -// are queued up to execute at a later time - -#pragma once - -#include "Lib/BaseType.h" -#include "GameNetwork/NetworkDefs.h" -#include "Common/UnicodeString.h" - -//----------------------------------------------------------------------------- -class NetCommandMsg : public MemoryPoolObject -{ - MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE(NetCommandMsg, "NetCommandMsg") -public: - NetCommandMsg(); - //virtual ~NetCommandMsg(); - inline UnsignedInt GetTimestamp() { return m_timestamp; } - inline void SetTimestamp(UnsignedInt timestamp) { m_timestamp = timestamp; } - inline void setExecutionFrame(UnsignedInt frame) { m_executionFrame = frame; } - inline void setPlayerID(UnsignedInt playerID) { m_playerID = playerID; } - inline void setID(UnsignedShort id) { m_id = id; } - inline UnsignedInt getExecutionFrame() { return m_executionFrame; } - inline UnsignedInt getPlayerID() { return m_playerID; } - inline UnsignedShort getID() { return m_id; } - inline void setNetCommandType(NetCommandType type) { m_commandType = type; } - inline NetCommandType getNetCommandType() { return m_commandType; } - virtual Int getSortNumber(); - void attach(); - void detach(); - -protected: - UnsignedInt m_timestamp; - UnsignedInt m_executionFrame; - UnsignedInt m_playerID; - UnsignedShort m_id; - - NetCommandType m_commandType; - Int m_referenceCount; -}; - - -//----------------------------------------------------------------------------- -/** - * The NetGameCommandMsg is the NetCommandMsg representation of a GameMessage - */ -class NetGameCommandMsg : public NetCommandMsg -{ - MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE(NetGameCommandMsg, "NetGameCommandMsg") -public: - NetGameCommandMsg(); - NetGameCommandMsg(GameMessage *msg); - //virtual ~NetGameCommandMsg(); - - GameMessage *constructGameMessage(); - void addArgument(const GameMessageArgumentDataType type, GameMessageArgumentType arg); - void setGameMessageType(GameMessage::Type type); - -protected: - Int m_numArgs; - Int m_argSize; - GameMessage::Type m_type; - GameMessageArgument *m_argList, *m_argTail; -}; - -//----------------------------------------------------------------------------- -/** - * The NetAckBothCommandMsg is the NetCommandMsg representation of the combination of a - * stage 1 ack and a stage 2 ack. - */ -class NetAckBothCommandMsg : public NetCommandMsg -{ - MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE(NetAckBothCommandMsg, "NetAckBothCommandMsg") -public: - NetAckBothCommandMsg(NetCommandMsg *msg); - NetAckBothCommandMsg(); - //virtual ~NetAckBothCommandMsg(); - - UnsignedShort getCommandID(); - void setCommandID(UnsignedShort commandID); - UnsignedByte getOriginalPlayerID(); - void setOriginalPlayerID(UnsignedByte originalPlayerID); - virtual Int getSortNumber(); - -protected: - UnsignedShort m_commandID; - UnsignedByte m_originalPlayerID; -}; - -//----------------------------------------------------------------------------- -/** - * The NetAckStage1CommandMsg is the NetCommandMsg representation of an ack message for the initial - * recipient. - */ -class NetAckStage1CommandMsg : public NetCommandMsg -{ - MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE(NetAckStage1CommandMsg, "NetAckStage1CommandMsg") -public: - NetAckStage1CommandMsg(NetCommandMsg *msg); - NetAckStage1CommandMsg(); - //virtual ~NetAckStage1CommandMsg(); - - UnsignedShort getCommandID(); - void setCommandID(UnsignedShort commandID); - UnsignedByte getOriginalPlayerID(); - void setOriginalPlayerID(UnsignedByte originalPlayerID); - virtual Int getSortNumber(); - -protected: - UnsignedShort m_commandID; - UnsignedByte m_originalPlayerID; -}; - -//----------------------------------------------------------------------------- -/** - * The NetAckStage2CommandMsg is the NetCommandMsg representation of an ack message for all eventual - * recipients. (when this is returned, all the players in the relay mask have received the packet) - */ -class NetAckStage2CommandMsg : public NetCommandMsg -{ - MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE(NetAckStage2CommandMsg, "NetAckStage2CommandMsg") -public: - NetAckStage2CommandMsg(NetCommandMsg *msg); - NetAckStage2CommandMsg(); - //virtual ~NetAckStage2CommandMsg(); - - UnsignedShort getCommandID(); - void setCommandID(UnsignedShort commandID); - UnsignedByte getOriginalPlayerID(); - void setOriginalPlayerID(UnsignedByte originalPlayerID); - virtual Int getSortNumber(); - -protected: - UnsignedShort m_commandID; - UnsignedByte m_originalPlayerID; -}; - -//----------------------------------------------------------------------------- -class NetFrameCommandMsg : public NetCommandMsg -{ - MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE(NetFrameCommandMsg, "NetFrameCommandMsg") -public: - NetFrameCommandMsg(); - //virtual ~NetFrameCommandMsg(); - - void setCommandCount(UnsignedShort commandCount); - UnsignedShort getCommandCount(); - -protected: - UnsignedShort m_commandCount; -}; - -//----------------------------------------------------------------------------- -class NetPlayerLeaveCommandMsg : public NetCommandMsg -{ - MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE(NetPlayerLeaveCommandMsg, "NetPlayerLeaveCommandMsg") -public: - NetPlayerLeaveCommandMsg(); - //virtual ~NetPlayerLeaveCommandMsg(); - - UnsignedByte getLeavingPlayerID(); - void setLeavingPlayerID(UnsignedByte id); - -protected: - UnsignedByte m_leavingPlayerID; -}; - -//----------------------------------------------------------------------------- -class NetRunAheadMetricsCommandMsg : public NetCommandMsg -{ - MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE(NetRunAheadMetricsCommandMsg, "NetRunAheadMetricsCommandMsg") -public: - NetRunAheadMetricsCommandMsg(); - //virtual ~NetRunAheadMetricsCommandMsg(); - - Real getAverageLatency(); - void setAverageLatency(Real avgLat); - Int getAverageFps(); - void setAverageFps(Int fps); - -protected: - Real m_averageLatency; - Int m_averageFps; -}; - -//----------------------------------------------------------------------------- -class NetRunAheadCommandMsg : public NetCommandMsg -{ - MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE(NetRunAheadCommandMsg, "NetRunAheadCommandMsg") -public: - NetRunAheadCommandMsg(); - //virtual ~NetRunAheadCommandMsg(); - - UnsignedShort getRunAhead(); - void setRunAhead(UnsignedShort runAhead); - - UnsignedByte getFrameRate(); - void setFrameRate(UnsignedByte frameRate); - -protected: - UnsignedShort m_runAhead; - UnsignedByte m_frameRate; -}; - -//----------------------------------------------------------------------------- -class NetDestroyPlayerCommandMsg : public NetCommandMsg -{ - MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE(NetDestroyPlayerCommandMsg, "NetDestroyPlayerCommandMsg") -public: - NetDestroyPlayerCommandMsg(); - //virtual ~NetDestroyPlayerCommandMsg(); - - UnsignedInt getPlayerIndex(); - void setPlayerIndex(UnsignedInt playerIndex); - -protected: - UnsignedInt m_playerIndex; -}; - -//----------------------------------------------------------------------------- -class NetKeepAliveCommandMsg : public NetCommandMsg -{ - MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE(NetKeepAliveCommandMsg, "NetKeepAliveCommandMsg") -public: - NetKeepAliveCommandMsg(); - //virtual ~NetKeepAliveCommandMsg(); -}; - -//----------------------------------------------------------------------------- -class NetDisconnectKeepAliveCommandMsg : public NetCommandMsg -{ - MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE(NetDisconnectKeepAliveCommandMsg, "NetDisconnectKeepAliveCommandMsg") -public: - NetDisconnectKeepAliveCommandMsg(); - //virtual ~NetDisconnectKeepAliveCommandMsg(); -}; - -//----------------------------------------------------------------------------- -class NetDisconnectPlayerCommandMsg : public NetCommandMsg -{ - MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE(NetDisconnectPlayerCommandMsg, "NetDisconnectPlayerCommandMsg") -public: - NetDisconnectPlayerCommandMsg(); - //virtual ~NetDisconnectPlayerCommandMsg(); - - UnsignedByte getDisconnectSlot(); - void setDisconnectSlot(UnsignedByte slot); - - UnsignedInt getDisconnectFrame(); - void setDisconnectFrame(UnsignedInt frame); - -protected: - UnsignedByte m_disconnectSlot; - UnsignedInt m_disconnectFrame; -}; - -//----------------------------------------------------------------------------- -class NetPacketRouterQueryCommandMsg : public NetCommandMsg -{ - MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE(NetPacketRouterQueryCommandMsg, "NetPacketRouterQueryCommandMsg") -public: - NetPacketRouterQueryCommandMsg(); - //virtual ~NetPacketRouterQueryCommandMsg(); -}; - -//----------------------------------------------------------------------------- -class NetPacketRouterAckCommandMsg : public NetCommandMsg -{ - MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE(NetPacketRouterAckCommandMsg, "NetPacketRouterAckCommandMsg") -public: - NetPacketRouterAckCommandMsg(); - //virtual ~NetPacketRouterAckCommandMsg(); -}; - -//----------------------------------------------------------------------------- -class NetDisconnectChatCommandMsg : public NetCommandMsg -{ - MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE(NetDisconnectChatCommandMsg, "NetDisconnectChatCommandMsg") -public: - NetDisconnectChatCommandMsg(); - //virtual ~NetDisconnectChatCommandMsg(); - - UnicodeString getText(); - void setText(UnicodeString text); - -protected: - UnicodeString m_text; -}; - -//----------------------------------------------------------------------------- -class NetChatCommandMsg : public NetCommandMsg -{ - MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE(NetChatCommandMsg, "NetChatCommandMsg") -public: - NetChatCommandMsg(); - //virtual ~NetChatCommandMsg(); - - UnicodeString getText(); - void setText(UnicodeString text); - - Int getPlayerMask( void ); - void setPlayerMask( Int playerMask ); - -protected: - UnicodeString m_text; - Int m_playerMask; -}; - -//----------------------------------------------------------------------------- -class NetDisconnectVoteCommandMsg : public NetCommandMsg -{ - MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE(NetDisconnectVoteCommandMsg, "NetDisconnectVoteCommandMsg") -public: - NetDisconnectVoteCommandMsg(); - //virtual ~NetDisconnectVoteCommandMsg(); - - UnsignedByte getSlot(); - void setSlot(UnsignedByte slot); - - UnsignedInt getVoteFrame(); - void setVoteFrame(UnsignedInt voteFrame); - -protected: - UnsignedByte m_slot; - UnsignedInt m_voteFrame; -}; - -//----------------------------------------------------------------------------- -class NetProgressCommandMsg: public NetCommandMsg -{ - MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE(NetProgressCommandMsg, "NetProgressCommandMsg") -public: - NetProgressCommandMsg( void ); - //virtual ~NetProgressCommandMsg( void ); - - UnsignedByte getPercentage(); - void setPercentage( UnsignedByte percent ); -protected: - UnsignedByte m_percent; -}; - -//----------------------------------------------------------------------------- -class NetWrapperCommandMsg : public NetCommandMsg -{ - MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE(NetWrapperCommandMsg, "NetWrapperCommandMsg") -public: - NetWrapperCommandMsg( void ); - //virtual ~NetWrapperCommandMsg(); - - UnsignedByte * getData(); - void setData(UnsignedByte *data, UnsignedInt dataLength); - - UnsignedInt getChunkNumber(); - void setChunkNumber(UnsignedInt chunkNumber); - - UnsignedInt getNumChunks(); - void setNumChunks(UnsignedInt numChunks); - - UnsignedInt getDataLength(); - - UnsignedInt getTotalDataLength(); - void setTotalDataLength(UnsignedInt totalDataLength); - - UnsignedInt getDataOffset(); - void setDataOffset(UnsignedInt offset); - - UnsignedShort getWrappedCommandID(); - void setWrappedCommandID(UnsignedShort wrappedCommandID); - -private: - UnsignedByte *m_data; - // using UnsignedInt's so we can send around files of effectively unlimited size easily - UnsignedInt m_dataLength; - UnsignedInt m_dataOffset; - UnsignedInt m_totalDataLength; - UnsignedInt m_chunkNumber; - UnsignedInt m_numChunks; - UnsignedShort m_wrappedCommandID; -}; - -//----------------------------------------------------------------------------- -class NetFileCommandMsg : public NetCommandMsg -{ - MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE(NetFileCommandMsg, "NetFileCommandMsg") -public: - NetFileCommandMsg(); - //virtual ~NetFileCommandMsg(); - - AsciiString getRealFilename(); - void setRealFilename(AsciiString filename); - - AsciiString getPortableFilename() { return m_portableFilename; } - void setPortableFilename(AsciiString filename) { m_portableFilename = filename; } - - UnsignedInt getFileLength(); - - UnsignedByte * getFileData(); - void setFileData(UnsignedByte *data, UnsignedInt dataLength); - -protected: - AsciiString m_portableFilename; - - UnsignedByte *m_data; - UnsignedInt m_dataLength; -}; - -//----------------------------------------------------------------------------- -class NetFileAnnounceCommandMsg : public NetCommandMsg -{ - MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE(NetFileAnnounceCommandMsg, "NetFileAnnounceCommandMsg") -public: - NetFileAnnounceCommandMsg(); - //virtual ~NetFileAnnounceCommandMsg(); - - AsciiString getRealFilename(); - void setRealFilename(AsciiString filename); - - AsciiString getPortableFilename() { return m_portableFilename; } - void setPortableFilename(AsciiString filename) { m_portableFilename = filename; } - - UnsignedShort getFileID(); - void setFileID(UnsignedShort fileID); - - UnsignedByte getPlayerMask(void); - void setPlayerMask(UnsignedByte playerMask); - -protected: - AsciiString m_portableFilename; - UnsignedShort m_fileID; - UnsignedByte m_playerMask; -}; - -//----------------------------------------------------------------------------- -class NetFileProgressCommandMsg : public NetCommandMsg -{ - MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE(NetFileProgressCommandMsg, "NetFileProgressCommandMsg") -public: - NetFileProgressCommandMsg(); - //virtual ~NetFileProgressCommandMsg(); - - UnsignedShort getFileID(); - void setFileID(UnsignedShort val); - - Int getProgress(); - void setProgress(Int val); - -protected: - UnsignedShort m_fileID; - Int m_progress; -}; - -//----------------------------------------------------------------------------- -class NetDisconnectFrameCommandMsg : public NetCommandMsg -{ - MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE(NetDisconnectFrameCommandMsg, "NetDisconnectFrameCommandMsg") -public: - NetDisconnectFrameCommandMsg(); - - UnsignedInt getDisconnectFrame(); - void setDisconnectFrame(UnsignedInt disconnectFrame); - -protected: - UnsignedInt m_disconnectFrame; -}; - -//----------------------------------------------------------------------------- -class NetDisconnectScreenOffCommandMsg : public NetCommandMsg -{ - MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE(NetDisconnectScreenOffCommandMsg, "NetDisconnectScreenOffCommandMsg") -public: - NetDisconnectScreenOffCommandMsg(); - - UnsignedInt getNewFrame(); - void setNewFrame(UnsignedInt newFrame); - -protected: - UnsignedInt m_newFrame; -}; - -//----------------------------------------------------------------------------- -class NetFrameResendRequestCommandMsg : public NetCommandMsg -{ - MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE(NetFrameResendRequestCommandMsg, "NetFrameResendRequestCommandMsg") -public: - NetFrameResendRequestCommandMsg(); - - UnsignedInt getFrameToResend(); - void setFrameToResend(UnsignedInt frame); - -protected: - UnsignedInt m_frameToResend; -}; diff --git a/Generals/Code/GameEngine/Include/GameNetwork/NetCommandRef.h b/Generals/Code/GameEngine/Include/GameNetwork/NetCommandRef.h deleted file mode 100644 index a5321e4df2..0000000000 --- a/Generals/Code/GameEngine/Include/GameNetwork/NetCommandRef.h +++ /dev/null @@ -1,146 +0,0 @@ -/* -** 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. // -// // -//////////////////////////////////////////////////////////////////////////////// - -#pragma once - -#include "GameNetwork/NetCommandMsg.h" -#include "Common/GameMemory.h" - -#if defined(RTS_DEBUG) -// #define DEBUG_NETCOMMANDREF -#endif - -#ifdef DEBUG_NETCOMMANDREF -#define NEW_NETCOMMANDREF(msg) newInstance(NetCommandRef)(msg, __FILE__, __LINE__) -#else -#define NEW_NETCOMMANDREF(msg) newInstance(NetCommandRef)(msg) -#endif - - -class NetCommandRef : public MemoryPoolObject -{ - MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE(NetCommandRef, "NetCommandRef") -public: -#ifdef DEBUG_NETCOMMANDREF - NetCommandRef(NetCommandMsg *msg, char *filename, int line); -#else - NetCommandRef(NetCommandMsg *msg); -#endif - //~NetCommandRef(); - - NetCommandMsg *getCommand(); - NetCommandRef *getNext(); - NetCommandRef *getPrev(); - void setNext(NetCommandRef *next); - void setPrev(NetCommandRef *prev); - - void setRelay(UnsignedByte relay); - UnsignedByte getRelay() const; - - time_t getTimeLastSent() const; - void setTimeLastSent(time_t timeLastSent); - -protected: - NetCommandMsg *m_msg; - NetCommandRef *m_next; - NetCommandRef *m_prev; - UnsignedByte m_relay; ///< Need this in the command reference since the relay value will be different depending on where this particular reference is being sent. - time_t m_timeLastSent; - -#ifdef DEBUG_NETCOMMANDREF - UnsignedInt m_id; -#endif -}; - -/** - * Return the command message. - */ -inline NetCommandMsg * NetCommandRef::getCommand() -{ - return m_msg; -} - -/** - * Return the next command ref in the list. - */ -inline NetCommandRef * NetCommandRef::getNext() -{ - return m_next; -} - -/** - * Return the previous command ref in the list. - */ -inline NetCommandRef * NetCommandRef::getPrev() -{ - return m_prev; -} - -/** - * Set the next command ref in the list. - */ -inline void NetCommandRef::setNext(NetCommandRef *next) -{ - m_next = next; -} - -/** - * Set the previous command ref in the list. - */ -inline void NetCommandRef::setPrev(NetCommandRef *prev) -{ - m_prev = prev; -} - -/** - * Return the time for the last time this command was sent from this reference. - */ -inline time_t NetCommandRef::getTimeLastSent() const -{ - return m_timeLastSent; -} - -/** - * Set the time for the last time this command was sent from this reference. - */ -inline void NetCommandRef::setTimeLastSent(time_t timeLastSent) -{ - m_timeLastSent = timeLastSent; -} - -/** - * Set the send relay for this reference of the command. - */ -inline void NetCommandRef::setRelay(UnsignedByte relay) -{ - m_relay = relay; -} - -/** - * Return the send relay for this refreence of the command. - */ -inline UnsignedByte NetCommandRef::getRelay() const -{ - return m_relay; -} diff --git a/Generals/Code/GameEngine/Include/GameNetwork/NetCommandWrapperList.h b/Generals/Code/GameEngine/Include/GameNetwork/NetCommandWrapperList.h deleted file mode 100644 index e61f43d7e1..0000000000 --- a/Generals/Code/GameEngine/Include/GameNetwork/NetCommandWrapperList.h +++ /dev/null @@ -1,78 +0,0 @@ -/* -** 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. // -// // -//////////////////////////////////////////////////////////////////////////////// - -////// NetCommandWrapperList.h //////////////////////////////// -// Bryan Cleveland - -#pragma once - -#include "GameNetwork/NetCommandList.h" - -class NetCommandWrapperListNode : public MemoryPoolObject -{ - MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE(NetCommandWrapperListNode, "NetCommandWrapperListNode") -public: - NetCommandWrapperListNode(NetWrapperCommandMsg *msg); - //virtual ~NetCommandWrapperListNode(); - - Bool isComplete(); - UnsignedShort getCommandID(); - UnsignedInt getRawDataLength(); - void copyChunkData(NetWrapperCommandMsg *msg); - UnsignedByte * getRawData(); - - Int getPercentComplete(void); - - NetCommandWrapperListNode *m_next; - -protected: - UnsignedShort m_commandID; - UnsignedByte *m_data; - UnsignedInt m_dataLength; - Bool *m_chunksPresent; - UnsignedInt m_numChunks; - UnsignedInt m_numChunksPresent; - -}; - -class NetCommandWrapperList : public MemoryPoolObject -{ - MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE(NetCommandWrapperList, "NetCommandWrapperList") -public: - NetCommandWrapperList(); - //virtual ~NetCommandWrapperList(); - - void init(); - void reset(); - - void processWrapper(NetCommandRef *ref); - NetCommandList * getReadyCommands(); - - Int getPercentComplete(UnsignedShort wrappedCommandID); - -protected: - void removeFromList(NetCommandWrapperListNode *node); - - NetCommandWrapperListNode *m_list; -}; diff --git a/Generals/Code/GameEngine/Include/GameNetwork/NetPacket.h b/Generals/Code/GameEngine/Include/GameNetwork/NetPacket.h deleted file mode 100644 index bf657ae5c0..0000000000 --- a/Generals/Code/GameEngine/Include/GameNetwork/NetPacket.h +++ /dev/null @@ -1,234 +0,0 @@ -/* -** 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. // -// // -//////////////////////////////////////////////////////////////////////////////// - -/* -Ok, how this should have been done is to make each of the command types -have a bitmask telling which command message header information -each command type required. That would make finding out the size of -a particular command easier to find, without so much repetitious code. -We would still need to have a separate function for each command type -for the data, but at least that wouldn't be repeating code, that would -be specialized code. -*/ - -#pragma once - -#include "NetworkDefs.h" - -#include "GameNetwork/NetCommandList.h" -#include "Common/MessageStream.h" -#include "Common/GameMemory.h" - -class NetPacket; - -typedef std::list NetPacketList; -typedef std::list::iterator NetPacketListIter; - -class NetPacket : public MemoryPoolObject -{ - MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE(NetPacket, "NetPacket") -public: - NetPacket(); - NetPacket(TransportMessage *msg); - //virtual ~NetPacket(); - - void init(); - void reset(); - void setAddress(Int addr, Int port); - Bool addCommand(NetCommandRef *msg); - Int getNumCommands(); - - NetCommandList *getCommandList(); - - static NetCommandRef * ConstructNetCommandMsgFromRawData(UnsignedByte *data, UnsignedShort dataLength); - static NetPacketList ConstructBigCommandPacketList(NetCommandRef *ref); - - UnsignedByte *getData(); - Int getLength(); - UnsignedInt getAddr(); - UnsignedShort getPort(); - -protected: - static UnsignedInt GetBufferSizeNeededForCommand(NetCommandMsg *msg); - static void FillBufferWithCommand(UnsignedByte *buffer, NetCommandRef *msg); - - // These functions return the size of the command without any compression, repetition, etc. - // i.e. All of the required fields are taken into account when returning the size. - static UnsignedInt GetGameCommandSize(NetCommandMsg *msg); - static UnsignedInt GetAckCommandSize(NetCommandMsg *msg); - static UnsignedInt GetFrameCommandSize(NetCommandMsg *msg); - static UnsignedInt GetPlayerLeaveCommandSize(NetCommandMsg *msg); - static UnsignedInt GetRunAheadMetricsCommandSize(NetCommandMsg *msg); - static UnsignedInt GetRunAheadCommandSize(NetCommandMsg *msg); - static UnsignedInt GetDestroyPlayerCommandSize(NetCommandMsg *msg); - static UnsignedInt GetKeepAliveCommandSize(NetCommandMsg *msg); - static UnsignedInt GetDisconnectKeepAliveCommandSize(NetCommandMsg *msg); - static UnsignedInt GetDisconnectPlayerCommandSize(NetCommandMsg *msg); - static UnsignedInt GetPacketRouterQueryCommandSize(NetCommandMsg *msg); - static UnsignedInt GetPacketRouterAckCommandSize(NetCommandMsg *msg); - static UnsignedInt GetDisconnectChatCommandSize(NetCommandMsg *msg); - static UnsignedInt GetDisconnectVoteCommandSize(NetCommandMsg *msg); - static UnsignedInt GetChatCommandSize(NetCommandMsg *msg); - static UnsignedInt GetProgressMessageSize(NetCommandMsg *msg); - static UnsignedInt GetLoadCompleteMessageSize(NetCommandMsg *msg); - static UnsignedInt GetTimeOutGameStartMessageSize(NetCommandMsg *msg); - static UnsignedInt GetWrapperCommandSize(NetCommandMsg *msg); - static UnsignedInt GetFileCommandSize(NetCommandMsg *msg); - static UnsignedInt GetFileAnnounceCommandSize(NetCommandMsg *msg); - static UnsignedInt GetFileProgressCommandSize(NetCommandMsg *msg); - static UnsignedInt GetDisconnectFrameCommandSize(NetCommandMsg *msg); - static UnsignedInt GetDisconnectScreenOffCommandSize(NetCommandMsg *msg); - static UnsignedInt GetFrameResendRequestCommandSize(NetCommandMsg *msg); - - static void FillBufferWithGameCommand(UnsignedByte *buffer, NetCommandRef *msg); - static void FillBufferWithAckCommand(UnsignedByte *buffer, NetCommandRef *msg); - static void FillBufferWithFrameCommand(UnsignedByte *buffer, NetCommandRef *msg); - static void FillBufferWithPlayerLeaveCommand(UnsignedByte *buffer, NetCommandRef *msg); - static void FillBufferWithRunAheadMetricsCommand(UnsignedByte *buffer, NetCommandRef *msg); - static void FillBufferWithRunAheadCommand(UnsignedByte *buffer, NetCommandRef *msg); - static void FillBufferWithDestroyPlayerCommand(UnsignedByte *buffer, NetCommandRef *msg); - static void FillBufferWithKeepAliveCommand(UnsignedByte *buffer, NetCommandRef *msg); - static void FillBufferWithDisconnectKeepAliveCommand(UnsignedByte *buffer, NetCommandRef *msg); - static void FillBufferWithDisconnectPlayerCommand(UnsignedByte *buffer, NetCommandRef *msg); - static void FillBufferWithPacketRouterQueryCommand(UnsignedByte *buffer, NetCommandRef *msg); - static void FillBufferWithPacketRouterAckCommand(UnsignedByte *buffer, NetCommandRef *msg); - static void FillBufferWithDisconnectChatCommand(UnsignedByte *buffer, NetCommandRef *msg); - static void FillBufferWithDisconnectVoteCommand(UnsignedByte *buffer, NetCommandRef *msg); - static void FillBufferWithChatCommand(UnsignedByte *buffer, NetCommandRef *msg); - static void FillBufferWithProgressMessage(UnsignedByte *buffer, NetCommandRef *msg); - static void FillBufferWithLoadCompleteMessage(UnsignedByte *buffer, NetCommandRef *msg); - static void FillBufferWithTimeOutGameStartMessage(UnsignedByte *buffer, NetCommandRef *msg); - static void FillBufferWithFileMessage(UnsignedByte *buffer, NetCommandRef *msg); - static void FillBufferWithFileProgressMessage(UnsignedByte *buffer, NetCommandRef *msg); - static void FillBufferWithFileAnnounceMessage(UnsignedByte *buffer, NetCommandRef *msg); - static void FillBufferWithDisconnectFrameMessage(UnsignedByte *buffer, NetCommandRef *msg); - static void FillBufferWithDisconnectScreenOffMessage(UnsignedByte *buffer, NetCommandRef *msg); - static void FillBufferWithFrameResendRequestMessage(UnsignedByte *buffer, NetCommandRef *msg); - - Bool addFrameCommand(NetCommandRef *msg); - Bool isRoomForFrameMessage(NetCommandRef *msg); - Bool addAckCommand(NetCommandRef *msg, UnsignedShort commandID, UnsignedByte originalPlayerID); - Bool addAckStage1Command(NetCommandRef *msg); - Bool addAckStage2Command(NetCommandRef *msg); - Bool addAckBothCommand(NetCommandRef *msg); - Bool isRoomForAckMessage(NetCommandRef *msg); - Bool addGameCommand(NetCommandRef *msg); - Bool isRoomForGameMessage(NetCommandRef *msg, GameMessage *gmsg); - Bool addPlayerLeaveCommand(NetCommandRef *msg); - Bool isRoomForPlayerLeaveMessage(NetCommandRef *msg); - Bool addRunAheadMetricsCommand(NetCommandRef *msg); - Bool isRoomForRunAheadMetricsMessage(NetCommandRef *msg); - Bool addRunAheadCommand(NetCommandRef *msg); - Bool isRoomForRunAheadMessage(NetCommandRef *msg); - Bool addDestroyPlayerCommand(NetCommandRef *msg); - Bool isRoomForDestroyPlayerMessage(NetCommandRef *msg); - Bool addKeepAliveCommand(NetCommandRef *msg); - Bool isRoomForKeepAliveMessage(NetCommandRef *msg); - Bool addDisconnectKeepAliveCommand(NetCommandRef *msg); - Bool isRoomForDisconnectKeepAliveMessage(NetCommandRef *msg); - Bool addDisconnectPlayerCommand(NetCommandRef *msg); - Bool isRoomForDisconnectPlayerMessage(NetCommandRef *msg); - Bool addPacketRouterQueryCommand(NetCommandRef *msg); - Bool isRoomForPacketRouterQueryMessage(NetCommandRef *msg); - Bool addPacketRouterAckCommand(NetCommandRef *msg); - Bool isRoomForPacketRouterAckMessage(NetCommandRef *msg); - Bool addDisconnectChatCommand(NetCommandRef *msg); - Bool isRoomForDisconnectChatMessage(NetCommandRef *msg); - Bool addChatCommand(NetCommandRef *msg); - Bool isRoomForChatMessage(NetCommandRef *msg); - Bool addDisconnectVoteCommand(NetCommandRef *msg); - Bool isRoomForDisconnectVoteMessage(NetCommandRef *msg); - Bool addProgressMessage( NetCommandRef *msg ); - Bool isRoomForProgressMessage( NetCommandRef *msg ); - Bool addLoadCompleteMessage( NetCommandRef *msg ); - Bool isRoomForLoadCompleteMessage( NetCommandRef *msg ); - Bool addTimeOutGameStartMessage( NetCommandRef *msg ); - Bool isRoomForTimeOutGameStartMessage( NetCommandRef *msg ); - Bool addWrapperCommand(NetCommandRef *msg); - Bool isRoomForWrapperMessage(NetCommandRef *msg); - Bool addFileCommand(NetCommandRef *msg); - Bool isRoomForFileMessage(NetCommandRef *msg); - Bool addFileAnnounceCommand(NetCommandRef *msg); - Bool isRoomForFileAnnounceMessage(NetCommandRef *msg); - Bool addFileProgressCommand(NetCommandRef *msg); - Bool isRoomForFileProgressMessage(NetCommandRef *msg); - Bool addDisconnectFrameCommand(NetCommandRef *msg); - Bool isRoomForDisconnectFrameMessage(NetCommandRef *msg); - Bool addDisconnectScreenOffCommand(NetCommandRef *msg); - Bool isRoomForDisconnectScreenOffMessage(NetCommandRef *msg); - Bool addFrameResendRequestCommand(NetCommandRef *msg); - Bool isRoomForFrameResendRequestMessage(NetCommandRef *msg); - - Bool isAckRepeat(NetCommandRef *msg); - Bool isAckBothRepeat(NetCommandRef *msg); - Bool isAckStage1Repeat(NetCommandRef *msg); - Bool isAckStage2Repeat(NetCommandRef *msg); - Bool isFrameRepeat(NetCommandRef *msg); - - static NetCommandMsg * readGameMessage(UnsignedByte *data, Int &i); - static NetCommandMsg * readAckBothMessage(UnsignedByte *data, Int &i); - static NetCommandMsg * readAckStage1Message(UnsignedByte *data, Int &i); - static NetCommandMsg * readAckStage2Message(UnsignedByte *data, Int &i); - static NetCommandMsg * readFrameMessage(UnsignedByte *data, Int &i); - static NetCommandMsg * readPlayerLeaveMessage(UnsignedByte *data, Int &i); - static NetCommandMsg * readRunAheadMetricsMessage(UnsignedByte *data, Int &i); - static NetCommandMsg * readRunAheadMessage(UnsignedByte *data, Int &i); - static NetCommandMsg * readDestroyPlayerMessage(UnsignedByte *data, Int &i); - static NetCommandMsg * readKeepAliveMessage(UnsignedByte *data, Int &i); - static NetCommandMsg * readDisconnectKeepAliveMessage(UnsignedByte *data, Int &i); - static NetCommandMsg * readDisconnectPlayerMessage(UnsignedByte *data, Int &i); - static NetCommandMsg * readPacketRouterQueryMessage(UnsignedByte *data, Int &i); - static NetCommandMsg * readPacketRouterAckMessage(UnsignedByte *data, Int &i); - static NetCommandMsg * readDisconnectChatMessage(UnsignedByte *data, Int &i); - static NetCommandMsg * readDisconnectVoteMessage(UnsignedByte *data, Int &i); - static NetCommandMsg * readChatMessage(UnsignedByte *data, Int &i); - static NetCommandMsg * readProgressMessage(UnsignedByte *data, Int &i); - static NetCommandMsg * readLoadCompleteMessage(UnsignedByte *data, Int &i); - static NetCommandMsg * readTimeOutGameStartMessage(UnsignedByte *data, Int &i); - static NetCommandMsg * readWrapperMessage(UnsignedByte *data, Int &i); - static NetCommandMsg * readFileMessage(UnsignedByte *data, Int &i); - static NetCommandMsg * readFileAnnounceMessage(UnsignedByte *data, Int &i); - static NetCommandMsg * readFileProgressMessage(UnsignedByte *data, Int &i); - static NetCommandMsg * readDisconnectFrameMessage(UnsignedByte *data, Int &i); - static NetCommandMsg * readDisconnectScreenOffMessage(UnsignedByte *data, Int &i); - static NetCommandMsg * readFrameResendRequestMessage(UnsignedByte *data, Int &i); - - void writeGameMessageArgumentToPacket(GameMessageArgumentDataType type, GameMessageArgumentType arg); - static void readGameMessageArgumentFromPacket(GameMessageArgumentDataType type, NetGameCommandMsg *msg, UnsignedByte *data, Int &i); - - void dumpPacketToLog(); - -protected: - UnsignedByte m_packet[MAX_PACKET_SIZE]; - Int m_packetLen; - UnsignedInt m_addr; - Int m_numCommands; - NetCommandRef* m_lastCommand; - UnsignedInt m_lastFrame; - UnsignedShort m_port; - UnsignedShort m_lastCommandID; - UnsignedByte m_lastPlayerID; - UnsignedByte m_lastCommandType; - UnsignedByte m_lastRelay; -}; diff --git a/Generals/Code/GameEngine/Include/GameNetwork/NetworkDefs.h b/Generals/Code/GameEngine/Include/GameNetwork/NetworkDefs.h deleted file mode 100644 index 138aaeb9db..0000000000 --- a/Generals/Code/GameEngine/Include/GameNetwork/NetworkDefs.h +++ /dev/null @@ -1,210 +0,0 @@ -/* -** 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. // -// // -//////////////////////////////////////////////////////////////////////////////// - -#pragma once - -#include "Lib/BaseType.h" -#include "Common/MessageStream.h" - -static const Int WOL_NAME_LEN = 64; - -/// Max number of commands per frame -static const Int MAX_COMMANDS = 256; - -extern Int MIN_LOGIC_FRAMES; -extern Int MAX_FRAMES_AHEAD; -extern Int MIN_RUNAHEAD; - -// FRAME_DATA_LENGTH needs to be MAX_FRAMES_AHEAD+1 because a player on a different -// computer can send commands for a frame that is one beyond twice the max runahead. -extern Int FRAME_DATA_LENGTH; -extern Int FRAMES_TO_KEEP; - -// This is the connection numbering: 1-8 are for players, 9 is a broadcast con. -enum ConnectionNumbers CPP_11(: Int) -{ - MAX_PLAYER = 7, // The index of the highest possible player number. This is 0 based, so the most players allowed in a game is MAX_PLAYER+1. - NUM_CONNECTIONS -}; - -static const Int MAX_SLOTS = MAX_PLAYER+1; - -// UDP (8 bytes) + IP header (28 bytes) = 36 bytes total. We want a total packet size of 512, so 512 - 36 = 476 -static const Int MAX_PACKET_SIZE = 476; - -/** - * Command packet - contains frame #, total # of commands, and each command. This is what gets sent - * to each player every frame - */ -#define MAX_MESSAGE_LEN 1024 -#define MAX_MESSAGES 128 -static const Int numCommandsPerCommandPacket = (MAX_MESSAGE_LEN - sizeof(UnsignedInt) - sizeof(UnsignedShort))/sizeof(GameMessage); -#pragma pack(push, 1) -struct CommandPacket -{ - UnsignedInt m_frame; - UnsignedShort m_numCommands; - unsigned char m_commands[numCommandsPerCommandPacket * sizeof(GameMessage)]; -}; -#pragma pack(pop) - -#define MAX_TRANSPORT_STATISTICS_SECONDS 30 - -#pragma pack(push, 1) -struct TransportMessageHeader -{ - UnsignedInt crc; ///< packet-level CRC (must be first in packet) - UnsignedShort magic; ///< Magic number identifying Generals packets -// Int id; -// NetMessageFlags flags; -}; -#pragma pack(pop) - -/** - * Transport message - encapsulating info kept by the transport layer about each - * packet. These structs make up the in/out buffers at the transport layer. - */ -#pragma pack(push, 1) -struct TransportMessage -{ - TransportMessageHeader header; - UnsignedByte data[MAX_MESSAGE_LEN]; - Int length; - UnsignedInt addr; - UnsignedShort port; -}; -#pragma pack(pop) - -#if defined(RTS_DEBUG) -#pragma pack(push, 1) -struct DelayedTransportMessage -{ - UnsignedInt deliveryTime; - TransportMessage message; -}; -#pragma pack(pop) -#endif - -/** - * Message types - */ -enum NetMessageFlag CPP_11(: Int) { - MSG_ACK = 1, - MSG_NEEDACK = 2, - MSG_SEQUENCED = 4, - MSG_SUPERCEDING = 8 -}; -typedef UnsignedByte NetMessageFlags; - -enum NetCommandType CPP_11(: Int) { - NETCOMMANDTYPE_UNKNOWN = -1, - NETCOMMANDTYPE_ACKBOTH = 0, - NETCOMMANDTYPE_ACKSTAGE1, - NETCOMMANDTYPE_ACKSTAGE2, - NETCOMMANDTYPE_FRAMEINFO, - NETCOMMANDTYPE_GAMECOMMAND, - NETCOMMANDTYPE_PLAYERLEAVE, - NETCOMMANDTYPE_RUNAHEADMETRICS, - NETCOMMANDTYPE_RUNAHEAD, - NETCOMMANDTYPE_DESTROYPLAYER, - NETCOMMANDTYPE_KEEPALIVE, - NETCOMMANDTYPE_DISCONNECTCHAT, - NETCOMMANDTYPE_CHAT, - NETCOMMANDTYPE_MANGLERQUERY, - NETCOMMANDTYPE_MANGLERRESPONSE, - NETCOMMANDTYPE_PROGRESS, - NETCOMMANDTYPE_LOADCOMPLETE, - NETCOMMANDTYPE_TIMEOUTSTART, - NETCOMMANDTYPE_WRAPPER, // A wrapper command that holds a command thats too big to fit in a single packet. - NETCOMMANDTYPE_FILE, - NETCOMMANDTYPE_FILEANNOUNCE, - NETCOMMANDTYPE_FILEPROGRESS, - NETCOMMANDTYPE_FRAMERESENDREQUEST, - - // Disconnect menu command section. - NETCOMMANDTYPE_DISCONNECTSTART, - NETCOMMANDTYPE_DISCONNECTKEEPALIVE, - NETCOMMANDTYPE_DISCONNECTPLAYER, - NETCOMMANDTYPE_PACKETROUTERQUERY, - NETCOMMANDTYPE_PACKETROUTERACK, - NETCOMMANDTYPE_DISCONNECTVOTE, - NETCOMMANDTYPE_DISCONNECTFRAME, - NETCOMMANDTYPE_DISCONNECTSCREENOFF, - NETCOMMANDTYPE_DISCONNECTEND, -}; - -enum NetLocalStatus CPP_11(: Int) { - NETLOCALSTATUS_PREGAME = 0, - NETLOCALSTATUS_INGAME, - NETLOCALSTATUS_LEAVING, - NETLOCALSTATUS_LEFT, - NETLOCALSTATUS_POSTGAME -}; - -enum PlayerLeaveCode CPP_11(: Int) { - PLAYERLEAVECODE_CLIENT = 0, - PLAYERLEAVECODE_LOCAL, - PLAYERLEAVECODE_PACKETROUTER, - PLAYERLEAVECODE_UNKNOWN -}; - -// Magic number for identifying a Generals packet. -static const UnsignedShort GENERALS_MAGIC_NUMBER = 0xF00D; - -// The number of fps history entries. -//static const Int NETWORK_FPS_HISTORY_LENGTH = 30; - -// The number of ping history entries. -//static const Int NETWORK_LATENCY_HISTORY_LENGTH = 200; - -// The number of miliseconds between run ahead metrics things -//static const Int NETWORK_RUN_AHEAD_METRICS_TIME = 5000; - -// The number of cushion values to keep. -//static const Int NETWORK_CUSHION_HISTORY_LENGTH = 10; - -// The amount of slack in the run ahead value. This is the percentage of the calculated run ahead that is added. -//static const Int NETWORK_RUN_AHEAD_SLACK = 20; - -// The number of seconds between when the connections to each player send a keep-alive packet. -// This should be less than 30 just to keep firewall ports open. -//static const Int NETWORK_KEEPALIVE_DELAY = 20; - -// The number of milliseconds between when the game gets stuck on a frame for a network stall and -// and when the disconnect dialog comes up. -//static const Int NETWORK_DISCONNECT_TIME = 5000; - -// The number of miliseconds between when a player's last disconnect keep alive command -// was recieved and when they are considered disconnected from the game. -//static const Int NETWORK_PLAYER_TIMEOUT_TIME = 60000; - -// The base port number used for the transport socket. A players slot number is added to this -// value to get their actual port number. -static const Int NETWORK_BASE_PORT_NUMBER = 8088; - -// the singleton -class NetworkInterface; -extern NetworkInterface *TheNetwork; - -#define PRINTF_IP_AS_4_INTS(ip) ((ip) >> 24) & 0xff, ((ip) >> 16) & 0xff, ((ip) >> 8 ) & 0xff, (ip) & 0xff diff --git a/Generals/Code/GameEngine/Include/GameNetwork/NetworkInterface.h b/Generals/Code/GameEngine/Include/GameNetwork/NetworkInterface.h deleted file mode 100644 index 74e3942ced..0000000000 --- a/Generals/Code/GameEngine/Include/GameNetwork/NetworkInterface.h +++ /dev/null @@ -1,136 +0,0 @@ -/* -** 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. // -// // -//////////////////////////////////////////////////////////////////////////////// - -// NetworkInterface.h /////////////////////////////////////////////////////////////// -// Network singleton class - defines interface to Network methods -// Author: Matthew D. Campbell, July 2001 - -#pragma once - -#include "Common/MessageStream.h" -#include "GameNetwork/ConnectionManager.h" -#include "GameNetwork/User.h" -#include "GameNetwork/NetworkDefs.h" - -// forward declarations - -struct CommandPacket; -class GameMessage; -class GameInfo; - -void ClearCommandPacket(UnsignedInt frame); ///< ClearCommandPacket clears the command packet at the start of the frame. -CommandPacket *GetCommandPacket(void); ///< TheNetwork calls GetCommandPacket to get commands to send. - - - -/** - * Interface definition for the Network. - */ -class NetworkInterface : public SubsystemInterface -{ -protected: - -public: - virtual ~NetworkInterface() { }; - - static NetworkInterface * createNetwork( void ); - - //--------------------------------------------------------------------------------------- - // SubsystemInterface functions - virtual void init( void ) = 0; ///< Initialize the network - virtual void reset( void ) = 0; ///< Re-initialize the network - virtual void update( void ) = 0; ///< Updates the network - virtual void liteupdate( void ) = 0; ///< does a lightweight update for passing messages around. - - virtual void setLocalAddress(UnsignedInt ip, UnsignedInt port) = 0; ///< Tell the network what local ip and port to bind to. - virtual Bool isFrameDataReady( void ) = 0; ///< Are the commands for the next frame available? - virtual Bool isStalling() = 0; - virtual void parseUserList( const GameInfo *game ) = 0; ///< Parse a userlist, creating connections - virtual void startGame(void) = 0; ///< Sets the network game frame counter to -1 - virtual UnsignedInt getRunAhead(void) = 0; ///< Get the current RunAhead value - virtual UnsignedInt getFrameRate(void) = 0; ///< Get the current allowed frame rate. - virtual UnsignedInt getPacketArrivalCushion(void) = 0; ///< Get the smallest packet arrival cushion since this was last called. - - // Chat functions - virtual void sendChat(UnicodeString text, Int playerMask) = 0; ///< Send a chat line using the normal system. - virtual void sendDisconnectChat(UnicodeString text) = 0; ///< Send a chat line using the disconnect manager. - - virtual void sendFile(AsciiString path, UnsignedByte playerMask, UnsignedShort commandID) = 0; - virtual UnsignedShort sendFileAnnounce(AsciiString path, UnsignedByte playerMask) = 0; - virtual Int getFileTransferProgress(Int playerID, AsciiString path) = 0; - virtual Bool areAllQueuesEmpty(void) = 0; - - virtual void quitGame() = 0; ///< Quit the game right now. - - virtual void selfDestructPlayer(Int index) = 0; - - virtual void voteForPlayerDisconnect(Int slot) = 0; ///< register a vote towards this player's disconnect. - virtual Bool isPacketRouter( void ) = 0; - - // Bandwidth metrics - virtual Real getIncomingBytesPerSecond( void ) = 0; - virtual Real getIncomingPacketsPerSecond( void ) = 0; - virtual Real getOutgoingBytesPerSecond( void ) = 0; - virtual Real getOutgoingPacketsPerSecond( void ) = 0; - virtual Real getUnknownBytesPerSecond( void ) = 0; - virtual Real getUnknownPacketsPerSecond( void ) = 0; - - virtual void updateLoadProgress( Int percent ) = 0; - virtual void loadProgressComplete( void ) = 0; - virtual void sendTimeOutGameStart( void ) = 0; - virtual UnsignedInt getLocalPlayerID()= 0; - virtual UnicodeString getPlayerName(Int playerNum)= 0; - virtual Int getNumPlayers() = 0; - - virtual Int getAverageFPS() = 0; - virtual Int getSlotAverageFPS(Int slot) = 0; - - virtual void attachTransport(Transport *transport) = 0; - virtual void initTransport() = 0; - virtual Bool sawCRCMismatch() = 0; - virtual void setSawCRCMismatch() = 0; - - virtual Bool isPlayerConnected(Int playerID) = 0; - - virtual void notifyOthersOfCurrentFrame() = 0; ///< Tells all the other players what frame we are on. - virtual void notifyOthersOfNewFrame(UnsignedInt frame) = 0; ///< Tells all the other players that we are on a new frame. - - virtual Int getExecutionFrame() = 0; ///< Returns the next valid frame for simultaneous command execution. - -#if defined(RTS_DEBUG) - virtual void toggleNetworkOn( void ) = 0; ///< toggle whether or not to send network traffic. -#endif - - // For disconnect blame assignment - virtual UnsignedInt getPingFrame() = 0; - virtual Int getPingsSent() = 0; - virtual Int getPingsRecieved() = 0; -}; - - -/** - * ResolveIP turns a string ("games2.westwood.com", or "192.168.0.1") into - * a 32-bit unsigned integer. - */ -UnsignedInt ResolveIP(AsciiString host); diff --git a/Generals/Code/GameEngine/Include/GameNetwork/RankPointValue.h b/Generals/Code/GameEngine/Include/GameNetwork/RankPointValue.h deleted file mode 100644 index 973eaedf5c..0000000000 --- a/Generals/Code/GameEngine/Include/GameNetwork/RankPointValue.h +++ /dev/null @@ -1,100 +0,0 @@ -/* -** 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. // -// // -//////////////////////////////////////////////////////////////////////////////// - -// FILE: RankPointValue.h ///////////////////////////////////////////////// -//----------------------------------------------------------------------------- -// -// Electronic Arts Pacific. -// -// Confidential Information -// Copyright (C) 2002 - All Rights Reserved -// -//----------------------------------------------------------------------------- -// -// created: Sep 2002 -// -// Filename: RankPointValue.h -// -// author: Chris Huybregts -// -// purpose: -// -//----------------------------------------------------------------------------- -/////////////////////////////////////////////////////////////////////////////// - -#pragma once - -//----------------------------------------------------------------------------- -// SYSTEM INCLUDES //////////////////////////////////////////////////////////// -//----------------------------------------------------------------------------- - -//----------------------------------------------------------------------------- -// USER INCLUDES ////////////////////////////////////////////////////////////// -//----------------------------------------------------------------------------- - -//----------------------------------------------------------------------------- -// FORWARD REFERENCES ///////////////////////////////////////////////////////// -//----------------------------------------------------------------------------- -class Image; -class PSPlayerStats; -//----------------------------------------------------------------------------- -// TYPE DEFINES /////////////////////////////////////////////////////////////// -//----------------------------------------------------------------------------- -enum -{ - RANK_PRIVATE = 0, - RANK_CORPORAL, - RANK_SERGEANT, - RANK_LIEUTENANT, - RANK_CAPTAIN, - RANK_MAJOR, - RANK_COLONEL, - RANK_BRIGADIER_GENERAL, - RANK_GENERAL, - RANK_COMMANDER_IN_CHIEF, - - MAX_RANKS -}; - -struct RankPoints -{ -RankPoints(void ); - Int m_ranks[MAX_RANKS]; - Real m_winMultiplier; - Real m_lostMultiplier; - Real m_hourSpentOnlineMultiplier; - Real m_completedSoloCampaigns; - Real m_disconnectMultiplier; -}; -//----------------------------------------------------------------------------- -// INLINING /////////////////////////////////////////////////////////////////// -//----------------------------------------------------------------------------- - -//----------------------------------------------------------------------------- -// EXTERNALS ////////////////////////////////////////////////////////////////// -//----------------------------------------------------------------------------- -Int CalculateRank( const PSPlayerStats& stats ); -Int GetFavoriteSide( const PSPlayerStats& stats ); -const Image* LookupSmallRankImage(Int side, Int rankPoints); -extern RankPoints *TheRankPointValues; diff --git a/Generals/Code/GameEngine/Include/GameNetwork/Transport.h b/Generals/Code/GameEngine/Include/GameNetwork/Transport.h deleted file mode 100644 index 8701cddd6c..0000000000 --- a/Generals/Code/GameEngine/Include/GameNetwork/Transport.h +++ /dev/null @@ -1,100 +0,0 @@ -/* -** 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. // -// // -//////////////////////////////////////////////////////////////////////////////// - -// Transport.h /////////////////////////////////////////////////////////////// -// Transport layer - a thin layer around a UDP socket, with queues. -// Author: Matthew D. Campbell, July 2001 - -#pragma once - -#include "GameNetwork/udp.h" -#include "GameNetwork/NetworkDefs.h" - -/** - * The transport layer handles the UDP socket for the game, and will packetize and - * de-packetize multiple ACK/CommandPacket/etc packets into larger aggregates. - */ -// we only ever allocate one of there, and it is quite large, so we really DON'T want -// it to be a MemoryPoolObject (srj) -class Transport //: public MemoryPoolObject -{ - //MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE(Transport, "Transport") -public: - - Transport(); - ~Transport(); - - Bool init( AsciiString ip, UnsignedShort port ); - Bool init( UnsignedInt ip, UnsignedShort port ); - void reset( void ); - Bool update( void ); ///< Call this once a GameEngine tick, regardless of whether the frame advances. - - Bool doRecv( void ); ///< call this to service the receive packets - Bool doSend( void ); ///< call this to service the send queue. - - Bool queueSend(UnsignedInt addr, UnsignedShort port, const UnsignedByte *buf, Int len /*, - NetMessageFlags flags, Int id */); ///< Queue a packet for sending to the specified address and port. This will be sent on the next update() call. - - inline Bool allowBroadcasts(Bool val) { if (!m_udpsock) return false; return (m_udpsock->AllowBroadcasts(val))?true:false; } - - // Latency insertion and packet loss - void setLatency( Bool val ) { m_useLatency = val; } - void setPacketLoss( Bool val ) { m_usePacketLoss = val; } - - // Bandwidth metrics - Real getIncomingBytesPerSecond( void ); - Real getIncomingPacketsPerSecond( void ); - Real getOutgoingBytesPerSecond( void ); - Real getOutgoingPacketsPerSecond( void ); - Real getUnknownBytesPerSecond( void ); - Real getUnknownPacketsPerSecond( void ); - - TransportMessage m_outBuffer[MAX_MESSAGES]; - TransportMessage m_inBuffer[MAX_MESSAGES]; - -#if defined(RTS_DEBUG) - DelayedTransportMessage m_delayedInBuffer[MAX_MESSAGES]; -#endif - - UnsignedShort m_port; -private: - Bool m_winsockInit; - UDP *m_udpsock; - - // Latency insertion and packet loss - Bool m_useLatency; - Bool m_usePacketLoss; - - // Bandwidth metrics - UnsignedInt m_incomingBytes[MAX_TRANSPORT_STATISTICS_SECONDS]; - UnsignedInt m_unknownBytes[MAX_TRANSPORT_STATISTICS_SECONDS]; - UnsignedInt m_outgoingBytes[MAX_TRANSPORT_STATISTICS_SECONDS]; - UnsignedInt m_incomingPackets[MAX_TRANSPORT_STATISTICS_SECONDS]; - UnsignedInt m_unknownPackets[MAX_TRANSPORT_STATISTICS_SECONDS]; - UnsignedInt m_outgoingPackets[MAX_TRANSPORT_STATISTICS_SECONDS]; - Int m_statisticsSlot; - UnsignedInt m_lastSecond; - - Bool isGeneralsPacket( TransportMessage *msg ); -}; diff --git a/Generals/Code/GameEngine/Include/GameNetwork/User.h b/Generals/Code/GameEngine/Include/GameNetwork/User.h deleted file mode 100644 index 959137cc0c..0000000000 --- a/Generals/Code/GameEngine/Include/GameNetwork/User.h +++ /dev/null @@ -1,57 +0,0 @@ -/* -** 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. // -// // -//////////////////////////////////////////////////////////////////////////////// - -/** - * User class used by the network. - */ - -#pragma once - -#include "GameNetwork/NetworkDefs.h" -#include "Common/UnicodeString.h" - -class User : public MemoryPoolObject -{ - MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE(User, "User") -public: - User() {} - User(UnicodeString name, UnsignedInt addr, UnsignedInt port); - User &operator= (const User *other); - Bool operator== (const User *other); - Bool operator!= (const User *other); - - inline UnicodeString GetName() { return m_name; } - void setName(UnicodeString name); - inline UnsignedShort GetPort() { return m_port; } - inline UnsignedInt GetIPAddr() { return m_ipaddr; } - inline void SetPort(UnsignedShort port) { m_port = port; } - inline void SetIPAddr(UnsignedInt ipaddr) { m_ipaddr = ipaddr; } - - -private: - UnicodeString m_name; - UnsignedShort m_port; - UnsignedInt m_ipaddr; -}; -EMPTY_DTOR(User) diff --git a/Generals/Code/GameEngine/Include/GameNetwork/WOLBrowser/FEBDispatch.h b/Generals/Code/GameEngine/Include/GameNetwork/WOLBrowser/FEBDispatch.h deleted file mode 100644 index e2a0207616..0000000000 --- a/Generals/Code/GameEngine/Include/GameNetwork/WOLBrowser/FEBDispatch.h +++ /dev/null @@ -1,103 +0,0 @@ -/* -** 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. // -// // -//////////////////////////////////////////////////////////////////////////////// - -// -// FEBDispatch class is a template class which, when inherited from, can implement the -// IDispatch for a COM object with a type library. -// - -#pragma once - -#include -extern CComModule _Module; -#include -#include // For _bstr_t. - -#include "oleauto.h" - -template -class FEBDispatch : -public CComObjectRootEx, -public CComCoClass, -public C -{ -public: - - BEGIN_COM_MAP(T) - COM_INTERFACE_ENTRY(C) - COM_INTERFACE_ENTRY_AGGREGATE(IID_IDispatch, m_dispatch) - END_COM_MAP() - - FEBDispatch() - { - m_ptinfo = NULL; - m_dispatch = NULL; - - ITypeLib *ptlib; - HRESULT hr; - HRESULT TypeLibraryLoadResult; - char filename[256]; - - GetModuleFileName(NULL, filename, sizeof(filename)); - _bstr_t bstr(filename); - - TypeLibraryLoadResult = LoadTypeLib(bstr, &ptlib); - - DEBUG_ASSERTCRASH(TypeLibraryLoadResult == 0, ("Can't load type library for Embedded Browser")); - - if (TypeLibraryLoadResult == S_OK) - { - hr = ptlib->GetTypeInfoOfGuid(*I, &m_ptinfo); - ptlib->Release(); - - if (hr == S_OK) - { - hr = CreateStdDispatch(static_cast(this), static_cast(this), m_ptinfo, &m_dispatch); - - m_dispatch->AddRef(); - // Don't release the IUnknown from CreateStdDispatch without calling AddRef. - // It looks like CreateStdDispatch doesn't call AddRef on the IUnknown it returns. - } - } - - if ( m_dispatch == NULL ) - { - DEBUG_LOG(("Error creating Dispatch for Web interface")); - } - } - - virtual ~FEBDispatch() - { - if (m_ptinfo) - m_ptinfo->Release(); - - if (m_dispatch) - m_dispatch->Release(); - } - - IUnknown *m_dispatch; - -private: - ITypeInfo *m_ptinfo; -}; diff --git a/Generals/Code/GameEngine/Include/GameNetwork/WOLBrowser/WebBrowser.h b/Generals/Code/GameEngine/Include/GameNetwork/WOLBrowser/WebBrowser.h deleted file mode 100644 index 8122da61ae..0000000000 --- a/Generals/Code/GameEngine/Include/GameNetwork/WOLBrowser/WebBrowser.h +++ /dev/null @@ -1,124 +0,0 @@ -/* -** 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. // -// // -//////////////////////////////////////////////////////////////////////////////// - -/****************************************************************************** -* -* NAME -* $Archive: $ -* -* DESCRIPTION -* Web Browser -* -* PROGRAMMER -* Bryan Cleveland -* $Author: $ -* -* VERSION INFO -* $Revision: $ -* $Modtime: $ -* -******************************************************************************/ - -#pragma once - -#include "Common/SubsystemInterface.h" -#include -#include -#include -#include "EABrowserDispatch/BrowserDispatch.h" -#include "FEBDispatch.h" -#include - -class GameWindow; - -class WebBrowserURL : public MemoryPoolObject -{ - MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE( WebBrowserURL, "WebBrowserURL" ) - -public: - - WebBrowserURL(); - // virtual destructor prototype defined by memory pool object - - const FieldParse *getFieldParse( void ) const { return m_URLFieldParseTable; } - - AsciiString m_tag; - AsciiString m_url; - - WebBrowserURL *m_next; - - static const FieldParse m_URLFieldParseTable[]; ///< the parse table for INI definition - -}; - - - -class WebBrowser : - public FEBDispatch, - public SubsystemInterface - { - public: - void init( void ); - void reset( void ); - void update( void ); - - // Create an instance of the embedded browser for Dune Emperor. - virtual Bool createBrowserWindow(const char *tag, GameWindow *win) = 0; - virtual void closeBrowserWindow(GameWindow *win) = 0; - - WebBrowserURL *makeNewURL(AsciiString tag); - WebBrowserURL *findURL(AsciiString tag); - - protected: - // Protected to prevent direct construction via new, use CreateInstance() instead. - WebBrowser(); - virtual ~WebBrowser(); - - // Protected to prevent copy and assignment - WebBrowser(const WebBrowser&); - const WebBrowser& operator=(const WebBrowser&); - -// Bool RetrievePageURL(const char* page, char* url, int size); -// Bool RetrieveHTMLPath(char* path, int size); - - protected: - ULONG mRefCount; - WebBrowserURL *m_urlList; - - //--------------------------------------------------------------------------- - // IUnknown methods - //--------------------------------------------------------------------------- - protected: - HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject) IUNKNOWN_NOEXCEPT; - ULONG STDMETHODCALLTYPE AddRef(void) IUNKNOWN_NOEXCEPT; - ULONG STDMETHODCALLTYPE Release(void) IUNKNOWN_NOEXCEPT; - - //--------------------------------------------------------------------------- - // IBrowserDispatch methods - //--------------------------------------------------------------------------- - public: - STDMETHOD(TestMethod)(Int num1); - }; - -extern CComObject *TheWebBrowser; diff --git a/Generals/Code/GameEngine/Include/GameNetwork/networkutil.h b/Generals/Code/GameEngine/Include/GameNetwork/networkutil.h deleted file mode 100644 index de7dc46c70..0000000000 --- a/Generals/Code/GameEngine/Include/GameNetwork/networkutil.h +++ /dev/null @@ -1,54 +0,0 @@ -/* -** 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. // -// // -//////////////////////////////////////////////////////////////////////////////// - -#pragma once - -#include "GameNetwork/NetworkDefs.h" -#include "GameNetwork/NetworkInterface.h" - -UnsignedInt AssembleIp(UnsignedByte a, UnsignedByte b, UnsignedByte c, UnsignedByte d); -UnsignedInt ResolveIP(AsciiString host); -UnsignedShort GenerateNextCommandID(); -Bool DoesCommandRequireACommandID(NetCommandType type); -Bool CommandRequiresAck(NetCommandMsg *msg); -Bool CommandRequiresDirectSend(NetCommandMsg *msg); -Bool IsCommandSynchronized(NetCommandType type); -const char* GetNetCommandTypeAsString(NetCommandType type); - -#ifdef DEBUG_LOGGING -extern "C" { -void dumpBufferToLog(const void *vBuf, Int len, const char *fname, Int line); -}; -#define LOGBUFFER(buf, len) dumpBufferToLog(buf, len, __FILE__, __LINE__) -#else -#define LOGBUFFER(buf, len) {} -#endif // DEBUG_LOGGING - -inline UnsignedInt AssembleIp(UnsignedByte a, UnsignedByte b, UnsignedByte c, UnsignedByte d) -{ - return ((UnsignedInt)(a) << 24) | - ((UnsignedInt)(b) << 16) | - ((UnsignedInt)(c) << 8) | - ((UnsignedInt)(d)); -} diff --git a/Generals/Code/GameEngine/Include/GameNetwork/udp.h b/Generals/Code/GameEngine/Include/GameNetwork/udp.h deleted file mode 100644 index f7dedc7ca0..0000000000 --- a/Generals/Code/GameEngine/Include/GameNetwork/udp.h +++ /dev/null @@ -1,125 +0,0 @@ -/* -** 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. // -// // -//////////////////////////////////////////////////////////////////////////////// - -#pragma once - -#ifdef _UNIX -#include -#endif - -#ifdef _WINDOWS -#include -#include -//#define close _close -//#define read _read -//#define write _write - -#else //UNIX -#include -#include -#include -#include -#include -#include -#include -#include -#include -#endif - -#ifdef AIX -#include -#endif - -#include "Lib/BaseType.h" - -#define DEFAULT_PROTOCOL 0 - -//#include "wlib/wstypes.h" -//#include "wlib/wtime.h" - -class UDP -{ - // DATA - private: - Int fd; - UnsignedInt myIP; - UnsignedShort myPort; - struct sockaddr_in addr; - - public: - // These defines specify a system independent way to - // get error codes for socket services. - enum sockStat CPP_11(: Int) - { - OK = 0, // Everything's cool - UNKNOWN = -1, // There was an error of unknown type - ISCONN = -2, // The socket is already connected - INPROGRESS = -3, // The socket is non-blocking and the operation - // isn't done yet - ALREADY = -4, // The socket is already attempting a connection - // but isn't done yet - AGAIN = -5, // Try again. - ADDRINUSE = -6, // Address already in use - ADDRNOTAVAIL = -7, // That address is not available on the remote host - BADF = -8, // Not a valid FD - CONNREFUSED = -9, // Connection was refused - INTR =-10, // Operation was interrupted - NOTSOCK =-11, // FD wasn't a socket - PIPE =-12, // That operation just made a SIGPIPE - WOULDBLOCK =-13, // That operation would block - INVAL =-14, // Invalid - TIMEDOUT =-15 // Timeout - }; - -// CODE - private: - Int SetBlocking(Int block); - - Int m_lastError; - - public: - UDP(); - ~UDP(); - Int Bind(UnsignedInt IP,UnsignedShort port); - Int Bind(const char *Host,UnsignedShort port); - Int Write(const unsigned char *msg,UnsignedInt len,UnsignedInt IP,UnsignedShort port); - Int Read(unsigned char *msg,UnsignedInt len,sockaddr_in *from); - sockStat GetStatus(void); - void ClearStatus(void); - //int Wait(Int sec,Int usec,fd_set &returnSet); - //int Wait(Int sec,Int usec,fd_set &givenSet,fd_set &returnSet); - - Int getLocalAddr(UnsignedInt &ip, UnsignedShort &port); - Int getFD(void) { return(fd); } - - Int SetInputBuffer(UnsignedInt bytes); - Int SetOutputBuffer(UnsignedInt bytes); - int GetInputBuffer(void); - int GetOutputBuffer(void); - Int AllowBroadcasts(Bool status); -}; - -#ifdef DEBUG_LOGGING -AsciiString GetWSAErrorString( Int error ); -#endif diff --git a/Generals/Code/GameEngine/Source/GameNetwork/Connection.cpp b/Generals/Code/GameEngine/Source/GameNetwork/Connection.cpp deleted file mode 100644 index 691b88aef6..0000000000 --- a/Generals/Code/GameEngine/Source/GameNetwork/Connection.cpp +++ /dev/null @@ -1,415 +0,0 @@ -/* -** 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 in the GameEngine - -#include "GameNetwork/Connection.h" -#include "GameNetwork/networkutil.h" -#include "GameLogic/GameLogic.h" - -enum { MaxQuitFlushTime = 30000 }; // wait this many milliseconds at most to retry things before quitting - -/** - * The constructor. - */ -Connection::Connection() { - m_transport = NULL; - m_user = NULL; - m_netCommandList = NULL; - m_retryTime = 2000; // set retry time to 2 seconds. - m_lastTimeSent = 0; - m_frameGrouping = 1; - m_isQuitting = false; - m_quitTime = 0; - // Added By Sadullah Nader - // clearing out the latency tracker - m_averageLatency = 0.0f; - Int i; - for(i = 0; i < CONNECTION_LATENCY_HISTORY_LENGTH; i++) - { - m_latencies[i] = 0.0f; - } - // End Add -} - -/** - * The destructor. - */ -Connection::~Connection() { - deleteInstance(m_user); - m_user = NULL; - - deleteInstance(m_netCommandList); - m_netCommandList = NULL; -} - -/** - * Initialize the connection and any subsystems. - */ -void Connection::init() { - m_transport = NULL; - - deleteInstance(m_user); - m_user = NULL; - - if (m_netCommandList == NULL) { - m_netCommandList = newInstance(NetCommandList); - m_netCommandList->init(); - } - m_netCommandList->reset(); - - m_lastTimeSent = 0; - m_frameGrouping = 1; - m_numRetries = 0; - m_retryMetricsTime = 0; - - for (Int i = 0; i < CONNECTION_LATENCY_HISTORY_LENGTH; ++i) { - m_latencies[i] = 0; - } - m_averageLatency = 0; - m_isQuitting = FALSE; - m_quitTime = 0; -} - -/** - * Take the connection back to the initial state. - */ -void Connection::reset() { - init(); -} - -/** - * Doesn't really do anything. - */ -void Connection::update() { -} - -/** - * Attach the transport object that this connection should use. - */ -void Connection::attachTransport(Transport *transport) { - m_transport = transport; -} - -/** - * Assign this connection a user. This is the user to whome we send all our packetized goodies. - */ -void Connection::setUser(User *user) { - deleteInstance(m_user); - m_user = user; -} - -/** - * Return the user object. - */ -User * Connection::getUser() { - return m_user; -} - -/** - * Add this network command to the send queue for this connection. - * The relay is the mask specifying the people the person we are sending to should send to. - * The relay mostly has to do with the packet router. - */ -void Connection::sendNetCommandMsg(NetCommandMsg *msg, UnsignedByte relay) { - static NetPacket *packet = NULL; - - // this is done so we don't have to allocate and delete a packet every time we send a message. - if (packet == NULL) { - packet = newInstance(NetPacket); - } - - - if (m_isQuitting) - return; - - if (m_netCommandList != NULL) { - // check to see if this command will fit in a packet. If not, we need to split it up. - // we are splitting up the command here so that the retry logic will not try to - // resend the ENTIRE command (i.e. multiple packets work of data) and only do the retry - // one wrapper command at a time. - packet->reset(); - - NetCommandRef *tempref = NEW_NETCOMMANDREF(msg); - - Bool msgFits = packet->addCommand(tempref); - deleteInstance(tempref); // delete the temporary reference. - tempref = NULL; - - if (!msgFits) { - NetCommandRef *origref = NEW_NETCOMMANDREF(msg); - origref->setRelay(relay); - // the message doesn't fit in a single packet, need to split it up. - NetPacketList packetList = NetPacket::ConstructBigCommandPacketList(origref); - NetPacketListIter tempPacketPtr = packetList.begin(); - - while (tempPacketPtr != packetList.end()) { - NetPacket *tempPacket = (*tempPacketPtr); - - NetCommandList *list = tempPacket->getCommandList(); - NetCommandRef *ref1 = list->getFirstMessage(); - while (ref1 != NULL) { - NetCommandRef *ref2 = m_netCommandList->addMessage(ref1->getCommand()); - ref2->setRelay(relay); - - ref1 = ref1->getNext(); - } - - deleteInstance(tempPacket); - tempPacket = NULL; - ++tempPacketPtr; - - deleteInstance(list); - list = NULL; - } - - deleteInstance(origref); - origref = NULL; - - return; - } - - // the message fits in a packet, add to the command list normally. - NetCommandRef *ref = m_netCommandList->addMessage(msg); - - if (ref != NULL) { - -/* -#if defined(RTS_DEBUG) - if (msg->getNetCommandType() == NETCOMMANDTYPE_GAMECOMMAND) { - DEBUG_LOG(("Connection::sendNetCommandMsg - added game command %d to net command list for frame %d.", - msg->getID(), msg->getExecutionFrame())); - } else if (msg->getNetCommandType() == NETCOMMANDTYPE_FRAMEINFO) { - DEBUG_LOG(("Connection::sendNetCommandMsg - added frame info for frame %d", msg->getExecutionFrame())); - } -#endif // RTS_DEBUG -*/ - - ref->setRelay(relay); - } - } -} - -void Connection::clearCommandsExceptFrom( Int playerIndex ) -{ - NetCommandRef *tmp = m_netCommandList->getFirstMessage(); - while (tmp) - { - NetCommandRef *next = tmp->getNext(); - NetCommandMsg *msg = tmp->getCommand(); - - if (msg->getPlayerID() != playerIndex) - { - DEBUG_LOG(("Connection::clearCommandsExceptFrom(%d) - clearing a command from player %d for frame %d", - playerIndex, tmp->getCommand()->getPlayerID(), tmp->getCommand()->getExecutionFrame())); - - m_netCommandList->removeMessage(tmp); - deleteInstance(tmp); - } - - tmp = next; - } -} - -Bool Connection::isQueueEmpty() { - if (m_netCommandList->getFirstMessage() == NULL) { - return TRUE; - } - return FALSE; -} - -void Connection::setQuitting( void ) -{ - m_isQuitting = TRUE; - m_quitTime = timeGetTime(); - DEBUG_LOG(("Connection::setQuitting() at time %d", m_quitTime)); -} - -/** - * This is the good part. We take all the network commands queued up for this connection, - * packetize them and put them on the transport's send queue for actual sending. - */ -UnsignedInt Connection::doSend() { - Int numpackets = 0; - time_t curtime = timeGetTime(); - Bool couldQueue = TRUE; - - // Do this check first, since it's an important fail-safe - if (m_isQuitting && curtime > m_quitTime + MaxQuitFlushTime) - { - DEBUG_LOG(("Timed out a quitting connection. Deleting all %d messages", m_netCommandList->length())); - m_netCommandList->reset(); - return 0; - } - - if ((curtime - m_lastTimeSent) < m_frameGrouping) { -// DEBUG_LOG(("not sending packet, time = %d, m_lastFrameSent = %d, m_frameGrouping = %d", curtime, m_lastTimeSent, m_frameGrouping)); - return 0; - } - - // iterate through all the messages and put them into a packet(s). - NetCommandRef *msg = m_netCommandList->getFirstMessage(); - - while ((msg != NULL) && couldQueue) { - NetPacket *packet = newInstance(NetPacket); - packet->init(); - packet->setAddress(m_user->GetIPAddr(), m_user->GetPort()); - - Bool notDone = TRUE; - - // add the command messages until either we run out of messages or the packet is full. - while ((msg != NULL) && notDone) { - NetCommandRef *next = msg->getNext(); // Need this since msg could be deleted - - time_t timeLastSent = msg->getTimeLastSent(); - - if (((curtime - timeLastSent) > m_retryTime) || (timeLastSent == -1)) { - notDone = packet->addCommand(msg); - if (notDone) { - // the msg command was added to the packet. - if (CommandRequiresAck(msg->getCommand())) { - if (timeLastSent != -1) { - ++m_numRetries; - } - doRetryMetrics(); - msg->setTimeLastSent(curtime); - } else { - m_netCommandList->removeMessage(msg); - deleteInstance(msg); - } - } - } - msg = next; - } - - if (msg != NULL) { - DEBUG_LOG(("didn't finish sending all commands in connection")); - } - - ++numpackets; - - /// @todo Make the act of giving the transport object a packet to send more efficient. Make the transport take a NetPacket object rather than the raw data, thus avoiding an extra memcpy. - if (packet->getNumCommands() > 0) { - // If the packet actually has any information to give, give it to the transport object - // for transmission. - couldQueue = m_transport->queueSend(packet->getAddr(), packet->getPort(), packet->getData(), packet->getLength()); - m_lastTimeSent = curtime; - } - - deleteInstance(packet); // delete the packet now that we're done with it. - } - - return numpackets; -} - -NetCommandRef * Connection::processAck(NetAckStage1CommandMsg *msg) { - return processAck(msg->getCommandID(), msg->getOriginalPlayerID()); -} - -NetCommandRef * Connection::processAck(NetAckBothCommandMsg *msg) { - return processAck(msg->getCommandID(), msg->getOriginalPlayerID()); -} - -NetCommandRef * Connection::processAck(NetCommandMsg *msg) { - if (msg->getNetCommandType() == NETCOMMANDTYPE_ACKSTAGE1) { - NetAckStage1CommandMsg *ackmsg = (NetAckStage1CommandMsg *)msg; - return processAck(ackmsg); - } - - if (msg->getNetCommandType() == NETCOMMANDTYPE_ACKBOTH) { - NetAckBothCommandMsg *ackmsg = (NetAckBothCommandMsg *)msg; - return processAck(ackmsg); - } - - return NULL; -} - -/** - * The person we are sending to has ack'd one of the messages we sent him. - * Take that message off the list of commands to send. - */ -NetCommandRef * Connection::processAck(UnsignedShort commandID, UnsignedByte originalPlayerID) { - NetCommandRef *temp = m_netCommandList->getFirstMessage(); - while ((temp != NULL) && ((temp->getCommand()->getID() != commandID) || (temp->getCommand()->getPlayerID() != originalPlayerID))) { - - // cycle through the commands till we find the one we need to remove. - // Need to check for both the command ID and the player ID. - temp = temp->getNext(); - } - if (temp == NULL) { - return NULL; - } - -#if defined(RTS_DEBUG) - Bool doDebug = FALSE; - if (temp->getCommand()->getNetCommandType() == NETCOMMANDTYPE_DISCONNECTFRAME) { - doDebug = TRUE; - } -#endif - - Int index = temp->getCommand()->getID() % CONNECTION_LATENCY_HISTORY_LENGTH; - m_averageLatency -= ((Real)(m_latencies[index])) / CONNECTION_LATENCY_HISTORY_LENGTH; - Real lat = timeGetTime() - temp->getTimeLastSent(); - m_averageLatency += lat / CONNECTION_LATENCY_HISTORY_LENGTH; - m_latencies[index] = lat; - -#if defined(RTS_DEBUG) - if (doDebug == TRUE) { - DEBUG_LOG(("Connection::processAck - disconnect frame command %d found, removing from command list.", commandID)); - } -#endif - m_netCommandList->removeMessage(temp); - return temp; -} - -void Connection::setFrameGrouping(time_t frameGrouping) { - m_frameGrouping = frameGrouping; -// m_retryTime = frameGrouping * 4; -} - -void Connection::doRetryMetrics() { - static Int numSeconds = 0; - time_t curTime = timeGetTime(); - - if ((curTime - m_retryMetricsTime) > 10000) { - m_retryMetricsTime = curTime; - ++numSeconds; -// DEBUG_LOG(("Retries in the last 10 seconds = %d, average latency = %fms", m_numRetries, m_averageLatency)); - m_numRetries = 0; -// m_retryTime = m_averageLatency * 1.5; - } -} - -#if defined(RTS_DEBUG) -void Connection::debugPrintCommands() { - NetCommandRef *ref = m_netCommandList->getFirstMessage(); - while (ref != NULL) { - DEBUG_LOG(("Connection::debugPrintCommands - ID: %d\tType: %s\tRelay: 0x%X for frame %d", - ref->getCommand()->getID(), GetNetCommandTypeAsString(ref->getCommand()->getNetCommandType()), - ref->getRelay(), ref->getCommand()->getExecutionFrame())); - ref = ref->getNext(); - } -} -#endif diff --git a/Generals/Code/GameEngine/Source/GameNetwork/ConnectionManager.cpp b/Generals/Code/GameEngine/Source/GameNetwork/ConnectionManager.cpp deleted file mode 100644 index 924e462b8f..0000000000 --- a/Generals/Code/GameEngine/Source/GameNetwork/ConnectionManager.cpp +++ /dev/null @@ -1,2416 +0,0 @@ -/* -** 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 in the GameEngine - -#include "Compression.h" -#include "strtok_r.h" -#include "Common/AudioEventRTS.h" -#include "Common/CRCDebug.h" -#include "Common/Debug.h" -#include "Common/file.h" -#include "Common/GameAudio.h" -#include "Common/LocalFileSystem.h" -#include "Common/Player.h" -#include "Common/PlayerList.h" -#include "Common/RandomValue.h" -#include "Common/Recorder.h" - -#include "GameClient/Diplomacy.h" -#include "GameClient/GameText.h" -#include "GameClient/MessageBox.h" -#include "GameNetwork/ConnectionManager.h" -#include "GameNetwork/LANAPICallbacks.h" -#include "GameNetwork/NAT.h" -#include "GameNetwork/NetCommandWrapperList.h" -#include "GameNetwork/networkutil.h" -#include "GameLogic/GameLogic.h" -#include "GameLogic/ScriptActions.h" -#include "GameLogic/ScriptEngine.h" -#include "GameLogic/VictoryConditions.h" -#include "GameClient/DisconnectMenu.h" -#include "GameClient/InGameUI.h" - - -/** - * Le destructor. - */ -ConnectionManager::~ConnectionManager(void) -{ - deleteInstance(m_localUser); - m_localUser = NULL; - - // Network will delete transports; we just forget them - delete m_transport; - m_transport = NULL; - - Int i = 0; - for (; i < MAX_SLOTS; ++i) { - deleteInstance(m_frameData[i]); - m_frameData[i] = NULL; - } - - for (i = 0; i < NUM_CONNECTIONS; ++i) { - deleteInstance(m_connections[i]); - m_connections[i] = NULL; - } - - // This is done here since TheDisconnectMenu should only be there if we are in a network game. - delete TheDisconnectMenu; - TheDisconnectMenu = NULL; - - delete m_disconnectManager; - m_disconnectManager = NULL; - - deleteInstance(m_pendingCommands); - m_pendingCommands = NULL; - - deleteInstance(m_relayedCommands); - m_relayedCommands = NULL; - - deleteInstance(m_netCommandWrapperList); - m_netCommandWrapperList = NULL; - - s_fileCommandMap.clear(); - s_fileRecipientMaskMap.clear(); - for (i = 0; i < MAX_SLOTS; ++i) { - s_fileProgressMap[i].clear(); - } -} - -/** - * Le constructor - */ -ConnectionManager::ConnectionManager(void) -{ - for (Int i = 0; i < MAX_SLOTS; ++i) { - m_frameData[i] = NULL; - } - m_transport = NULL; - m_disconnectManager = NULL; - m_pendingCommands = NULL; - m_relayedCommands = NULL; - m_localAddr = 0; - m_localPort = 0; - m_netCommandWrapperList = NULL; - m_localUser = NULL; - m_localUser = newInstance(User); -} - -/** - * Initialize the connection manager and any subsystems. - */ -void ConnectionManager::init() -{ -// if (m_transport == NULL) { -// m_transport = new Transport; -// } -// m_transport->reset(); - - UnsignedInt i = 0; - for (; i < NUM_CONNECTIONS; ++i) { - m_connections[i] = NULL; - } - - if (m_pendingCommands == NULL) { - m_pendingCommands = newInstance(NetCommandList); - m_pendingCommands->init(); - } - m_pendingCommands->reset(); - - if (m_relayedCommands == NULL) { - m_relayedCommands = newInstance(NetCommandList); - m_relayedCommands->init(); - } - m_relayedCommands->reset(); - - m_localSlot = -1; -#ifdef MEMORYPOOL_DEBUG - TheMemoryPoolFactory->debugSetInitFillerIndex(m_localSlot); -#endif - m_packetRouterSlot = 0; /// @todo The LAN/WOL interface should be telling us who the packet router is based on machine specs passed around through game options. - for (i = 0; i < MAX_SLOTS; ++i) { - m_packetRouterFallback[i] = -1; - } - - for (i = 0; i < MAX_SLOTS; ++i) { - deleteInstance(m_frameData[i]); - m_frameData[i] = NULL; - } - -// m_averageFps = 30; // since 30 fps is the desired rate, we'll start off at that. -// m_averageLatency = (Real)0.2; // 200ms seems like a good starting point. - - for (i = 0; i < MAX_SLOTS; ++i) { - m_fpsAverages[i] = -1; - } - for (i = 0; i < MAX_SLOTS; ++i) { - m_latencyAverages[i] = 0.0; // using zero since all floating point standards should be able to specify 0.0 accurately. - } - m_smallestPacketArrivalCushion = -1; - - m_frameMetrics.init(); - - TheDisconnectMenu = NEW DisconnectMenu; - TheDisconnectMenu->init(); - - m_disconnectManager = NEW DisconnectManager; - m_disconnectManager->init(); - - TheDisconnectMenu->attachDisconnectManager(m_disconnectManager); - TheDisconnectMenu->hideScreen(); - - m_netCommandWrapperList = newInstance(NetCommandWrapperList); - m_netCommandWrapperList->init(); - - s_fileCommandMap.clear(); - s_fileRecipientMaskMap.clear(); - for (i = 0; i < MAX_SLOTS; ++i) { - s_fileProgressMap[i].clear(); - } -} - -/** - * Reset the connection manager and any subsystems. - */ -void ConnectionManager::reset() -{ -// if (m_transport == NULL) { -// m_transport = new Transport; -// } -// m_transport->reset(); - - delete m_transport; - m_transport = NULL; - - UnsignedInt i = 0; - for (; i < (UnsignedInt)NUM_CONNECTIONS; ++i) { - deleteInstance(m_connections[i]); - m_connections[i] = NULL; - } - - for (i=0; i<(UnsignedInt)MAX_SLOTS; ++i) - { - deleteInstance(m_frameData[i]); - m_frameData[i] = NULL; - } - - if (m_pendingCommands == NULL) { - m_pendingCommands = newInstance(NetCommandList); - m_pendingCommands->init(); - } - m_pendingCommands->reset(); - - if (m_relayedCommands == NULL) { - m_relayedCommands = newInstance(NetCommandList); - m_relayedCommands->init(); - } - m_relayedCommands->reset(); - - if (m_netCommandWrapperList == NULL) { - m_netCommandWrapperList = newInstance(NetCommandWrapperList); - m_netCommandWrapperList->init(); - } - m_netCommandWrapperList->reset(); - - m_localSlot = -1; -#ifdef MEMORYPOOL_DEBUG - TheMemoryPoolFactory->debugSetInitFillerIndex(m_localSlot); -#endif - m_packetRouterSlot = -1; - - for (i = 0; i < TheGlobalData->m_networkFPSHistoryLength; ++i) { - m_fpsAverages[i] = -1; - } - for (i = 0; i < TheGlobalData->m_networkLatencyHistoryLength; ++i) { - m_latencyAverages[i] = 0.0; - } - - for (i = 0; i < (UnsignedInt)MAX_SLOTS; ++i) { - m_packetRouterFallback[i] = -1; - } - - m_frameMetrics.reset(); -} - -UnsignedInt ConnectionManager::getPingFrame() -{ - return (m_disconnectManager)?m_disconnectManager->getPingFrame():0; -} - -Int ConnectionManager::getPingsSent() -{ - return (m_disconnectManager)?m_disconnectManager->getPingsSent():0; -} - -Int ConnectionManager::getPingsRecieved() -{ - return (m_disconnectManager)?m_disconnectManager->getPingsRecieved():0; -} - -Bool ConnectionManager::isPlayerConnected( Int playerID ) -{ - return ( playerID == m_localSlot || (m_connections[playerID] && !m_connections[playerID]->isQuitting()) ); -} - -void ConnectionManager::attachTransport(Transport *transport) { - delete m_transport; - m_transport = transport; -} - -/** - * zero out the command counts for the given frames. Presently this is used for - * the start of a game since there won't be any commands for the first few frames due to runahead. - */ -void ConnectionManager::zeroFrames(UnsignedInt startingFrame, UnsignedInt numFrames) { - for (Int i = 0; i < MAX_SLOTS; ++i) { - if (m_frameData[i] != NULL) { -// DEBUG_LOG(("Calling zeroFrames on player %d, starting frame %d, numFrames %d", i, startingFrame, numFrames)); - m_frameData[i]->zeroFrames(startingFrame, numFrames); - } - } -} - -/** - * Destroy any game messages that are left over due to the run ahead. - */ -void ConnectionManager::destroyGameMessages() { - for (Int i = 0; i < MAX_SLOTS; ++i) { - // Need to destroy these game messages because when the game ends, there are - // still some game messages left over because of the run ahead aspect of - // network play. - if (m_frameData[i] != NULL) { - m_frameData[i]->destroyGameMessages(); - } - } -} - -/** - * ConnectionManager::doRelay() - * Queries the transport for commands that need to be relayed to another client. - * Get those commands and relay them to the appropriate Connection(s). We make the - * assumption that a command will only be relayed once. - */ -void ConnectionManager::doRelay() { - static Int numPackets = 0; - static Int numCommands = 0; - - NetPacket *packet = NULL; - - for (Int i = 0; i < MAX_MESSAGES; ++i) { - if (m_transport->m_inBuffer[i].length != 0) { - // This transport buffer has yet to be processed. - - // make a NetPacket out of this data so it can be broken up into individual commands. - packet = newInstance(NetPacket)(&(m_transport->m_inBuffer[i])); - - //DEBUG_LOG(("ConnectionManager::doRelay() - got a packet with %d commands", packet->getNumCommands())); - //LOGBUFFER( packet->getData(), packet->getLength() ); - - // Get the command list from the packet. - NetCommandList *cmdList = packet->getCommandList(); - NetCommandRef *cmd = cmdList->getFirstMessage(); - - // Iterate through the commands in this packet and send them to the proper connections. - while (cmd != NULL) { - //DEBUG_LOG(("ConnectionManager::doRelay() - Looking at a command of type %s", - //GetNetCommandTypeAsString(cmd->getCommand()->getNetCommandType()))); - if (CommandRequiresAck(cmd->getCommand())) { - ackCommand(cmd, m_localSlot); - } - if (!processNetCommand(cmd)) { - sendRemoteCommand(cmd); - } - cmd = cmd->getNext(); - - ++numCommands; - } - ++numPackets; - - // Delete this packet since we won't be needing it anymore. - deleteInstance(packet); - packet = NULL; - - deleteInstance(cmdList); - cmdList = NULL; - - // signal that this has been processed. - m_transport->m_inBuffer[i].length = 0; - } - } - - NetCommandList *cmdList = m_netCommandWrapperList->getReadyCommands(); - NetCommandRef *cmd = cmdList->getFirstMessage(); - while (cmd != NULL) { - if (CommandRequiresAck(cmd->getCommand())) { - ackCommand(cmd, m_localSlot); - } - if (!processNetCommand(cmd)) { - sendRemoteCommand(cmd); - } - cmd = cmd->getNext(); - - ++numCommands; - } - ++numPackets; - - // Delete this packet since we won't be needing it anymore. - deleteInstance(packet); - packet = NULL; - - deleteInstance(cmdList); - cmdList = NULL; -} - -/** - * This is where the non-synchronized network commands should be processed. - * Return TRUE if the command should not be relayed. Return FALSE if it should be relayed. - */ -Bool ConnectionManager::processNetCommand(NetCommandRef *ref) { - NetCommandMsg *msg = ref->getCommand(); - - if ((msg->getNetCommandType() == NETCOMMANDTYPE_ACKSTAGE1) || - (msg->getNetCommandType() == NETCOMMANDTYPE_ACKSTAGE2) || - (msg->getNetCommandType() == NETCOMMANDTYPE_ACKBOTH)) { - - processAck(msg); - return FALSE; - } - - if ((m_connections[msg->getPlayerID()] == NULL) && (msg->getPlayerID() != m_localSlot)) { - // if this is from a player that is no longer in the game, then ignore them. - return TRUE; - } - - if (msg->getNetCommandType() == NETCOMMANDTYPE_WRAPPER) { - processWrapper(ref); // need to send the NetCommandRef since we have to construct the relay for the wrapped command. - return FALSE; - } - - if ((msg->getPlayerID() >= 0) && (msg->getPlayerID() < MAX_SLOTS) && (msg->getPlayerID() != m_localSlot)) { - if (m_connections[msg->getPlayerID()] == NULL) { - return TRUE; - } - } - - // Don't allow an out of date command to be sent through. - // Its unnecessary traffic and it could cause problems. - // - // This was a fix for a command count bug where a command would be - // executed, then a command for that old frame would be added to the - // FrameData for that frame + 256, and would screw up the command count. - - if (IsCommandSynchronized(msg->getNetCommandType())) { - if (ref->getCommand()->getExecutionFrame() < TheGameLogic->getFrame()) { - return TRUE; - } - } - - if (msg->getNetCommandType() == NETCOMMANDTYPE_FRAMEINFO) { - processFrameInfo((NetFrameCommandMsg *)msg); - - // need to set the relay so we don't send it to ourselves. - UnsignedByte relay = ref->getRelay(); - relay = relay & (0xff ^ (1 << m_localSlot)); - ref->setRelay(relay); - return FALSE; - } - - if (msg->getNetCommandType() == NETCOMMANDTYPE_PROGRESS) - { - //DEBUG_LOG(("ConnectionManager::processNetCommand - got a progress net command from player %d", msg->getPlayerID())); - processProgress((NetProgressCommandMsg *) msg); - - // need to set the relay so we don't send it to ourselves. - UnsignedByte relay = ref->getRelay(); - relay = relay & (0xff ^ (1 << m_localSlot)); - ref->setRelay(relay); - return FALSE; - } - - if (msg->getNetCommandType() == NETCOMMANDTYPE_TIMEOUTSTART) - { - DEBUG_LOG(("ConnectionManager::processNetCommand - got a TimeOut GameStart net command from player %d", msg->getPlayerID())); - processTimeOutGameStart(msg); - return FALSE; - } - - if (msg->getNetCommandType() == NETCOMMANDTYPE_RUNAHEADMETRICS) { - processRunAheadMetrics((NetRunAheadMetricsCommandMsg *)msg); - return TRUE; - } - - if (msg->getNetCommandType() == NETCOMMANDTYPE_KEEPALIVE) { - return TRUE; - } - - if ((msg->getNetCommandType() > NETCOMMANDTYPE_DISCONNECTSTART) && (msg->getNetCommandType() < NETCOMMANDTYPE_DISCONNECTEND)) { - m_disconnectManager->processDisconnectCommand(ref, this); - return TRUE; - } - - if (msg->getNetCommandType() == NETCOMMANDTYPE_DISCONNECTCHAT) { - processDisconnectChat((NetDisconnectChatCommandMsg *)msg); - } - - if (msg->getNetCommandType() == NETCOMMANDTYPE_LOADCOMPLETE) - { - DEBUG_LOG(("ConnectionManager::processNetCommand - got a Load Complete net command from player %d", msg->getPlayerID())); - processLoadComplete(msg); - return FALSE; - } - - if (msg->getNetCommandType() == NETCOMMANDTYPE_CHAT) { - processChat((NetChatCommandMsg *)msg); - return FALSE; - } - - if (msg->getNetCommandType() == NETCOMMANDTYPE_FILE) { - processFile((NetFileCommandMsg *)msg); - return FALSE; - } - - if (msg->getNetCommandType() == NETCOMMANDTYPE_FILEANNOUNCE) { - processFileAnnounce((NetFileAnnounceCommandMsg *)msg); - return FALSE; - } - - if (msg->getNetCommandType() == NETCOMMANDTYPE_FILEPROGRESS) { - processFileProgress((NetFileProgressCommandMsg *)msg); - return FALSE; - } - - if (msg->getNetCommandType() == NETCOMMANDTYPE_FRAMERESENDREQUEST) { - processFrameResendRequest((NetFrameResendRequestCommandMsg *)msg); - return TRUE; - } - - return FALSE; -} - -void ConnectionManager::processFrameResendRequest(NetFrameResendRequestCommandMsg *msg) { - // first make sure this is a valid slot - Int playerID = msg->getPlayerID(); - if ((playerID < 0) || (playerID >= MAX_SLOTS)) { - return; - } - - // make sure this player is still in our game. - if ((m_connections[playerID] == NULL) || (m_connections[playerID]->isQuitting() == TRUE)) { - return; - } - - sendFrameDataToPlayer(playerID, msg->getFrameToResend()); -} - -/** - * We have received a wrapper for a command too big to fit in a packet. - */ -void ConnectionManager::processWrapper(NetCommandRef *ref) -{ - NetWrapperCommandMsg *wrapperMsg = (NetWrapperCommandMsg *)(ref->getCommand()); - UnsignedShort commandID = wrapperMsg->getWrappedCommandID(); - DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("ConnectionManager::processWrapper() - wrapped commandID is %d, commandID is %d", - commandID, wrapperMsg->getID())); - Int origProgress = 0; - FileCommandMap::iterator fcIt = s_fileCommandMap.find(commandID); - if (fcIt != s_fileCommandMap.end()) - { - origProgress = s_fileProgressMap[m_localSlot][commandID]; - } - DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("ConnectionManager::processWrapper() - origProgress[%d] == %d for command %d", - m_localSlot, origProgress, commandID)); - - m_netCommandWrapperList->processWrapper(ref); - - if (fcIt != s_fileCommandMap.end()) - { - Int newProgress = m_netCommandWrapperList->getPercentComplete(commandID); - DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("ConnectionManager::processWrapper() - newProgress[%d] == %d for command %d", - m_localSlot, newProgress, commandID)); - if (newProgress > origProgress && newProgress < 100) - { - DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("ConnectionManager::processWrapper() - sending a NetFileProgressCommandMsg")); - s_fileProgressMap[m_localSlot][commandID] = newProgress; - - Int progressMask = 0xff ^ (1 << m_localSlot); - NetFileProgressCommandMsg *msg = newInstance(NetFileProgressCommandMsg); - msg->setPlayerID(m_localSlot); - msg->setID(0); - if (DoesCommandRequireACommandID(msg->getNetCommandType())) - { - msg->setID(GenerateNextCommandID()); - } - msg->setFileID(commandID); - msg->setProgress(newProgress); - sendLocalCommand(msg, progressMask); - processFileProgress(msg); - msg->detach(); - } - } -} - -/** - * A client has sent us their run ahead metrics, lets store them away for future calculations. - */ -void ConnectionManager::processRunAheadMetrics(NetRunAheadMetricsCommandMsg *msg) -{ - UnsignedInt player = msg->getPlayerID(); - if ((player >= 0) && (player < MAX_SLOTS) && (isPlayerConnected(player))) { - m_latencyAverages[player] = msg->getAverageLatency(); - m_fpsAverages[player] = msg->getAverageFps(); - //DEBUG_LOG(("ConnectionManager::processRunAheadMetrics - player %d, fps = %d, latency = %f", player, msg->getAverageFps(), msg->getAverageLatency())); - if (m_fpsAverages[player] > 100) { - // limit the reported frame rate average to 100. This is done because if a - // user alt-tab's out of the game their frame rate climbs to in the neighborhood of - // 300, that was deemed "ugly" by the powers that be. - m_fpsAverages[player] = 100; - } - } -} - -void ConnectionManager::processDisconnectChat(NetDisconnectChatCommandMsg *msg) -{ - UnicodeString unitext; - UnicodeString name; - UnsignedByte playerID = msg->getPlayerID(); - if (playerID == m_localSlot) { - name = m_localUser->GetName(); - } else if (isPlayerConnected(playerID)) { - name = m_connections[playerID]->getUser()->GetName(); - } - unitext.format(L"[%ls] %ls", name.str(), msg->getText().str()); -// DEBUG_LOG(("ConnectionManager::processDisconnectChat - got message from player %d, message is %ls", playerID, unitext.str())); - TheDisconnectMenu->showChat(unitext); // <-- need to implement this -} - -void ConnectionManager::processChat(NetChatCommandMsg *msg) -{ - UnicodeString unitext; - UnicodeString name; - UnsignedByte playerID = msg->getPlayerID(); - //DEBUG_LOG(("processChat(): playerID = %d", playerID)); - if (playerID == m_localSlot) { - name = m_localUser->GetName(); - //DEBUG_LOG(("connection is NULL, using %ls", name.str())); - } else if (((m_connections[playerID] != NULL) && (m_connections[playerID]->isQuitting() == FALSE))) { - name = m_connections[playerID]->getUser()->GetName(); - //DEBUG_LOG(("connection is non-NULL, using %ls", name.str())); - } - unitext.format(L"[%ls] %ls", name.str(), msg->getText().str()); -// DEBUG_LOG(("ConnectionManager::processChat - got message from player %d (mask %8.8X), message is %ls", playerID, msg->getPlayerMask(), unitext.str())); - - AsciiString playerName; - playerName.format("player%d", msg->getPlayerID()); - const Player *player = ThePlayerList->findPlayerWithNameKey( TheNameKeyGenerator->nameToKey( playerName ) ); - if (!player) - { - TheInGameUI->message(UnicodeString(L"%ls"), unitext.str()); - return; - } - - Bool fromObserver = !player->isPlayerActive(); - Bool amIObserver = !ThePlayerList->getLocalPlayer()->isPlayerActive(); - Bool canSeeChat = (amIObserver || !fromObserver) && !TheGameInfo->getConstSlot(playerID)->isMuted(); - - if ( ((1<getPlayerMask() ) && canSeeChat ) - { - RGBColor rgb; - rgb.setFromInt(player->getPlayerColor()); - TheInGameUI->messageColor(&rgb, UnicodeString(L"%ls"), unitext.str()); - - // feedback for received chat messages in-game - AudioEventRTS audioEvent("GUICommunicatorIncoming"); - TheAudio->addAudioEvent(&audioEvent); - } -} - -void ConnectionManager::processFile(NetFileCommandMsg *msg) -{ -#ifdef DEBUG_LOGGING - UnicodeString log; - log.format(L"Saw file transfer: '%hs' of %d bytes from %d", msg->getPortableFilename().str(), msg->getFileLength(), msg->getPlayerID()); - DEBUG_LOG(("%ls", log.str())); -#endif - - AsciiString realFileName = msg->getRealFilename(); - if (realFileName.isEmpty()) - { - // TheSuperHackers @security slurmlord 18/06/2025 As the file name/path from the NetFileCommandMsg failed to normalize, - // in other words is bogus and points outside of the approved target directory, avoid an arbitrary file overwrite vulnerability - // by simply returning and let the transfer time out. - DEBUG_LOG(("Got a file name transferred that failed to normalize: '%s'!", msg->getPortableFilename().str())); - return; - } - - if (TheFileSystem->doesFileExist(realFileName.str())) - { - DEBUG_LOG(("File exists already!")); - //return; - } - - UnsignedByte *buf = msg->getFileData(); - Int len = msg->getFileLength(); - - // uncompress Targas -#ifdef COMPRESS_TARGAS - Bool deleteBuf = FALSE; - if (msg->getFilename().endsWith(".tga") && CompressionManager::isDataCompressed(buf, len)) - { - Int uncompLen = CompressionManager::getUncompressedSize(buf, len); - UnsignedByte *uncompBuffer = NEW UnsignedByte[uncompLen]; - Int actualLen = CompressionManager::decompressData(buf, len, uncompBuffer, uncompLen); - if (actualLen == uncompLen) - { - DEBUG_LOG(("Uncompressed Targa after map transfer")); - deleteBuf = TRUE; - buf = uncompBuffer; - len = uncompLen; - } - else - { - DEBUG_LOG(("Failed to uncompress Targa after map transfer")); - delete[] uncompBuffer; // failed to decompress, so just use the source - } - } -#endif // COMPRESS_TARGAS - - File *fp = TheFileSystem->openFile(realFileName.str(), File::CREATE | File::BINARY | File::WRITE); - if (fp) - { - fp->write(buf, len); - fp->close(); - fp = NULL; - DEBUG_LOG(("Wrote %d bytes to file %s!", len, realFileName.str())); - - } - else - { - DEBUG_LOG(("Cannot open file!")); - } - - DEBUG_LOG(("ConnectionManager::processFile() - sending a NetFileProgressCommandMsg")); - - Int commandID = msg->getID(); - Int newProgress = 100; - - s_fileProgressMap[m_localSlot][commandID] = newProgress; - - Int progressMask = 0xff ^ (1 << m_localSlot); - NetFileProgressCommandMsg *progressMsg = newInstance(NetFileProgressCommandMsg); - progressMsg->setPlayerID(m_localSlot); - progressMsg->setID(0); - if (DoesCommandRequireACommandID(progressMsg->getNetCommandType())) - { - progressMsg->setID(GenerateNextCommandID()); - } - progressMsg->setFileID(commandID); - progressMsg->setProgress(newProgress); - sendLocalCommand(progressMsg, progressMask); - processFileProgress(progressMsg); - progressMsg->detach(); - -#ifdef COMPRESS_TARGAS - if (deleteBuf) - { - delete[] buf; - buf = NULL; - } -#endif // COMPRESS_TARGAS -} - -void ConnectionManager::processFileAnnounce(NetFileAnnounceCommandMsg *msg) -{ - DEBUG_LOG(("ConnectionManager::processFileAnnounce() - expecting '%s' (%s) in command %d", msg->getPortableFilename().str(), msg->getRealFilename().str(), msg->getFileID())); - s_fileCommandMap[msg->getFileID()] = msg->getRealFilename(); - s_fileRecipientMaskMap[msg->getFileID()] = msg->getPlayerMask(); - for (Int i=0; igetPlayerMask() ) - { - s_fileProgressMap[i][msg->getFileID()] = 0; - } - else - { - s_fileProgressMap[i][msg->getFileID()] = 100; // they don't need to get it, so they're already done. - } - } -} - -void ConnectionManager::processFileProgress(NetFileProgressCommandMsg *msg) -{ - DEBUG_LOG(("ConnectionManager::processFileProgress() - command %d is at %d%%", - msg->getFileID(), msg->getProgress())); - Int oldProgress = s_fileProgressMap[msg->getPlayerID()][msg->getFileID()]; - - s_fileProgressMap[msg->getPlayerID()][msg->getFileID()] = max(oldProgress, msg->getProgress()); -} - -void ConnectionManager::processProgress( NetProgressCommandMsg *msg ) -{ - TheGameLogic->processProgress(msg->getPlayerID(), msg->getPercentage()); -} - -void ConnectionManager::processLoadComplete( NetCommandMsg *msg ) -{ - TheGameLogic->processProgressComplete(msg->getPlayerID()); -} - -void ConnectionManager::processTimeOutGameStart( NetCommandMsg *msg ) -{ - TheGameLogic->timeOutGameStart(); -} - -/** - * Another client has sent us the command count for a new frame. - */ -void ConnectionManager::processFrameInfo(NetFrameCommandMsg *msg) { - //stupid frame info, why don't you process yourself? - - UnsignedInt playerID = msg->getPlayerID(); - - if ((playerID >= 0) && (playerID < MAX_SLOTS)) { - if (m_frameData[playerID] != NULL) { -// DEBUG_LOG(("ConnectionManager::processFrameInfo - player %d, frame %d, command count %d, received on frame %d", playerID, msg->getExecutionFrame(), msg->getCommandCount(), TheGameLogic->getFrame())); - m_frameData[playerID]->setFrameCommandCount(msg->getExecutionFrame(), msg->getCommandCount()); - } - } -} - -/** - * We just got a stage 1 ack from someone. So we should remove it from the connection that sent it so - * it doesn't keep resending it. - */ -void ConnectionManager::processAckStage1(NetCommandMsg *msg) { -#if defined(RTS_DEBUG) - Bool doDebug = (msg->getNetCommandType() == NETCOMMANDTYPE_DISCONNECTFRAME) ? TRUE : FALSE; -#endif - - UnsignedByte playerID = msg->getPlayerID(); - NetCommandRef *ref = NULL; - -#if defined(RTS_DEBUG) - if (doDebug == TRUE) { - DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("ConnectionManager::processAck - processing ack for command %d from player %d", ((NetAckStage1CommandMsg *)msg)->getCommandID(), playerID)); - } -#endif - - if ((playerID >= 0) && (playerID < NUM_CONNECTIONS)) { - if (m_connections[playerID] != NULL) { - ref = m_connections[playerID]->processAck(msg); - } - } else { - DEBUG_ASSERTCRASH((playerID >= 0) && (playerID < NUM_CONNECTIONS), ("ConnectionManager::processAck - %d is an invalid player number", playerID)); - } - - if (ref != NULL) { - if (ref->getCommand()->getNetCommandType() == NETCOMMANDTYPE_FRAMEINFO) { - m_frameMetrics.processLatencyResponse(((NetFrameCommandMsg *)(ref->getCommand()))->getExecutionFrame()); - } - - deleteInstance(ref); - ref = NULL; - } -} - -/** - * We just got a stage 2 ack from someone. So remove it from the pending commands list so it doesn't - * get sent in the case of a new packet router. - */ -void ConnectionManager::processAckStage2(NetCommandMsg *msg) { - UnsignedShort commandID = 0; - UnsignedByte playerID = 0; - if (msg->getNetCommandType() == NETCOMMANDTYPE_ACKSTAGE2) { - commandID = ((NetAckStage2CommandMsg *)msg)->getCommandID(); - playerID = ((NetAckStage2CommandMsg *)msg)->getOriginalPlayerID(); - } else if (msg->getNetCommandType() == NETCOMMANDTYPE_ACKBOTH) { - commandID = ((NetAckBothCommandMsg *)msg)->getCommandID(); - playerID = ((NetAckBothCommandMsg *)msg)->getOriginalPlayerID(); - } else { - return; - } - - NetCommandRef *ref = m_pendingCommands->findMessage(commandID, playerID); - if (ref != NULL) { - //DEBUG_LOG(("ConnectionManager::processAckStage2 - removing command %d from the pending commands list.", commandID)); - DEBUG_ASSERTCRASH((m_localSlot == playerID), ("Found a command in the pending commands list that wasn't originated by the local player")); - m_pendingCommands->removeMessage(ref); - deleteInstance(ref); - ref = NULL; - } else { - //DEBUG_LOG(("ConnectionManager::processAckStage2 - Couldn't find command %d from player %d in the pending commands list.", commandID, playerID)); - } - - ref = m_relayedCommands->findMessage(commandID, playerID); - if (ref != NULL) { - //DEBUG_LOG(("ConnectionManager::processAckStage2 - found command ID %d from player %d in the relayed commands list.", commandID, playerID)); - UnsignedByte prevRelay = ref->getRelay(); - UnsignedByte relay = prevRelay & ~(1 << msg->getPlayerID()); - //DEBUG_LOG(("ConnectionManager::processAckStage2 - relay was %d and is now %d", relay, prevRelay)); - if (relay == 0) { - //DEBUG_LOG(("ConnectionManager::processAckStage2 - relay is 0, removing command from the relayed commands list.")); - m_relayedCommands->removeMessage(ref); - NetAckStage2CommandMsg *ackmsg = newInstance(NetAckStage2CommandMsg)(ref->getCommand()); - sendLocalCommand(ackmsg, 1 << ackmsg->getOriginalPlayerID()); - deleteInstance(ref); - ref = NULL; - - ackmsg->detach(); - ackmsg = NULL; - } else { - ref->setRelay(relay); - } - } -} - -/** - * We just got a "both" ack from someone. So process it as both a stage 1 and stage 2 ack. - */ -void ConnectionManager::processAck(NetCommandMsg *msg) { - if ((msg->getNetCommandType() == NETCOMMANDTYPE_ACKSTAGE1) || (msg->getNetCommandType() == NETCOMMANDTYPE_ACKBOTH)) { - processAckStage1(msg); - } - if ((msg->getNetCommandType() == NETCOMMANDTYPE_ACKSTAGE2) || (msg->getNetCommandType() == NETCOMMANDTYPE_ACKBOTH)) { - processAckStage2(msg); - } -} - -/** - * A player has just left our game. Delete their connection and frame data manager. - * return codes are: - * PLAYERLEAVECODE_UNKNOWN - player didn't have a valid slot number. - * PLAYERLEAVECODE_CLIENT - someone in the game that wasn't us or the packet router. - * PLAYERLEAVECODE_LOCAL - We are leaving the game, we could also be the packet router. - * PLAYERLEAVECODE_PACKETROUTER - The packet router left the game. - * - * If we are leaving and are also the packet router, it will return the PLAYERLEAVECODE_LOCAL return code. - */ -PlayerLeaveCode ConnectionManager::processPlayerLeave(NetPlayerLeaveCommandMsg *msg) { - UnsignedByte playerID = msg->getLeavingPlayerID(); - if ((playerID != m_localSlot) && (m_connections[playerID] != NULL)) { - DEBUG_LOG(("ConnectionManager::processPlayerLeave() - setQuitting() on player %d on frame %d", playerID, TheGameLogic->getFrame())); - m_connections[playerID]->setQuitting(); - } - DEBUG_ASSERTCRASH(m_frameData[playerID]->getIsQuitting() == FALSE, ("Player %d is already quitting", playerID)); - if ((playerID != m_localSlot) && (m_frameData[playerID] != NULL) && (m_frameData[playerID]->getIsQuitting() == FALSE)) { - DEBUG_LOG(("ConnectionManager::processPlayerLeave - setQuitFrame on player %d for frame %d", playerID, TheGameLogic->getFrame()+1)); - m_frameData[playerID]->setQuitFrame(TheGameLogic->getFrame() + FRAMES_TO_KEEP + 1); - } - - if (playerID == m_localSlot) - { - // we're leaving, so mark our connections and frame datas to go away. - for (Int i=0; iclearCommandsExceptFrom(m_localSlot); - m_connections[i]->setQuitting(); - } - } - } - - PlayerLeaveCode code = disconnectPlayer(playerID); - DEBUG_LOG(("ConnectionManager::processPlayerLeave() - just disconnected player %d with ret code %d", playerID, code)); - if (code == PLAYERLEAVECODE_PACKETROUTER) - resendPendingCommands(); - - PopulateInGameDiplomacyPopup(); - return code; -} - -UnsignedInt ConnectionManager::getPacketRouterFallbackSlot(Int packetRouterNumber) { - if ((packetRouterNumber >= 0) && (packetRouterNumber < MAX_SLOTS)) { - return m_packetRouterFallback[packetRouterNumber]; - } - return MAX_SLOTS; -} - -UnsignedInt ConnectionManager::getPacketRouterSlot() { - return m_packetRouterSlot; -} - -Bool ConnectionManager::areAllQueuesEmpty(void) { - Bool retval = TRUE; - for (Int i = 0; (i < MAX_SLOTS) && retval; ++i) { - if (m_connections[i] != NULL) { - if (m_connections[i]->isQueueEmpty() == FALSE) { - //DEBUG_LOG(("ConnectionManager::areAllQueuesEmpty() - m_connections[%d] is not empty", i)); - //m_connections[i]->debugPrintCommands(); - retval = FALSE; - } - } - } - - return retval; -} - -Bool ConnectionManager::canILeave() { - return areAllQueuesEmpty(); -} - -/** - * The local player is leaving. Tell the local player as well as the other players - * to remove this player at the specified frame. - */ -void ConnectionManager::handleLocalPlayerLeaving(UnsignedInt frame) { - NetPlayerLeaveCommandMsg *msg = newInstance(NetPlayerLeaveCommandMsg); - - msg->setLeavingPlayerID(m_localSlot); - msg->setExecutionFrame(frame); - if (DoesCommandRequireACommandID(msg->getNetCommandType())) { - msg->setID(GenerateNextCommandID()); - } - msg->setPlayerID(m_localSlot); - - DEBUG_LOG(("ConnectionManager::handleLocalPlayerLeaving - Local player leaving on frame %d", frame)); - DEBUG_ASSERTCRASH(m_packetRouterSlot >= 0, ("ConnectionManager::handleLocalPlayerLeaving, packet router is %d, illegal value.", m_packetRouterSlot)); - - sendLocalCommand(msg); - - msg->detach(); -} - -/** - * We just got a message that needs to be ack'd, so ack it! - */ -void ConnectionManager::ackCommand(NetCommandRef *ref, UnsignedInt localSlot) { - NetCommandMsg *msg = ref->getCommand(); - NetCommandMsg *ackmsg; - UnsignedShort commandID; - UnsignedByte originalPlayerID; - UnsignedByte sendRelay = 0; - - // Make send relay a bitmask for the connections that the relay will actually be sent to. This is - // necessary to determine whether or not we have to wait to send a stage 2 ack. - for (Int i = 0; i < MAX_SLOTS; ++i) { - if (((m_connections[i] != NULL) && (m_connections[i]->isQuitting() == FALSE))) { - sendRelay = sendRelay | (1 << i); - } - } - -#if defined(RTS_DEBUG) - Bool doDebug = (msg->getNetCommandType() == NETCOMMANDTYPE_DISCONNECTFRAME) ? TRUE : FALSE; -#endif - - sendRelay = sendRelay & ref->getRelay(); - if (sendRelay == 0) { - NetAckBothCommandMsg *bothmsg = newInstance(NetAckBothCommandMsg)(ref->getCommand()); - ackmsg = bothmsg; - commandID = bothmsg->getCommandID(); - originalPlayerID = bothmsg->getOriginalPlayerID(); -#if defined(RTS_DEBUG) - if (doDebug) { - DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("ConnectionManager::ackCommand - doing ack both for command %d from player %d", bothmsg->getCommandID(), bothmsg->getOriginalPlayerID())); - } -#endif - } else { - NetAckStage1CommandMsg *stage1msg = newInstance(NetAckStage1CommandMsg)(ref->getCommand()); - ackmsg = stage1msg; - commandID = stage1msg->getCommandID(); - originalPlayerID = stage1msg->getOriginalPlayerID(); -#if defined(RTS_DEBUG) - if (doDebug) { - DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("ConnectionManager::ackCommand - doing ack stage 1 for command %d from player %d", stage1msg->getCommandID(), stage1msg->getOriginalPlayerID())); - } -#endif - } - - ackmsg->setPlayerID(localSlot); // Tell the player who this ack is coming from. - - if (CommandRequiresDirectSend(msg) && CommandRequiresAck(msg)) { - // Send this ack directly back to the sending player, don't go through the packet router. - if ((msg->getPlayerID() >= 0) && (msg->getPlayerID() < MAX_SLOTS)) { - if (m_connections[msg->getPlayerID()] != NULL) { - m_connections[msg->getPlayerID()]->sendNetCommandMsg(ackmsg, 1 << msg->getPlayerID()); - } - } - } else { - // The local connection may be the packet router, in that case, the connection would be NULL. So do something about it! - if ((m_packetRouterSlot >= 0) && (m_packetRouterSlot < MAX_SLOTS)) { - if (m_connections[m_packetRouterSlot] != NULL) { -// DEBUG_LOG(("ConnectionManager::ackCommand - acking command %d from player %d to packet router.", commandID, m_packetRouterSlot)); - m_connections[m_packetRouterSlot]->sendNetCommandMsg(ackmsg, 1 << m_packetRouterSlot); - } else if (m_localSlot == m_packetRouterSlot) { - // we are the packet router, send the ack to the player that sent the command. - if ((msg->getPlayerID() >= 0) && (msg->getPlayerID() < MAX_SLOTS)) { - if (m_connections[msg->getPlayerID()] != NULL) { -// DEBUG_LOG(("ConnectionManager::ackCommand - acking command %d from player %d directly to player.", commandID, msg->getPlayerID())); - m_connections[msg->getPlayerID()]->sendNetCommandMsg(ackmsg, 1 << msg->getPlayerID()); - } else { - // DEBUG_ASSERTCRASH(m_connections[msg->getPlayerID()] != NULL, ("Connection to player is NULL")); - } - } else { - DEBUG_ASSERTCRASH((msg->getPlayerID() >= 0) && (msg->getPlayerID() < MAX_SLOTS), ("Command sent by an invalid player ID.")); - } - } else { - DEBUG_ASSERTCRASH(m_connections[m_packetRouterSlot] != NULL, ("Connection to packet router is NULL")); - } - } else { - DEBUG_ASSERTCRASH((m_packetRouterSlot >= 0) && (m_packetRouterSlot < MAX_SLOTS), ("I don't know who the packet router is.")); - } - } - - ackmsg->detach(); -} - -/** - * This is where we relay a command from one client to others (including ourselves). - * This should only be done by the current packet router. - */ -void ConnectionManager::sendRemoteCommand(NetCommandRef *msg) { - UnsignedByte actualRelay = 0; - if (msg->getCommand() == NULL) { - return; - } - - DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("ConnectionManager::sendRemoteCommand - sending net command %d of type %s from player %d, relay is 0x%x", - msg->getCommand()->getID(), GetNetCommandTypeAsString(msg->getCommand()->getNetCommandType()), msg->getCommand()->getPlayerID(), msg->getRelay())); - - UnsignedByte relay = msg->getRelay(); - if ((relay & (1 << m_localSlot)) && (m_frameData[msg->getCommand()->getPlayerID()] != NULL)) { - if (IsCommandSynchronized(msg->getCommand()->getNetCommandType())) { - DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("ConnectionManager::sendRemoteCommand - adding net command of type %s to player %d for frame %d", GetNetCommandTypeAsString(msg->getCommand()->getNetCommandType()), msg->getCommand()->getPlayerID(), msg->getCommand()->getExecutionFrame())); - m_frameData[msg->getCommand()->getPlayerID()]->addNetCommandMsg(msg->getCommand()); - } - } - - for (Int i = 0; i < MAX_SLOTS; ++i) { - if ((relay & (1 << i)) && ((m_connections[i] != NULL) && (m_connections[i]->isQuitting() == FALSE))) { - DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("ConnectionManager::sendRemoteCommand - relaying command %d to player %d", msg->getCommand()->getID(), i)); - m_connections[i]->sendNetCommandMsg(msg->getCommand(), 1 << i); - actualRelay = actualRelay | (1 << i); - } - } - - if ((actualRelay != 0) && (CommandRequiresAck(msg->getCommand()) == TRUE)) { - NetCommandRef *ref = m_relayedCommands->addMessage(msg->getCommand()); - if (ref != NULL) { - ref->setRelay(actualRelay); - //DEBUG_LOG(("ConnectionManager::sendRemoteCommand - command %d added to relayed commands with relay %d", msg->getCommand()->getID(), ref->getRelay())); - } - } - - // Do some metrics to find the minimum packet arrival cushion. - if (IsCommandSynchronized(msg->getCommand()->getNetCommandType())) { -// DEBUG_LOG(("ConnectionManager::sendRemoteCommand - about to call allCommandsReady")); - if (allCommandsReady(msg->getCommand()->getExecutionFrame(), TRUE)) { - UnsignedInt cushion = msg->getCommand()->getExecutionFrame() - TheGameLogic->getFrame(); - if ((cushion < m_smallestPacketArrivalCushion) || (m_smallestPacketArrivalCushion == -1)) { - m_smallestPacketArrivalCushion = cushion; - } - m_frameMetrics.addCushion(cushion); -// DEBUG_LOG(("Adding %d to cushion for frame %d", cushion, msg->getCommand()->getExecutionFrame())); - } - } -} - -/** - * ConnectionManager::update - * Update the connections. Tell them to do the receive and send. Also relay - * commands to their final destinations as necessary. - */ -void ConnectionManager::update(Bool isInGame) { -// -// 1. do this -// 2. do that -// 3. do something else -// 4. blow something up -// 5. bust some cap -// - - if ((m_localAddr == 0) || (m_localPort == 0)) { - // we don't have a local address or port yet, this is bad. - DEBUG_ASSERTCRASH((m_localAddr != 0) && (m_localPort != 0), ("ConnectionManager doesn't have a local address.")); - return; - } - - m_transport->doRecv(); - - if (isInGame) { - m_disconnectManager->update(this); - } - - // take the packets from the transport, break them up into commands, and give them to the appropriate connections. - doRelay(); - - // send any necessary keep-alive packets. - doKeepAlive(); - - for (Int i = 0; i < NUM_CONNECTIONS; ++i) { - if (m_connections[i] != NULL) { - /* - if (m_connections[i]->isQueueEmpty() == FALSE) { -// DEBUG_LOG(("ConnectionManager::update - calling doSend on connection %d", i)); - } - */ - - m_connections[i]->doSend(); - - if (m_connections[i]->isQuitting() && m_connections[i]->isQueueEmpty()) - { - DEBUG_LOG(("ConnectionManager::update - deleting connection for slot %d", i)); - deleteInstance(m_connections[i]); - m_connections[i] = NULL; - } - } - - if ((m_frameData[i] != NULL) && (m_frameData[i]->getIsQuitting() == TRUE)) { - if (m_frameData[i]->getQuitFrame() == TheGameLogic->getFrame()) { - DEBUG_LOG(("ConnectionManager::update - deleting frame data for slot %d on quitting frame %d", i, m_frameData[i]->getQuitFrame())); - deleteInstance(m_frameData[i]); - m_frameData[i] = NULL; - } - } - } - - m_transport->doSend(); -} - -void ConnectionManager::updateRunAhead(Int oldRunAhead, Int frameRate, Bool didSelfSlug, Int nextExecutionFrame) { - static time_t lasttimesent = 0; - time_t curTime = timeGetTime(); - - if ((lasttimesent == 0) || ((curTime - lasttimesent) > TheGlobalData->m_networkRunAheadMetricsTime)) { - if (m_localSlot == m_packetRouterSlot) { - // We are the packet router, time to compute a new run ahead for this game. - m_latencyAverages[m_localSlot] = m_frameMetrics.getAverageLatency(); - - // since we are now using the display frame rate rather than the logic frame rate to get our average FPS, - // it doesn't make sense to send the desired logic frame rate if we "slugged" ourself. -// if (didSelfSlug) { -// m_fpsAverages[m_localSlot] = frameRate; -// } else { - m_fpsAverages[m_localSlot] = m_frameMetrics.getAverageFPS(); -// } - if (didSelfSlug) { - //DEBUG_LOG(("ConnectionManager::updateRunAhead - local player run ahead metrics, fps = %d, actual fps = %d, latency = %f, didSelfSlug = true", m_fpsAverages[m_localSlot], m_frameMetrics.getAverageFPS(), m_latencyAverages[m_localSlot])); - } else { - //DEBUG_LOG(("ConnectionManager::updateRunAhead - local player run ahead metrics, fps = %d, latency = %f, didSelfSlug = false", m_fpsAverages[m_localSlot], m_latencyAverages[m_localSlot])); - } - Int minFps; - Int minFpsPlayer; - getMinimumFps(minFps, minFpsPlayer); - DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("ConnectionManager::updateRunAhead - max latency = %f, min fps = %d, min fps player = %d old FPS = %d", getMaximumLatency(), minFps, minFpsPlayer, frameRate)); - if ((minFps >= ((frameRate * 9) / 10)) && (minFps < frameRate)) { - // if the minimum fps is within 10% of the desired framerate, then keep the current minimum fps. - minFps = frameRate; - } - - // TheSuperHackers @info this clamps the logic time scale fps in network games - minFps = clamp(MIN_LOGIC_FRAMES, minFps, TheGlobalData->m_framesPerSecondLimit); - DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("ConnectionManager::updateRunAhead - minFps after adjustment is %d", minFps)); - - // TheSuperHackers @bugfix Mauller 21/08/2025 calculate the runahead so it always follows the latency - // The runahead should always be rounded up to the next integer value to prevent variations in latency from causing stutter - // The network slack pushes the runahead up to the next value when the latency is within the slack percentage of the current runahead - const Real runAheadSlackScale = 1.0f + ( (Real)TheGlobalData->m_networkRunAheadSlack / 100.0f ); - Int newRunAhead = ceilf( getMaximumLatency() * runAheadSlackScale * (Real)minFps ); - - // TheSuperHackers @info if the runahead goes below 3 logic frames it can start to introduce stutter - // We also limit the upper range of the runahead to prevent it getting out of hand - newRunAhead = clamp(MIN_RUNAHEAD, newRunAhead, MAX_FRAMES_AHEAD / 2); - - NetRunAheadCommandMsg *msg = newInstance(NetRunAheadCommandMsg); - msg->setPlayerID(m_localSlot); - if (DoesCommandRequireACommandID(msg->getNetCommandType())) { - msg->setID(GenerateNextCommandID()); - } - - // needs to be set to the greater of getExecutionFrame and TheGameLogic->getFrame() + oldRunAhead - // This prevents the case of... - // run ahead starts at 30 - // run ahead changes to 10 at frame 31 (the command was created on frame 1) - // run ahead changes to 10 at frame 56 (the command was created on frame 46) - // notice that 56 is within the previous run ahead of 30 which has triggered - // the frame command count being set for frames 1 through 60 since run ahead - // didn't change for the first time till frame 31. This creates an extra command - // for frame 56 that isn't accounted for in the frame command count that is sent - // out in the NetFrameCommandMsg. sheesh. - if (nextExecutionFrame > (TheGameLogic->getFrame() + oldRunAhead)) { - msg->setExecutionFrame(nextExecutionFrame); - } else { - msg->setExecutionFrame(TheGameLogic->getFrame() + oldRunAhead); - } - - msg->setRunAhead(newRunAhead); - msg->setFrameRate(minFps); - //DEBUG_LOG(("ConnectionManager::updateRunAhead - new run ahead = %d, new frame rate = %d, execution frame %d", newRunAhead, minFps, msg->getExecutionFrame())); - sendLocalCommand(msg, 0xff ^ (1 << minFpsPlayer)); // Send the packet to everyone but the lowest FPS player. - - NetRunAheadCommandMsg *msg2 = newInstance(NetRunAheadCommandMsg); - msg2->setPlayerID(m_localSlot); - if (DoesCommandRequireACommandID(msg2->getNetCommandType())) { - /* - * Ok there needs to be a big friggin comment about this change... - * What happens is that the two run ahead commands get sent to different players - * using different command ID's. So player 1 has the run ahead command as command x - * and player 2 has the command as command x+1. This is all good except when it comes - * to players being disconnected. With the new disconnect scheme player 1 could potentially - * send his run ahead command to player 2 (or the other way around) to let player 2 catch - * up to him. So if player 2 has his run ahead command as x+1 and now he gets player 1's - * command list with the run ahead command listed as command x, he won't see them as being - * the same command and will now think he has two different run ahead commands for that frame - * and thus his command list will have an extra command and he will never be able to recover. - * So to fix this we have to use the same command ID for both run ahead commands. That way - * when the commands are copied places for the disconnect screen they will be seen as the - * same command, and all will be good. - */ -// msg2->setID(GenerateNextCommandID()); - msg2->setID(msg->getID()); - } - if (nextExecutionFrame > (TheGameLogic->getFrame() + oldRunAhead)) { - msg2->setExecutionFrame(nextExecutionFrame); - } else { - msg2->setExecutionFrame(TheGameLogic->getFrame() + oldRunAhead); - } - - // Let the player with the slowest FPS run a little faster than the other computers... - // just in case they are able to. Then we might be able to run the game faster which would be good. - Int newMinFps = (minFps * 11) / 10; - if (newMinFps == minFps) { - newMinFps = minFps + 1; - } - if (newMinFps > 30) { - newMinFps = 30; // Cap FPS to 30. - } - msg2->setRunAhead(newRunAhead); - msg2->setFrameRate(newMinFps); - - sendLocalCommand(msg2, 1 << minFpsPlayer); - - msg->detach(); - msg2->detach(); - } else { - // We are not the packet router, send our metrics info to the packet router. - NetRunAheadMetricsCommandMsg *msg = newInstance(NetRunAheadMetricsCommandMsg); - msg->setPlayerID(m_localSlot); - if (DoesCommandRequireACommandID(msg->getNetCommandType())) { - msg->setID(GenerateNextCommandID()); - } - msg->setAverageLatency(m_frameMetrics.getAverageLatency()); - - // see above for explanation. -// if (didSelfSlug) { -// msg->setAverageFps(frameRate); -// } else { - msg->setAverageFps(m_frameMetrics.getAverageFPS()); -// } - if (didSelfSlug) { - //DEBUG_LOG(("ConnectionManager::updateRunAhead - average latency = %f, average fps = %d, actual fps = %d, didSelfSlug = true", m_frameMetrics.getAverageLatency(), m_frameMetrics.getAverageFPS(), m_frameMetrics.getAverageFPS())); - } else { - //DEBUG_LOG(("ConnectionManager::updateRunAhead - average latency = %f, average fps = %d, didSelfSlug = false", m_frameMetrics.getAverageLatency(), m_frameMetrics.getAverageFPS())); - } - m_connections[m_packetRouterSlot]->sendNetCommandMsg(msg, 1 << m_packetRouterSlot); - msg->detach(); - } - lasttimesent = curTime; - } -} - -Real ConnectionManager::getMaximumLatency() { - Real maxLatency = 0.0f; - - for (Int i = 0; i < MAX_SLOTS; ++i) { - if (isPlayerConnected(i) && m_latencyAverages[i] > maxLatency) { - maxLatency = m_latencyAverages[i]; - } - } - - return maxLatency; -} - -void ConnectionManager::getMinimumFps(Int &minFps, Int &minFpsPlayer) { - minFps = -1; - minFpsPlayer = -1; -// DEBUG_LOG_RAW(("ConnectionManager::getMinimumFps -")); - for (Int i = 0; i < MAX_SLOTS; ++i) { - if ((m_connections[i] != NULL) || (i == m_localSlot)) { -// DEBUG_LOG_RAW((" %d: %d,", i, m_fpsAverages[i])); - if (m_fpsAverages[i] != -1) { - if ((minFps == -1) || (m_fpsAverages[i] < minFps)) { - minFps = m_fpsAverages[i]; - minFpsPlayer = i; - } - } - } - } -// DEBUG_LOG_RAW(("\n")); -} - -UnsignedInt ConnectionManager::getMinimumCushion() { - return m_frameMetrics.getMinimumCushion(); -} - -/** - * The commands for the given frame are all ready, time to send out our command count for that frame. - */ -void ConnectionManager::processFrameTick(UnsignedInt frame) { - if ((m_frameData[m_localSlot] == NULL) || (m_frameData[m_localSlot]->getIsQuitting() == TRUE)) { - // if the local frame data stuff is NULL, we must be leaving the game. - return; - } - UnsignedShort commandCount = m_frameData[m_localSlot]->getCommandCount(frame); - NetFrameCommandMsg *msg = newInstance(NetFrameCommandMsg); - msg->setExecutionFrame(frame); - msg->setCommandCount(commandCount); - if (DoesCommandRequireACommandID(msg->getNetCommandType())) { - msg->setID(GenerateNextCommandID()); - } - msg->setPlayerID(m_localSlot); - - m_frameMetrics.doPerFrameMetrics(frame); - - DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("ConnectionManager::processFrameTick - sending frame info for frame %d, ID %d, command count %d", frame, msg->getID(), commandCount)); - - sendLocalCommand(msg, 0xff & ~(1 << m_localSlot)); - - msg->detach(); -} - -/** - * Set the local address. - */ -void ConnectionManager::setLocalAddress(UnsignedInt ip, UnsignedInt port) { - DEBUG_LOG(("ConnectionManager::setLocalAddress() - local address is %X:%d", ip, port)); - m_localAddr = ip; - m_localPort = port; -} - -/** - * Initialize the transport object - */ -void ConnectionManager::initTransport() { - DEBUG_ASSERTCRASH((m_transport == NULL), ("m_transport already exists when trying to init it.")); - DEBUG_LOG(("ConnectionManager::initTransport - Initializing Transport")); - - delete m_transport; - m_transport = new Transport; - m_transport->reset(); - m_transport->init(m_localAddr, m_localPort); -} - -/** - * This is where the commands from the local client are sent to the other clients in - * the game. This is also where the local commands are put into the frame data for - * future execution. - */ -void ConnectionManager::sendLocalGameMessage(GameMessage *msg, UnsignedInt frame) { - UnsignedShort currentID = 0; - if (DoesCommandRequireACommandID(NETCOMMANDTYPE_GAMECOMMAND)) { - currentID = GenerateNextCommandID(); - } - - NetCommandMsg *netmsg = newInstance(NetGameCommandMsg)(msg); - netmsg->setExecutionFrame(frame); - netmsg->setPlayerID(m_localSlot); - netmsg->setID(currentID); - - sendLocalCommand(netmsg); - - netmsg->detach(); -} - -/** - * This is a NetCommandMsg that originated on the local computer. Send this to everyone specified - * in the relay field. Commands sent in this way go through the packet router. - */ -void ConnectionManager::sendLocalCommand(NetCommandMsg *msg, UnsignedByte relay /* = 0xff by default*/) { - if (CommandRequiresDirectSend(msg) || (m_packetRouterSlot < 0) || (m_packetRouterSlot >= MAX_SLOTS) || (m_connections[m_packetRouterSlot] == NULL)) { - sendLocalCommandDirect(msg, relay); - return; - } - msg->attach(); - - DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("ConnectionManager::sendLocalCommand - sending net command %d of type %s", msg->getID(), - GetNetCommandTypeAsString(msg->getNetCommandType()))); - - if (relay & (1 << m_localSlot)) { - DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("ConnectionManager::sendLocalCommand - adding net command of type %s to player %d for frame %d", GetNetCommandTypeAsString(msg->getNetCommandType()), msg->getPlayerID(), msg->getExecutionFrame())); - m_frameData[m_localSlot]->addNetCommandMsg(msg); - } - - // Send the packet to everyone else - if (m_localSlot == m_packetRouterSlot) { - // I am the packet router, I need to send this packet to everyone individually. - for (Int i = 0; i < MAX_SLOTS; ++i) { - // Send it to all open connections. - if (((m_connections[i] != NULL) && (m_connections[i]->isQuitting() == FALSE)) && (relay & (1 << i))) { - // Set the relay mask to only go to this player so he knows not to relay it to anyone else. - UnsignedByte temprelay = 1 << i; - m_connections[i]->sendNetCommandMsg(msg, temprelay); // This will create a new copy of netmsg for this connection. - } - } - } else { - // Send the command to everyone else via the packet router. - UnsignedByte temprelay = relay & ~(1 << m_localSlot); // Tell the packet router to relay the message to everyone but myself. - // Hopefully the packet router is smart enough to not send it - // to slots that are not in the game. - - m_connections[m_packetRouterSlot]->sendNetCommandMsg(msg, temprelay); // This will create a new copy of netmsg for this connection. - - if (CommandRequiresAck(msg)) { - NetCommandRef *ref = m_pendingCommands->addMessage(msg); - //DEBUG_LOG(("ConnectionManager::sendLocalCommand - added command %d to pending commands list.", msg->getID())); - if (ref != NULL) { - ref->setRelay(temprelay); - } - } - } - - msg->detach(); // detach from the command msg. -} - -/** - * This is a NetCommandMsg that originated on the local computer. Send this to everyone specified - * in the relay field. Commands sent in this way do not go through the packet router. - */ -void ConnectionManager::sendLocalCommandDirect(NetCommandMsg *msg, UnsignedByte relay) { - msg->attach(); - - if (((relay & (1 << m_localSlot)) != 0) && (m_frameData[m_localSlot] != NULL)) { - if (IsCommandSynchronized(msg->getNetCommandType()) == TRUE) { - DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("ConnectionManager::sendLocalCommandDirect - adding net command of type %s to player %d for frame %d", GetNetCommandTypeAsString(msg->getNetCommandType()), msg->getPlayerID(), msg->getExecutionFrame())); - m_frameData[m_localSlot]->addNetCommandMsg(msg); - } - } - - for (Int i = 0; i < MAX_SLOTS; ++i) { - if ((relay & (1 << i)) != 0) { - if ((m_connections[i] != NULL) && (m_connections[i]->isQuitting() == FALSE)) { - UnsignedByte temprelay = 1 << i; - m_connections[i]->sendNetCommandMsg(msg, temprelay); - DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("ConnectionManager::sendLocalCommandDirect - Sending direct command %d of type %s to player %d", msg->getID(), GetNetCommandTypeAsString(msg->getNetCommandType()), i)); - } - } - } - - msg->detach(); -} - -Int commandsReadyDebugSpewage = 0; - -/** - * Returns true if all the commands for the given frame are ready to be executed. - */ -Bool ConnectionManager::allCommandsReady(UnsignedInt frame, Bool justTesting /* = FALSE */) { - Bool retval = TRUE; - FrameDataReturnType frameRetVal = FRAMEDATA_NOTREADY; -// retval = FALSE; // ****for testing purposes only!!!!!!**** - Int i = 0; - for (; (i < MAX_SLOTS) && retval; ++i) { - if ((m_frameData[i] != NULL) && (m_frameData[i]->getIsQuitting() == FALSE)) { -/* - if (!(m_frameData[i]->allCommandsReady(frame, (frame != commandsReadyDebugSpewage) && (justTesting == FALSE)))) { - if ((frame != commandsReadyDebugSpewage) && (justTesting == FALSE)) { - DEBUG_LOG(("ConnectionManager::allCommandsReady, frame %d player %d not ready.", frame, i)); - commandsReadyDebugSpewage = frame; - } - retval = FALSE; - } else { -// DEBUG_LOG(("ConnectionManager::allCommandsReady, frame %d player %d is ready.", frame, i)); - } -*/ - - frameRetVal = m_frameData[i]->allCommandsReady(frame, (frame != commandsReadyDebugSpewage) && (justTesting == FALSE)); - if (frameRetVal == FRAMEDATA_NOTREADY) { - retval = FALSE; - } else if (frameRetVal == FRAMEDATA_RESEND) { - requestFrameDataResend(i, frame); - retval = FALSE; - } - } - } - - if (frameRetVal == FRAMEDATA_RESEND) { - // this frame's data is really screwed up, we need to clean it out so it can be resent to us. - for (i = 0; i < MAX_SLOTS; ++i) { - if ((m_frameData[i] != NULL) && (i != m_localSlot)) { - m_frameData[i]->resetFrame(frame, FALSE); - } - } - } - - if ((retval == TRUE) && (justTesting == FALSE)) { - m_disconnectManager->allCommandsReady(TheGameLogic->getFrame(), this); - retval = m_disconnectManager->allowedToContinue(); // allow the disconnect manager to keep us on this frame - // in case we are waiting for a new packet router or something. - } - - return retval; -} - -void ConnectionManager::handleAllCommandsReady(void) -{ - m_disconnectManager->allCommandsReady(TheGameLogic->getFrame(), this, FALSE); -} - - -/** - * Only call this after making sure that all the commands are there for this frame. - * After calling this the commands for this frame will be removed from the connection. - * - * BGC - To account for the case where the host disconnects without sending the - * same commands to all players, we now have to keep around the last 'run ahead' - * frames so we can potentially send those commands to the other players in the - * game so they can catch up. - */ -NetCommandList *ConnectionManager::getFrameCommandList(UnsignedInt frame) -{ - NetCommandList *retlist = newInstance(NetCommandList); - retlist->init(); - - for (Int i = 0; i < MAX_SLOTS; ++i) { - if (m_frameData[i] != NULL) { - retlist->appendList(m_frameData[i]->getFrameCommandList(frame)); - if (frame > FRAMES_TO_KEEP) { - m_frameData[i]->resetFrame(frame - FRAMES_TO_KEEP); // After getting the commands for that frame from this - // FrameDataManager object, we need to tell it that we're - // done with the messages for that frame. - DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("getFrameCommandList - called reset frame on player %d for frame %d", i, frame - FRAMES_TO_KEEP)); - } - } - } - - return retlist; // retlist deallocated by calling function. -} - -void ConnectionManager::setFrameGrouping(time_t frameGrouping) { - // Since we are the packet router, we should send more packets per second since we - // may become the latency bottleneck for sending packets from one player to the next. - // This is probably ok since the packet router should have the fastest connection of all - // the players in the game. - if (m_localSlot == m_packetRouterSlot) { - frameGrouping = frameGrouping / 2; - } - for (Int i = 0; i < MAX_SLOTS; ++i) { - if (m_connections[i] != NULL) { - m_connections[i]->setFrameGrouping(frameGrouping); - } - } -} - -/* -void ConnectionManager::determineRouterFallbackPlan() { - memset(m_packetRouterFallback, 0, sizeof(m_packetRouterFallback)); - Int curnum = 1; - for (Int i = 0; i < MAX_SLOTS; ++i) { - if (m_connections[i] != NULL) { - m_packetRouterFallback[i] = curnum; - if (curnum == 1) { - m_packetRouterSlot = i; - } - ++curnum; - } - } -} -*/ - -void ConnectionManager::doKeepAlive() { - static Int nextIndex = 0; - static time_t startTime = 0; - - time_t curTime = timeGetTime(); - - if (startTime == 0) { - startTime = curTime; - return; - } - - time_t numSeconds = (curTime - startTime) / 1000; - - while ((nextIndex <= numSeconds) && (nextIndex < MAX_SLOTS)) { -// DEBUG_LOG(("ConnectionManager::doKeepAlive - trying to send keep alive message to player %d", nextIndex)); - if (m_connections[nextIndex] != NULL) { - NetKeepAliveCommandMsg *msg = newInstance(NetKeepAliveCommandMsg); - msg->setPlayerID(m_localSlot); - if (DoesCommandRequireACommandID(msg->getNetCommandType()) == TRUE) { - msg->setID(GenerateNextCommandID()); - } -// DEBUG_LOG(("ConnectionManager::doKeepAlive - sending keep alive message to player %d", nextIndex)); - sendLocalCommandDirect(msg, 1 << nextIndex); - msg->detach(); - } - ++nextIndex; - } - if (nextIndex == MAX_SLOTS) { - nextIndex = 0; - startTime = curTime; - } -} - -PlayerLeaveCode ConnectionManager::disconnectPlayer(Int slot) { - // Need to do the deletion of the slot's connection and frame data here. - PlayerLeaveCode retval = PLAYERLEAVECODE_CLIENT; - DEBUG_LOG(("ConnectionManager::disconnectPlayer - disconnecting slot %d on frame %d", slot, TheGameLogic->getFrame())); - - if ((slot < 0) || (slot >= MAX_SLOTS)) { - return PLAYERLEAVECODE_UNKNOWN; - } - - if (TheGameInfo) - { - GameSlot *gSlot = TheGameInfo->getSlot( slot ); - if (gSlot && !gSlot->lastFrameInGame()) - { - DEBUG_LOG(("ConnectionManager::disconnectPlayer(%d) - slot is last in the game on frame %d", - slot, TheGameLogic->getFrame())); - gSlot->setLastFrameInGame(TheGameLogic->getFrame()); - } - } - - UnicodeString unicodeName; - unicodeName = getPlayerName(slot); - if (unicodeName.getLength() > 0 && m_connections[slot]) { - TheInGameUI->message("Network:PlayerLeftGame", unicodeName.str()); - - // People are boneheads. Also play a sound - static AudioEventRTS leftGameSound("GUIMessageReceived"); - TheAudio->addAudioEvent(&leftGameSound); - } - - if ((m_frameData[slot] != NULL) && (m_frameData[slot]->getIsQuitting() == FALSE)) { - DEBUG_LOG(("ConnectionManager::disconnectPlayer - deleting player %d frame data", slot)); - deleteInstance(m_frameData[slot]); - m_frameData[slot] = NULL; - } - - if (m_connections[slot] != NULL && !m_connections[slot]->isQuitting()) { - DEBUG_LOG(("ConnectionManager::disconnectPlayer - deleting player %d connection", slot)); - deleteInstance(m_connections[slot]); - m_connections[slot] = NULL; - } - -// if (playerID == m_localSlot) { -// TheMessageStream->appendMessage(GameMessage::MSG_CLEAR_GAME_DATA); -// } - - if (slot == m_packetRouterSlot) { - Int index = 0; - while ((index < (MAX_SLOTS-1)) && (m_packetRouterFallback[index] != m_packetRouterSlot)) { - ++index; - } - ++index; - m_packetRouterSlot = m_packetRouterFallback[index]; - DEBUG_LOG(("Packet router left. New packet router is slot %d", m_packetRouterSlot)); - retval = PLAYERLEAVECODE_PACKETROUTER; - } - if (m_localSlot == slot) { - DEBUG_LOG(("Disconnecting self")); - retval = PLAYERLEAVECODE_LOCAL; - } - - // Take the player out of the fallback plan - Int fallbackindex = 0; - while ((fallbackindex < MAX_SLOTS) && (m_packetRouterFallback[fallbackindex] != slot)) { - ++fallbackindex; - } - - for (Int i = fallbackindex; i < MAX_SLOTS-1; ++i) { - m_packetRouterFallback[i] = m_packetRouterFallback[i+1]; - } - m_packetRouterFallback[MAX_SLOTS-1] = -1; - - return retval; -} - -void ConnectionManager::quitGame() { - // Need to do the NetDisconnectPlayerCommandMsg creation and sending here. - NetDisconnectPlayerCommandMsg *disconnectMsg = newInstance(NetDisconnectPlayerCommandMsg); - disconnectMsg->setDisconnectSlot(m_localSlot); - disconnectMsg->setPlayerID(m_localSlot); - if (DoesCommandRequireACommandID(disconnectMsg->getNetCommandType())) { - disconnectMsg->setID(GenerateNextCommandID()); - } - //DEBUG_LOG(("ConnectionManager::disconnectLocalPlayer - about to send disconnect command")); - sendLocalCommandDirect(disconnectMsg, 0xff ^ (1 << m_localSlot)); - - //DEBUG_LOG(("ConnectionManager::disconnectLocalPlayer - about to flush connections")); - flushConnections(); // need to do this so our packet actually gets sent before the connections are deleted. - //DEBUG_LOG(("ConnectionManager::disconnectLocalPlayer - done flushing connections")); - - disconnectMsg->detach(); - -#if RTS_GENERALS - // if we get here, we hit Quit on the disconnect screen. Mark everyone as having disconnected from us - // so the online stats can give us appropriate feedback. - if (TheGameInfo) - { - for (Int i = 0; i < MAX_SLOTS; ++i) - { - GameSlot *gSlot = TheGameInfo->getSlot( i ); - if (gSlot && !gSlot->lastFrameInGame()) - { - gSlot->markAsDisconnected(); - } - } - } -#endif - - disconnectLocalPlayer(); -} - -void ConnectionManager::disconnectLocalPlayer() { - // kill the frame data and the connections for all the other players. - DEBUG_LOG(("ConnectionManager::disconnectLocalPlayer()")); - for (Int i = 0; i < MAX_SLOTS; ++i) { - if (i != m_localSlot) { - disconnectPlayer(i); - } - } -} - -/** - * Takes all the commands that are ready to send and sends them right now. - */ -void ConnectionManager::flushConnections() { - for (Int i = 0; i < MAX_SLOTS; ++i) { - if (m_connections[i] != NULL) { -// DEBUG_LOG(("ConnectionManager::flushConnections - flushing connection to player %d", i)); - /* - if (m_connections[i]->isQueueEmpty()) { -// DEBUG_LOG(("ConnectionManager::flushConnections - connection queue empty")); - } - */ - m_connections[i]->doSend(); - } - } - - if (m_transport != NULL) { - m_transport->doSend(); - } -} - -void ConnectionManager::resendPendingCommands() { - //DEBUG_LOG(("ConnectionManager::resendPendingCommands()")); - if (m_pendingCommands == NULL) { - return; - } - - NetCommandRef *ref = m_pendingCommands->getFirstMessage(); - while (ref != NULL) { - //DEBUG_LOG(("ConnectionManager::resendPendingCommands - resending command %d", ref->getCommand()->getID())); - sendLocalCommand(ref->getCommand(), ref->getRelay()); - ref = ref->getNext(); - } -} - -UnsignedInt ConnectionManager::getLocalPlayerID() { - return m_localSlot; -} - -UnicodeString ConnectionManager::getPlayerName(Int playerNum) { - UnicodeString retval; - if( playerNum == m_localSlot ) { - retval = m_localUser->GetName(); - } else if (((m_connections[playerNum] != NULL) && (m_connections[playerNum]->isQuitting() == FALSE))) { - retval = m_connections[playerNum]->getUser()->GetName(); - } - return retval; -} - -/** - * Take a user list and make connections and frame data manager objects for each of the players. - * For now, this is also how we'll determine the packet router fallback plan. - */ -void ConnectionManager::parseUserList(const GameInfo *game) -{ - if (!game) - return; - - Int i; - Int numUsers = 0; - m_localSlot = -1; - DEBUG_LOG(("Local slot is %d", game->getLocalSlotNum())); - for (i=0; igetConstSlot(i); // badness, but since we cast right back to const, we should be ok - if (slot->isHuman()) - { - if (game->getLocalSlotNum() == i) - { - m_localSlot = i; - m_localUser->setName(slot->getName()); - } - - if (m_localSlot != i) - { - m_connections[i] = newInstance(Connection)(); - m_connections[i]->init(); - m_connections[i]->attachTransport(m_transport); -// UnsignedShort port = (TheNAT)?TheNAT->getSlotPort(i):8088; - UnsignedShort port = slot->getPort(); - m_connections[i]->setUser(newInstance(User)(slot->getName(), slot->getIP(), port)); - m_frameData[i] = newInstance(FrameDataManager)(FALSE); - DEBUG_LOG(("Remote user is at %X:%d", slot->getIP(), slot->getPort())); - } - else - { - DEBUG_LOG(("Local user is %d (%X:%d)", m_localSlot, slot->getIP(), slot->getPort())); - m_frameData[i] = newInstance(FrameDataManager)(TRUE); - } - m_frameData[i]->init(); - m_frameData[i]->reset(); - - m_packetRouterFallback[numUsers] = i; - - ++numUsers; - - } - } -#ifdef MEMORYPOOL_DEBUG - TheMemoryPoolFactory->debugSetInitFillerIndex(m_localSlot); -#endif - - /* - if ( numUsers < 2 || m_localSlot == -1 ) - { - DEBUG_CRASH(("FAILED parseUserList - network game won't work as expected")); - return; - } - - char * list = strdup(buf); - char *listPtr = list; - if (!list) - return; - - User users[MAX_SLOTS]; - int localUser = -1; - int i; - - for (i=0; i= MAX_SLOTS) - { - DEBUG_LOG(("ConnectionManager::parseUserList - (numUsers = %d) FAILED parseUserList with list [%s]", numUsers, buf)); - return; - } - - addrAsciiStr = addrStr; - UnsignedInt addr = ResolveIP(addrAsciiStr); - UnsignedInt port = atoi(portStr); - -// if ((m_localAddr != addr) || (m_localPort != port)) { - if (loginName.compare(nameStr) != 0) { - m_connections[numUsers] = newInstance(Connection)(); - m_connections[numUsers]->init(); - m_connections[numUsers]->attachTransport(m_transport); - m_connections[numUsers]->setUser(newInstance(User)(nameStr, addr, port)); - - m_frameData[numUsers] = newInstance(FrameDataManager)(FALSE); - - DEBUG_LOG(("ConnectionManager::parseUserList - User %d is %s", numUsers, nameStr)); - } else { - m_localSlot = numUsers; - m_localUser.setName(nameStr); - - DEBUG_LOG(("ConnectionManager::parseUserList - User %d is %s", numUsers, nameStr)); - DEBUG_LOG(("Local user is %d", m_localSlot)); - - m_frameData[numUsers] = newInstance(FrameDataManager)(TRUE); - } - m_frameData[numUsers]->init(); - m_frameData[numUsers]->reset(); - - m_packetRouterFallback[numUsers] = numUsers; - - numUsers++; - } - - if (numUsers < 2 || m_localSlot == -1) - { - DEBUG_LOG(("ConnectionManager::parseUserList - FAILED (local user = %d, num players = %d) with list [%s]", m_localSlot, numUsers, buf)); - return; - } - - free(list); // from the strdup above. - list = NULL; - */ -} - -/** - * Return the number of incoming bytes per second averaged over 30 sec. - */ -Real ConnectionManager::getIncomingBytesPerSecond( void ) -{ - if (m_transport) - return m_transport->getIncomingBytesPerSecond(); - else - return 0.0; -} - -/** - * Return the number of incoming packets per second averaged over the last 30 sec. - */ -Real ConnectionManager::getIncomingPacketsPerSecond( void ) -{ - if (m_transport) - return m_transport->getIncomingPacketsPerSecond(); - else - return 0.0; -} - -/** - * Return the number of outgoing bytes per second averaged over the last 30 sec. - */ -Real ConnectionManager::getOutgoingBytesPerSecond( void ) -{ - if (m_transport) - return m_transport->getOutgoingBytesPerSecond(); - else - return 0.0; -} - -/** - * Return the number of outgoing packets per second averaged over the last 30 sec. - */ -Real ConnectionManager::getOutgoingPacketsPerSecond( void ) -{ - if (m_transport) { - return m_transport->getOutgoingPacketsPerSecond(); - } else { - return 0.0; - } -} - -/** - * Return the number of bytes not from generals clients received per second averaged over the last 30 sec. - */ -Real ConnectionManager::getUnknownBytesPerSecond( void ) -{ - if (m_transport) - return m_transport->getUnknownBytesPerSecond(); - else - return 0.0; -} - -/** - * Return the number ov packets not from generals clients received per second averaged over the last 30 sec. - */ -Real ConnectionManager::getUnknownPacketsPerSecond( void ) -{ - if (m_transport) - return m_transport->getUnknownPacketsPerSecond(); - else - return 0.0; -} - -/** - * Return the smallest packet arrival cushion since this was last called. - */ -UnsignedInt ConnectionManager::getPacketArrivalCushion() { - UnsignedInt retval = m_smallestPacketArrivalCushion; - m_smallestPacketArrivalCushion = -1; - return retval; -} - -void ConnectionManager::sendChat(UnicodeString text, Int playerMask, UnsignedInt executionFrame) -{ - NetChatCommandMsg *msg = newInstance(NetChatCommandMsg); - msg->setText(text); - msg->setPlayerMask(playerMask); - msg->setPlayerID(m_localSlot); - msg->setID(0); - msg->setExecutionFrame(executionFrame); - if (DoesCommandRequireACommandID(msg->getNetCommandType())) - { - msg->setID(GenerateNextCommandID()); - } - DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("Chat message has ID of %d, mask of %8.8X, text of %ls", msg->getID(), msg->getPlayerMask(), msg->getText().str())); - - sendLocalCommand(msg, 0xff ^ (1 << m_localSlot)); - processChat(msg); - - msg->detach(); -} - -void ConnectionManager::sendDisconnectChat(UnicodeString text) { - NetDisconnectChatCommandMsg *msg = newInstance(NetDisconnectChatCommandMsg); - msg->setPlayerID(m_localSlot); - if (DoesCommandRequireACommandID(msg->getNetCommandType())) { - msg->setID(GenerateNextCommandID()); - } - msg->setText(text); - - sendLocalCommandDirect(msg, 0xff ^ (1 << m_localSlot)); - processDisconnectChat(msg); -} - -UnsignedShort ConnectionManager::sendFileAnnounce(AsciiString path, UnsignedByte playerMask) -{ - File *theFile = TheLocalFileSystem->openFile(path.str()); - if (!theFile || !theFile->size()) - { - UnicodeString log; - log.format(L"Not sending file '%hs' to %X", path.str(), playerMask); - DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("%ls", log.str())); - if (TheLAN) - TheLAN->OnChat(UnicodeString(L"sendFile"), 0, log, LANAPI::LANCHAT_SYSTEM); - return 0; - } - - theFile->close(); - - Int announceMask = 0xff ^ (1 << m_localSlot); - NetFileAnnounceCommandMsg *announceMsg = newInstance(NetFileAnnounceCommandMsg); - announceMsg->setPlayerID(m_localSlot); - if (DoesCommandRequireACommandID(announceMsg->getNetCommandType()) == TRUE) { - announceMsg->setID(GenerateNextCommandID()); - } - announceMsg->setRealFilename(path); - announceMsg->setPlayerMask(playerMask); - UnsignedShort fileID = GenerateNextCommandID(); - announceMsg->setFileID(fileID); - DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("ConnectionManager::sendFileAnnounce() - creating announce message with ID of %d from %d to mask %X for '%s' going to %X as command %d", - announceMsg->getID(), announceMsg->getPlayerID(), announceMask, announceMsg->getRealFilename().str(), - announceMsg->getPlayerMask(), announceMsg->getFileID())); - - processFileAnnounce(announceMsg); // set up things for the host - - DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("Sending file announce to %X", announceMask)); - sendLocalCommand(announceMsg, announceMask); - announceMsg->detach(); - - return fileID; -} - -void ConnectionManager::sendFile(AsciiString path, UnsignedByte playerMask, UnsignedShort commandID) -{ - File *theFile = TheLocalFileSystem->openFile(path.str()); - if (!theFile || !theFile->size()) - { - UnicodeString log; - log.format(L"Not sending file '%hs' to %X", path.str(), playerMask); - DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("%ls", log.str())); - if (TheLAN) - TheLAN->OnChat(UnicodeString(L"sendFile"), 0, log, LANAPI::LANCHAT_SYSTEM); - return; - } - - Int len = theFile->size(); - char *buf = theFile->readEntireAndClose(); - - // compress Targas -#ifdef COMPRESS_TARGAS - char *compressedBuf = NULL; - Int compressedLen = path.endsWith(".tga")?CompressionManager::getMaxCompressedSize(len, CompressionManager::getPreferredCompression()):0; - Int compressedSize = 0; - if (compressedLen) - compressedSize = CompressionManager::compressData(CompressionManager::getPreferredCompression(), - buf, len, compressedBuf, compressedLen); - - if (!compressedSize) - { - delete[] compressedBuf; - compressedBuf = NULL; - } -#endif // COMPRESS_TARGAS - - NetFileCommandMsg *fileMsg = newInstance(NetFileCommandMsg); - fileMsg->setPlayerID(m_localSlot); - fileMsg->setID(commandID); - fileMsg->setRealFilename(path); -#ifdef COMPRESS_TARGAS - if (compressedBuf) - { - DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("Compressed '%s' from %d to %d (%g%%) before transfer", path.str(), len, compressedSize, - (Real)compressedSize/(Real)len*100.0f)); - fileMsg->setFileData((unsigned char *)compressedBuf, compressedSize); - } - else -#endif // COMPRESS_TARGAS - { - fileMsg->setFileData((unsigned char *)buf, len); - } - - DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("ConnectionManager::sendFile() - creating file message with ID of %d for '%s' going to %X from %d, size of %d", - fileMsg->getID(), fileMsg->getRealFilename().str(), playerMask, fileMsg->getPlayerID(), fileMsg->getFileLength())); - - delete[] buf; - buf = NULL; -#ifdef COMPRESS_TARGAS - delete[] compressedBuf; - compressedBuf = NULL; -#endif // COMPRESS_TARGAS - - DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("Sending file: '%s', len %d, to %X", path.str(), len, playerMask)); - - sendLocalCommand(fileMsg, playerMask); - - fileMsg->detach(); -} - -Int ConnectionManager::getFileTransferProgress(Int playerID, AsciiString path) -{ - FileCommandMap::iterator commandIt = s_fileCommandMap.begin(); - while (commandIt != s_fileCommandMap.end()) - { - //DEBUG_LOG(("ConnectionManager::getFileTransferProgress(%s): looking at existing transfer of '%s'", - // path.str(), commandIt->second.str())); - if (commandIt->second == path) - { - return s_fileProgressMap[playerID][commandIt->first]; - } - ++commandIt; - } - //DEBUG_LOG(("Falling back to 0, since we couldn't find the map")); - DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("ConnectionManager::getFileTransferProgress: path %s not found",path.str())); - return 0; -} - - -void ConnectionManager::voteForPlayerDisconnect(Int slot) { - if (m_disconnectManager != NULL) { - m_disconnectManager->voteForPlayerDisconnect(slot, this); - } -} - -Int ConnectionManager::getNumPlayers() -{ - Int retval = 0; - for (Int i = 0; i < MAX_SLOTS; ++i) - { - if (isPlayerConnected(i)) { - ++retval; - } - } - - return retval; -} - -void ConnectionManager::updateLoadProgress( Int progress ) -{ - NetProgressCommandMsg *msg = newInstance(NetProgressCommandMsg); - msg->setPercentage( progress ); - msg->setPlayerID( m_localSlot ); - if (DoesCommandRequireACommandID(msg->getNetCommandType()) == TRUE) { - msg->setID(GenerateNextCommandID()); - } - processProgress(msg); - sendLocalCommand(msg, 0xff ^ (1 << m_localSlot)); - - msg->detach(); -} - -void ConnectionManager::loadProgressComplete() -{ - NetCommandMsg *msg = newInstance(NetCommandMsg); - msg->setPlayerID( m_localSlot ); - if (DoesCommandRequireACommandID(msg->getNetCommandType()) == TRUE) { - msg->setID(GenerateNextCommandID()); - } - msg->setNetCommandType(NETCOMMANDTYPE_LOADCOMPLETE); - processLoadComplete(msg); - sendLocalCommand(msg, 0xff ^ (1 << m_localSlot)); - - msg->detach(); -} - -void ConnectionManager::sendTimeOutGameStart() -{ - NetCommandMsg *msg = newInstance(NetCommandMsg); - msg->setPlayerID( m_localSlot ); - msg->setNetCommandType(NETCOMMANDTYPE_TIMEOUTSTART); - if (DoesCommandRequireACommandID(msg->getNetCommandType()) == TRUE) { - msg->setID(GenerateNextCommandID()); - } - processTimeOutGameStart(msg); - sendLocalCommand(msg, 0xff ^ (1 << m_localSlot)); - - msg->detach(); -} - -Bool ConnectionManager::isPacketRouter( void ) -{ - return m_localSlot == m_packetRouterSlot; -} - -Int ConnectionManager::getAverageFPS( void ) -{ - return m_frameMetrics.getAverageFPS(); -} - -Int ConnectionManager::getSlotAverageFPS(Int slot) { - if ((slot < 0) || (slot >= MAX_SLOTS)) { - return -1; - } - if ((m_packetRouterSlot != m_localSlot) && (slot == m_localSlot)) { - // our framerate data isn't valid for other players unless we are the - // packet router, so don't fake someone out. - return -1; - } - return m_fpsAverages[slot]; -} - -#if defined(RTS_DEBUG) -void ConnectionManager::debugPrintConnectionCommands() { - DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("ConnectionManager::debugPrintConnectionCommands - begin commands")); - for (Int i = 0; i < MAX_SLOTS; ++i) { - if (m_connections[i] != NULL) { - DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("ConnectionManager::debugPrintConnectionCommands - commands for connection %d", i)); - m_connections[i]->debugPrintCommands(); - } - } - DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("ConnectionManager::debugPrintConnectionCommands - end commands")); -} -#endif - -void ConnectionManager::notifyOthersOfCurrentFrame(Int frame) { - NetDisconnectFrameCommandMsg *msg = newInstance(NetDisconnectFrameCommandMsg); - - msg->setPlayerID(m_localSlot); - msg->setDisconnectFrame(frame); - if (DoesCommandRequireACommandID(msg->getNetCommandType())) { - msg->setID(GenerateNextCommandID()); - } - - DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("ConnectionManager::notifyOthersOfCurrentFrame - sending disconnect frame of %d, command ID = %d", frame, msg->getID())); - sendLocalCommandDirect(msg, 0xff ^ (1 << m_localSlot)); - NetCommandRef *ref = NEW_NETCOMMANDREF(msg); - ref->setRelay(1 << m_localSlot); - m_disconnectManager->processDisconnectCommand(ref, this); - deleteInstance(ref); - - msg->detach(); - - DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("ConnectionManager::notifyOthersOfCurrentFrame - start screen on debug stuff")); -#if defined(RTS_DEBUG) - debugPrintConnectionCommands(); -#endif -} - -void ConnectionManager::notifyOthersOfNewFrame(UnsignedInt frame) { - NetDisconnectScreenOffCommandMsg *msg = newInstance(NetDisconnectScreenOffCommandMsg); - - msg->setPlayerID(m_localSlot); - msg->setNewFrame(frame); - if (DoesCommandRequireACommandID(msg->getNetCommandType())) { - msg->setID(GenerateNextCommandID()); - } - - sendLocalCommandDirect(msg, 0xff ^ (1 << m_localSlot)); - NetCommandRef *ref = NEW_NETCOMMANDREF(msg); - ref->setRelay(1 << m_localSlot); - m_disconnectManager->processDisconnectCommand(ref, this); - deleteInstance(ref); - - msg->detach(); -} - -void ConnectionManager::sendFrameDataToPlayer(UnsignedInt playerID, UnsignedInt startingFrame) { - DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("ConnectionManager::sendFrameDataToPlayer - sending frame data to player %d starting with frame %d", playerID, startingFrame)); - for (UnsignedInt frame = startingFrame; frame < TheGameLogic->getFrame(); ++frame) { - sendSingleFrameToPlayer(playerID, frame); - } - DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("ConnectionManager::sendFrameDataToPlayer - done sending commands to player %d", playerID)); -} - -void ConnectionManager::sendSingleFrameToPlayer(UnsignedInt playerID, UnsignedInt frame) { - if ((TheGameLogic->getFrame() - FRAMES_TO_KEEP) > frame) { - DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("ConnectionManager::sendSingleFrameToPlayer - player %d requested frame %d when we are on frame %d, this is too far in the past.", playerID, frame, TheGameLogic->getFrame())); - return; - } - - UnsignedByte relay = 1 << playerID; - - DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("ConnectionManager::sendFrameDataToPlayer - sending data for frame %d", frame)); - for (Int i = 0; i < MAX_SLOTS; ++i) { - if ((m_frameData[i] != NULL) && (i != playerID)) { // no need to send his own commands to him. - NetCommandList *list = m_frameData[i]->getFrameCommandList(frame); - if (list != NULL) { - NetCommandRef *ref = list->getFirstMessage(); - while (ref != NULL) { - DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("ConnectionManager::sendFrameDataToPlayer - sending command %d from player %d to player %d using relay 0x%x", ref->getCommand()->getID(), i, playerID, relay)); - sendLocalCommandDirect(ref->getCommand(), relay); - ref = ref->getNext(); - } - } - UnsignedInt frameCommandCount = m_frameData[i]->getFrameCommandCount(frame); - NetFrameCommandMsg *msg = newInstance(NetFrameCommandMsg); - msg->setExecutionFrame(frame); - msg->setCommandCount(frameCommandCount); - if (DoesCommandRequireACommandID(msg->getNetCommandType())) { - msg->setID(GenerateNextCommandID()); - } - msg->setPlayerID(i); - DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("ConnectionManager::sendFrameDataToPlayer - sending frame info from player %d to player %d for frame %d with command count %d and ID %d and relay %d", i, playerID, msg->getExecutionFrame(), msg->getCommandCount(), msg->getID(), relay)); - sendLocalCommandDirect(msg, relay); - msg->detach(); - } - } -} - -UnsignedInt ConnectionManager::getNextPacketRouterSlot(UnsignedInt playerID) { - Int index = 0; - while ((index < (MAX_SLOTS-1)) && (m_packetRouterFallback[index] != playerID)) { - ++index; - } - ++index; - return m_packetRouterFallback[index]; -} - -void ConnectionManager::requestFrameDataResend(Int playerID, UnsignedInt frame) { - NetFrameResendRequestCommandMsg *msg = newInstance(NetFrameResendRequestCommandMsg); - msg->setPlayerID(m_localSlot); - msg->setFrameToResend(frame); - if (DoesCommandRequireACommandID(msg->getNetCommandType())) { - msg->setID(GenerateNextCommandID()); - } - - if (isPlayerConnected(playerID) == FALSE) { - playerID = 0; - while ((playerID < MAX_SLOTS) && (isPlayerConnected(playerID) == FALSE)) { - ++playerID; - } - } - - if (playerID < MAX_SLOTS) { - sendLocalCommandDirect(msg, 1 << playerID); - } - - msg->detach(); -} diff --git a/Generals/Code/GameEngine/Source/GameNetwork/DisconnectManager.cpp b/Generals/Code/GameEngine/Source/GameNetwork/DisconnectManager.cpp deleted file mode 100644 index d7c1add1c9..0000000000 --- a/Generals/Code/GameEngine/Source/GameNetwork/DisconnectManager.cpp +++ /dev/null @@ -1,808 +0,0 @@ -/* -** 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 in the GameEngine - -#include "Common/Recorder.h" -#include "GameClient/DisconnectMenu.h" -#include "GameClient/InGameUI.h" -#include "GameLogic/GameLogic.h" -#include "GameNetwork/DisconnectManager.h" -#include "GameNetwork/NetworkInterface.h" -#include "GameNetwork/networkutil.h" -#include "GameNetwork/GameSpy/PingThread.h" -#include "GameNetwork/GameSpy/GSConfig.h" - - -DisconnectManager::DisconnectManager() -{ - // Added By Sadullah Nader - // Initializations missing and needed - Int i; - m_currentPacketRouterIndex = 0; - m_lastFrame = 0; - m_lastFrameTime = 0; - m_lastKeepAliveSendTime = 0; - m_haveNotifiedOtherPlayersOfCurrentFrame = FALSE; - m_timeOfDisconnectScreenOn = 0; - - for( i = 0; i < MAX_SLOTS; ++i) { - m_packetRouterFallback[i] = 0; - } - - m_packetRouterTimeout = 0; - for( i = 0; i < MAX_SLOTS -1; ++i) { - m_playerTimeouts[i] = 0; - } - - for( i = 0; i < MAX_SLOTS; ++i) { - for (Int j = 0; j < MAX_SLOTS; ++j) { - m_playerVotes[i][j].vote = FALSE; - m_playerVotes[i][j].frame = 0; - } - } -} - -DisconnectManager::~DisconnectManager() { -} - -void DisconnectManager::init() { - TheDisconnectMenu->hideScreen(); // make sure the screen starts out hidden. - m_lastFrame = 0; - m_lastFrameTime = -1; - m_lastKeepAliveSendTime = -1; - m_disconnectState = DISCONNECTSTATETYPE_SCREENOFF; - m_currentPacketRouterIndex = 0; - m_timeOfDisconnectScreenOn = 0; - - Int i = 0; - for (; i < MAX_SLOTS; ++i) { - for (Int j = 0; j < MAX_SLOTS; ++j) { - m_playerVotes[i][j].vote = FALSE; - m_playerVotes[i][j].frame = 0; - } - } - - for (i = 0; i < MAX_SLOTS; ++i) { - m_disconnectFrames[i] = 0; - m_disconnectFramesReceived[i] = FALSE; - } - - m_pingFrame = 0; - m_pingsSent = 0; - m_pingsRecieved = 0; -} - -void DisconnectManager::update(ConnectionManager *conMgr) { - if (m_lastFrameTime == -1) { - m_lastFrameTime = timeGetTime(); - } - - // The game logic stalls on the frame we are currently waiting for commands on, - // so we have to check for the current logic frame being one higher than - // the last one we had the commands ready for. - if (TheGameLogic->getFrame() == m_lastFrame) { - time_t curTime = timeGetTime(); - if ((curTime - m_lastFrameTime) > TheGlobalData->m_networkDisconnectTime) { - if (m_disconnectState == DISCONNECTSTATETYPE_SCREENOFF) { - turnOnScreen(conMgr); - } - sendKeepAlive(conMgr); - } - } else { - nextFrame(TheGameLogic->getFrame(), conMgr); - } - - if (m_disconnectState != DISCONNECTSTATETYPE_SCREENOFF) { - updateDisconnectStatus(conMgr); - - // check to see if we need to send pings - if (m_pingFrame < TheGameLogic->getFrame()) - { - time_t curTime = timeGetTime(); - if ((curTime - m_lastFrameTime) > 10000) /// @todo: plug in some better measure here - { - m_pingFrame = TheGameLogic->getFrame(); - m_pingsSent = 0; - m_pingsRecieved = 0; - - // Send the pings - if (ThePinger) - { - //use next ping server - static size_t serverIndex = 0; - serverIndex++; - - AsciiStringList pingServers = TheGameSpyConfig->getPingServers(); - - if( serverIndex >= pingServers.size() ) - serverIndex = 0; //wrap back to first ping server - - std::list::iterator it = pingServers.begin(); - for( size_t i = 0; i < serverIndex; i++ ) - it++; - - PingRequest req; - req.hostname = it->str(); - req.repetitions = 5; - req.timeout = 2000; - m_pingsSent = req.repetitions; - ThePinger->addRequest(req); - DEBUG_LOG(("DisconnectManager::update() - requesting %d pings of %d from %s", - req.repetitions, req.timeout, req.hostname.c_str())); - } - } - } - - // update the ping thread, tracking pings if we are on the same frame - if (ThePinger) - { - PingResponse resp; - while (ThePinger->getResponse(resp)) - { - if (m_pingFrame != TheGameLogic->getFrame()) - { - // wrong frame - we're not pinging yet - DEBUG_LOG(("DisconnectManager::update() - discarding ping of %d from %s (%d reps)", - resp.avgPing, resp.hostname.c_str(), resp.repetitions)); - } - else - { - // right frame - DEBUG_LOG(("DisconnectManager::update() - keeping ping of %d from %s (%d reps)", - resp.avgPing, resp.hostname.c_str(), resp.repetitions)); - if (resp.avgPing < 2000) - { - m_pingsRecieved += resp.repetitions; - } - } - } - } - } -} - -UnsignedInt DisconnectManager::getPingFrame() -{ - return m_pingFrame; -} - -Int DisconnectManager::getPingsSent() -{ - return m_pingsSent; -} - -Int DisconnectManager::getPingsRecieved() -{ - return m_pingsRecieved; -} - - -void DisconnectManager::updateDisconnectStatus(ConnectionManager *conMgr) { - for (Int i = 0; i < MAX_SLOTS; ++i) { - if (conMgr->isPlayerConnected(i)) { - Int slot = translatedSlotPosition(i, conMgr->getLocalPlayerID()); - if (slot != -1) { - time_t curTime = timeGetTime(); - time_t newTime = TheGlobalData->m_networkPlayerTimeoutTime - (curTime - m_playerTimeouts[slot]); - -// if someone is more than 2/3 timed out, lets get our frame numbers sync'd up. Also if someone is voted out -// lets do the same thing. - - if (m_haveNotifiedOtherPlayersOfCurrentFrame == FALSE) { - if ((newTime < TheGlobalData->m_networkPlayerTimeoutTime / 3) || (isPlayerVotedOut(slot, conMgr) == TRUE)) { - TheNetwork->notifyOthersOfCurrentFrame(); - m_haveNotifiedOtherPlayersOfCurrentFrame = TRUE; - } - - DEBUG_LOG(("DisconnectManager::updateDisconnectStatus - curTime = %d, m_timeOfDisconnectScreenOn = %d, curTime - m_timeOfDisconnectScreenOn = %d", curTime, m_timeOfDisconnectScreenOn, curTime - m_timeOfDisconnectScreenOn)); - - if (m_timeOfDisconnectScreenOn != 0) { - if ((curTime - m_timeOfDisconnectScreenOn) > TheGlobalData->m_networkDisconnectScreenNotifyTime) { - TheNetwork->notifyOthersOfCurrentFrame(); - m_haveNotifiedOtherPlayersOfCurrentFrame = TRUE; - } - } - } - - if ((newTime < 0) || (isPlayerVotedOut(slot, conMgr) == TRUE)) { - newTime = 0; - DEBUG_LOG(("DisconnectManager::updateDisconnectStatus - player %d(translated slot %d) has been voted out or timed out", i, slot)); - if (allOnSameFrame(conMgr) == TRUE) { - DEBUG_LOG(("DisconnectManager::updateDisconnectStatus - all on same frame")); - if (isLocalPlayerNextPacketRouter(conMgr) == TRUE) { - DEBUG_LOG(("DisconnectManager::updateDisconnectStatus - local player is next packet router")); - DEBUG_LOG(("DisconnectManager::updateDisconnectStatus - about to do the disconnect procedure for player %d", i)); - sendDisconnectCommand(i, conMgr); - disconnectPlayer(i, conMgr); - sendPlayerDestruct(i, conMgr); - } else { - DEBUG_LOG(("DisconnectManager::updateDisconnectStatus - local player is not the next packet router")); - } - } else { - DEBUG_LOG(("DisconnectManager::updateDisconnectStatus - not all on same frame")); - } - } - TheDisconnectMenu->setPlayerTimeoutTime(slot, newTime); - } - } - } -} - -void DisconnectManager::updateWaitForPacketRouter(ConnectionManager *conMgr) { -/* - time_t curTime = timeGetTime(); - time_t newTime = TheGlobalData->m_networkPlayerTimeoutTime - (curTime - m_packetRouterTimeout); - if (newTime < 0) { - newTime = 0; - - // The guy that we were hoping would be the new packet router isn't. We're screwed, get out of the game. - - DEBUG_LOG(("DisconnectManager::updateWaitForPacketRouter - timed out waiting for new packet router, quitting game")); - TheNetwork->quitGame(); - } - TheDisconnectMenu->setPacketRouterTimeoutTime(newTime); -*/ -} - -void DisconnectManager::processDisconnectCommand(NetCommandRef *ref, ConnectionManager *conMgr) { - NetCommandMsg *msg = ref->getCommand(); - if (msg->getNetCommandType() == NETCOMMANDTYPE_DISCONNECTKEEPALIVE) { - processDisconnectKeepAlive(msg, conMgr); - } else if (msg->getNetCommandType() == NETCOMMANDTYPE_DISCONNECTPLAYER) { - processDisconnectPlayer(msg, conMgr); - } else if (msg->getNetCommandType() == NETCOMMANDTYPE_PACKETROUTERQUERY) { - processPacketRouterQuery(msg, conMgr); - } else if (msg->getNetCommandType() == NETCOMMANDTYPE_PACKETROUTERACK) { - processPacketRouterAck(msg, conMgr); - } else if (msg->getNetCommandType() == NETCOMMANDTYPE_DISCONNECTVOTE) { - processDisconnectVote(msg, conMgr); - } else if (msg->getNetCommandType() == NETCOMMANDTYPE_DISCONNECTFRAME) { - processDisconnectFrame(msg, conMgr); - } else if (msg->getNetCommandType() == NETCOMMANDTYPE_DISCONNECTSCREENOFF) { - processDisconnectScreenOff(msg, conMgr); - } -} - -void DisconnectManager::processDisconnectKeepAlive(NetCommandMsg *msg, ConnectionManager *conMgr) { - NetDisconnectKeepAliveCommandMsg *cmdMsg = (NetDisconnectKeepAliveCommandMsg *)msg; - Int slot = translatedSlotPosition(cmdMsg->getPlayerID(), conMgr->getLocalPlayerID()); - if (slot != -1) { - resetPlayerTimeout(slot); - } -} - -void DisconnectManager::processDisconnectPlayer(NetCommandMsg *msg, ConnectionManager *conMgr) { - NetDisconnectPlayerCommandMsg *cmdMsg = (NetDisconnectPlayerCommandMsg *)msg; - DEBUG_LOG(("DisconnectManager::processDisconnectPlayer - Got disconnect player command from player %d. Disconnecting player %d on frame %d", msg->getPlayerID(), cmdMsg->getDisconnectSlot(), cmdMsg->getDisconnectFrame())); - DEBUG_ASSERTCRASH(TheGameLogic->getFrame() == cmdMsg->getDisconnectFrame(), ("disconnecting player on the wrong frame!!!")); - disconnectPlayer(cmdMsg->getDisconnectSlot(), conMgr); -} - -void DisconnectManager::processPacketRouterQuery(NetCommandMsg *msg, ConnectionManager *conMgr) { - NetPacketRouterQueryCommandMsg *cmdMsg = (NetPacketRouterQueryCommandMsg *)msg; - DEBUG_LOG(("DisconnectManager::processPacketRouterQuery - got a packet router query command from player %d", msg->getPlayerID())); - - if (conMgr->getPacketRouterSlot() == conMgr->getLocalPlayerID()) { - NetPacketRouterAckCommandMsg *ackmsg = newInstance(NetPacketRouterAckCommandMsg); - ackmsg->setPlayerID(conMgr->getLocalPlayerID()); - if (DoesCommandRequireACommandID(ackmsg->getNetCommandType()) == TRUE) { - ackmsg->setID(GenerateNextCommandID()); - } - DEBUG_LOG(("DisconnectManager::processPacketRouterQuery - We are the new packet router, responding with an packet router ack. Local player is %d", ackmsg->getPlayerID())); - conMgr->sendLocalCommandDirect(ackmsg, 1 << cmdMsg->getPlayerID()); - ackmsg->detach(); - } else { - DEBUG_LOG(("DisconnectManager::processPacketRouterQuery - We are NOT the new packet router, these are not the droids you're looking for.")); - } -} - -void DisconnectManager::processPacketRouterAck(NetCommandMsg *msg, ConnectionManager *conMgr) { - NetPacketRouterAckCommandMsg *cmdMsg = (NetPacketRouterAckCommandMsg *)msg; - DEBUG_LOG(("DisconnectManager::processPacketRouterAck - got packet router ack command from player %d", msg->getPlayerID())); - - if (conMgr->getPacketRouterSlot() == cmdMsg->getPlayerID()) { - DEBUG_LOG(("DisconnectManager::processPacketRouterAck - packet router command is from who it should be.")); - resetPacketRouterTimeout(); - Int currentPacketRouterSlot = conMgr->getPacketRouterSlot(); - Int currentPacketRouterIndex = 0; - while ((currentPacketRouterSlot != conMgr->getPacketRouterFallbackSlot(currentPacketRouterIndex)) && (currentPacketRouterIndex < MAX_SLOTS)) { - ++currentPacketRouterIndex; - } - DEBUG_ASSERTCRASH((currentPacketRouterIndex < MAX_SLOTS), ("Invalid packet router index")); - - DEBUG_LOG(("DisconnectManager::processPacketRouterAck - New packet router confirmed, resending pending commands")); - conMgr->resendPendingCommands(); - m_currentPacketRouterIndex = currentPacketRouterIndex; - DEBUG_LOG(("DisconnectManager::processPacketRouterAck - Setting disconnect state to screen on.")); - m_disconnectState = DISCONNECTSTATETYPE_SCREENON; ///< set it to screen on so that the next call to AllCommandsReady can set up everything for the next frame properly. - } -} - -void DisconnectManager::processDisconnectVote(NetCommandMsg *msg, ConnectionManager *conMgr) { - NetDisconnectVoteCommandMsg *cmdMsg = (NetDisconnectVoteCommandMsg *)msg; - DEBUG_LOG(("DisconnectManager::processDisconnectVote - Got a disconnect vote for player %d command from player %d", cmdMsg->getSlot(), cmdMsg->getPlayerID())); - Int transSlot = translatedSlotPosition(msg->getPlayerID(), conMgr->getLocalPlayerID()); - - if (isPlayerInGame(transSlot, conMgr) == FALSE) { - // if they've been timed out, voted out, disconnected, don't count their vote. - return; - } - - applyDisconnectVote(cmdMsg->getSlot(), cmdMsg->getVoteFrame(), cmdMsg->getPlayerID(), conMgr); -} - -void DisconnectManager::processDisconnectFrame(NetCommandMsg *msg, ConnectionManager *conMgr) { - NetDisconnectFrameCommandMsg *cmdMsg = (NetDisconnectFrameCommandMsg *)msg; - UnsignedInt playerID = cmdMsg->getPlayerID(); - if (m_disconnectFrames[playerID] >= cmdMsg->getDisconnectFrame()) { - // this message isn't valid, we have a disconnect frame that is later than this already. - return; - } - - if (m_disconnectFramesReceived[playerID] == TRUE) { - DEBUG_LOG(("DisconnectManager::processDisconnectFrame - Got two disconnect frames without an intervening disconnect screen off command from player %d. Frames are %d and %d", playerID, m_disconnectFrames[playerID], cmdMsg->getDisconnectFrame())); - } - - DEBUG_LOG(("DisconnectManager::processDisconnectFrame - about to call resetPlayersVotes for player %d", playerID)); - resetPlayersVotes(playerID, cmdMsg->getDisconnectFrame()-1, conMgr); - - m_disconnectFrames[playerID] = cmdMsg->getDisconnectFrame(); - m_disconnectFramesReceived[playerID] = TRUE; - DEBUG_LOG(("DisconnectManager::processDisconnectFrame - Got a disconnect frame for player %d, frame = %d, local player is %d, local disconnect frame = %d, command id = %d", cmdMsg->getPlayerID(), cmdMsg->getDisconnectFrame(), conMgr->getLocalPlayerID(), m_disconnectFrames[conMgr->getLocalPlayerID()], cmdMsg->getID())); - - if (playerID == conMgr->getLocalPlayerID()) { - DEBUG_LOG(("DisconnectManager::processDisconnectFrame - player %d is the local player", playerID)); - // we just got the message from the local player, check to see if we need to send - // commands to anyone we already have heard from. - for (Int i = 0; i < MAX_SLOTS; ++i) { - if (i != playerID) { - Int transSlot = translatedSlotPosition(i, conMgr->getLocalPlayerID()); - if (isPlayerInGame(transSlot, conMgr) == TRUE) { - if ((m_disconnectFrames[i] < m_disconnectFrames[playerID]) && (m_disconnectFramesReceived[i] == TRUE)) { - DEBUG_LOG(("DisconnectManager::processDisconnectFrame - I have more frames than player %d, my frame = %d, their frame = %d", i, m_disconnectFrames[conMgr->getLocalPlayerID()], m_disconnectFrames[i])); - conMgr->sendFrameDataToPlayer(i, m_disconnectFrames[i]); - } - } - } - } - } else if ((m_disconnectFrames[playerID] < m_disconnectFrames[conMgr->getLocalPlayerID()]) && (m_disconnectFramesReceived[playerID] == TRUE)) { - DEBUG_LOG(("DisconnectManager::processDisconnectFrame - I have more frames than player %d, my frame = %d, their frame = %d", playerID, m_disconnectFrames[conMgr->getLocalPlayerID()], m_disconnectFrames[playerID])); - conMgr->sendFrameDataToPlayer(playerID, m_disconnectFrames[playerID]); - } -} - -void DisconnectManager::processDisconnectScreenOff(NetCommandMsg *msg, ConnectionManager *conMgr) { - NetDisconnectScreenOffCommandMsg *cmdMsg = (NetDisconnectScreenOffCommandMsg *)msg; - UnsignedInt playerID = cmdMsg->getPlayerID(); - - DEBUG_LOG(("DisconnectManager::processDisconnectScreenOff - got a screen off command from player %d for frame %d", cmdMsg->getPlayerID(), cmdMsg->getNewFrame())); - - if ((playerID < 0) || (playerID >= MAX_SLOTS)) { - return; - } - - UnsignedInt newFrame = cmdMsg->getNewFrame(); - if (newFrame >= m_disconnectFrames[playerID]) { - DEBUG_LOG(("DisconnectManager::processDisconnectScreenOff - resetting the disconnect screen status for player %d", playerID)); - m_disconnectFramesReceived[playerID] = FALSE; - m_disconnectFrames[playerID] = newFrame; // just in case we get packets out of order and the disconnect screen off message gets here before the disconnect frame message. - - DEBUG_LOG(("DisconnectManager::processDisconnectScreenOff - about to call resetPlayersVotes for player %d", playerID)); - resetPlayersVotes(playerID, cmdMsg->getNewFrame(), conMgr); - } -} - -void DisconnectManager::applyDisconnectVote(Int slot, UnsignedInt frame, Int fromSlot, ConnectionManager *conMgr) { - m_playerVotes[slot][fromSlot].vote = TRUE; - m_playerVotes[slot][fromSlot].frame = frame; - Int numVotes = countVotesForPlayer(slot); - DEBUG_LOG(("DisconnectManager::applyDisconnectVote - added a vote to disconnect slot %d, from slot %d, for frame %d, current votes are %d", slot, fromSlot, frame, numVotes)); - Int transSlot = translatedSlotPosition(slot, conMgr->getLocalPlayerID()); - if (transSlot != -1) { - TheDisconnectMenu->updateVotes(transSlot, numVotes); - } -} - -void DisconnectManager::nextFrame(UnsignedInt frame, ConnectionManager *conMgr) { - m_lastFrame = frame; - m_lastFrameTime = timeGetTime(); - resetPlayerTimeouts(conMgr); -} - -void DisconnectManager::allCommandsReady(UnsignedInt frame, ConnectionManager *conMgr, Bool waitForPacketRouter) { - if (m_disconnectState != DISCONNECTSTATETYPE_SCREENOFF) { - DEBUG_LOG(("DisconnectManager::allCommandsReady - setting screen state to off.")); - - TheDisconnectMenu->hideScreen(); - m_disconnectState = DISCONNECTSTATETYPE_SCREENOFF; - TheNetwork->notifyOthersOfNewFrame(frame); - - // reset the votes since we're moving to a new frame. - for (Int i = 0; i < MAX_SLOTS; ++i) { - m_playerVotes[i][conMgr->getLocalPlayerID()].vote = FALSE; - } - - DEBUG_LOG(("DisconnectManager::allCommandsReady - resetting m_timeOfDisconnectScreenOn")); - m_timeOfDisconnectScreenOn = 0; - } -} - -Bool DisconnectManager::allowedToContinue() { - if (m_disconnectState != DISCONNECTSTATETYPE_SCREENOFF) { - return FALSE; - } - return TRUE; -} - -void DisconnectManager::sendKeepAlive(ConnectionManager *conMgr) { - time_t curTime = timeGetTime(); - - if (((curTime - m_lastKeepAliveSendTime) > 500) || (m_lastKeepAliveSendTime == -1)) { - NetDisconnectKeepAliveCommandMsg *msg = newInstance(NetDisconnectKeepAliveCommandMsg); - msg->setPlayerID(conMgr->getLocalPlayerID()); - if (DoesCommandRequireACommandID(msg->getNetCommandType()) == TRUE) { - msg->setID(GenerateNextCommandID()); - } - conMgr->sendLocalCommandDirect(msg, 0xff ^ (1 << msg->getPlayerID())); - msg->detach(); - - m_lastKeepAliveSendTime = curTime; - } -} - -void DisconnectManager::populateDisconnectScreen(ConnectionManager *conMgr) { - for (Int i = 0; i < MAX_SLOTS; ++i) { - UnicodeString name = conMgr->getPlayerName(i); - Int slot = translatedSlotPosition(i, conMgr->getLocalPlayerID()); - if (slot != -1) { - TheDisconnectMenu->setPlayerName(slot, name); - - Int numVotes = countVotesForPlayer(i); - TheDisconnectMenu->updateVotes(slot, numVotes); - } - } -} - -Int DisconnectManager::translatedSlotPosition(Int slot, Int localSlot) { - if (slot < localSlot) { - return slot; - } - - if (slot == localSlot) { - return -1; - } - - return (slot - 1); -} - -Int DisconnectManager::untranslatedSlotPosition(Int slot, Int localSlot) { - if (slot == -1) { - return localSlot; - } - - if (slot < localSlot) { - return slot; - } - - return (slot + 1); -} - -void DisconnectManager::resetPlayerTimeouts(ConnectionManager *conMgr) { - // reset the player timeouts. - for (Int i = 0; i < MAX_SLOTS; ++i) { - Int slot = translatedSlotPosition(i, conMgr->getLocalPlayerID()); - if (slot != -1) { - resetPlayerTimeout(slot); - } - } -} - -void DisconnectManager::resetPlayerTimeout(Int slot) { - m_playerTimeouts[slot] = timeGetTime(); -} - -void DisconnectManager::resetPacketRouterTimeout() { - m_packetRouterTimeout = timeGetTime(); -} - -void DisconnectManager::turnOnScreen(ConnectionManager *conMgr) { - TheDisconnectMenu->showScreen(); - DEBUG_LOG(("DisconnectManager::turnOnScreen - turning on screen on frame %d", TheGameLogic->getFrame())); - m_disconnectState = DISCONNECTSTATETYPE_SCREENON; - m_lastKeepAliveSendTime = -1; - populateDisconnectScreen(conMgr); - resetPlayerTimeouts(conMgr); - TheDisconnectMenu->hidePacketRouterTimeout(); - - m_haveNotifiedOtherPlayersOfCurrentFrame = FALSE; - - m_timeOfDisconnectScreenOn = timeGetTime(); - DEBUG_LOG(("DisconnectManager::turnOnScreen - turned on screen at time %d", m_timeOfDisconnectScreenOn)); -} - -void DisconnectManager::disconnectPlayer(Int slot, ConnectionManager *conMgr) { - DEBUG_LOG(("DisconnectManager::disconnectPlayer - Disconnecting slot number %d on frame %d", slot, TheGameLogic->getFrame())); - DEBUG_ASSERTCRASH((slot >= 0) && (slot < MAX_SLOTS), ("Attempting to disconnect an invalid slot number")); - if ((slot < 0) || (slot >= (MAX_SLOTS))) { - return; - } - - if (TheGameInfo) - { - GameSlot *gSlot = TheGameInfo->getSlot( slot ); - if (gSlot) - { - gSlot->markAsDisconnected(); - } - } - - Int transSlot = translatedSlotPosition(slot, conMgr->getLocalPlayerID()); - - if (transSlot != -1) { - // Ignore any disconnect commands that tell us to disconnect ourselves. - - // Get the disconnecting player off the disconnect window. - UnicodeString uname = conMgr->getPlayerName(slot); - TheRecorder->logPlayerDisconnect(uname, slot); - TheDisconnectMenu->removePlayer(transSlot, uname); - - PlayerLeaveCode retcode = conMgr->disconnectPlayer(slot); - DEBUG_ASSERTCRASH((retcode != PLAYERLEAVECODE_UNKNOWN), ("Invalid player leave code")); - - if (retcode == PLAYERLEAVECODE_PACKETROUTER) { - DEBUG_LOG(("DisconnectManager::disconnectPlayer - disconnecting player was packet router.")); - - conMgr->resendPendingCommands(); - } - } -} - -void DisconnectManager::sendDisconnectCommand(Int slot, ConnectionManager *conMgr) { - DEBUG_LOG(("DisconnectManager::sendDisconnectCommand - Sending disconnect command for slot number %d", slot)); - DEBUG_ASSERTCRASH((slot >= 0) && (slot < MAX_SLOTS), ("Attempting to send a disconnect command for an invalid slot number")); - if ((slot < 0) || (slot >= (MAX_SLOTS))) { - return; - } - - UnsignedInt disconnectFrame = getMaxDisconnectFrame(); - - // Need to do the NetDisconnectPlayerCommandMsg creation and sending here. - NetDisconnectPlayerCommandMsg *msg = newInstance(NetDisconnectPlayerCommandMsg); - msg->setDisconnectSlot(slot); - msg->setDisconnectFrame(disconnectFrame); - msg->setPlayerID(conMgr->getLocalPlayerID()); - if (DoesCommandRequireACommandID(msg->getNetCommandType())) { - msg->setID(GenerateNextCommandID()); - } - - conMgr->sendLocalCommand(msg); - - DEBUG_LOG(("DisconnectManager::sendDisconnectCommand - Sending disconnect command for slot number %d for frame %d", slot, disconnectFrame)); - - msg->detach(); -} - -void DisconnectManager::sendVoteCommand(Int slot, ConnectionManager *conMgr) { - NetDisconnectVoteCommandMsg *msg = newInstance(NetDisconnectVoteCommandMsg); - - msg->setPlayerID(conMgr->getLocalPlayerID()); - msg->setSlot(slot); - msg->setVoteFrame(TheGameLogic->getFrame()); - if (DoesCommandRequireACommandID(msg->getNetCommandType()) == TRUE) { - msg->setID(GenerateNextCommandID()); - } - - conMgr->sendLocalCommandDirect(msg, 0xff & ~(1 << conMgr->getLocalPlayerID())); - - msg->detach(); -} - -void DisconnectManager::voteForPlayerDisconnect(Int slot, ConnectionManager *conMgr) { - Int transSlot = untranslatedSlotPosition(slot, conMgr->getLocalPlayerID()); - - if (m_playerVotes[transSlot][conMgr->getLocalPlayerID()].vote == FALSE) { - m_playerVotes[transSlot][conMgr->getLocalPlayerID()].vote = TRUE; - - sendVoteCommand(transSlot, conMgr); - - // we use the game logic frame cause we might not have sent out our own disconnect frame yet. - applyDisconnectVote(transSlot, TheGameLogic->getFrame(), conMgr->getLocalPlayerID(), conMgr); - } -} - -void DisconnectManager::recalculatePacketRouterIndex(ConnectionManager *conMgr) { - Int currentPacketRouterSlot = conMgr->getPacketRouterSlot(); - m_currentPacketRouterIndex = 0; - while ((currentPacketRouterSlot != conMgr->getPacketRouterFallbackSlot(m_currentPacketRouterIndex)) && (m_currentPacketRouterIndex < MAX_SLOTS)) { - ++m_currentPacketRouterIndex; - } - DEBUG_ASSERTCRASH((m_currentPacketRouterIndex < MAX_SLOTS), ("Invalid packet router index")); -} - -Bool DisconnectManager::allOnSameFrame(ConnectionManager *conMgr) { - Bool retval = TRUE; - for (Int i = 0; (i < MAX_SLOTS) && (retval == TRUE); ++i) { - Int transSlot = translatedSlotPosition(i, conMgr->getLocalPlayerID()); - if (transSlot == -1) { - continue; - } - if ((conMgr->isPlayerConnected(i) == TRUE) && (isPlayerInGame(transSlot, conMgr) == TRUE)) { - // ok, i is someone who is in the game and hasn't timed out yet or been voted out. - if (m_disconnectFramesReceived[i] == FALSE) { - // we don't know what frame they are on yet. - retval = FALSE; - } - if ((m_disconnectFramesReceived[i] == TRUE) && (m_disconnectFrames[conMgr->getLocalPlayerID()] != m_disconnectFrames[i])) { - // We know their frame, but they aren't on the same frame as us. - retval = FALSE; - } - } - } - return retval; -} - -Bool DisconnectManager::isLocalPlayerNextPacketRouter(ConnectionManager *conMgr) { - UnsignedInt localSlot = conMgr->getLocalPlayerID(); - UnsignedInt packetRouterSlot = conMgr->getPacketRouterSlot(); - Int transSlot = translatedSlotPosition(packetRouterSlot, localSlot); - - // stop when we have found a packet router that is connected - while ((transSlot != -1) && (isPlayerInGame(transSlot, conMgr) == FALSE)) { - packetRouterSlot = conMgr->getNextPacketRouterSlot(packetRouterSlot); - if ((packetRouterSlot >= MAX_SLOTS) || (packetRouterSlot < 0)) { - // don't know who the next packet router is going to be, - // so this game is not going to go anywhere anymore. - DEBUG_CRASH(("no more players left to be the packet router, this shouldn't happen.")); - return FALSE; - } - transSlot = translatedSlotPosition(packetRouterSlot, localSlot); - } - - if (packetRouterSlot == localSlot) { - return TRUE; - } - - return FALSE; -} - -Bool DisconnectManager::hasPlayerTimedOut(Int slot) { - if (slot == -1) { - return FALSE; - } - - time_t newTime = TheGlobalData->m_networkPlayerTimeoutTime - (timeGetTime() - m_playerTimeouts[slot]); - if (newTime <= 0) { - return TRUE; - } - - return FALSE; -} - -// this function assumes that we are the packet router. (or at least that -// we will be after everyone is getting disconnected) -void DisconnectManager::sendPlayerDestruct(Int slot, ConnectionManager *conMgr) { - UnsignedShort currentID = 0; - if (DoesCommandRequireACommandID(NETCOMMANDTYPE_DESTROYPLAYER)) - { - currentID = GenerateNextCommandID(); - } - - DEBUG_LOG(("Queueing DestroyPlayer %d for frame %d on frame %d as command %d", - slot, TheNetwork->getExecutionFrame()+1, TheGameLogic->getFrame(), currentID)); - - NetDestroyPlayerCommandMsg *netmsg = newInstance(NetDestroyPlayerCommandMsg); - netmsg->setExecutionFrame(TheNetwork->getExecutionFrame()+1); - netmsg->setPlayerID(conMgr->getLocalPlayerID()); - netmsg->setID(currentID); - netmsg->setPlayerIndex(slot); - conMgr->sendLocalCommand(netmsg); - netmsg->detach(); -} - -// the 'slot' variable is supposed to be a translated slot position. (translated slot meaning -// that it is the player's position in the disconnect menu) -Bool DisconnectManager::isPlayerVotedOut(Int slot, ConnectionManager *conMgr) { - if (slot == -1) { - // we can't vote out ourselves. - return FALSE; - } - Int transSlot = untranslatedSlotPosition(slot, conMgr->getLocalPlayerID()); - Int numVotes = countVotesForPlayer(transSlot); - if (numVotes >= (conMgr->getNumPlayers() - 1)) { - return TRUE; - } - return FALSE; -} - -UnsignedInt DisconnectManager::getMaxDisconnectFrame() { - UnsignedInt retval = 0; - for (Int i = 0; i < MAX_SLOTS; ++i) { - if (m_disconnectFrames[i] > retval) { - retval = m_disconnectFrames[i]; - } - } - return retval; -} - -Bool DisconnectManager::isPlayerInGame(Int slot, ConnectionManager *conMgr) { - Int transSlot = untranslatedSlotPosition(slot, conMgr->getLocalPlayerID()); - DEBUG_ASSERTCRASH((transSlot >= 0) && (transSlot < MAX_SLOTS), ("invalid slot number")); - if (((transSlot < 0) || (transSlot >= MAX_SLOTS)) || conMgr->isPlayerConnected(transSlot) == FALSE) { - return FALSE; - } - - if (isPlayerVotedOut(slot, conMgr) == TRUE) { - return FALSE; - } - - if (hasPlayerTimedOut(slot) == TRUE) { - return FALSE; - } - - return TRUE; -} - -void DisconnectManager::playerHasAdvancedAFrame(Int slot, UnsignedInt frame) { - // if they have advanced beyond the frame they had been previously disconnecting on. - if (frame >= m_disconnectFrames[slot]) { - m_disconnectFrames[slot] = frame; // just in case we get a disconnect frame command after this is called. - m_disconnectFramesReceived[slot] = FALSE; - } -} - -Int DisconnectManager::countVotesForPlayer(Int slot) { - if ((slot < 0) || (slot >= MAX_SLOTS)) { - return 0; - } - - Int retval = 0; - for (Int i = 0; i < MAX_SLOTS; ++i) { - // using TheGameLogic->getFrame() cause we might not have sent our disconnect frame yet. - if ((m_playerVotes[slot][i].vote == TRUE) && (m_playerVotes[slot][i].frame == TheGameLogic->getFrame())) { - ++retval; - } - } - - return retval; -} - -void DisconnectManager::resetPlayersVotes(Int playerID, UnsignedInt frame, ConnectionManager *conMgr) { - DEBUG_LOG(("DisconnectManager::resetPlayersVotes - resetting player %d's votes on frame %d", playerID, frame)); - - // we need to reset this player's votes that happened before or on the given frame. - for(Int i = 0; i < MAX_SLOTS; ++i) { - if (m_playerVotes[i][playerID].frame <= frame) { - DEBUG_LOG(("DisconnectManager::resetPlayersVotes - resetting player %d's vote for player %d from frame %d on frame %d", playerID, i, m_playerVotes[i][playerID].frame, frame)); - m_playerVotes[i][playerID].vote = FALSE; - } - } - - Int numVotes = countVotesForPlayer(playerID); - DEBUG_LOG(("DisconnectManager::resetPlayersVotes - after adjusting votes, player %d has %d votes", playerID, numVotes)); - Int transSlot = translatedSlotPosition(playerID, conMgr->getLocalPlayerID()); - if (transSlot != -1) { - TheDisconnectMenu->updateVotes(transSlot, numVotes); - } -} diff --git a/Generals/Code/GameEngine/Source/GameNetwork/DownloadManager.cpp b/Generals/Code/GameEngine/Source/GameNetwork/DownloadManager.cpp deleted file mode 100644 index 221ed56f95..0000000000 --- a/Generals/Code/GameEngine/Source/GameNetwork/DownloadManager.cpp +++ /dev/null @@ -1,224 +0,0 @@ -/* -** 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. // -// // -//////////////////////////////////////////////////////////////////////////////// - -// FILE: DownloadManager.cpp ////////////////////////////////////////////////////// -// Generals download manager code -// Author: Matthew D. Campbell, July 2002 - -#include "PreRTS.h" // This must go first in EVERY cpp file in the GameEngine - -#include "GameClient/GameText.h" -#include "GameNetwork/DownloadManager.h" - -DownloadManager *TheDownloadManager; - -DownloadManager::DownloadManager() -{ - m_download = NEW CDownload(this); - m_wasError = m_sawEnd = false; - - //Added By Sadullah Nader - //Initializations missing and needed - - m_queuedDownloads.clear(); - - // - - m_statusString = TheGameText->fetch("FTP:StatusIdle"); - - // ----- Initialize Winsock ----- - m_winsockInit = true; - WORD verReq = MAKEWORD(2, 2); - WSADATA wsadata; - - int err = WSAStartup(verReq, &wsadata); - if (err != 0) - { - m_winsockInit = false; - } - else - { - if ((LOBYTE(wsadata.wVersion) != 2) || (HIBYTE(wsadata.wVersion) !=2)) - { - WSACleanup(); - m_winsockInit = false; - } - } - -} - -DownloadManager::~DownloadManager() -{ - delete m_download; - if (m_winsockInit) - { - WSACleanup(); - m_winsockInit = false; - } -} - -void DownloadManager::init( void ) -{ -} - -void DownloadManager::reset( void ) -{ -} - -HRESULT DownloadManager::update( void ) -{ - return m_download->PumpMessages(); -} - -HRESULT DownloadManager::downloadFile( AsciiString server, AsciiString username, AsciiString password, AsciiString file, AsciiString localfile, AsciiString regkey, Bool tryResume ) -{ - return m_download->DownloadFile( server.str(), username.str(), password.str(), file.str(), localfile.str(), regkey.str(), tryResume ); -} - -void DownloadManager::queueFileForDownload( AsciiString server, AsciiString username, AsciiString password, AsciiString file, AsciiString localfile, AsciiString regkey, Bool tryResume ) -{ - QueuedDownload q; - q.file = file; - q.localFile = localfile; - q.password = password; - q.regKey = regkey; - q.server = server; - q.tryResume = tryResume; - q.userName = username; - - m_queuedDownloads.push_back(q); -} - -HRESULT DownloadManager::downloadNextQueuedFile( void ) -{ - QueuedDownload q; - std::list::iterator it = m_queuedDownloads.begin(); - if (it != m_queuedDownloads.end()) - { - q = *it; - m_queuedDownloads.pop_front(); - m_wasError = m_sawEnd = false; - return downloadFile( q.server, q.userName, q.password, q.file, q.localFile, q.regKey, q.tryResume ); - } - else - { - DEBUG_CRASH(("Starting non-existent download!")); - return S_OK; - } -} - -AsciiString DownloadManager::getLastLocalFile( void ) -{ - char buf[256] = ""; - m_download->GetLastLocalFile(buf, 256); - return buf; -} - -HRESULT DownloadManager::OnError( Int error ) -{ - m_wasError = true; - AsciiString s = "FTP:UnknownError"; - switch (error) - { - case DOWNLOADEVENT_NOSUCHSERVER: - s = "FTP:NoSuchServer"; - break; - case DOWNLOADEVENT_COULDNOTCONNECT: - s = "FTP:CouldNotConnect"; - break; - case DOWNLOADEVENT_LOGINFAILED: - s = "FTP:LoginFailed"; - break; - case DOWNLOADEVENT_NOSUCHFILE: - s = "FTP:NoSuchFile"; - break; - case DOWNLOADEVENT_LOCALFILEOPENFAILED: - s = "FTP:LocalFileOpenFailed"; - break; - case DOWNLOADEVENT_TCPERROR: - s = "FTP:TCPError"; - break; - case DOWNLOADEVENT_DISCONNECTERROR: - s = "FTP:DisconnectError"; - break; - } - m_errorString = TheGameText->fetch(s); - DEBUG_LOG(("DownloadManager::OnError(): %s(%d)", s.str(), error)); - return S_OK; -} - -HRESULT DownloadManager::OnEnd() -{ - m_sawEnd = true; - DEBUG_LOG(("DownloadManager::OnEnd()")); - return S_OK; -} - -HRESULT DownloadManager::OnQueryResume() -{ - DEBUG_LOG(("DownloadManager::OnQueryResume()")); - //return DOWNLOADEVENT_DONOTRESUME; - return DOWNLOADEVENT_RESUME; -} - -HRESULT DownloadManager::OnProgressUpdate( Int bytesread, Int totalsize, Int timetaken, Int timeleft ) -{ - DEBUG_LOG(("DownloadManager::OnProgressUpdate(): %d/%d %d/%d", bytesread, totalsize, timetaken, timeleft)); - return S_OK; -} - -HRESULT DownloadManager::OnStatusUpdate( Int status ) -{ - AsciiString s = "FTP:StatusNone"; - switch (status) - { - case DOWNLOADSTATUS_CONNECTING: - s = "FTP:StatusConnecting"; - break; - case DOWNLOADSTATUS_LOGGINGIN: - s = "FTP:StatusLoggingIn"; - break; - case DOWNLOADSTATUS_FINDINGFILE: - s = "FTP:StatusFindingFile"; - break; - case DOWNLOADSTATUS_QUERYINGRESUME: - s = "FTP:StatusQueryingResume"; - break; - case DOWNLOADSTATUS_DOWNLOADING: - s = "FTP:StatusDownloading"; - break; - case DOWNLOADSTATUS_DISCONNECTING: - s = "FTP:StatusDisconnecting"; - break; - case DOWNLOADSTATUS_FINISHING: - s = "FTP:StatusFinishing"; - break; - case DOWNLOADSTATUS_DONE: - s = "FTP:StatusDone"; - break; - } - m_statusString = TheGameText->fetch(s); - DEBUG_LOG(("DownloadManager::OnStatusUpdate(): %s(%d)", s.str(), status)); - return S_OK; -} diff --git a/Generals/Code/GameEngine/Source/GameNetwork/FileTransfer.cpp b/Generals/Code/GameEngine/Source/GameNetwork/FileTransfer.cpp deleted file mode 100644 index e30a4ed52f..0000000000 --- a/Generals/Code/GameEngine/Source/GameNetwork/FileTransfer.cpp +++ /dev/null @@ -1,283 +0,0 @@ -/* -** 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. // -// // -//////////////////////////////////////////////////////////////////////////////// - -/////////////////////////////////////////////////////////////////////////////////////// -// FILE: FileTransfer.cpp -// Author: Matthew D. Campbell, December 2002 -// Description: File Transfer wrapper using TheNetwork -/////////////////////////////////////////////////////////////////////////////////////// - -#include "PreRTS.h" // This must go first in EVERY cpp file in the GameEngine - -#include "GameClient/LoadScreen.h" -#include "GameClient/Shell.h" -#include "GameNetwork/FileTransfer.h" -#include "GameNetwork/networkutil.h" - -//------------------------------------------------------------------------------------- -//------------------------------------------------------------------------------------- - -static Bool doFileTransfer( AsciiString filename, MapTransferLoadScreen *ls, Int mask ) -{ - Bool fileTransferDone = FALSE; - Int fileTransferPercent = 0; - Int i; - - if (mask) - { - ls->setCurrentFilename(filename); - UnsignedInt startTime = timeGetTime(); - const Int timeoutPeriod = 2*60*1000; - ls->processTimeout(timeoutPeriod/1000); - - ls->update(0); - fileTransferDone = FALSE; - fileTransferPercent = 0; - - UnsignedShort fileCommandID = 0; - Bool sentFile = FALSE; - if (TheGameInfo->amIHost()) - { - Sleep(500); - fileCommandID = TheNetwork->sendFileAnnounce(filename, mask); - } - else - { - sentFile = TRUE; - } - - DEBUG_LOG(("Starting file transfer loop")); - - while (!fileTransferDone) - { - if (!sentFile && TheNetwork->areAllQueuesEmpty()) - { - TheNetwork->sendFile(filename, mask, fileCommandID); - sentFile = TRUE; - } - - // get the progress for each player, and take the min for our overall progress - fileTransferDone = TRUE; - fileTransferPercent = 100; - for (i=1; igetConstSlot(i)->isHuman() && !TheGameInfo->getConstSlot(i)->hasMap()) - { - Int slotTransferPercent = TheNetwork->getFileTransferProgress(i, filename); - fileTransferPercent = min(fileTransferPercent, slotTransferPercent); - - if (slotTransferPercent == 0) - ls->processProgress(i, slotTransferPercent, "MapTransfer:Preparing"); - else if (slotTransferPercent < 100) - ls->processProgress(i, slotTransferPercent, "MapTransfer:Recieving"); - else - ls->processProgress(i, slotTransferPercent, "MapTransfer:Done"); - } - } - if (fileTransferPercent < 100) - { - fileTransferDone = FALSE; - if (fileTransferPercent == 0) - ls->processProgress(0, fileTransferPercent, "MapTransfer:Preparing"); - else - ls->processProgress(0, fileTransferPercent, "MapTransfer:Sending"); - } - else - { - DEBUG_LOG(("File transfer is 100%%!")); - ls->processProgress(0, fileTransferPercent, "MapTransfer:Done"); - } - - Int now = timeGetTime(); - if (now > startTime + timeoutPeriod) // bail if we don't finish in a reasonable amount of time - { - DEBUG_LOG(("Timing out file transfer")); - break; - } - else - { - ls->processTimeout((startTime + timeoutPeriod - now)/1000); - } - - ls->update(fileTransferPercent); - } - - if (!fileTransferDone) - { - return FALSE; - } - } - - return TRUE; -} - -//------------------------------------------------------------------------------------- -//------------------------------------------------------------------------------------- - -AsciiString GetBasePathFromPath( AsciiString path ) -{ - const char *s = path.reverseFind('\\'); - if (s) - { - Int len = s - path.str(); - - AsciiString base; - char *buf = base.getBufferForRead(len + 1); - memcpy(buf, path.str(), len); - buf[len] = 0; - return buf; - } - return AsciiString::TheEmptyString; -} - -AsciiString GetFileFromPath( AsciiString path ) -{ - const char *s = path.reverseFind('\\'); - if (s) - return s+1; - return path; -} - -AsciiString GetExtensionFromFile( AsciiString fname ) -{ - const char *s = fname.reverseFind('.'); - if (s) - return s+1; - return fname; -} - -AsciiString GetBaseFileFromFile( AsciiString fname ) -{ - const char *s = fname.reverseFind('.'); - if (s) - { - Int len = s - fname.str(); - - AsciiString base; - char *buf = base.getBufferForRead(len + 1); - memcpy(buf, fname.str(), len); - buf[len] = 0; - return buf; - } - return AsciiString::TheEmptyString; -} - -AsciiString GetPreviewFromMap( AsciiString path ) -{ - AsciiString fname = GetBaseFileFromFile(GetFileFromPath(path)); - AsciiString base = GetBasePathFromPath(path); - - AsciiString out; - out.format("%s\\%s.tga", base.str(), fname.str()); - return out; -} - -AsciiString GetINIFromMap( AsciiString path ) -{ - AsciiString base = GetBasePathFromPath(path); - - AsciiString out; - out.format("%s\\map.ini", base.str()); - return out; -} - -AsciiString GetStrFileFromMap( AsciiString path ) -{ - AsciiString base = GetBasePathFromPath(path); - - AsciiString out; - out.format("%s\\map.str", base.str()); - return out; -} - -AsciiString GetSoloINIFromMap( AsciiString path ) -{ - AsciiString base = GetBasePathFromPath(path); - - AsciiString out; - out.format("%s\\solo.ini", base.str()); - return out; -} - -AsciiString GetAssetUsageFromMap( AsciiString path ) -{ - AsciiString base = GetBasePathFromPath(path); - - AsciiString out; - out.format("%s\\assetusage.txt", base.str()); - return out; -} - -AsciiString GetReadmeFromMap( AsciiString path ) -{ - AsciiString base = GetBasePathFromPath(path); - - AsciiString out; - out.format("%s\\readme.txt", base.str()); - return out; -} - -//------------------------------------------------------------------------------------- -//------------------------------------------------------------------------------------- - -Bool DoAnyMapTransfers(GameInfo *game) -{ - TheGameInfo = game; - Int mask = 0; - Int i=0; - for (i=1; igetConstSlot(i)->isHuman() && !TheGameInfo->getConstSlot(i)->hasMap()) - { - DEBUG_LOG(("Adding player %d to transfer mask", i)); - mask |= (1<hideShell(); - MapTransferLoadScreen *ls = NEW MapTransferLoadScreen; - ls->init(TheGameInfo); - Bool ok = TRUE; - if (TheGameInfo->getMapContentsMask() & 2) - ok = doFileTransfer(GetPreviewFromMap(game->getMap()), ls, mask); - if (ok && TheGameInfo->getMapContentsMask() & 4) - ok = doFileTransfer(GetINIFromMap(game->getMap()), ls, mask); - if (ok && TheGameInfo->getMapContentsMask() & 8) - ok = doFileTransfer(GetStrFileFromMap(game->getMap()), ls, mask); - if (ok && TheGameInfo->getMapContentsMask() & 16) - ok = doFileTransfer(GetSoloINIFromMap(game->getMap()), ls, mask); - if (ok && TheGameInfo->getMapContentsMask() & 32) - ok = doFileTransfer(GetAssetUsageFromMap(game->getMap()), ls, mask); - if (ok && TheGameInfo->getMapContentsMask() & 64) - ok = doFileTransfer(GetReadmeFromMap(game->getMap()), ls, mask); - if (ok) - ok = doFileTransfer(game->getMap(), ls, mask); - delete ls; - ls = NULL; - if (!ok) - TheShell->showShell(); - return ok; -} diff --git a/Generals/Code/GameEngine/Source/GameNetwork/FirewallHelper.cpp b/Generals/Code/GameEngine/Source/GameNetwork/FirewallHelper.cpp deleted file mode 100644 index 8a2d756945..0000000000 --- a/Generals/Code/GameEngine/Source/GameNetwork/FirewallHelper.cpp +++ /dev/null @@ -1,1574 +0,0 @@ -/* -** 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. // -// // -//////////////////////////////////////////////////////////////////////////////// - - -/*********************************************************************************************** - *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S *** - *********************************************************************************************** - * * - * Project Name : Command & Conquer * - * * - * $Archive:: /RedAlert2/NAT.cpp $* - * * - * $Author:: Steve_t $* - * * - * $Modtime:: 3/15/01 12:00PM $* - * * - * $Revision:: 1 $* - * * - * * - *---------------------------------------------------------------------------------------------* - * * - * * - *---------------------------------------------------------------------------------------------* - * * - * Functions: * - * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - -#include "PreRTS.h" // This must go first in EVERY cpp file in the GameEngine - -#include "Common/crc.h" -#include "Common/UserPreferences.h" -#include "GameNetwork/FirewallHelper.h" -#include "GameNetwork/NAT.h" -#include "GameNetwork/udp.h" -#include "GameNetwork/NetworkDefs.h" -#include "GameNetwork/GameSpy/GSConfig.h" - - -FirewallHelperClass *TheFirewallHelper = NULL; - -FirewallHelperClass * createFirewallHelper() -{ - return NEW FirewallHelperClass(); -} - - -/*********************************************************************************************** - * FirewallHelperClass::FirewallHelperClass -- Constructor * - * * - * * - * * - * INPUT: Nothing * - * * - * OUTPUT: Nothing * - * * - * WARNINGS: None * - * * - * HISTORY: * - * 3/15/01 5:03PM ST : Created * - *=============================================================================================*/ -/* static */ Int FirewallHelperClass::m_sourcePortPool = 4096; - -FirewallHelperClass::FirewallHelperClass(void) -{ - //Added Sadullah Nader - //Initializations missing and needed - m_currentTry = 0; - m_numManglers = 0; - m_numResponses = 0; - m_packetID = 0; - m_timeoutLength = 0; - m_timeoutStart = 0; - // - - m_behavior = FIREWALL_TYPE_UNKNOWN; - m_lastBehavior = FIREWALL_TYPE_UNKNOWN; - m_sourcePortAllocationDelta = 0; - m_lastSourcePortAllocationDelta = 0; - Int i = 0; - for (; i < MAX_SPARE_SOCKETS; ++i) { - m_spareSockets[i].port = 0; - m_messages[i].length = 0; - m_mangledPorts[i] = 0; - m_sparePorts[i] = 0; - } - - for (i = 0; i < MAX_NUM_MANGLERS; i++) - { - m_manglers[i] = 0; - } - - m_currentState = DETECTIONSTATE_IDLE; - - m_sourcePortPool = 4096 + ((timeGetTime() / 1000) % 1000); // do this to make sure we don't use the same source - // port before a previous connection has had a chance - // to time out. -} - - - -/*********************************************************************************************** - * FirewallHelperClass::~FirewallHelperClass -- Destructor * - * * - * * - * * - * INPUT: Nothing * - * * - * OUTPUT: Nothing * - * * - * WARNINGS: None * - * * - * HISTORY: * - * 4/16/02 BGC : Created * - *=============================================================================================*/ -FirewallHelperClass::~FirewallHelperClass() -{ - reset(); -} - -/*********************************************************************************************** - * FirewallHelperClass::Reset -- Cleans out the object * - * * - * * - * * - * INPUT: Nothing * - * * - * OUTPUT: Nothing * - * * - * WARNINGS: None * - * * - * HISTORY: * - * 3/29/01 1:04AM ST : Created * - *=============================================================================================*/ -void FirewallHelperClass::reset(void) -{ - closeAllSpareSockets(); - m_currentState = DETECTIONSTATE_IDLE; - for (Int i = 0; i < MAX_SPARE_SOCKETS; ++i) { - m_messages[i].length = 0; - } -} - - - - -/*********************************************************************************************** - * FirewallHelperClass::Detect_Firewall -- See what our firewall is up to * - * * - * * - * * - * INPUT: Nothing * - * * - * OUTPUT: Nothing * - * * - * WARNINGS: None * - * * - * HISTORY: * - * 3/15/01 6:47PM ST : Created * - *=============================================================================================*/ -Bool FirewallHelperClass::detectFirewall(void) -{ - OptionPreferences pref; - - OptionPreferences::const_iterator it = pref.find("FirewallNeedToRefresh"); - if (it != pref.end()) { - AsciiString str = it->second; - if (str.compareNoCase("TRUE") == 0) { - TheWritableGlobalData->m_firewallBehavior = FIREWALL_TYPE_UNKNOWN; - } - } - - if (TheWritableGlobalData->m_firewallBehavior == FIREWALL_TYPE_UNKNOWN) { - detectFirewallBehavior(); - - return FALSE; - } else { - DEBUG_LOG(("FirewallHelperClass::detectFirewall - firewall behavior already specified as %d, port allocation delta is %d, skipping detection.", TheWritableGlobalData->m_firewallBehavior, TheWritableGlobalData->m_firewallPortAllocationDelta)); - } - - return TRUE; -} - - -Bool FirewallHelperClass::behaviorDetectionUpdate() -{ - if (m_currentState == DETECTIONSTATE_IDLE) { - return FALSE; - } - - if (m_currentState == DETECTIONSTATE_DONE) { - return TRUE; - } - - if (m_currentState == DETECTIONSTATE_BEGIN) { - return detectionBeginUpdate(); - } - - if (m_currentState == DETECTIONSTATE_TEST1) { - return detectionTest1Update(); - } - - if (m_currentState == DETECTIONSTATE_TEST2) { - return detectionTest2Update(); - } - - if (m_currentState == DETECTIONSTATE_TEST3) { - return detectionTest3Update(); - } - - if (m_currentState == DETECTIONSTATE_TEST3_WAITFORRESPONSES) { - return detectionTest3WaitForResponsesUpdate(); - } - - if (m_currentState == DETECTIONSTATE_TEST4_1) { - return detectionTest4Stage1Update(); - } - - if (m_currentState == DETECTIONSTATE_TEST4_2) { - return detectionTest4Stage2Update(); - } - - if (m_currentState == DETECTIONSTATE_TEST5) { - return detectionTest5Update(); - } - - return TRUE; -} - -/*********************************************************************************************** - * FHC::getNextTemporarySourcePort -- Get a throwaway source port for temporary use * - * * - * * - * * - * INPUT: number of ports in sequence to skip * - * * - * OUTPUT: port number * - * * - * WARNINGS: None * - * * - * HISTORY: * - * 3/15/01 12:06PM ST : Created * - *=============================================================================================*/ -UnsignedShort FirewallHelperClass::getNextTemporarySourcePort(Int skip) -{ - UnsignedShort return_port = (UnsignedShort) m_sourcePortPool; - - /* - ** Try max 256 ports until we find one we can bind to a socket. - */ - Int tries = 256; - if (skip == 0) { - skip = 1; - } - - while (tries--) { - - m_sourcePortPool += skip; - return_port = (UnsignedShort) m_sourcePortPool; - - if (m_sourcePortPool > 65535) { - m_sourcePortPool = 2048; - } - - /* - ** Validate the port by trying to bind it to a socket. - */ - Bool result = openSpareSocket(return_port); - - if (result) { - closeSpareSocket(return_port); - return(return_port); - } else { - DEBUG_LOG(("FirewallHelperClass::getNextTemporarySourcePort - failed to open socket on port %d", return_port)); - } - } - - return(return_port); - -} - - - - - -/*********************************************************************************************** - * FHC::sendToManglerFromPort -- Send to the mangler from the specified port * - * * - * * - * * - * INPUT: Address of mangler server * - * Source port to send *from* * - * * - * OUTPUT: True if sent OK * - * * - * WARNINGS: None * - * * - * HISTORY: * - * 3/15/01 12:47PM ST : Created * - *=============================================================================================*/ -Bool FirewallHelperClass::sendToManglerFromPort(UnsignedInt address, UnsignedShort port, UnsignedShort packetID, Bool blitzme) -{ - DEBUG_LOG(("sizeof(ManglerMessage) == %d, sizeof(ManglerData) == %d", - sizeof(ManglerMessage), sizeof(ManglerData))); - - /* - ** Build the packet to send out. - */ - ManglerMessage packet; - memset(&(packet.data),0x44, sizeof(ManglerData)); - packet.data.NetCommandType = 12; // mangler request. - packet.data.PacketID = packetID; - if (blitzme) { - packet.data.BlitzMe = 1; - } else { - packet.data.BlitzMe = 0; - } - packet.data.magic = GENERALS_MAGIC_NUMBER; - packet.data.OriginalPortNumber = port; -/* - DEBUG_LOG_RAW(("Pre-Adjust Buffer = ")); - for (Int i = 0; i < sizeof(ManglerData); ++i) { - DEBUG_LOG_RAW(("%02x", *(((unsigned char *)(&(packet.data))) + i))); - } - DEBUG_LOG_RAW(("\n")); -*/ - byteAdjust(&(packet.data)); -/* - DEBUG_LOG_RAW(("Pre-CRC Buffer = ")); - for (i = 0; i < sizeof(ManglerData); ++i) { - DEBUG_LOG_RAW(("%02x", *(((unsigned char *)(&(packet.data))) + i))); - } - DEBUG_LOG_RAW(("\n")); -*/ - CRC crc; - crc.computeCRC((unsigned char *)(&(packet.data.magic)), sizeof(ManglerData) - sizeof(unsigned int)); - packet.data.CRC = htonl(crc.get()); - - packet.length = sizeof(ManglerData); - - DEBUG_LOG(("FirewallHelperClass::sendToManglerFromPort - Sending from port %d to %d.%d.%d.%d:%d", (UnsignedInt)port, - PRINTF_IP_AS_4_INTS(address), MANGLER_PORT)); -/* - DEBUG_LOG_RAW(("Buffer = ")); - for (i = 0; i < sizeof(ManglerData); ++i) { - DEBUG_LOG_RAW(("%02x", *(((unsigned char *)(&(packet.data))) + i))); - } - DEBUG_LOG_RAW(("\n")); -*/ - SpareSocketStruct *spareSocket = findSpareSocketByPort(port); -// DEBUG_LOG(("PacketID = %u", packetID)); -// DEBUG_LOG(("OriginalPortNumber = %u", port)); - - if (spareSocket == NULL) { - DEBUG_ASSERTCRASH(spareSocket != NULL, ("Could not find spare socket for send.")); - DEBUG_LOG(("FirewallHelperClass::sendToManglerFromPort - failed to find the spare socket for port %d", port)); - return FALSE; - } - - spareSocket->udp->Write((UnsignedByte *) &packet, sizeof(ManglerData), address, MANGLER_PORT); - - return(TRUE); -} - - -SpareSocketStruct * FirewallHelperClass::findSpareSocketByPort(UnsignedShort port) { - DEBUG_LOG(("FirewallHelperClass::findSpareSocketByPort - trying to find spare socket with port %d", port)); - for (Int i = 0; i < MAX_SPARE_SOCKETS; ++i) { - if (m_spareSockets[i].port == port) { - DEBUG_LOG(("FirewallHelperClass::findSpareSocketByPort - found it!")); - return &(m_spareSockets[i]); - } - } - - DEBUG_LOG(("FirewallHelperClass::findSpareSocketByPort - didn't find it")); - return NULL; -} - -ManglerMessage * FirewallHelperClass::findEmptyMessage() { - for (Int i = 0; i < MAX_SPARE_SOCKETS; ++i) { - if (m_messages[i].length == 0) { - return &(m_messages[i]); - } - } - return NULL; -} - -void FirewallHelperClass::byteAdjust(ManglerData *data) { -// for (Int i = 0; i < len/4; ++i) { -// *buf = htonl(*buf); -// ++buf; -// } - data->CRC = htonl(data->CRC); - data->magic = htons(data->magic); - data->MyMangledPortNumber = htons(data->MyMangledPortNumber); - data->OriginalPortNumber = htons(data->OriginalPortNumber); - data->PacketID = htons(data->PacketID); -} - -/*********************************************************************************************** - * FHC::Get_Mangler_Response_On_Port -- Get the manglers response to a specific query * - * * - * * - * * - * INPUT: Packet id of packet we are looking for * - * * - * OUTPUT: Port the mangler saw this packet come from. * - * * - * WARNINGS: None * - * * - * HISTORY: * - * 3/15/01 12:51PM ST : Created * - *=============================================================================================*/ -UnsignedShort FirewallHelperClass::getManglerResponse(UnsignedShort packetID, Int time) -{ - ManglerMessage *msg = NULL; - -// SpareSocketStruct *spareSocket = NULL; - - sockaddr_in addr; - - Int i = 0; - for (; i < MAX_SPARE_SOCKETS; ++i) { - if (m_spareSockets[i].udp != NULL) { - ManglerMessage *message = findEmptyMessage(); - if (message == NULL) { - break; - } - Int retval = m_spareSockets[i].udp->Read((unsigned char *)message, sizeof(ManglerData), &addr); - if (retval > 0) { - CRC crc; - crc.computeCRC((unsigned char *)(&(message->data.magic)), sizeof(ManglerData) - sizeof(unsigned int)); - if (crc.get() != htonl(message->data.CRC)) { - DEBUG_LOG(("FirewallHelperClass::getManglerResponse - Saw message, CRC mismatch. Expected CRC %u, computed CRC %u", message->data.CRC, crc.get())); - continue; - } - byteAdjust(&(message->data)); - message->length = retval; - DEBUG_LOG(("FirewallHelperClass::getManglerResponse - Saw message of %d bytes from mangler %d on port %u", retval, i, m_spareSockets[i].port)); - DEBUG_LOG(("FirewallHelperClass::getManglerResponse - Message has packet ID %d 0x%08X, looking for packet id %d 0x%08X", message->data.PacketID, message->data.PacketID, packetID, packetID)); - if (message->data.PacketID == packetID) { - DEBUG_LOG(("FirewallHelperClass::getManglerResponse - packet ID's match, returning message")); - msg = message; - message->length = 0; - } - if (ntohs(message->data.PacketID) == packetID) { - DEBUG_LOG(("FirewallHelperClass::getManglerResponse - NETWORK BYTE ORDER packet ID's match, returning message")); - msg = message; - message->length = 0; - } - } - } - } - - // See if we have already received it and saved it. - if (msg == NULL) { - for (i = 0; i < MAX_SPARE_SOCKETS; ++i) { - if ((m_messages[i].length != 0) && (m_messages[i].data.PacketID == packetID)) { - msg = &(m_messages[i]); - msg->length = 0; - } - } - } - - if (msg == NULL) { - return 0; - } - - UnsignedShort mangled_port = msg->data.MyMangledPortNumber; - DEBUG_LOG(("Mangler is seeing packets from port %d as coming from port %d", (UnsignedInt)msg->data.OriginalPortNumber, (UnsignedInt)mangled_port)); - return mangled_port; -} - - - - -/*********************************************************************************************** - * FirewallHelperClass::Write_Firewall_Settings -- Save out firewall settings. * - * * - * * - * * - * INPUT: Nothing * - * * - * OUTPUT: Nothing * - * * - * WARNINGS: None * - * * - * HISTORY: * - * 3/22/01 10:23PM ST : Created * - *=============================================================================================*/ -void FirewallHelperClass::writeFirewallBehavior(void) -{ - OptionPreferences pref; - - char num[16]; - num[0] = 0; - itoa(TheGlobalData->m_firewallBehavior, num, 10); - AsciiString numstr; - numstr = num; - (pref)["FirewallBehavior"] = numstr; - - TheWritableGlobalData->m_firewallPortAllocationDelta = TheFirewallHelper->getSourcePortAllocationDelta(); - num[0] = 0; - itoa(TheGlobalData->m_firewallPortAllocationDelta, num, 10); - numstr = num; - (pref)["FirewallPortAllocationDelta"] = numstr; - - pref.write(); -} - - -/*********************************************************************************************** - * FirewallHelperClass::flagNeedToRefresh -- Flag that the next time we log in we need to * - * refresh our firewall settings. * - * * - * * - * * - * INPUT: flag - whether or not to refresh...munkee * - * * - * OUTPUT: Nothing * - * * - * WARNINGS: None * - * * - * HISTORY: * - * 2/19/03 4:30PM BGC : Created * - *=============================================================================================*/ -void FirewallHelperClass::flagNeedToRefresh(Bool flag) -{ - OptionPreferences pref; - - (pref)["FirewallNeedToRefresh"] = flag ? AsciiString("TRUE") : AsciiString("FALSE"); - - pref.write(); -} - - -/*********************************************************************************************** - * FirewallHelperClass::Read_Firewall_Behavior -- Read in old firewall settings * - * * - * * - * * - * INPUT: Nothing * - * * - * OUTPUT: Nothing * - * * - * WARNINGS: None * - * * - * HISTORY: * - * 3/22/01 10:25PM ST : Created * - *=============================================================================================*/ -void FirewallHelperClass::readFirewallBehavior(void) -{ -#if (0) - m_lastBehavior = (FirewallBehaviorType) ConfigINI.Get_Int("MultiPlayer", "FirewallSettings", FIREWALL_UNKNOWN); - m_lastSourcePortAllocationDelta = ConfigINI.Get_Int("MultiPlayer", "FirewallDelta", 1); -#endif //(0) -} - - - -/*********************************************************************************************** - * FHC::detectFirewallBehavior -- What is that wacky firewall doing to our packet headers? * - * * - * * - * * - * INPUT: Nothing * - * * - * OUTPUT: Firewall behavior * - * * - * WARNINGS: None * - * * - * HISTORY: * - * 3/15/01 12:30PM ST : Created * - *=============================================================================================*/ -void FirewallHelperClass::detectFirewallBehavior(/*Bool &canRecord*/) -{ - m_behavior = FIREWALL_TYPE_SIMPLE; - - m_currentState = DETECTIONSTATE_BEGIN; -} - -FirewallHelperClass::FirewallBehaviorType FirewallHelperClass::getFirewallBehavior() { - m_currentState = DETECTIONSTATE_IDLE; - return m_behavior; -} - -Short FirewallHelperClass::getSourcePortAllocationDelta() { - return m_sourcePortAllocationDelta; -} - -/* static */ void FirewallHelperClass::getManglerName(Int manglerIndex, Char *nameBuf) -{ - AsciiString host; - UnsignedShort port; - TheGameSpyConfig->getManglerLocation(manglerIndex, host, port); - strcpy(nameBuf, host.str()); -} - -Bool FirewallHelperClass::detectionBeginUpdate() { -// UnsignedShort mangler_port = MANGLER_PORT; - m_packetID = 0x7f00; - //int current_mangler = 0; - - /* - ** Well, we are going to need some manglers. - */ - - UnsignedByte mangler_addresses[4][4]; - -// Int delta = 0; - - - /* - ** If the user specified a particular port to use then we act as if there is no firewall. - */ - if (TheWritableGlobalData->m_firewallPortOverride != 0) { - m_behavior = FIREWALL_TYPE_SIMPLE; - DEBUG_LOG(("Source port %d specified by user", TheGlobalData->m_firewallPortOverride)); - - if (TheGlobalData->m_firewallSendDelay) { - UnsignedInt addbehavior = FIREWALL_TYPE_NETGEAR_BUG; - addbehavior |= (UnsignedInt)m_behavior; - m_behavior = (FirewallBehaviorType) addbehavior; - DEBUG_LOG(("Netgear bug specified by command line or SendDelay flag")); - } - m_currentState = DETECTIONSTATE_DONE; - return TRUE; - } - - - - m_timeoutStart = timeGetTime(); - m_timeoutLength = 5000; - DEBUG_LOG(("About to call gethostbyname for the mangler address")); - int namenum = 0; - - do { - AsciiString host; - UnsignedShort port; - TheGameSpyConfig->getManglerLocation(namenum, host, port); - const char *mangler_name_ptr = host.str(); - DEBUG_LOG(("Looking at %s:%d", host.str(), port)); - - /* - ** Use the wolapi supplied mangler info if available. - */ -// if (NumManglerServers > namenum) { -// mangler_name_ptr = &ManglerServerAddress[namenum][0]; -// mangler_port = ManglerServerPort[namenum]; - //current_mangler = CurrentManglerServer; -// DEBUG_LOG(("Using mangler from servserv")); -// } - namenum++; - - if (strlen(mangler_name_ptr) == 0) { - break; - } - - /* - ** Do the lookup. - */ - struct hostent *host_info = gethostbyname(mangler_name_ptr); - - if (!host_info) { - DEBUG_LOG(("gethostbyname failed! Error code %d", WSAGetLastError())); - break; - } - - /* - ** See if we already have that address in the list. - */ - Bool found = FALSE; - for (Int i=0 ; ih_addr_list[0][0], 4) == 0) { - found = TRUE; - break; - } - } - /* - ** Add the address in if we didn't find it. - */ - if (!found) { - Int m = m_numManglers++; - memcpy(&mangler_addresses[m][0], &host_info->h_addr_list[0][0], 4); - ntohl((UnsignedInt)mangler_addresses[m]); - DEBUG_LOG(("Found mangler address at %d.%d.%d.%d", mangler_addresses[m][0], mangler_addresses[m][1], mangler_addresses[m][2], mangler_addresses[m][3])); - } - - } while ((m_numManglers < MAX_NUM_MANGLERS) && ((timeGetTime() - m_timeoutStart) < m_timeoutLength)); - - - DEBUG_ASSERTCRASH(m_numManglers > 2, ("not enough mangler addresses found.")); - if (m_numManglers < 3) { - m_currentState = DETECTIONSTATE_DONE; - return TRUE; - } - - for (Int i=0 ; im_firewallSendDelay) { - UnsignedInt addbehavior = FIREWALL_TYPE_NETGEAR_BUG; - addbehavior |= (UnsignedInt)m_behavior; - m_behavior = (FirewallBehaviorType) addbehavior; - DEBUG_LOG(("FirewallHelperClass::detectionBeginUpdate - Netgear bug specified by command line or SendDelay flag")); - } else { - DEBUG_LOG(("FirewallHelperClass::detectionBeginUpdate - Netgear bug not specified")); - } - - /* - ** OK, we have our manglers. - ** - ** First test, see if there is any port mangling at all. - ** - ** - ** - */ - - DEBUG_LOG(("About to start mangler test 1")); - /* - ** Get a spare port number and create a new socket to bind it to. - */ - m_sparePorts[0] = getNextTemporarySourcePort(0); - if (!openSpareSocket(m_sparePorts[0])) { - m_currentState = DETECTIONSTATE_DONE; - return TRUE; - } - - /* - ** Send to the mangler from this port until we get a response. - */ - m_timeoutStart = timeGetTime(); - m_timeoutLength = 6000; - - sendToManglerFromPort(m_manglers[0], m_sparePorts[0], m_packetID); - m_currentState = DETECTIONSTATE_TEST1; - return FALSE; -} - - -Bool FirewallHelperClass::detectionTest1Update() { - - m_mangledPorts[0] = getManglerResponse(m_packetID); - - /* - ** See if we got no response or a non-mangled response. - */ - if (m_mangledPorts[0] == 0 || m_mangledPorts[0] == m_sparePorts[0]) { - if (m_mangledPorts[0] == m_sparePorts[0]) { - m_sourcePortAllocationDelta = 0; - DEBUG_LOG(("FirewallHelperClass::detectionTest1Update - Non-mangled response from mangler, quitting test.")); - } - if ((m_mangledPorts[0] == 0) && ((timeGetTime() - m_timeoutStart) < m_timeoutLength)) { - // we are still waiting for a response and haven't timed out yet. - DEBUG_LOG(("FirewallHelperClass::detectionTest1Update - waiting for response from mangler.")); - return FALSE; - } - if ((m_mangledPorts[0] == 0) && ((timeGetTime() - m_timeoutStart) >= m_timeoutLength)) { - // we are still waiting for a response and we timed out. - DEBUG_LOG(("FirewallHelperClass::detectionTest1Update - timed out waiting for response from mangler.")); - } - // either we have received a non-mangled response or we timed out waiting for a response. - closeSpareSocket(m_sparePorts[0]); - - m_currentState = DETECTIONSTATE_DONE; - return TRUE; - } - - DEBUG_LOG(("FirewallHelperClass::detectionTest1Update - test 1 complete")); - /* - ** Test one completed, time to start up the second test. - ** - ** Second test. See if the ports are mangled differently for different destination IPs. - ** - ** We can use the spare socket from the last test and send to a different mangler. - ** - */ - - /* - ** Send to the mangler from this port until we get a response. - */ - m_timeoutStart = timeGetTime(); - m_timeoutLength = 6000; - m_mangledPorts[1] = 0; - sendToManglerFromPort(m_manglers[1], m_sparePorts[0], m_packetID+1); - - m_currentState = DETECTIONSTATE_TEST2; - return FALSE; -} - -Bool FirewallHelperClass::detectionTest2Update() { - - m_mangledPorts[1] = getManglerResponse(m_packetID+1); - - if (m_mangledPorts[1] == 0) { - if ((timeGetTime() - m_timeoutStart) <= m_timeoutLength) { - return FALSE; - } - DEBUG_LOG(("FirewallHelperClass::detectionTest2Update - timed out waiting for mangler response")); - m_currentState = DETECTIONSTATE_DONE; - return TRUE; - } - - /* - ** We are done with this socket/port - */ - closeSpareSocket(m_sparePorts[0]); - - /* - ** See if we got no response or a non-mangled response. - */ - if (m_mangledPorts[1] == 0 || m_mangledPorts[1] == m_sparePorts[0]) { - m_currentState = DETECTIONSTATE_DONE; - UnsignedInt addBehavior = (UnsignedInt)FIREWALL_TYPE_SIMPLE; - addBehavior |= (UnsignedInt)m_behavior; - m_behavior = (FirewallBehaviorType)addBehavior; - - if (m_mangledPorts[1] == 0) { - DEBUG_LOG(("FirewallHelperClass::detectionTest2Update - got no response from mangler")); - } else { - DEBUG_LOG(("FirewallHelperClass::detectionTest2Update - got a mangler response, no port mangling")); - } - DEBUG_LOG(("FirewallHelperClass::detectionTest2Update - Setting behavior to SIMPLE, done testing")); - return TRUE; - } - - if (m_mangledPorts[0] == m_mangledPorts[1]) { - DEBUG_LOG(("FirewallHelperClass::detectionTest2Update - port mangling doesn't depend on destination IP, setting to DUMB_MANGLING")); - UnsignedInt addBehavior = (UnsignedInt)FIREWALL_TYPE_DUMB_MANGLING; - addBehavior |= (UnsignedInt)m_behavior; - m_behavior = (FirewallBehaviorType)addBehavior; - } else { - DEBUG_LOG(("FirewallHelperClass::detectionTest2Update - port mangling depends on destination IP, setting to SMART_MANGLING")); - UnsignedInt addBehavior = (UnsignedInt)FIREWALL_TYPE_SMART_MANGLING; - addBehavior |= (UnsignedInt)m_behavior; - m_behavior = (FirewallBehaviorType)addBehavior; - } - - - - - /* - ** Third test. - ** - ** This test tries to detect a pattern in the ports allocated by the NAT. - ** We use several source ports for this one. - ** - */ - - m_currentTry = 0; - m_packetID = m_packetID + 10; - - DEBUG_LOG(("FirewallHelperClass::detectionTest2Update - moving on to 3rd test")); - - m_currentState = DETECTIONSTATE_TEST3; - return FALSE; -} - -Bool FirewallHelperClass::detectionTest3Update() { - /* - ** Try this whole thing a max of 3 times. - */ - if (m_currentTry < 3) { - memset(m_sparePorts, 0, sizeof(m_sparePorts)); - memset(m_mangledPorts, 0, sizeof(m_mangledPorts)); - - /* - ** Open a socket for each source port. - ** We should use a non-linear set of source ports so we can detect the NAT32 relative offset - ** case. - */ - Int i=0; - for (; i m_timeoutLength) { - /* - ** Close down those sockets - we are finished with them. - */ - for (Int j=0 ; j (int)FIREWALL_TYPE_SIMPLE) { - /* - ** If the delta we got last time we played looks good then use that. - */ - m_sourcePortAllocationDelta = m_lastSourcePortAllocationDelta; - } - DEBUG_LOG(("FirewallHelperClass::detectionTest3WaitForResponsesUpdate - didn't get enough responses, using %d as the source port allocation delta, finished test", m_sourcePortAllocationDelta)); - m_currentState = DETECTIONSTATE_DONE; - return TRUE; - } - - - Bool relative_delta = FALSE; - Bool looks_good = FALSE; - Int delta = getNATPortAllocationScheme(m_numResponses, m_sparePorts, m_mangledPorts, relative_delta, looks_good); - DEBUG_LOG(("FirewallHelperClass::detectionTest3WaitForResponsesUpdate - getNATPortAllocationScheme returned %d", delta)); - - if (delta) { - - /* - ** Hey, we got it! - */ - UnsignedInt addbehavior = 0; - if (relative_delta) { - DEBUG_LOG(("FirewallHelperClass::detectionTest3WaitForResponsesUpdate - detected RELATIVE PORT ALLOCATION")); - addbehavior = (UnsignedInt)FIREWALL_TYPE_RELATIVE_PORT_ALLOCATION; - } else { - DEBUG_LOG(("FirewallHelperClass::detectionTest3WaitForResponsesUpdate - detected SIMPLE PORT ALLOCATION")); - addbehavior = (UnsignedInt)FIREWALL_TYPE_SIMPLE_PORT_ALLOCATION; - } - addbehavior |= (UnsignedInt)m_behavior; - m_behavior = (FirewallBehaviorType) addbehavior; - - m_sourcePortAllocationDelta = delta; - DEBUG_LOG(("FirewallHelperClass::detectionTest3WaitForResponsesUpdate - setting source port delta to %d", delta)); - } else { - DEBUG_LOG(("FirewallHelperClass::detectionTest3WaitForResponsesUpdate - didn't get a delta value")); - if (m_lastSourcePortAllocationDelta != 0 && (Int)m_lastBehavior > (Int)FIREWALL_TYPE_SIMPLE) { - /* - ** If the delta we got last time we played looks good then use that. - */ - DEBUG_LOG(("FirewallHelperClass::detectionTest3WaitForResponsesUpdate - using the port allocation delta we have from before which is %d", m_lastSourcePortAllocationDelta)); - m_sourcePortAllocationDelta = m_lastSourcePortAllocationDelta; - } - ++m_currentTry; - m_currentState = DETECTIONSTATE_TEST3; - return FALSE; - } - - DEBUG_LOG(("FirewallHelperClass::detectionTest3WaitForRepsonsesUpdate - starting 4th test")); - /* - ** Fourth test. - ** - ** Test to see if the NAT mangles differently per destination port at the same IP. - */ - if ((m_behavior & FIREWALL_TYPE_SMART_MANGLING) != 0) { - - if ((m_behavior & FIREWALL_TYPE_SIMPLE_PORT_ALLOCATION) != 0) { - - DEBUG_LOG(("FirewallHelperClass::detectionTest3WaitForRepsonsesUpdate - simple port allocation, Testing to see if the NAT mangles differently per destination port at the same IP")); - - /* - ** We need 2 source ports for this. - */ - m_sparePorts[0] = getNextTemporarySourcePort(0); - if (!openSpareSocket(m_sparePorts[0])) { - m_currentState = DETECTIONSTATE_DONE; - DEBUG_LOG(("FirewallHelperClass::detectionTest3WaitForRepsonsesUpdate - Failed to open first spare port, bailing")); - return TRUE; - } - - m_sparePorts[1] = getNextTemporarySourcePort(0); - if (!openSpareSocket(m_sparePorts[1])) { - closeSpareSocket(m_sparePorts[0]); - m_currentState = DETECTIONSTATE_DONE; - DEBUG_LOG(("FirewallHelperClass::detectionTest3WaitForRepsonsesUpdate - Failed to open second spare port, bailing")); - return TRUE; - } - - /* - ** Get a reference port. - */ - m_timeoutStart = timeGetTime(); - m_timeoutLength = 4000; - m_mangledPorts[0] = 0; - m_packetID += 10; - - /* - ** Wait for a response. - */ - sendToManglerFromPort(m_manglers[0], m_sparePorts[0], m_packetID); - - m_currentState = DETECTIONSTATE_TEST4_1; - return FALSE; - } else { - /* - ** NAT32 uses different mangled source ports for different destination ports. - */ - DEBUG_LOG(("FirewallHelperClass::detectionTest3WaitForRepsonsesUpdate - relative port allocation, NAT32 right?")); - UnsignedInt addbehavior = 0; - addbehavior = (UnsignedInt)FIREWALL_TYPE_DESTINATION_PORT_DELTA; - DEBUG_LOG(("FirewallHelperClass::detectionTest3WaitForRepsonsesUpdate - adding DESTINATION PORT DELTA to behavior")); - addbehavior |= (UnsignedInt)m_behavior; - m_behavior = (FirewallBehaviorType) addbehavior; - } - } else { - DEBUG_LOG(("FirewallHelperClass::detectionTest3WaitForResponsesUpdate - We don't have smart mangling, skipping test 4, entering test 5")); - } - - DEBUG_LOG(("FirewallHelperClass::detectionTest3WaitForRepsonsesUpdate - entering test 5")); - - m_currentState = DETECTIONSTATE_TEST5; - return FALSE; -} - - - -Bool FirewallHelperClass::detectionTest4Stage1Update() { - m_mangledPorts[0] = getManglerResponse(m_packetID); - - if (m_mangledPorts[0] == 0) { - if ((timeGetTime() - m_timeoutStart) > m_timeoutLength) { - closeSpareSocket(m_sparePorts[0]); - closeSpareSocket(m_sparePorts[1]); - m_currentState = DETECTIONSTATE_DONE; - DEBUG_LOG(("FirewallHelperClass::detectionTest4Stage1Update - timed out waiting for mangler response, quitting")); - return TRUE; - } - return FALSE; - } - - /* - ** Send out to a different port at that IP. - ** We won't get a response for this. - */ - UnsignedInt addr = m_manglers[0]; - UnsignedShort port1 = m_sparePorts[0] + 1; - sendToManglerFromPort(addr, port1, m_packetID); - sendToManglerFromPort(addr, port1, m_packetID); - sendToManglerFromPort(addr, port1, m_packetID); - - /* - ** We can't get a response from a different destination port so the only way to detect - ** this behavior is to check the next mangled port allocation to see if it's double - ** what we would normally expect. - */ - m_packetID++; - m_timeoutStart = timeGetTime(); - m_timeoutLength = 4000; - - sendToManglerFromPort(m_manglers[0], m_sparePorts[1], m_packetID); - - m_currentState = DETECTIONSTATE_TEST4_2; - return FALSE; -} - -Bool FirewallHelperClass::detectionTest4Stage2Update() { - m_mangledPorts[1] = getManglerResponse(m_packetID); - - if (m_mangledPorts[1] == 0) { - if ((timeGetTime() - m_timeoutStart) > m_timeoutLength) { - closeSpareSocket(m_sparePorts[0]); - closeSpareSocket(m_sparePorts[1]); - m_currentState = DETECTIONSTATE_DONE; - DEBUG_LOG(("FirewallHelperClass::detectionTest4Stage2Update - timed out waiting for the second mangler response, quitting")); - return TRUE; - } - return FALSE; - } - - if (m_mangledPorts[1] != m_mangledPorts[0] + m_sourcePortAllocationDelta) { - DEBUG_LOG(("FirewallHelperClass::detectionTest4Stage2Update - NAT uses different source ports for different destination ports")); - - UnsignedInt addbehavior = 0; - addbehavior = (UnsignedInt)FIREWALL_TYPE_DESTINATION_PORT_DELTA; - addbehavior |= (UnsignedInt)m_behavior; - m_behavior = (FirewallBehaviorType) addbehavior; - } else { - DEBUG_ASSERTCRASH(m_mangledPorts[1] == m_mangledPorts[0] + m_sourcePortAllocationDelta, ("Problem getting the source port deltas.")); - if (m_mangledPorts[1] == m_mangledPorts[0] + m_sourcePortAllocationDelta) { - DEBUG_LOG(("FirewallHelperClass::detectionTest4Stage2Update - NAT uses the same source port for different destination ports")); - } else { - DEBUG_LOG(("FirewallHelperClass::detectionTest4Stage2Update - Unable to complete destination port mangling test")); - DEBUG_CRASH(("Unable to complete destination port mangling test")); - } - } - - m_currentState = DETECTIONSTATE_TEST5; - - return detectionTest5Update(); -} - -Bool FirewallHelperClass::detectionTest5Update() { - /* - ** We have done all the tests we *have* to. There's other info that it would be nice to know though. - ** - ** Test for the netgear bug behavior. - */ -#if (0) -// moved to before test 1. Moved because this flag could be specified for another firewall -// for testing purposes and never get this far because it has behavior that doesn't require -// all the tests to be performed. -// BGC 10/1/02 - DEBUG_LOG(("FirewallHelperClass::detectionTest5Update - Testing for Netgear bug")); - - /* - ** See if the user specified a netgear firewall - that will save us the trouble. - */ - if (TheGlobalData->m_firewallSendDelay) { - UnsignedInt addbehavior = FIREWALL_TYPE_NETGEAR_BUG; - addbehavior |= (UnsignedInt)m_behavior; - m_behavior = (FirewallBehaviorType) addbehavior; - DEBUG_LOG(("FirewallHelperClass::detectionTest5Update - Netgear bug specified by command line or SendDelay flag")); - } else { - DEBUG_LOG(("FirewallHelperClass::detectionTest5Update - Netgear bug not specified")); - } -#endif // #if (0) - - DEBUG_LOG_RAW(("FirewallHelperClass::detectionTest5Update - All done, behavior is: ")); - - if ((m_behavior & FIREWALL_TYPE_SIMPLE) != 0) { - DEBUG_LOG_RAW((" FIREWALL_TYPE_SIMPLE ")); - } - if ((m_behavior & FIREWALL_TYPE_DUMB_MANGLING) != 0) { - DEBUG_LOG_RAW((" FIREWALL_TYPE_DUMB_MANGLING ")); - } - if ((m_behavior & FIREWALL_TYPE_SMART_MANGLING) != 0) { - DEBUG_LOG_RAW((" FIREWALL_TYPE_SMART_MANGLING ")); - } - if ((m_behavior & FIREWALL_TYPE_NETGEAR_BUG) != 0) { - DEBUG_LOG_RAW((" FIREWALL_TYPE_NETGEAR_BUG ")); - } - if ((m_behavior & FIREWALL_TYPE_SIMPLE_PORT_ALLOCATION) != 0) { - DEBUG_LOG_RAW((" FIREWALL_TYPE_SIMPLE_PORT_ALLOCATION ")); - } - if ((m_behavior & FIREWALL_TYPE_RELATIVE_PORT_ALLOCATION) != 0) { - DEBUG_LOG_RAW((" FIREWALL_TYPE_RELATIVE_PORT_ALLOCATION ")); - } - if ((m_behavior & FIREWALL_TYPE_DESTINATION_PORT_DELTA) != 0) { - DEBUG_LOG_RAW((" FIREWALL_TYPE_DESTINATION_PORT_DELTA ")); - } - - DEBUG_LOG_RAW(("\n")); - - m_currentState = DETECTIONSTATE_DONE; - return TRUE; -} - - -/*********************************************************************************************** - * FHC::Get_NAT_Port_Allocation_Scheme -- Find out how a NAT is allocating ports * - * * - * * - * * - * INPUT: Number of ports we should analyze * - * List of original port numbers * - * List of mangled port numbers * - * relative_delta (out) Is the delta relative to the original port number? * - * looks_good (out) Do all the values point to the same delta? * - * * - * OUTPUT: Port allocation delta * - * * - * WARNINGS: None * - * * - * HISTORY: * - * 3/15/01 4:45PM ST : Created * - *=============================================================================================*/ -Int FirewallHelperClass::getNATPortAllocationScheme(Int numPorts, UnsignedShort *originalPorts, UnsignedShort *mangledPorts, Bool &relativeDelta, Bool &looksGood) -{ - DEBUG_ASSERTCRASH(numPorts > 3, ("numPorts too small")); - - DEBUG_LOG(("Looking for port allocation pattern in originalPorts %d, %d, %d, %d", originalPorts[0], originalPorts[1], originalPorts[2], originalPorts[3])); - - /* - ** Sort the mangled ports into order - should be easier to detect patterns. - ** Stupid bubble sort will do. original_ports may be out of oder after the sort. - */ - for (Int x=0 ; x mangledPorts[y+1]) { - Int temp = mangledPorts[y]; - mangledPorts[y] = mangledPorts[y+1]; - mangledPorts[y+1] = temp; - temp = originalPorts[y]; - originalPorts[y] = originalPorts[y+1]; - originalPorts[y+1] = temp; - } - } - } - - /* - ** Now start looking for patterns in the port numbers. Possible patterns include. - ** - ** Incremental. Port numbers are allocated incrementally. - ** Every 'n' ports. NAT adds 'n' port numbers when allocating ports. - ** - ** Also, schemes may be absolute or relative to the original port number. - */ - - /* - ** 1. Check for absolute sequential allocation. - */ - if (mangledPorts[1] - mangledPorts[0] == 1) { - if (mangledPorts[2] - mangledPorts[1] == 1) { - if (mangledPorts[3] - mangledPorts[2] == 1) { - DEBUG_LOG(("Incremental port allocation detected")); - relativeDelta = FALSE; - looksGood = TRUE; - return(1); - } - } - } - - /* - ** 2. Check for semi sequential. - */ - if (mangledPorts[1] - mangledPorts[0] == 2) { - if (mangledPorts[2] - mangledPorts[1] == 2) { - if (mangledPorts[3] - mangledPorts[2] == 2) { - DEBUG_LOG(("Semi-incremental port allocation detected")); - relativeDelta = FALSE; - looksGood = TRUE; - return(2); - } - } - } - - Int diff1 = mangledPorts[1] - mangledPorts[0]; - Int diff2 = mangledPorts[2] - mangledPorts[1]; - Int diff3 = mangledPorts[3] - mangledPorts[2]; - - - /* - ** 3. Check for absolute scheme skipping 'n' ports. - */ - if (diff1 == diff2 && diff2 == diff3) { - DEBUG_LOG(("Looks good for absolute allocation sequence delta of %d", diff1)); - relativeDelta = FALSE; - looksGood = TRUE; - return(diff1); - } - - if (diff1 == diff2) { - DEBUG_LOG(("Probable absolute allocation sequence delta of %d", diff1)); - relativeDelta = FALSE; - looksGood = FALSE; - return(diff1); - } - - if (diff2 == diff3) { - DEBUG_LOG(("Probable absolute allocation sequence delta of %d", diff2)); - relativeDelta = FALSE; - looksGood = FALSE; - return(diff2); - } - - - - - /* - ** Insert more tests here if we can think of any!!!!! - */ - - - - /* - ** 4. Check for relative scheme skipping 'n' ports. NAT32 behaves this way, it skips 100 ports - ** each time. - */ - for (Int i=0 ; iBind((UnsignedInt)0, port) != 0) { - DEBUG_CRASH(("FirewallHelperClass::openSpareSocket - Failed to init spare socket")); - return FALSE; - } - - m_spareSockets[i].port = port; - DEBUG_LOG(("FirewallHelperClass::openSpareSocket - port %d is open for send", port)); - return TRUE; -} - -/* - * closeSpareSocket - closes a socket at a specific port. - */ -void FirewallHelperClass::closeSpareSocket(UnsignedShort port) { - for (Int i = 0; i < MAX_SPARE_SOCKETS; ++i) { - if (m_spareSockets[i].port == port) { - delete m_spareSockets[i].udp; - m_spareSockets[i].udp = NULL; - m_spareSockets[i].port = 0; - break; - } - } -} - -/* - * closeAllSpareSockets - closes all spare sockets, duh. - */ -void FirewallHelperClass::closeAllSpareSockets() { - for (Int i = 0; i < MAX_SPARE_SOCKETS; ++i) { - delete (m_spareSockets[i].udp); - m_spareSockets[i].udp = NULL; - m_spareSockets[i].port = 0; - } -} diff --git a/Generals/Code/GameEngine/Source/GameNetwork/FrameData.cpp b/Generals/Code/GameEngine/Source/GameNetwork/FrameData.cpp deleted file mode 100644 index 165c6161e8..0000000000 --- a/Generals/Code/GameEngine/Source/GameNetwork/FrameData.cpp +++ /dev/null @@ -1,203 +0,0 @@ -/* -** 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 in the GameEngine - -#include "GameNetwork/FrameData.h" -#include "GameNetwork/networkutil.h" - -/** - * Constructor - */ -FrameData::FrameData() -{ - m_frame = 0; - m_commandList = NULL; - m_commandCount = 0; - m_frameCommandCount = -1; - //Added By Sadullah Nader - //Initializations missing and needed - m_lastFailedCC = 0; - m_lastFailedFrameCC = 0; - // -} - -/** - * Destructor - */ -FrameData::~FrameData() -{ - deleteInstance(m_commandList); - m_commandList = NULL; -} - -/** - * Initialize this thing. - */ -void FrameData::init() -{ - m_frame = 0; - if (m_commandList == NULL) { - m_commandList = newInstance(NetCommandList); - m_commandList->init(); - } - m_commandList->reset(); - - m_frameCommandCount = -1; - //DEBUG_LOG(("FrameData::init")); - m_commandCount = 0; - m_lastFailedCC = -2; - m_lastFailedFrameCC = -2; -} - -/** - * Reset this thing. - */ -void FrameData::reset() { - init(); -} - -/** - * update the thing, doesn't do anything at the moment. - */ -void FrameData::update() { -} - -/** - * return the frame number this frame data is associated with. - */ -UnsignedInt FrameData::getFrame() { - return m_frame; -} - -/** - * Assign the frame number this frame data is associated with. - */ -void FrameData::setFrame(UnsignedInt frame) { - m_frame = frame; -} - -/** - * Returns true if all the frame command count is equal to the number of commands that have been received. - */ -FrameDataReturnType FrameData::allCommandsReady(Bool debugSpewage) { - if (m_frameCommandCount == m_commandCount) { - m_lastFailedFrameCC = -2; - m_lastFailedCC = -2; - return FRAMEDATA_READY; - } - - if (debugSpewage) { - if ((m_lastFailedFrameCC != m_frameCommandCount) || (m_lastFailedCC != m_commandCount)) { - DEBUG_LOG(("FrameData::allCommandsReady - failed, frame command count = %d, command count = %d", m_frameCommandCount, m_commandCount)); - m_lastFailedFrameCC = m_frameCommandCount; - m_lastFailedCC = m_commandCount; - } - } - - if (m_commandCount > m_frameCommandCount) { - DEBUG_LOG(("FrameData::allCommandsReady - There are more commands than there should be (%d, should be %d). Commands in command list are...", m_commandCount, m_frameCommandCount)); - NetCommandRef *ref = m_commandList->getFirstMessage(); - while (ref != NULL) { - DEBUG_LOG(("%s, frame = %d, id = %d", GetNetCommandTypeAsString(ref->getCommand()->getNetCommandType()), ref->getCommand()->getExecutionFrame(), ref->getCommand()->getID())); - ref = ref->getNext(); - } - DEBUG_LOG(("FrameData::allCommandsReady - End of command list.")); - DEBUG_LOG(("FrameData::allCommandsReady - about to clear the command list")); - reset(); - DEBUG_LOG(("FrameData::allCommandsReady - command list cleared. command list length = %d, command count = %d, frame command count = %d", m_commandList->length(), m_commandCount, m_frameCommandCount)); - return FRAMEDATA_RESEND; - } - return FRAMEDATA_NOTREADY; -} - -/** - * Set the command count for this frame - */ -void FrameData::setFrameCommandCount(UnsignedInt frameCommandCount) { - //DEBUG_LOG(("setFrameCommandCount to %d for frame %d", frameCommandCount, m_frame)); - m_frameCommandCount = frameCommandCount; -} - -/** - * Get the command count for this frame. - */ -UnsignedInt FrameData::getFrameCommandCount() { - return m_frameCommandCount; -} - -/** - * return the number of commands received so far. - */ -UnsignedInt FrameData::getCommandCount() { - return m_commandCount; -} - -/** - * Add a command to this frame - */ -void FrameData::addCommand(NetCommandMsg *msg) { - // need to add the message in order of command ID - if (m_commandList == NULL) { - init(); - } - - // We don't need to worry about setting the relay since its not getting sent anywhere. - if (m_commandList->findMessage(msg) != NULL) { - // We don't want to add the same command twice. - return; - } - m_commandList->addMessage(msg); - - ++m_commandCount; - //DEBUG_LOG(("added command %d, type = %d(%s), command count = %d, frame command count = %d", msg->getID(), msg->getNetCommandType(), GetNetCommandTypeAsString(msg->getNetCommandType()), m_commandCount, m_frameCommandCount)); -} - -/** - * Return the list of commands for this frame - */ -NetCommandList * FrameData::getCommandList() { - return m_commandList; -} - -/** - * Set both the command count and the frame command count to 0. - */ -void FrameData::zeroFrame() { - m_commandCount = 0; - m_frameCommandCount = 0; -} - -/** - * destroy all the commands in this frame. - */ -void FrameData::destroyGameMessages() { - if (m_commandList == NULL) { - return; - } - - m_commandList->reset(); - m_commandCount = 0; -} diff --git a/Generals/Code/GameEngine/Source/GameNetwork/FrameDataManager.cpp b/Generals/Code/GameEngine/Source/GameNetwork/FrameDataManager.cpp deleted file mode 100644 index c82d1cfd2e..0000000000 --- a/Generals/Code/GameEngine/Source/GameNetwork/FrameDataManager.cpp +++ /dev/null @@ -1,203 +0,0 @@ -/* -** 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 in the GameEngine - -#include "GameNetwork/FrameDataManager.h" -#include "GameNetwork/networkutil.h" - -/** - * Constructor. isLocal tells it whether its the frame data manager for the local player or not. - */ -FrameDataManager::FrameDataManager(Bool isLocal) { - m_isLocal = isLocal; - - m_frameData = NEW FrameData[FRAME_DATA_LENGTH]; - - m_isQuitting = FALSE; - m_quitFrame = 0; -} - -/** - * destructor. - */ -FrameDataManager::~FrameDataManager() { - for (Int i = 0; i < FRAME_DATA_LENGTH; ++i) { - m_frameData[i].reset(); - } - delete[] m_frameData; - m_frameData = NULL; -} - -/** - * Initialize all of the frame datas associated with this manager. - */ -void FrameDataManager::init() { - for (Int i = 0; i < FRAME_DATA_LENGTH; ++i) { - m_frameData[i].init(); - if (m_isLocal) { - // If this is the local connection, adjust the frame command count. - m_frameData[i].setFrameCommandCount(m_frameData[i].getCommandCount()); - } - } - - m_isQuitting = FALSE; - m_quitFrame = 0; -} - -/** - * Reset the state of all the frames. - */ -void FrameDataManager::reset() { - init(); -} - -/** - * update function. Does nothing at this time. - */ -void FrameDataManager::update() { -} - -/** - * Add a network command to the appropriate frame. - */ -void FrameDataManager::addNetCommandMsg(NetCommandMsg *msg) { - UnsignedInt frame = msg->getExecutionFrame(); - UnsignedInt frameindex = frame % FRAME_DATA_LENGTH; - DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("FrameDataManager::addNetCommandMsg - about to add a command of type %s for frame %d, frame index %d", GetNetCommandTypeAsString(msg->getNetCommandType()), frame, frameindex)); - m_frameData[frameindex].addCommand(msg); - - if (m_isLocal) { - // If this is the local connection, adjust the frame command count. - m_frameData[frameindex].setFrameCommandCount(m_frameData[frameindex].getCommandCount()); - } -} - -/** - * Returns true if all the commands for the given frame are ready. - */ -FrameDataReturnType FrameDataManager::allCommandsReady(UnsignedInt frame, Bool debugSpewage) { - UnsignedInt frameindex = frame % FRAME_DATA_LENGTH; - //DEBUG_ASSERTCRASH(m_frameData[frameindex].getFrame() == frame || frame == 256, ("Looking at old commands!")); - return m_frameData[frameindex].allCommandsReady(debugSpewage); -} - -/** - * Returns the command list for the given frame. - */ -NetCommandList * FrameDataManager::getFrameCommandList(UnsignedInt frame) { - UnsignedInt frameindex = frame % FRAME_DATA_LENGTH; - return m_frameData[frameindex].getCommandList(); -} - -/** - * Reset the contents of the given frame. - */ -void FrameDataManager::resetFrame(UnsignedInt frame, Bool isAdvancing) { - UnsignedInt frameindex = frame % FRAME_DATA_LENGTH; - - m_frameData[frameindex].reset(); - - if (isAdvancing) { - m_frameData[frameindex].setFrame(frame + MAX_FRAMES_AHEAD); - } - - if (m_isLocal) { - m_frameData[frameindex].setFrameCommandCount(m_frameData[frameindex].getCommandCount()); - } - - DEBUG_ASSERTCRASH(m_frameData[frameindex].getCommandCount() == 0, ("we just reset the frame data and the command count is not zero, huh?")); -} - -/** - * Returns the command count for the given frame. - */ -UnsignedInt FrameDataManager::getCommandCount(UnsignedInt frame) { - UnsignedInt frameindex = frame % FRAME_DATA_LENGTH; - - return m_frameData[frameindex].getCommandCount(); -} - -/** - * Set the frame command count for the given frame. - */ -void FrameDataManager::setFrameCommandCount(UnsignedInt frame, UnsignedInt commandCount) { - UnsignedInt frameindex = frame % FRAME_DATA_LENGTH; - - m_frameData[frameindex].setFrameCommandCount(commandCount); -} - -/** - * - */ -UnsignedInt FrameDataManager::getFrameCommandCount(UnsignedInt frame) { - UnsignedInt frameindex = frame % FRAME_DATA_LENGTH; - - return m_frameData[frameindex].getFrameCommandCount(); -} - -/** - * Set both the command count and the frame command count to 0 for the given frames. - */ -void FrameDataManager::zeroFrames(UnsignedInt startingFrame, UnsignedInt numFrames) { - UnsignedInt frameIndex = startingFrame % FRAME_DATA_LENGTH; - for (UnsignedInt i = 0; i < numFrames; ++i) { - //DEBUG_LOG(("Calling zeroFrame for frame index %d", frameIndex)); - m_frameData[frameIndex].zeroFrame(); - ++frameIndex; - frameIndex = frameIndex % FRAME_DATA_LENGTH; - } -} - -/** - * Destroy all the commands held by this object. - */ -void FrameDataManager::destroyGameMessages() { - for (Int i = 0; i < FRAME_DATA_LENGTH; ++i) { - m_frameData[i].destroyGameMessages(); - } -} - -/** - * Sets the quit frame, also sets the isQuitting flag. - */ -void FrameDataManager::setQuitFrame(UnsignedInt frame) { - m_isQuitting = TRUE; - m_quitFrame = frame; -} - -/** - * returns the quit frame. - */ -UnsignedInt FrameDataManager::getQuitFrame() { - return m_quitFrame; -} - -/** - * returns true if this frame data manager is quitting. - */ -Bool FrameDataManager::getIsQuitting() { - return m_isQuitting; -} diff --git a/Generals/Code/GameEngine/Source/GameNetwork/FrameMetrics.cpp b/Generals/Code/GameEngine/Source/GameNetwork/FrameMetrics.cpp deleted file mode 100644 index 411daf7278..0000000000 --- a/Generals/Code/GameEngine/Source/GameNetwork/FrameMetrics.cpp +++ /dev/null @@ -1,141 +0,0 @@ -/* -** 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. // -// // -//////////////////////////////////////////////////////////////////////////////// - -/** FrameMetrics.cpp */ - -#include "PreRTS.h" // This must go first in EVERY cpp file in the GameEngine - -#include "GameNetwork/FrameMetrics.h" -#include "GameClient/Display.h" -#include "GameNetwork/networkutil.h" - -FrameMetrics::FrameMetrics() -{ - //Added By Sadullah Nader - //Initializations missing and needed - m_averageFps = 0.0f; - m_averageLatency = 0.0f; - m_cushionIndex = 0; - m_fpsListIndex = 0; - m_lastFpsTimeThing = 0; - m_minimumCushion = 0; - - m_pendingLatencies = NEW time_t[MAX_FRAMES_AHEAD]; - for(Int i = 0; i < MAX_FRAMES_AHEAD; i++) - m_pendingLatencies[i] = 0; - // - m_fpsList = NEW Real[TheGlobalData->m_networkFPSHistoryLength]; - m_latencyList = NEW Real[TheGlobalData->m_networkLatencyHistoryLength]; -} - -FrameMetrics::~FrameMetrics() { - delete m_fpsList; - m_fpsList = NULL; - - delete m_latencyList; - m_latencyList = NULL; - - delete[] m_pendingLatencies; - m_pendingLatencies = NULL; -} - -void FrameMetrics::init() { - m_averageFps = 30; - m_averageLatency = (Real)0.2; - m_minimumCushion = -1; - - UnsignedInt i = 0; - for (; i < TheGlobalData->m_networkFPSHistoryLength; ++i) { - m_fpsList[i] = 30.0; - } - m_fpsListIndex = 0; - for (i = 0; i < TheGlobalData->m_networkLatencyHistoryLength; ++i) { - m_latencyList[i] = (Real)0.2; - } - m_cushionIndex = 0; -} - -void FrameMetrics::reset() { - init(); -} - -void FrameMetrics::doPerFrameMetrics(UnsignedInt frame) { - // Do the measurement of the fps. - time_t curTime = timeGetTime(); - if ((curTime - m_lastFpsTimeThing) >= 1000) { -// if ((m_fpsListIndex % 16) == 0) { -// DEBUG_LOG(("FrameMetrics::doPerFrameMetrics - adding %f to fps history. average before: %f ", m_fpsList[m_fpsListIndex], m_averageFps)); -// } - m_averageFps -= ((m_fpsList[m_fpsListIndex])) / TheGlobalData->m_networkFPSHistoryLength; // subtract out the old value from the average. - m_fpsList[m_fpsListIndex] = TheDisplay->getAverageFPS(); -// m_fpsList[m_fpsListIndex] = TheGameClient->getFrame() - m_fpsStartingFrame; - m_averageFps += ((Real)(m_fpsList[m_fpsListIndex])) / TheGlobalData->m_networkFPSHistoryLength; // add the new value to the average. -// DEBUG_LOG(("average after: %f", m_averageFps)); - ++m_fpsListIndex; - m_fpsListIndex %= TheGlobalData->m_networkFPSHistoryLength; - m_lastFpsTimeThing = curTime; - } - - Int pendingLatenciesIndex = frame % MAX_FRAMES_AHEAD; - m_pendingLatencies[pendingLatenciesIndex] = curTime; - -} - -void FrameMetrics::processLatencyResponse(UnsignedInt frame) { - time_t curTime = timeGetTime(); - Int pendingIndex = frame % MAX_FRAMES_AHEAD; - time_t timeDiff = curTime - m_pendingLatencies[pendingIndex]; - - Int latencyListIndex = frame % TheGlobalData->m_networkLatencyHistoryLength; - m_averageLatency -= m_latencyList[latencyListIndex] / TheGlobalData->m_networkLatencyHistoryLength; - m_latencyList[latencyListIndex] = (Real)timeDiff / (Real)1000; // convert to seconds from milliseconds. - m_averageLatency += m_latencyList[latencyListIndex] / TheGlobalData->m_networkLatencyHistoryLength; - - if (frame % 16 == 0) { -// DEBUG_LOG(("ConnectionManager::processFrameInfoAck - average latency = %f", m_averageLatency)); - } -} - -void FrameMetrics::addCushion(Int cushion) { - ++m_cushionIndex; - m_cushionIndex %= TheGlobalData->m_networkCushionHistoryLength; - if (m_cushionIndex == 0) { - m_minimumCushion = -1; - } - if ((cushion < m_minimumCushion) || (m_minimumCushion == -1)) { - m_minimumCushion = cushion; - } -} - -Int FrameMetrics::getAverageFPS() { - return (Int)m_averageFps; -} - -Real FrameMetrics::getAverageLatency() { - return m_averageLatency; -} - -Int FrameMetrics::getMinimumCushion() { - return m_minimumCushion; -} diff --git a/Generals/Code/GameEngine/Source/GameNetwork/GameInfo.cpp b/Generals/Code/GameEngine/Source/GameNetwork/GameInfo.cpp deleted file mode 100644 index 4eda3b00ac..0000000000 --- a/Generals/Code/GameEngine/Source/GameNetwork/GameInfo.cpp +++ /dev/null @@ -1,1649 +0,0 @@ -/* -** 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. // -// // -//////////////////////////////////////////////////////////////////////////////// - -// FILE: GameInfo.cpp ////////////////////////////////////////////////////// -// game setup state info -// Author: Matthew D. Campbell, December 2001 - -#include "PreRTS.h" // This must go first in EVERY cpp file in the GameEngine - -#include "Common/CRCDebug.h" -#include "Common/file.h" -#include "Common/FileSystem.h" -#include "Common/GameState.h" -#include "GameClient/GameText.h" -#include "GameClient/MapUtil.h" -#include "Common/MultiplayerSettings.h" -#include "Common/PlayerTemplate.h" -#include "Common/Xfer.h" -#include "GameNetwork/FileTransfer.h" -#include "GameNetwork/GameInfo.h" -#include "GameNetwork/GameSpy/ThreadUtils.h" -#include "GameNetwork/GameSpy/StagingRoomGameInfo.h" -#include "GameNetwork/LANAPI.h" // for testing packet size -#include "GameNetwork/LANAPICallbacks.h" // for testing packet size -#include "strtok_r.h" - - - -GameInfo *TheGameInfo = NULL; - -// GameSlot ---------------------------------------- - -GameSlot::GameSlot() -{ - reset(); -} - -void GameSlot::reset() -{ - m_state = SLOT_CLOSED; // decent default - m_isAccepted = false; - m_hasMap = true; - m_color = -1; - m_startPos = -1; - m_playerTemplate = -1; - m_teamNumber = -1; - m_NATBehavior = FirewallHelperClass::FIREWALL_TYPE_SIMPLE; - m_lastFrameInGame = 0; - m_disconnected = FALSE; - m_port = 0; - m_isMuted = FALSE; - m_origPlayerTemplate = -1; - m_origStartPos = -1; - m_origColor = -1; -} - -void GameSlot::saveOffOriginalInfo( void ) -{ - DEBUG_LOG(("GameSlot::saveOffOriginalInfo() - orig was color=%d, pos=%d, house=%d", - m_origColor, m_origStartPos, m_origPlayerTemplate)); - m_origPlayerTemplate = m_playerTemplate; - m_origStartPos = m_startPos; - m_origColor = m_color; - DEBUG_LOG(("GameSlot::saveOffOriginalInfo() - color=%d, pos=%d, house=%d", - m_color, m_startPos, m_playerTemplate)); -} - -static Int getSlotIndex(const GameSlot *slot) -{ - for (Int i=0; igetConstSlot(i) == slot) - return i; - } - return -1; -} - -static Bool isSlotLocalAlly(const GameSlot *slot) -{ - Int slotIndex = getSlotIndex(slot); - Int localIndex = TheGameInfo->getLocalSlotNum(); - const GameSlot *localSlot = TheGameInfo->getConstSlot(localIndex); - - // if either doesn't exist, not an ally - if (slotIndex < 0 || localIndex < 0) - return FALSE; - - // if slot is us, ally - if (slotIndex == localIndex) - return TRUE; - - // if slot is same team as us, ally - if (slot->getTeamNumber() == localSlot->getTeamNumber() && slot->getTeamNumber() >= 0) - return TRUE; - - // if we're an observer, we see all - if (localSlot->getOriginalPlayerTemplate() == PLAYERTEMPLATE_OBSERVER) - return TRUE; - - // nope - return FALSE; -} - -UnicodeString GameSlot::getApparentPlayerTemplateDisplayName( void ) const -{ - if (TheMultiplayerSettings && TheMultiplayerSettings->showRandomPlayerTemplate() && - m_origPlayerTemplate == PLAYERTEMPLATE_RANDOM && !isSlotLocalAlly(this)) - { - return TheGameText->fetch("GUI:Random"); - } - else if (m_origPlayerTemplate == PLAYERTEMPLATE_OBSERVER) - { - return TheGameText->fetch("GUI:Observer"); - } - DEBUG_LOG(("Fetching player template display name for player template %d (orig is %d)", - m_playerTemplate, m_origPlayerTemplate)); - if (m_playerTemplate < 0) - { - return TheGameText->fetch("GUI:Random"); - } - return ThePlayerTemplateStore->getNthPlayerTemplate(m_playerTemplate)->getDisplayName(); -} - -Int GameSlot::getApparentPlayerTemplate( void ) const -{ - if (TheMultiplayerSettings && TheMultiplayerSettings->showRandomPlayerTemplate() && - !isSlotLocalAlly(this)) - { - return m_origPlayerTemplate; - } - return m_playerTemplate; -} - -Int GameSlot::getApparentColor( void ) const -{ - if (TheMultiplayerSettings && m_origPlayerTemplate == PLAYERTEMPLATE_OBSERVER) - return TheMultiplayerSettings->getColor(PLAYERTEMPLATE_OBSERVER)->getColor(); - - if (TheMultiplayerSettings && TheMultiplayerSettings->showRandomColor() && - !isSlotLocalAlly(this)) - { - return m_origColor; - } - return m_color; -} - -Int GameSlot::getApparentStartPos( void ) const -{ - if (TheMultiplayerSettings && TheMultiplayerSettings->showRandomStartPos() && - !isSlotLocalAlly(this)) - { - return m_origStartPos; - } - return m_startPos; -} - - -void GameSlot::unAccept( void ) -{ - if (isHuman()) - { - m_isAccepted = false; - } -} - -void GameSlot::setMapAvailability( Bool hasMap ) -{ - if (isHuman()) - { - m_hasMap = hasMap; - } -} - -void GameSlot::setState( SlotState state, UnicodeString name, UnsignedInt IP ) -{ - if (!(isAI() && (state == SLOT_EASY_AI || state == SLOT_MED_AI || state == SLOT_BRUTAL_AI))) - { - m_color = -1; - m_startPos = -1; - m_playerTemplate = -1; - m_teamNumber = -1; - - if (state == SLOT_OPEN && TheGameSpyGame && TheGameSpyGame->getConstSlot(0) == this) - { - DEBUG_CRASH(("Game Is Hosed!")); - } - } - if (state == SLOT_PLAYER) - { - reset(); - m_state = state; - m_name = name; - } - else - { - m_state = state; - m_isAccepted = true; - m_hasMap = true; - switch(state) - { - case SLOT_OPEN: - m_name = TheGameText->fetch("GUI:Open"); - break; - case SLOT_EASY_AI: - m_name = TheGameText->fetch("GUI:EasyAI"); - break; - case SLOT_MED_AI: - m_name = TheGameText->fetch("GUI:MediumAI"); - break; - case SLOT_BRUTAL_AI: - m_name = TheGameText->fetch("GUI:HardAI"); - break; - case SLOT_CLOSED: - default: - m_name = TheGameText->fetch("GUI:Closed"); - break; - } - } - - m_IP = IP; -} - -// Various tests -Bool GameSlot::isHuman( void ) const -{ - return m_state == SLOT_PLAYER; -} - -Bool GameSlot::isOccupied( void ) const -{ - return m_state == SLOT_PLAYER || m_state == SLOT_EASY_AI || m_state == SLOT_MED_AI || m_state == SLOT_BRUTAL_AI; -} - -Bool GameSlot::isAI( void ) const -{ - return m_state == SLOT_EASY_AI || m_state == SLOT_MED_AI || m_state == SLOT_BRUTAL_AI; -} - -Bool GameSlot::isPlayer( AsciiString userName ) const -{ - UnicodeString uName; - uName.translate(userName); - return (m_state == SLOT_PLAYER && !m_name.compareNoCase(uName)); -} - -Bool GameSlot::isPlayer( UnicodeString userName ) const -{ - return (m_state == SLOT_PLAYER && !m_name.compareNoCase(userName)); -} - -Bool GameSlot::isPlayer( UnsignedInt ip ) const -{ - return (m_state == SLOT_PLAYER && m_IP == ip); -} - -Bool GameSlot::isOpen( void ) const -{ - return m_state == SLOT_OPEN; -} - -// GameInfo ---------------------------------------- - -GameInfo::GameInfo() -{ - for (int i=0; im_defaultStartingCash; - - // - - for (Int i=0; ireset(); - } - - m_preorderMask = 0; -} - -Bool GameInfo::isPlayerPreorder(Int index) -{ - if (index >= 0 && index < MAX_SLOTS) - return ((m_preorderMask & (1 << index)) != 0); - return FALSE; -} - -void GameInfo::markPlayerAsPreorder(Int index) -{ - if (index >= 0 && index < MAX_SLOTS) - m_preorderMask |= 1 << index; -} - - -void GameInfo::clearSlotList( void ) -{ - for (int i=0; isetState(SLOT_CLOSED); - } -} - -Int GameInfo::getNumPlayers( void ) const -{ - Int numPlayers = 0; - for (int i=0; iisOccupied()) - numPlayers++; - } - return numPlayers; -} - -Int GameInfo::getNumNonObserverPlayers( void ) const -{ - Int numPlayers = 0; - for (int i=0; iisOccupied() && m_slot[i]->getPlayerTemplate() != PLAYERTEMPLATE_OBSERVER) - numPlayers++; - } - return numPlayers; -} - -Int GameInfo::getMaxPlayers( void ) const -{ - if (!TheMapCache) - return -1; - - AsciiString lowerMap = m_mapName; - lowerMap.toLower(); - MapCache::iterator it = TheMapCache->find(lowerMap); - if (it == TheMapCache->end()) - return -1; - MapMetaData data = it->second; - return data.m_numPlayers; -} - -void GameInfo::enterGame( void ) -{ - DEBUG_ASSERTCRASH(!m_inGame && !m_inProgress, ("Entering game at a bad time!")); - reset(); - m_inGame = true; - m_inProgress = false; -} - -void GameInfo::leaveGame( void ) -{ - DEBUG_ASSERTCRASH(m_inGame && !m_inProgress, ("Leaving game at a bad time!")); - reset(); -} - -void GameInfo::startGame( Int gameID ) -{ - DEBUG_ASSERTCRASH(m_inGame && !m_inProgress, ("Starting game at a bad time!")); - m_gameID = gameID; - closeOpenSlots(); - m_inProgress = true; -} - -void GameInfo::endGame( void ) -{ - DEBUG_ASSERTCRASH(m_inGame && m_inProgress, ("Ending game without playing one!")); - m_inGame = false; - m_inProgress = false; -} - -void GameInfo::setSlot( Int slotNum, GameSlot slotInfo ) -{ - DEBUG_ASSERTCRASH( slotNum >= 0 && slotNum < MAX_SLOTS, ("GameInfo::setSlot - Invalid slot number")); - if (slotNum < 0 || slotNum >= MAX_SLOTS) - return; - - DEBUG_ASSERTCRASH( m_slot[slotNum], ("NULL slot pointer")); - if (!m_slot[slotNum]) - return; - -// Bool isHuman = slotInfo.isHuman(); -// Bool wasHuman = m_slot[slotNum]->isHuman(); - - if (slotNum == 0) - { - slotInfo.setAccept(); - slotInfo.setMapAvailability(true); - } - *m_slot[slotNum] = slotInfo; - -#ifdef DEBUG_LOGGING - UnsignedInt ip = slotInfo.getIP(); -#endif - - DEBUG_LOG(("GameInfo::setSlot - setting slot %d to be player %ls with IP %d.%d.%d.%d", slotNum, slotInfo.getName().str(), - PRINTF_IP_AS_4_INTS(ip))); -} - -GameSlot* GameInfo::getSlot( Int slotNum ) -{ - DEBUG_ASSERTCRASH( slotNum >= 0 && slotNum < MAX_SLOTS, ("GameInfo::getSlot - Invalid slot number")); - if (slotNum < 0 || slotNum >= MAX_SLOTS) - return NULL; - - DEBUG_ASSERTCRASH( m_slot[slotNum], ("NULL slot pointer") ); - return m_slot[slotNum]; -} - -const GameSlot* GameInfo::getConstSlot( Int slotNum ) const -{ - DEBUG_ASSERTCRASH( slotNum >= 0 && slotNum < MAX_SLOTS, ("GameInfo::getSlot - Invalid slot number")); - if (slotNum < 0 || slotNum >= MAX_SLOTS) - return NULL; - - DEBUG_ASSERTCRASH( m_slot[slotNum], ("NULL slot pointer") ); - return m_slot[slotNum]; -} - -Int GameInfo::getLocalSlotNum( void ) const -{ - DEBUG_ASSERTCRASH(m_inGame, ("Looking for local game slot while not in game")); - if (!m_inGame) - return -1; - - for (Int i=0; iisPlayer(m_localIP)) - return i; - } - return -1; -} - -Int GameInfo::getSlotNum( AsciiString userName ) const -{ - DEBUG_ASSERTCRASH(m_inGame, ("Looking for game slot while not in game")); - if (!m_inGame) - return -1; - - UnicodeString uName; - uName.translate(userName); - for (Int i=0; iisPlayer( uName )) - return i; - } - return -1; -} - -Bool GameInfo::amIHost( void ) const -{ - DEBUG_ASSERTCRASH(m_inGame, ("Looking for game slot while not in game")); - if (!m_inGame) - return false; - - return getConstSlot(0)->isPlayer(m_localIP); -} - -void GameInfo::setMap( AsciiString mapName ) -{ - m_mapName = mapName; - if (m_inGame && amIHost()) - { - const MapMetaData *mapData = TheMapCache->findMap( mapName ); - if (mapData) - { - m_mapMask = 1; - AsciiString path = mapName; - path.truncateBy(3); - path.concat("tga"); - DEBUG_LOG(("GameInfo::setMap() - Looking for '%s'", path.str())); - File *fp = TheFileSystem->openFile(path.str()); - if (fp) - { - m_mapMask |= 2; - fp->close(); - fp = NULL; - } - - AsciiString newMapName; - if (mapName.getLength() > 0) - { - AsciiString token; - mapName.nextToken(&token, "\\/"); - // add all the tokens except the last one. - // that way we don't add the filename, just the - // directory name, we can do this since the filename - // is just the directory name with the file extention - // added onto it. - while (mapName.find('\\') != NULL) - { - if (newMapName.getLength() > 0) - { - newMapName.concat('/'); - } - newMapName.concat(token); - mapName.nextToken(&token, "\\/"); - } - } - newMapName.concat("/map.ini"); - DEBUG_LOG(("GameInfo::setMap() - Looking for '%s'", newMapName.str())); - fp = TheFileSystem->openFile(newMapName.str()); - if (fp) - { - m_mapMask |= 4; - fp->close(); - fp = NULL; - } - - path = GetStrFileFromMap(m_mapName); - DEBUG_LOG(("GameInfo::setMap() - Looking for '%s'", path.str())); - fp = TheFileSystem->openFile(path.str()); - if (fp) - { - m_mapMask |= 8; - fp->close(); - fp = NULL; - } - - path = GetSoloINIFromMap(m_mapName); - DEBUG_LOG(("GameInfo::setMap() - Looking for '%s'", path.str())); - fp = TheFileSystem->openFile(path.str()); - if (fp) - { - m_mapMask |= 16; - fp->close(); - fp = NULL; - } - - path = GetAssetUsageFromMap(m_mapName); - DEBUG_LOG(("GameInfo::setMap() - Looking for '%s'", path.str())); - fp = TheFileSystem->openFile(path.str()); - if (fp) - { - m_mapMask |= 32; - fp->close(); - fp = NULL; - } - - path = GetReadmeFromMap(m_mapName); - DEBUG_LOG(("GameInfo::setMap() - Looking for '%s'", path.str())); - fp = TheFileSystem->openFile(path.str()); - if (fp) - { - m_mapMask |= 64; - fp->close(); - fp = NULL; - } - } - else - { - m_mapMask = 0; - } - } -} - -void GameInfo::setMapContentsMask( Int mask ) -{ - m_mapMask = mask; -} - -void GameInfo::setMapCRC( UnsignedInt mapCRC ) -{ - m_mapCRC = mapCRC; - if (!TheMapCache) - return; - - // check the map cache - if (m_inGame && getLocalSlotNum() >= 0) - { - //TheMapCache->updateCache(); - AsciiString lowerMap = m_mapName; - lowerMap.toLower(); - //DEBUG_LOG(("GameInfo::setMapCRC - looking for map file \"%s\" in the map cache", lowerMap.str())); - std::map::iterator it = TheMapCache->find(lowerMap); - if (it == TheMapCache->end()) - { - /* - DEBUG_LOG(("GameInfo::setMapCRC - could not find map file.")); - it = TheMapCache->begin(); - while (it != TheMapCache->end()) - { - DEBUG_LOG(("\t\"%s\"", it->first.str())); - ++it; - } - */ - getSlot(getLocalSlotNum())->setMapAvailability(false); - } - else if (m_mapCRC != it->second.m_CRC) - { - DEBUG_LOG(("GameInfo::setMapCRC - map CRC's do not match (%X/%X).", m_mapCRC, it->second.m_CRC)); - getSlot(getLocalSlotNum())->setMapAvailability(false); - } - else - { - //DEBUG_LOG(("GameInfo::setMapCRC - map CRC's match.")); - getSlot(getLocalSlotNum())->setMapAvailability(true); - } - } -} - -void GameInfo::setMapSize( UnsignedInt mapSize ) -{ - m_mapSize = mapSize; - if (!TheMapCache) - return; - - // check the map cache - if (m_inGame && getLocalSlotNum() >= 0) - { - //TheMapCache->updateCache(); - AsciiString lowerMap = m_mapName; - lowerMap.toLower(); - std::map::iterator it = TheMapCache->find(lowerMap); - if (it == TheMapCache->end()) - { - DEBUG_LOG(("GameInfo::setMapSize - could not find map file.")); - getSlot(getLocalSlotNum())->setMapAvailability(false); - } - else if (m_mapCRC != it->second.m_CRC) - { - DEBUG_LOG(("GameInfo::setMapSize - map CRC's do not match.")); - getSlot(getLocalSlotNum())->setMapAvailability(false); - } - else - { - //DEBUG_LOG(("GameInfo::setMapSize - map CRC's match.")); - getSlot(getLocalSlotNum())->setMapAvailability(true); - } - } -} - -void GameInfo::setSeed( Int seed ) -{ - m_seed = seed; -} - -void GameInfo::setSlotPointer( Int index, GameSlot *slot ) -{ - if (index < 0 || index >= MAX_SLOTS) - return; - - m_slot[index] = slot; -} - -void GameInfo::setSuperweaponRestriction( UnsignedShort restriction ) -{ - m_superweaponRestriction = restriction; -} - -void GameInfo::setStartingCash( const Money & startingCash ) -{ - m_startingCash = startingCash; -} - -Bool GameInfo::isColorTaken(Int colorIdx, Int slotToIgnore ) const -{ - for (Int i=0; igetColor() == colorIdx && i != slotToIgnore) - return true; - } - return false; -} - -Bool GameInfo::isStartPositionTaken(Int positionIdx, Int slotToIgnore ) const -{ - for (Int i=0; igetStartPos() == positionIdx && i != slotToIgnore) - return true; - } - return false; -} - -void GameInfo::resetAccepted( void ) -{ - GameSlot *slot = getSlot(0); - if (slot) - slot->setAccept(); - for(int i = 1; i< MAX_SLOTS; i++) - { - slot = getSlot(i); - if (slot) - slot->unAccept(); - } -} - -void GameInfo::resetStartSpots() -{ - GameSlot *slot = NULL; - for (Int i = 0; i < MAX_SLOTS; ++i) - { - slot = getSlot(i); - if (slot != NULL) - { - slot->setStartPos(-1); - } - } -} - -// adjust the slots in the game to open or closed -// depending on the players in there now and the number of -// players the map can hold. -void GameInfo::adjustSlotsForMap() -{ - const MapMetaData *md = TheMapCache->findMap(m_mapName); - if (md != NULL) - { - // get the number of players allowed from the map. - Int numPlayers = md->m_numPlayers; - Int numPlayerSlots = 0; - - // first get the number of occupied slots. - Int i = 0; - for (; i < MAX_SLOTS; ++i) - { - GameSlot *tempSlot = getSlot(i); - if (tempSlot->isOccupied()) - { - ++numPlayerSlots; - } - } - - // now go through and close the appropriate number of slots. - // note that no players are kicked in this process, we leave - // that up to the user. - for (i = 0; i < MAX_SLOTS; ++i) - { - // we have room for more players, if this slot is unoccupied, set it to open. - GameSlot *slot = getSlot(i); - if (numPlayers > numPlayerSlots) - { - if (!(slot->isOccupied())) - { - GameSlot newSlot; - newSlot.setState(SLOT_OPEN); - setSlot(i, newSlot); - ++numPlayerSlots; - } - } - else - { - if (!(slot->isOccupied())) - { - // we don't have any more room, set this slot to closed. - GameSlot newSlot; - newSlot.setState(SLOT_CLOSED); - setSlot(i, newSlot); - } - } - } - } -} - -void GameInfo::closeOpenSlots() -{ - for (Int i = 0; i < MAX_SLOTS; ++i) - { - GameSlot *slot = getSlot(i); - if (!(slot->isOccupied())) - { - GameSlot newSlot; - newSlot.setState(SLOT_CLOSED); - setSlot(i, newSlot); - } - } -} - -static Bool isSlotLocalAlly(GameInfo *game, const GameSlot *slot) -{ - const GameSlot *localSlot = game->getConstSlot(game->getLocalSlotNum()); - if (!localSlot) - return TRUE; - - if (slot == localSlot) - return TRUE; - - if (slot->getTeamNumber() < 0) - return FALSE; - - return slot->getTeamNumber() == localSlot->getTeamNumber(); -} - -Bool GameInfo::isSkirmish(void) -{ - Bool sawAI = FALSE; - - for (Int i=0; iisHuman()) - return FALSE; - - if (getConstSlot(i)->isAI()) - { - if (isSlotLocalAlly(getConstSlot(i))) - return FALSE; - sawAI = TRUE; - } - } - return sawAI; -} - -Bool GameInfo::isMultiPlayer(void) -{ - for (Int i=0; iisHuman()) - return TRUE; - } - - return FALSE; -} - -Bool GameInfo::isSandbox(void) -{ - Int localSlotNum = getLocalSlotNum(); - Int localTeam = getConstSlot(localSlotNum)->getTeamNumber(); - for (Int i=0; iisOccupied() && (slot->getTeamNumber() < 0 || slot->getTeamNumber() != localTeam)) - return FALSE; - } - return TRUE; -} - - -// Convenience Functions ---------------------------------------- - -static const char slotListID = 'S'; - -AsciiString GameInfoToAsciiString( const GameInfo *game ) -{ - if (!game) - return AsciiString::TheEmptyString; - - AsciiString mapName = game->getMap(); - mapName = TheGameState->realMapPathToPortableMapPath(mapName); - AsciiString newMapName; - if (mapName.getLength() > 0) - { - AsciiString token; - mapName.nextToken(&token, "\\/"); - // add all the tokens except the last one. - // that way we don't add the filename, just the - // directory name, we can do this since the filename - // is just the directory name with the file extention - // added onto it. - while (mapName.find('\\') != NULL) - { - if (newMapName.getLength() > 0) - { - newMapName.concat('/'); - } - newMapName.concat(token); - mapName.nextToken(&token, "\\/"); - } - DEBUG_LOG(("Map name is %s", mapName.str())); - } - - AsciiString optionsString; -#if RTS_GENERALS - optionsString.format("M=%2.2x%s;MC=%X;MS=%d;SD=%d;C=%d;", game->getMapContentsMask(), newMapName.str(), - game->getMapCRC(), game->getMapSize(), game->getSeed(), game->getCRCInterval()); -#else - optionsString.format("US=%d;M=%2.2x%s;MC=%X;MS=%d;SD=%d;C=%d;SR=%u;SC=%u;O=%c;", game->getUseStats(), game->getMapContentsMask(), newMapName.str(), - game->getMapCRC(), game->getMapSize(), game->getSeed(), game->getCRCInterval(), game->getSuperweaponRestriction(), - game->getStartingCash().countMoney(), game->oldFactionsOnly() ? 'Y' : 'N' ); -#endif - - //add player info for each slot - optionsString.concat(slotListID); - optionsString.concat('='); - for (Int i=0; igetConstSlot(i); - - AsciiString str; - if (slot && slot->isHuman()) - { - AsciiString tmp; //all this data goes after name - tmp.format( ",%X,%d,%c%c,%d,%d,%d,%d,%d:", - slot->getIP(), slot->getPort(), - (slot->isAccepted()?'T':'F'), - (slot->hasMap()?'T':'F'), - slot->getColor(), slot->getPlayerTemplate(), - slot->getStartPos(), slot->getTeamNumber(), - slot->getNATBehavior() ); - //make sure name doesn't cause overflow of m_lanMaxOptionsLength - int lenCur = tmp.getLength() + optionsString.getLength() + 2; //+2 for H and trailing ; - int lenRem = m_lanMaxOptionsLength - lenCur; //length remaining before overflowing - int lenMax = lenRem / (MAX_SLOTS-i); //share lenRem with all remaining slots - AsciiString name = WideCharStringToMultiByte(slot->getName().str()).c_str(); - while( name.getLength() > lenMax ) - name.removeLastChar(); //what a horrible way to truncate. I hate AsciiString. - - str.format( "H%s%s", name.str(), tmp.str() ); - } - else if (slot && slot->isAI()) - { - Char c; - if (slot->getState() == SLOT_EASY_AI) - c = 'E'; - else if (slot->getState() == SLOT_MED_AI) - c = 'M'; - else - c = 'H'; - str.format("C%c,%d,%d,%d,%d:", c, - slot->getColor(), slot->getPlayerTemplate(), - slot->getStartPos(), slot->getTeamNumber()); - } - else if (slot && slot->getState() == SLOT_OPEN) - { - str = "O:"; - } - else if (slot && slot->getState() == SLOT_CLOSED) - { - str = "X:"; - } - else - { - DEBUG_ASSERTCRASH(false, ("Bad slot type")); - str = "X:"; - } - optionsString.concat(str); - } - optionsString.concat(';'); - - DEBUG_ASSERTCRASH(!TheLAN || (optionsString.getLength() < m_lanMaxOptionsLength), - ("WARNING: options string is longer than expected! Length is %d, but max is %d!", - optionsString.getLength(), m_lanMaxOptionsLength)); - - return optionsString; -} - -static Int grabHexInt(const char *s) -{ - char tmp[5] = "0xff"; - tmp[2] = s[0]; - tmp[3] = s[1]; - Int b = strtol(tmp, NULL, 16); - return b; -} -Bool ParseAsciiStringToGameInfo(GameInfo *game, AsciiString options) -{ - // Parse game options - char *buf = strdup(options.str()); - char *bufPtr = buf; - char *strPos, *keyValPair; - GameSlot newSlot[MAX_SLOTS]; - Bool optionsOk = true; - AsciiString mapName; - Int mapContentsMask; - UnsignedInt mapCRC, mapSize; - Int seed = 0; - Int crc = 100; - Bool sawCRC = FALSE; - Bool oldFactionsOnly = FALSE; - Int useStats = TRUE; - Money startingCash = TheGlobalData->m_defaultStartingCash; - UnsignedShort restriction = 0; // Always the default - - Bool sawMap = FALSE; - Bool sawMapCRC = FALSE; - Bool sawMapSize = FALSE; - Bool sawSeed = FALSE; - Bool sawSlotlist = FALSE; - Bool sawUseStats = FALSE; - Bool sawSuperweaponRestriction = FALSE; - Bool sawStartingCash = FALSE; - Bool sawOldFactions = FALSE; - - //DEBUG_LOG(("Saw options of %s", options.str())); - DEBUG_LOG(("ParseAsciiStringToGameInfo - parsing [%s]", options.str())); - - - while ( (keyValPair = strtok_r(bufPtr, ";", &strPos)) != NULL ) - { - bufPtr = NULL; // strtok within the same string - - AsciiString key, val; - char *pos = NULL; - char *keyPtr, *valPtr; - keyPtr = (strtok_r(keyValPair, "=", &pos)); - valPtr = (strtok_r(NULL, "\n", &pos)); - if (keyPtr) - key = keyPtr; - if (valPtr) - val = valPtr; - - if (val.isEmpty()) - { - optionsOk = false; - DEBUG_LOG(("ParseAsciiStringToGameInfo - saw empty value, quitting")); - break; - } - - if (key.compare("US") == 0) - { - useStats = atoi(val.str()); - sawUseStats = true; - } - else - if (key.compare("M") == 0) - { - if (val.getLength() < 3) - { - optionsOk = FALSE; - DEBUG_LOG(("ParseAsciiStringToGameInfo - saw bogus map; quitting")); - break; - } - mapContentsMask = grabHexInt(val.str()); - AsciiString tempstr; - AsciiString token; - tempstr = val.str()+2; - tempstr.nextToken(&token, "\\/"); - while (tempstr.getLength() > 0) - { - mapName.concat(token); - mapName.concat('\\'); - tempstr.nextToken(&token, "\\/"); - } - mapName.concat(token); - mapName.concat('\\'); - mapName.concat(token); - mapName.concat('.'); - mapName.concat(TheMapCache->getMapExtension()); - AsciiString realMapName = TheGameState->portableMapPathToRealMapPath(mapName); - if (realMapName.isEmpty()) - { - // TheSuperHackers @security slurmlord 18/06/2025 As the map file name/path from the AsciiString failed to normalize, - // in other words is bogus and points outside of the approved target directory for maps, avoid an arbitrary file overwrite vulnerability - // if the save or network game embeds a custom map to store at the location, by flagging the options as not OK and rejecting the game. - optionsOk = FALSE; - DEBUG_LOG(("ParseAsciiStringToGameInfo - saw bogus map name ('%s'); quitting", mapName.str())); - break; - } - mapName = realMapName; - sawMap = true; - DEBUG_LOG(("ParseAsciiStringToGameInfo - map name is %s", mapName.str())); - } - else if (key.compare("MC") == 0) - { - mapCRC = 0; - sscanf(val.str(), "%X", &mapCRC); - sawMapCRC = true; - } - else if (key.compare("MS") == 0) - { - mapSize = atoi(val.str()); - sawMapSize = true; - } - else if (key.compare("SD") == 0) - { - seed = atoi(val.str()); - sawSeed = true; -// DEBUG_LOG(("ParseAsciiStringToGameInfo - random seed is %d", seed)); - } - else if (key.compare("C") == 0) - { - crc = atoi(val.str()); - sawCRC = TRUE; - } - else if (key.compare("SR") == 0 ) - { - restriction = (UnsignedShort)atoi(val.str()); - sawSuperweaponRestriction = TRUE; - } - else if (key.compare("SC") == 0 ) - { - UnsignedInt startingCashAmount = strtoul( val.str(), NULL, 10 ); - startingCash.init(); - startingCash.deposit( startingCashAmount, FALSE, FALSE ); - sawStartingCash = TRUE; - } - else if (key.compare("O") == 0 ) - { - oldFactionsOnly = ( val.compareNoCase( "Y" ) == 0 ); - sawOldFactions = TRUE; - } - else if (key.getLength() == 1 && *key.str() == slotListID) - { - sawSlotlist = true; - /// @TODO: Need to read in all the slot info... big mess right now. - char *rawSlotBuf = strdup(val.str()); - char *freeMe = NULL; - AsciiString rawSlot; -// Bool slotsOk = true; //flag that lets us know whether or not the slot list is good. - -// DEBUG_LOG(("ParseAsciiStringToGameInfo - Parsing slot list")); - for (int i=0; i= TheMultiplayerSettings->getNumColors()) - { - optionsOk = false; - DEBUG_LOG(("ParseAsciiStringToGameInfo - player color was invalid, quitting")); - break; - } - newSlot[i].setColor(color); - //DEBUG_LOG(("ParseAsciiStringToGameInfo - player color set to %d", color)); - - //Read playerTemplate index - slotValue = strtok_r(NULL,",",&slotPos); - if(slotValue.isEmpty()) - { - optionsOk = false; - DEBUG_LOG(("ParseAsciiStringToGameInfo - slotValue player template is empty, quitting")); - break; - } - Int playerTemplate = atoi(slotValue.str()); - if (playerTemplate < PLAYERTEMPLATE_MIN || playerTemplate >= ThePlayerTemplateStore->getPlayerTemplateCount()) - { - optionsOk = false; - DEBUG_LOG(("ParseAsciiStringToGameInfo - player template value is invalid, quitting")); - break; - } - newSlot[i].setPlayerTemplate(playerTemplate); - //DEBUG_LOG(("ParseAsciiStringToGameInfo - player template is %d", playerTemplate)); - - //Read start position index - slotValue = strtok_r(NULL,",",&slotPos); - if(slotValue.isEmpty()) - { - optionsOk = false; - DEBUG_LOG(("ParseAsciiStringToGameInfo - slotValue start position is empty, quitting")); - break; - } - Int startPos = atoi(slotValue.str()); - if (startPos < -1 || startPos >= MAX_SLOTS) - { - optionsOk = false; - DEBUG_LOG(("ParseAsciiStringToGameInfo - player start position is invalid, quitting")); - break; - } - newSlot[i].setStartPos(startPos); - //DEBUG_LOG(("ParseAsciiStringToGameInfo - player start position is %d", startPos)); - - //Read team index - slotValue = strtok_r(NULL,",",&slotPos); - if(slotValue.isEmpty()) - { - optionsOk = false; - DEBUG_LOG(("ParseAsciiStringToGameInfo - slotValue team number is empty, quitting")); - break; - } - Int team = atoi(slotValue.str()); - if (team < -1 || team >= MAX_SLOTS/2) - { - optionsOk = false; - DEBUG_LOG(("ParseAsciiStringToGameInfo - team number is invalid, quitting")); - break; - } - newSlot[i].setTeamNumber(team); - //DEBUG_LOG(("ParseAsciiStringToGameInfo - team number is %d", team)); - - // Read the NAT behavior - slotValue = strtok_r(NULL, ",",&slotPos); - if (slotValue.isEmpty()) - { - optionsOk = false; - DEBUG_LOG(("ParseAsciiStringToGameInfo - NAT behavior is empty, quitting")); - break; - } - FirewallHelperClass::FirewallBehaviorType NATType = (FirewallHelperClass::FirewallBehaviorType)atoi(slotValue.str()); - if ((NATType < FirewallHelperClass::FIREWALL_MIN) || - (NATType > FirewallHelperClass::FIREWALL_MAX)) { - optionsOk = false; - DEBUG_LOG(("ParseAsciiStringToGameInfo - NAT behavior is invalid, quitting")); - break; - } - newSlot[i].setNATBehavior(NATType); - DEBUG_LOG(("ParseAsciiStringToGameInfo - NAT behavior is %X", NATType)); - } - break; - case 'C': - { - DEBUG_LOG(("ParseAsciiStringToGameInfo - AI player")); - char *slotPos = NULL; - //Parse out the Name - AsciiString slotValue(strtok_r((char *)rawSlot.str(),",",&slotPos)); - if(slotValue.isEmpty()) - { - optionsOk = false; - DEBUG_LOG(("ParseAsciiStringToGameInfo - slotValue AI Type is empty, quitting")); - break; - } - - switch(*(slotValue.str() + 1)) - { - case 'E': - { - newSlot[i].setState(SLOT_EASY_AI); - //DEBUG_LOG(("ParseAsciiStringToGameInfo - Easy AI")); - } - break; - case 'M': - { - newSlot[i].setState(SLOT_MED_AI); - //DEBUG_LOG(("ParseAsciiStringToGameInfo - Medium AI")); - } - break; - case 'H': - { - newSlot[i].setState(SLOT_BRUTAL_AI); - //DEBUG_LOG(("ParseAsciiStringToGameInfo - Brutal AI")); - } - break; - default: - { - optionsOk = false; - DEBUG_LOG(("ParseAsciiStringToGameInfo - Unknown AI, quitting")); - } - break; - } - - //Read color index - slotValue = strtok_r(NULL,",",&slotPos); - if(slotValue.isEmpty()) - { - optionsOk = false; - DEBUG_LOG(("ParseAsciiStringToGameInfo - slotValue color is empty, quitting")); - break; - } - Int color = atoi(slotValue.str()); - if (color < -1 || color >= TheMultiplayerSettings->getNumColors()) - { - optionsOk = false; - DEBUG_LOG(("ParseAsciiStringToGameInfo - player color was invalid, quitting")); - break; - } - newSlot[i].setColor(color); - //DEBUG_LOG(("ParseAsciiStringToGameInfo - player color set to %d", color)); - - //Read playerTemplate index - slotValue = strtok_r(NULL,",",&slotPos); - if(slotValue.isEmpty()) - { - optionsOk = false; - DEBUG_LOG(("ParseAsciiStringToGameInfo - slotValue player template is empty, quitting")); - break; - } - Int playerTemplate = atoi(slotValue.str()); - if (playerTemplate < PLAYERTEMPLATE_MIN || playerTemplate >= ThePlayerTemplateStore->getPlayerTemplateCount()) - { - optionsOk = false; - DEBUG_LOG(("ParseAsciiStringToGameInfo - player template value is invalid, quitting")); - break; - } - newSlot[i].setPlayerTemplate(playerTemplate); - //DEBUG_LOG(("ParseAsciiStringToGameInfo - player template is %d", playerTemplate)); - - //Read start pos - slotValue = strtok_r(NULL,",",&slotPos); - if(slotValue.isEmpty()) - { - optionsOk = false; - DEBUG_LOG(("ParseAsciiStringToGameInfo - slotValue start pos is empty, quitting")); - break; - } - Int startPos = atoi(slotValue.str()); - Bool isStartPosBad = FALSE; - if (startPos < -1 || startPos >= MAX_SLOTS) - { - isStartPosBad = TRUE; - } - for (Int j=0; j= 0 && startPos == newSlot[i].getStartPos()) - { - isStartPosBad = TRUE; // can't have multiple people using the same start pos - } - } - if (isStartPosBad) - { - optionsOk = false; - DEBUG_LOG(("ParseAsciiStringToGameInfo - start pos is invalid, quitting")); - break; - } - newSlot[i].setStartPos(startPos); - //DEBUG_LOG(("ParseAsciiStringToGameInfo - start spot is %d", startPos)); - - //Read team index - slotValue = strtok_r(NULL,",",&slotPos); - if(slotValue.isEmpty()) - { - optionsOk = false; - DEBUG_LOG(("ParseAsciiStringToGameInfo - slotValue team number is empty, quitting")); - break; - } - Int team = atoi(slotValue.str()); - if (team < -1 || team >= MAX_SLOTS/2) - { - optionsOk = false; - DEBUG_LOG(("ParseAsciiStringToGameInfo - team number is invalid, quitting")); - break; - } - newSlot[i].setTeamNumber(team); - //DEBUG_LOG(("ParseAsciiStringToGameInfo - team number is %d", team)); - - } - break; - case 'O': - { - newSlot[i].setState( SLOT_OPEN ); - //DEBUG_LOG(("ParseAsciiStringToGameInfo - Slot is open")); - } - break; - case 'X': - { - newSlot[i].setState( SLOT_CLOSED ); - //DEBUG_LOG(("ParseAsciiStringToGameInfo - Slot is closed")); - } - break; - default: - { - optionsOk = false; - DEBUG_LOG(("ParseAsciiStringToGameInfo - unrecognized slot entry, quitting")); - } - break; - } - } - - free(freeMe); - } - else - { - optionsOk = false; - break; - } - } - - free(buf); - - // TheSuperHackers @tweak The following settings are no longer - // a strict requirement in the Zero Hour Replay file: - // * UseStats - // * SuperweaponRestriction - // * StartingCash - // * OldFactionsOnly - // In Generals they never were. - if (optionsOk && sawMap && sawMapCRC && sawMapSize && sawSeed && sawSlotlist && sawCRC) - { - // We were setting the Global Data directly here, but Instead, I'm now - // first setting the data in game. We'll set the global data when - // we start a game. - if (!game) - return true; - - //DEBUG_LOG(("ParseAsciiStringToGameInfo - game options all good, setting info")); - - for(Int i = 0; isetSlot(i,newSlot[i]); - - game->setMap(mapName); - game->setMapCRC(mapCRC); - game->setMapSize(mapSize); - game->setMapContentsMask(mapContentsMask); - game->setSeed(seed); - game->setCRCInterval(crc); - game->setUseStats(useStats); - game->setSuperweaponRestriction(restriction); - game->setStartingCash(startingCash); - game->setOldFactionsOnly(oldFactionsOnly); - - return true; - } - - DEBUG_LOG(("ParseAsciiStringToGameInfo - game options messed up")); - return false; -} - - -//---------------------------------------------------------------------------------------------------------- -//---------------------------------------------------------------------------------------------------------- - -//------------------------- SkirmishGameInfo --------------------------------------------------------------- - -// ------------------------------------------------------------------------------------------------ -/** CRC */ -// ------------------------------------------------------------------------------------------------ -void SkirmishGameInfo::crc( Xfer *xfer ) -{ -} - -// ------------------------------------------------------------------------------------------------ -/** Xfer Method */ -// ------------------------------------------------------------------------------------------------ -void SkirmishGameInfo::xfer( Xfer *xfer ) -{ -#if RTS_GENERALS - const XferVersion currentVersion = 2; -#else - const XferVersion currentVersion = 4; -#endif - XferVersion version = currentVersion; - xfer->xferVersion( &version, currentVersion ); - - - xfer->xferInt(&m_preorderMask); - xfer->xferInt(&m_crcInterval); - xfer->xferBool(&m_inGame); - xfer->xferBool(&m_inProgress); - xfer->xferBool(&m_surrendered); - xfer->xferInt(&m_gameID); - - Int slot = MAX_SLOTS; - xfer->xferInt(&slot); - DEBUG_ASSERTCRASH(slot==MAX_SLOTS, ("MAX_SLOTS changed, need to change version. jba.")); - - for (slot = 0; slot < MAX_SLOTS; slot++) - { - Int state = m_slot[slot]->getState(); - xfer->xferInt(&state); - - UnicodeString name=m_slot[slot]->getName(); - if (version >= 2) - { - xfer->xferUnicodeString(&name); - } - - Bool isAccepted=m_slot[slot]->isAccepted(); - xfer->xferBool(&isAccepted); - - Bool isMuted=m_slot[slot]->isMuted(); - xfer->xferBool(&isMuted); - m_slot[slot]->mute(isMuted); - - Int color=m_slot[slot]->getColor(); - xfer->xferInt(&color); - - Int startPos=m_slot[slot]->getStartPos(); - xfer->xferInt(&startPos); - - Int playerTemplate=m_slot[slot]->getPlayerTemplate(); - xfer->xferInt(&playerTemplate); - - Int teamNumber=m_slot[slot]->getTeamNumber(); - xfer->xferInt(&teamNumber); - - Int origColor=m_slot[slot]->getOriginalColor(); - xfer->xferInt(&origColor); - - Int origStartPos=m_slot[slot]->getOriginalStartPos(); - xfer->xferInt(&origStartPos); - - Int origPlayerTemplate=m_slot[slot]->getOriginalPlayerTemplate(); - xfer->xferInt(&origPlayerTemplate); - - if( xfer->getXferMode() == XFER_LOAD ) { - m_slot[slot]->setState((SlotState)state, name); - if (isAccepted) m_slot[slot]->setAccept(); - - m_slot[slot]->setPlayerTemplate(origPlayerTemplate); - m_slot[slot]->setStartPos(origStartPos); - m_slot[slot]->setColor(origColor); - m_slot[slot]->saveOffOriginalInfo(); - - m_slot[slot]->setTeamNumber(teamNumber); - m_slot[slot]->setColor(color); - m_slot[slot]->setStartPos(startPos); - m_slot[slot]->setPlayerTemplate(playerTemplate); - } - } - - xfer->xferUnsignedInt(&m_localIP); - - xfer->xferMapName(&m_mapName); - xfer->xferUnsignedInt(&m_mapCRC); - xfer->xferUnsignedInt(&m_mapSize); - xfer->xferInt(&m_mapMask); - xfer->xferInt(&m_seed); - - if ( version >= 3 ) - { - xfer->xferUnsignedShort( &m_superweaponRestriction ); - - if ( version == 3 ) - { - // Version 3 had a bool which is now gone - Bool obsoleteBool; - xfer->xferBool( &obsoleteBool ); - } - - xfer->xferSnapshot( &m_startingCash ); - } - else if ( xfer->getXferMode() == XFER_LOAD ) - { - m_superweaponRestriction = 0; - m_startingCash = TheGlobalData->m_defaultStartingCash; - } - -} - -// ------------------------------------------------------------------------------------------------ -/** Load post process */ -// ------------------------------------------------------------------------------------------------ -void SkirmishGameInfo::loadPostProcess( void ) -{ -} - - diff --git a/Generals/Code/GameEngine/Source/GameNetwork/GameMessageParser.cpp b/Generals/Code/GameEngine/Source/GameNetwork/GameMessageParser.cpp deleted file mode 100644 index c6fa9b90ef..0000000000 --- a/Generals/Code/GameEngine/Source/GameNetwork/GameMessageParser.cpp +++ /dev/null @@ -1,101 +0,0 @@ -/* -** 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 in the GameEngine - -#include "GameNetwork/GameMessageParser.h" - -//---------------------------------------------------------------------------- -GameMessageParser::GameMessageParser() -{ - m_first = NULL; - m_argTypeCount = 0; -} - -//---------------------------------------------------------------------------- -GameMessageParser::GameMessageParser(GameMessage *msg) -{ - m_first = NULL; - m_argTypeCount = 0; - - UnsignedByte argCount = msg->getArgumentCount(); - GameMessageArgumentDataType lasttype = ARGUMENTDATATYPE_UNKNOWN; - Int thisTypeCount = 0; - - for (UnsignedByte i = 0; i < argCount; ++i) { - GameMessageArgumentDataType type = msg->getArgumentDataType(i); - if (type != lasttype) { - if (thisTypeCount > 0) { - addArgType(lasttype, thisTypeCount); - ++m_argTypeCount; - } - lasttype = type; - thisTypeCount = 0; - } - ++thisTypeCount; - } - if (thisTypeCount > 0) { - addArgType(lasttype, thisTypeCount); - ++m_argTypeCount; - } -} - -//---------------------------------------------------------------------------- -GameMessageParser::~GameMessageParser() -{ - GameMessageParserArgumentType *temp = NULL; - while (m_first != NULL) { - temp = m_first->getNext(); - deleteInstance(m_first); - m_first = temp; - } -} - -//---------------------------------------------------------------------------- -void GameMessageParser::addArgType(GameMessageArgumentDataType type, Int argCount) -{ - if (m_first == NULL) { - m_first = newInstance(GameMessageParserArgumentType)(type, argCount); - m_last = m_first; - return; - } - - m_last->setNext(newInstance(GameMessageParserArgumentType)(type, argCount)); - m_last = m_last->getNext(); -} - -//---------------------------------------------------------------------------- -GameMessageParserArgumentType::GameMessageParserArgumentType(GameMessageArgumentDataType type, Int argCount) -{ - m_next = NULL; - m_type = type; - m_argCount = argCount; -} - -//---------------------------------------------------------------------------- -GameMessageParserArgumentType::~GameMessageParserArgumentType() -{ -} - diff --git a/Generals/Code/GameEngine/Source/GameNetwork/GameSpy/Chat.cpp b/Generals/Code/GameEngine/Source/GameNetwork/GameSpy/Chat.cpp deleted file mode 100644 index 190df8a9a6..0000000000 --- a/Generals/Code/GameEngine/Source/GameNetwork/GameSpy/Chat.cpp +++ /dev/null @@ -1,351 +0,0 @@ -/* -** 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. // -// // -//////////////////////////////////////////////////////////////////////////////// - -// FILE: Chat.cpp ////////////////////////////////////////////////////// -// Generals GameSpy chat-related code -// Author: Matthew D. Campbell, July 2002 - -#include "PreRTS.h" // This must go first in EVERY cpp file in the GameEngine - -#include "Common/AudioEventRTS.h" -#include "Common/INI.h" -#include "GameClient/GameText.h" -#include "GameClient/GadgetListBox.h" -#include "GameClient/LanguageFilter.h" -#include "GameClient/GameWindowManager.h" -#include "GameNetwork/GameSpy/PeerDefsImplementation.h" -#include "GameNetwork/GameSpy/PeerThread.h" -#include "GameClient/InGameUI.h" - -#define OFFSET(x) (sizeof(Int) * (x)) -static const FieldParse GameSpyColorFieldParse[] = -{ - - { "Default", INI::parseColorInt, NULL, OFFSET(GSCOLOR_DEFAULT) }, - { "CurrentRoom", INI::parseColorInt, NULL, OFFSET(GSCOLOR_CURRENTROOM) }, - { "ChatRoom", INI::parseColorInt, NULL, OFFSET(GSCOLOR_ROOM) }, - { "Game", INI::parseColorInt, NULL, OFFSET(GSCOLOR_GAME) }, - { "GameFull", INI::parseColorInt, NULL, OFFSET(GSCOLOR_GAME_FULL) }, - { "GameCRCMismatch", INI::parseColorInt, NULL, OFFSET(GSCOLOR_GAME_CRCMISMATCH) }, - { "PlayerNormal", INI::parseColorInt, NULL, OFFSET(GSCOLOR_PLAYER_NORMAL) }, - { "PlayerOwner", INI::parseColorInt, NULL, OFFSET(GSCOLOR_PLAYER_OWNER) }, - { "PlayerBuddy", INI::parseColorInt, NULL, OFFSET(GSCOLOR_PLAYER_BUDDY) }, - { "PlayerSelf", INI::parseColorInt, NULL, OFFSET(GSCOLOR_PLAYER_SELF) }, - { "PlayerIgnored", INI::parseColorInt, NULL, OFFSET(GSCOLOR_PLAYER_IGNORED) }, - { "ChatNormal", INI::parseColorInt, NULL, OFFSET(GSCOLOR_CHAT_NORMAL) }, - { "ChatEmote", INI::parseColorInt, NULL, OFFSET(GSCOLOR_CHAT_EMOTE) }, - { "ChatOwner", INI::parseColorInt, NULL, OFFSET(GSCOLOR_CHAT_OWNER) }, - { "ChatOwnerEmote", INI::parseColorInt, NULL, OFFSET(GSCOLOR_CHAT_OWNER_EMOTE) }, - { "ChatPriv", INI::parseColorInt, NULL, OFFSET(GSCOLOR_CHAT_PRIVATE) }, - { "ChatPrivEmote", INI::parseColorInt, NULL, OFFSET(GSCOLOR_CHAT_PRIVATE_EMOTE) }, - { "ChatPrivOwner", INI::parseColorInt, NULL, OFFSET(GSCOLOR_CHAT_PRIVATE_OWNER) }, - { "ChatPrivOwnerEmote", INI::parseColorInt, NULL, OFFSET(GSCOLOR_CHAT_PRIVATE_OWNER_EMOTE) }, - { "ChatBuddy", INI::parseColorInt, NULL, OFFSET(GSCOLOR_CHAT_BUDDY) }, - { "ChatSelf", INI::parseColorInt, NULL, OFFSET(GSCOLOR_CHAT_SELF) }, - { "AcceptTrue", INI::parseColorInt, NULL, OFFSET(GSCOLOR_ACCEPT_TRUE) }, - { "AcceptFalse", INI::parseColorInt, NULL, OFFSET(GSCOLOR_ACCEPT_FALSE) }, - { "MapSelected", INI::parseColorInt, NULL, OFFSET(GSCOLOR_MAP_SELECTED) }, - { "MapUnselected", INI::parseColorInt, NULL, OFFSET(GSCOLOR_MAP_UNSELECTED) }, - { "MOTD", INI::parseColorInt, NULL, OFFSET(GSCOLOR_MOTD) }, - { "MOTDHeading", INI::parseColorInt, NULL, OFFSET(GSCOLOR_MOTD_HEADING) }, - - { NULL, NULL, NULL, 0 } - -}; - -void INI::parseOnlineChatColorDefinition( INI* ini ) -{ - // parse the ini definition - ini->initFromINI( GameSpyColor, GameSpyColorFieldParse ); -} - - -Color GameSpyColor[GSCOLOR_MAX] = -{ - GameMakeColor(255,255,255,255), // GSCOLOR_DEFAULT - GameMakeColor(255,255, 0,255), // GSCOLOR_CURRENTROOM - GameMakeColor(255,255,255,255), // GSCOLOR_ROOM - GameMakeColor(128,128,0,255), // GSCOLOR_GAME - GameMakeColor(128,128,128,255), // GSCOLOR_GAME_FULL - GameMakeColor(128,128,128,255), // GSCOLOR_GAME_CRCMISMATCH -#if RTS_GENERALS - GameMakeColor(255, 0, 0,255), // GSCOLOR_PLAYER_NORMAL -#else - GameMakeColor(255,255,255,255), // GSCOLOR_PLAYER_NORMAL -#endif - GameMakeColor(255, 0,255,255), // GSCOLOR_PLAYER_OWNER - GameMakeColor(255, 0,128,255), // GSCOLOR_PLAYER_BUDDY - GameMakeColor(255, 0, 0,255), // GSCOLOR_PLAYER_SELF - GameMakeColor(128,128,128,255), // GSCOLOR_PLAYER_IGNORED -#if RTS_GENERALS - GameMakeColor(255,0,0,255), // GSCOLOR_CHAT_NORMAL -#else - GameMakeColor(255,255,255,255), // GSCOLOR_CHAT_NORMAL -#endif - GameMakeColor(255,128,0,255), // GSCOLOR_CHAT_EMOTE, - GameMakeColor(255,255,0,255), // GSCOLOR_CHAT_OWNER, - GameMakeColor(128,255,0,255), // GSCOLOR_CHAT_OWNER_EMOTE, - GameMakeColor(0,0,255,255), // GSCOLOR_CHAT_PRIVATE, - GameMakeColor(0,255,255,255), // GSCOLOR_CHAT_PRIVATE_EMOTE, - GameMakeColor(255,0,255,255), // GSCOLOR_CHAT_PRIVATE_OWNER, - GameMakeColor(255,128,255,255), // GSCOLOR_CHAT_PRIVATE_OWNER_EMOTE, - GameMakeColor(255, 0,255,255), // GSCOLOR_CHAT_BUDDY, - GameMakeColor(255, 0,128,255), // GSCOLOR_CHAT_SELF, - GameMakeColor( 0,255, 0,255), // GSCOLOR_ACCEPT_TRUE, - GameMakeColor(255, 0, 0,255), // GSCOLOR_ACCEPT_FALSE, - GameMakeColor(255,255, 0,255), // GSCOLOR_MAP_SELECTED, - GameMakeColor(255,255,255,255), // GSCOLOR_MAP_UNSELECTED, - GameMakeColor(255,255,255,255), // GSCOLOR_MOTD, - GameMakeColor(255,255, 0,255), // GSCOLOR_MOTD_HEADING, -}; - -Bool GameSpyInfo::sendChat( UnicodeString message, Bool isAction, GameWindow *playerListbox ) -{ - static UnicodeString s_prevMsg = UnicodeString::TheEmptyString; //stop spam before it happens - - RoomType roomType = StagingRoom; - if (getCurrentGroupRoom()) - roomType = GroupRoom; - - PeerRequest req; - req.text = message.str(); - - message.trim(); - // Echo the user's input to the chat window - if (!message.isEmpty()) - { - if (!playerListbox) - { // Public message - if( isAction || message.compare(s_prevMsg) != 0 ) //don't send duplicate messages - { - req.message.isAction = isAction; - req.peerRequestType = PeerRequest::PEERREQUEST_MESSAGEROOM; - TheGameSpyPeerMessageQueue->addRequest(req); - s_prevMsg = message; - } - return false; - } - - // Get the selections (is this a private message?) - Int maxSel = GadgetListBoxGetMaxSelectedLength(playerListbox); - Int *selections; - GadgetListBoxGetSelected(playerListbox, (Int *)&selections); - - if (selections[0] == -1) - { // Public message - if( isAction || message.compare(s_prevMsg) != 0 ) //don't send duplicate messages - { - req.message.isAction = isAction; - req.peerRequestType = PeerRequest::PEERREQUEST_MESSAGEROOM; - TheGameSpyPeerMessageQueue->addRequest(req); - s_prevMsg = message; - } - return false; - } - else - { - // Private message - - // Construct a list - AsciiString names = AsciiString::TheEmptyString; - AsciiString tmp = AsciiString::TheEmptyString; - AsciiString aStr; // AsciiString buf for translating Unicode entries - names.format("%s", TheGameSpyInfo->getLocalName().str()); - for (int i=0; igetLocalName())) - { - tmp.format(",%s", aStr.str()); - names.concat(tmp); - } - } - else - { - break; - } - } - - if (!names.isEmpty()) - { - req.nick = names.str(); - req.message.isAction = isAction; - req.peerRequestType = PeerRequest::PEERREQUEST_MESSAGEPLAYER; - TheGameSpyPeerMessageQueue->addRequest(req); - } - s_prevMsg = message; - return true; - } - } - s_prevMsg = message; - return false; -} - -void GameSpyInfo::addChat( AsciiString nick, Int profileID, UnicodeString msg, Bool isPublic, Bool isAction, GameWindow *win ) -{ - PlayerInfoMap::iterator it = getPlayerInfoMap()->find(nick); - if (it != getPlayerInfoMap()->end()) - { - addChat( it->second, msg, isPublic, isAction, win ); - } - else - { - } -} - -void GameSpyInfo::addChat( PlayerInfo p, UnicodeString msg, Bool isPublic, Bool isAction, GameWindow *win ) -{ - Int style; - if(isSavedIgnored(p.m_profileID) || isIgnored(p.m_name)) - return; - - Bool isOwner = p.m_flags & PEER_FLAG_OP; - Bool isBuddy = getBuddyMap()->find(p.m_profileID) != getBuddyMap()->end(); - - Bool isMe = p.m_name.compare(TheGameSpyInfo->getLocalName()) == 0; - - if(!isMe) - { - if(m_disallowAsainText) - { - const WideChar *buff = msg.str(); - Int length = msg.getLength(); - for(Int i = 0; i < length; ++i) - { - if(buff[i] >= 256) - return; - } - } - else if(m_disallowNonAsianText) - { - const WideChar *buff = msg.str(); - Int length = msg.getLength(); - Bool hasUnicode = FALSE; - for(Int i = 0; i < length; ++i) - { - if(buff[i] >= 256) - { - hasUnicode = TRUE; - break; - } - } - if(!hasUnicode) - return; - } - - if (!isPublic) - { - AudioEventRTS privMsgAudio("GUIMessageReceived"); - - if( TheAudio ) - { - TheAudio->addAudioEvent( &privMsgAudio ); - } - } - } - - - if (isBuddy) - { - style = GSCOLOR_CHAT_BUDDY; - } - else if (isPublic && isAction) - { - style = (isOwner)?GSCOLOR_CHAT_OWNER_EMOTE:GSCOLOR_CHAT_EMOTE; - } - else if (isPublic) - { - style = (isOwner)?GSCOLOR_CHAT_OWNER:GSCOLOR_CHAT_NORMAL; - } - else if (isAction) - { - style = (isOwner)?GSCOLOR_CHAT_PRIVATE_OWNER_EMOTE:GSCOLOR_CHAT_PRIVATE_EMOTE; - } - else - { - style = (isOwner)?GSCOLOR_CHAT_PRIVATE_OWNER:GSCOLOR_CHAT_PRIVATE; - } - - UnicodeString name; - name.translate(p.m_name); - - // filters language -// if( TheGlobalData->m_languageFilterPref ) -// { - TheLanguageFilter->filterLine(msg); -// } - - UnicodeString fullMsg; - if (isAction) - { - fullMsg.format( L"%ls %ls", name.str(), msg.str() ); - } - else - { - fullMsg.format( L"[%ls] %ls", name.str(), msg.str() ); - } - - Int index = addText(fullMsg, GameSpyColor[style], win); - if (index >= 0) - { - GadgetListBoxSetItemData(win, (void *)p.m_profileID, index); - } -} - -Int GameSpyInfo::addText( UnicodeString message, Color c, GameWindow *win ) -{ - if (TheGameSpyGame && TheGameSpyGame->isInGame() && TheGameSpyGame->isGameInProgress()) - { - static AudioEventRTS messageFromChatSound("GUIMessageReceived"); - TheAudio->addAudioEvent(&messageFromChatSound); - - TheInGameUI->message(message); - } - - if (!win) - { - // try to pick up a registered text window - if (m_textWindows.empty()) - return -1; - - win = *(m_textWindows.begin()); - } - Int index = GadgetListBoxAddEntryText(win, message, c, -1, -1); - GadgetListBoxSetItemData(win, (void *)-1, index); - - return index; -} - -void GameSpyInfo::registerTextWindow( GameWindow *win ) -{ - m_textWindows.insert(win); -} - -void GameSpyInfo::unregisterTextWindow( GameWindow *win ) -{ - m_textWindows.erase(win); -} - diff --git a/Generals/Code/GameEngine/Source/GameNetwork/GameSpy/GSConfig.cpp b/Generals/Code/GameEngine/Source/GameNetwork/GameSpy/GSConfig.cpp deleted file mode 100644 index d79709d92e..0000000000 --- a/Generals/Code/GameEngine/Source/GameNetwork/GameSpy/GSConfig.cpp +++ /dev/null @@ -1,482 +0,0 @@ -/* -** 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. // -// // -//////////////////////////////////////////////////////////////////////////////// - -/////////////////////////////////////////////////////////////////////////////////////// -// FILE: GSConfig.cpp -// Author: Matthew D. Campbell, Sept 2002 -// Description: GameSpy online config -/////////////////////////////////////////////////////////////////////////////////////// - -// INCLUDES /////////////////////////////////////////////////////////////////////////// -#include "PreRTS.h" // This must go first in EVERY cpp file in the GameEngine - -#include "Common/GameState.h" -#include "GameClient/MapUtil.h" -#include "GameNetwork/GameSpy/GSConfig.h" -#include "GameNetwork/RankPointValue.h" - - -/////////////////////////////////////////////////////////////////////////////////////// - -GameSpyConfigInterface *TheGameSpyConfig = NULL; - -class GameSpyConfig : public GameSpyConfigInterface -{ -public: - GameSpyConfig( AsciiString config ); - ~GameSpyConfig() {} - - // Pings - std::list getPingServers(void) { return m_pingServers; } - Int getNumPingRepetitions(void) { return m_pingReps; } - Int getPingTimeoutInMs(void) { return m_pingTimeout; } - virtual Int getPingCutoffGood( void ) { return m_pingCutoffGood; } - virtual Int getPingCutoffBad( void ) { return m_pingCutoffBad; } - - // QM - std::list getQMMaps(void) { return m_qmMaps; } - Int getQMBotID(void) { return m_qmBotID; } - Int getQMChannel(void) { return m_qmChannel; } - void setQMChannel(Int channel) { m_qmChannel = channel; } - - // Player Info - Int getPointsForRank(Int rank); - virtual Bool isPlayerVIP(Int id); - - virtual Bool getManglerLocation(Int index, AsciiString& host, UnsignedShort& port); - - // Ladder / Any other external parsing - AsciiString getLeftoverConfig(void) { return m_leftoverConfig; } - - // NAT Timeouts - virtual Int getTimeBetweenRetries() { return m_natRetryInterval; } - virtual Int getMaxManglerRetries() { return m_natMaxManglerRetries; } - virtual time_t getRetryInterval() { return m_natManglerRetryInterval; } - virtual time_t getKeepaliveInterval() { return m_natKeepaliveInterval; } - virtual time_t getPortTimeout() { return m_natPortTimeout; } - virtual time_t getRoundTimeout() { return m_natRoundTimeout; } - - // Custom match - virtual Bool restrictGamesToLobby() { return m_restrictGamesToLobby; } - -protected: - std::list m_pingServers; - Int m_pingReps; - Int m_pingTimeout; - Int m_pingCutoffGood; - Int m_pingCutoffBad; - - Int m_natRetryInterval; - Int m_natMaxManglerRetries; - time_t m_natManglerRetryInterval; - time_t m_natKeepaliveInterval; - time_t m_natPortTimeout; - time_t m_natRoundTimeout; - - std::vector m_manglerHosts; - std::vector m_manglerPorts; - - std::list m_qmMaps; - Int m_qmBotID; - Int m_qmChannel; - - Bool m_restrictGamesToLobby; - - std::set m_vip; // VIP people - - Int m_rankPoints[MAX_RANKS]; - - AsciiString m_leftoverConfig; -}; - -/////////////////////////////////////////////////////////////////////////////////////// - -GameSpyConfigInterface* GameSpyConfigInterface::create(AsciiString config) -{ - return NEW GameSpyConfig(config); -} - -/////////////////////////////////////////////////////////////////////////////////////// - -class SectionChecker -{ -public: - typedef std::list SectionList; - void addVar(const Bool *var) { m_bools.push_back(var); } - Bool isInSection(); -protected: - SectionList m_bools; -}; -Bool SectionChecker::isInSection() { - Bool ret = FALSE; - for (SectionList::const_iterator it = m_bools.begin(); it != m_bools.end(); ++it) - { - ret = ret || **it; - } - return ret; -} - -/////////////////////////////////////////////////////////////////////////////////////// - -GameSpyConfig::GameSpyConfig( AsciiString config ) : -m_natRetryInterval(1000), -m_natMaxManglerRetries(25), -m_natManglerRetryInterval(300), -m_natKeepaliveInterval(15000), -m_natPortTimeout(10000), -m_natRoundTimeout(10000), -m_pingReps(1), -m_pingTimeout(1000), -m_pingCutoffGood(300), -m_pingCutoffBad(600), -m_restrictGamesToLobby(FALSE), -m_qmBotID(0), -m_qmChannel(0) -{ - m_rankPoints[0] = 0; - m_rankPoints[1] = 5; - m_rankPoints[2] = 10; - m_rankPoints[3] = 20; - m_rankPoints[4] = 50; - m_rankPoints[5] = 100; - m_rankPoints[6] = 200; - m_rankPoints[7] = 500; - m_rankPoints[8] = 1000; - m_rankPoints[9] = 2000; - - AsciiString line; - Bool inPingServers = FALSE; - Bool inPingDuration = FALSE; - Bool inQMMaps = FALSE; - Bool inQMBot = FALSE; - Bool inManglers = FALSE; - Bool inVIP = FALSE; - Bool inNAT = FALSE; - Bool inCustom = FALSE; - - SectionChecker sections; - sections.addVar(&inPingServers); - sections.addVar(&inPingDuration); - sections.addVar(&inQMMaps); - sections.addVar(&inQMBot); - sections.addVar(&inManglers); - sections.addVar(&inVIP); - sections.addVar(&inNAT); - sections.addVar(&inCustom); - - while (config.nextToken(&line, "\n")) - { - if (line.getCharAt(line.getLength()-1) == '\r') - line.removeLastChar(); // there is a trailing '\r' - - line.trim(); - - if (line.isEmpty()) - continue; - - if (!sections.isInSection() && line.compare("") == 0) - { - inPingServers = TRUE; - } - else if (inPingServers && line.compare("") == 0) - { - inPingServers = FALSE; - } - else if (!sections.isInSection() && line.compare("") == 0) - { - inPingDuration = TRUE; - } - else if (inPingDuration && line.compare("") == 0) - { - inPingDuration = FALSE; - } - else if (!sections.isInSection() && line.compare("") == 0) - { - inQMMaps = TRUE; - } - else if (inQMMaps && line.compare("") == 0) - { - inQMMaps = FALSE; - } - else if (!sections.isInSection() && line.compare("") == 0) - { - inManglers = TRUE; - } - else if (inManglers && line.compare("") == 0) - { - inManglers = FALSE; - } - else if (!sections.isInSection() && line.compare("") == 0) - { - inQMBot = TRUE; - } - else if (inQMBot && line.compare("") == 0) - { - inQMBot = FALSE; - } - else if (!sections.isInSection() && line.compare("") == 0) - { - inVIP = TRUE; - } - else if (inVIP && line.compare("") == 0) - { - inVIP = FALSE; - } - else if (!sections.isInSection() && line.compare("") == 0) - { - inNAT = TRUE; - } - else if (inNAT && line.compare("") == 0) - { - inNAT = FALSE; - } - else if (!sections.isInSection() && line.compare("") == 0) - { - inCustom = TRUE; - } - else if (inCustom && line.compare("") == 0) - { - inCustom = FALSE; - } - else if (inVIP) - { - line.toLower(); - if (line.getLength()) - { - Int val = atoi(line.str()); - if (val > 0) - m_vip.insert(val); - } - } - else if (inPingServers) - { - line.toLower(); - m_pingServers.push_back(line); - } - else if (inPingDuration) - { - line.toLower(); - AsciiString key, val; - if (line.nextToken(&key, " =")) - { - if (key == "reps") - { - if (line.nextToken(&val, " =")) - { - m_pingReps = atoi(val.str()); - } - } - else if (key == "timeout") - { - if (line.nextToken(&val, " =")) - { - m_pingTimeout = atoi(val.str()); - } - } - else if (key == "low") - { - if (line.nextToken(&val, " =")) - { - m_pingCutoffGood = atoi(val.str()); - } - } - else if (key == "med") - { - if (line.nextToken(&val, " =")) - { - m_pingCutoffBad = atoi(val.str()); - } - } - } - } - else if (inManglers) - { - line.trim(); - line.toLower(); - AsciiString hostStr; - AsciiString portStr; - line.nextToken(&hostStr, ":"); - line.nextToken(&portStr, ":\n\r"); - if (hostStr.isNotEmpty() && portStr.isNotEmpty()) - { - m_manglerHosts.push_back(hostStr); - m_manglerPorts.push_back(atoi(portStr.str())); - } - } - else if (inQMMaps) - { - line.toLower(); - AsciiString mapName; - mapName.format("%s\\%s\\%s.map", TheMapCache->getMapDir().str(), line.str(), line.str()); - mapName = TheGameState->portableMapPathToRealMapPath(TheGameState->realMapPathToPortableMapPath(mapName)); - mapName.toLower(); - - // [SKB: Jul 01 2003 @ 6:43pm] : - // German2 is missing some maps because of content. But, we need the m_qmMaps - // to contain same number of strings as the Retail version so that the - // QM Bot thinks that they have the same number of maps. - #if RTS_GENERALS - m_qmMaps.push_back(mapName); - #else - const MapMetaData *md = TheMapCache->findMap(mapName); - if (md) - { - m_qmMaps.push_back(mapName); - } - #endif - } - else if (inQMBot) - { - line.toLower(); - AsciiString key, val; - if (line.nextToken(&key, " =")) - { - if (key == "id") - { - if (line.nextToken(&val, " =")) - { - m_qmBotID = atoi(val.str()); - } - } - } - } - else if (inNAT) - { - line.toLower(); - AsciiString key, val; - if (line.nextToken(&key, " =")) - { - if (key == "retryinterval") - { - if (line.nextToken(&val, " =")) - { - m_natRetryInterval = atoi(val.str()); - } - } - else if (key == "manglerretries") - { - if (line.nextToken(&val, " =")) - { - m_natMaxManglerRetries = atoi(val.str()); - } - } - else if (key == "manglerinterval") - { - if (line.nextToken(&val, " =")) - { - m_natManglerRetryInterval = atoi(val.str()); - } - } - else if (key == "keepaliveinterval") - { - if (line.nextToken(&val, " =")) - { - m_natKeepaliveInterval = atoi(val.str()); - } - } - else if (key == "porttimeout") - { - if (line.nextToken(&val, " =")) - { - m_natPortTimeout = atoi(val.str()); - } - } - else if (key == "roundtimeout") - { - if (line.nextToken(&val, " =")) - { - m_natRoundTimeout = atoi(val.str()); - } - } - else - { - DEBUG_LOG(("Unknown key '%s' = '%s' in NAT block of GameSpy Config", key.str(), val.str())); - } - } - else - { - DEBUG_LOG(("Key '%s' missing val in NAT block of GameSpy Config", key.str())); - } - } - else if (inCustom) - { - line.toLower(); - AsciiString key, val; - if (line.nextToken(&key, " =") && line.nextToken(&val, " =")) - { - if (key == "restricted") - { - m_restrictGamesToLobby = atoi(val.str()); - } - else - { - DEBUG_LOG(("Unknown key '%s' = '%s' in Custom block of GameSpy Config", key.str(), val.str())); - } - } - else - { - DEBUG_LOG(("Key '%s' missing val in Custom block of GameSpy Config", key.str())); - } - } - else - { - m_leftoverConfig.concat(line); - m_leftoverConfig.concat('\n'); - } - } - -} - -/////////////////////////////////////////////////////////////////////////////////////// - -Int GameSpyConfig::getPointsForRank(Int rank) -{ - if (rank >= MAX_RANKS) rank = MAX_RANKS-1; - if (rank < 0) rank = 0; - return m_rankPoints[rank]; -} - -/////////////////////////////////////////////////////////////////////////////////////// - -Bool GameSpyConfig::getManglerLocation(Int index, AsciiString& host, UnsignedShort& port) -{ - if (index < 0 || index >= m_manglerHosts.size()) - { - return FALSE; - } - - host = m_manglerHosts[index]; - port = m_manglerPorts[index]; - return TRUE; -} - -/////////////////////////////////////////////////////////////////////////////////////// - -Bool GameSpyConfig::isPlayerVIP(Int id) -{ - std::set::const_iterator it = std::find(m_vip.begin(), m_vip.end(), id); - return it != m_vip.end(); -} - -/////////////////////////////////////////////////////////////////////////////////////// diff --git a/Generals/Code/GameEngine/Source/GameNetwork/GameSpy/LadderDefs.cpp b/Generals/Code/GameEngine/Source/GameNetwork/GameSpy/LadderDefs.cpp deleted file mode 100644 index 75112dc687..0000000000 --- a/Generals/Code/GameEngine/Source/GameNetwork/GameSpy/LadderDefs.cpp +++ /dev/null @@ -1,525 +0,0 @@ -/* -** 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. // -// // -//////////////////////////////////////////////////////////////////////////////// - -// FILE: LadderDefs.cpp ////////////////////////////////////////////////////// -// Generals ladder code -// Author: Matthew D. Campbell, August 2002 - -#include "PreRTS.h" // This must go first in EVERY cpp file in the GameEngine - -#include "GameNetwork/GameSpy/ThreadUtils.h" -#include "GameNetwork/GameSpy/LadderDefs.h" -#include "GameNetwork/GameSpy/PeerDefs.h" -#include "GameNetwork/GameSpy/GSConfig.h" -#include "Common/GameState.h" -#include "Common/file.h" -#include "Common/FileSystem.h" -#include "Common/PlayerTemplate.h" -#include "GameClient/GameText.h" -#include "GameClient/MapUtil.h" - - -LadderList *TheLadderList = NULL; - -LadderInfo::LadderInfo() -{ - playersPerTeam = 1; - minWins = 0; - maxWins = 0; - randomMaps = TRUE; - randomFactions = TRUE; - validQM = TRUE; - validCustom = FALSE; - port = 0; - submitReplay = FALSE; - index = -1; -} - -static LadderInfo *parseLadder(AsciiString raw) -{ - DEBUG_LOG(("Looking at ladder:\n%s", raw.str())); - LadderInfo *lad = NULL; - AsciiString line; - while (raw.nextToken(&line, "\n")) - { - if (line.getCharAt(line.getLength()-1) == '\r') - line.removeLastChar(); // there is a trailing '\r' - - line.trim(); - - if (line.isEmpty()) - continue; - - // woohoo! got a line! - line.trim(); - if ( !lad && line.startsWith("' - line = line.str() + 7; // the "name = MultiByteToWideCharSingleLine(tokenName.str()).c_str(); - lad->name.truncateTo(20); // Per Harvard's request, ladder names are limited to 20 chars - lad->address = tokenAddr; - lad->port = atoi(tokenPort.str()); - lad->homepageURL = tokenHomepage; - } - else if ( lad && line.startsWith("Name ") ) - { - lad->name = MultiByteToWideCharSingleLine(line.str() + 5).c_str(); - } - else if ( lad && line.startsWith("Desc ") ) - { - lad->description = MultiByteToWideCharSingleLine(line.str() + 5).c_str(); - } - else if ( lad && line.startsWith("Loc ") ) - { - lad->location = MultiByteToWideCharSingleLine(line.str() + 4).c_str(); - } - else if ( lad && line.startsWith("TeamSize ") ) - { - lad->playersPerTeam = atoi(line.str() + 9); - } - else if ( lad && line.startsWith("RandomMaps ") ) - { - lad->randomMaps = atoi(line.str() + 11); - } - else if ( lad && line.startsWith("RandomFactions ") ) - { - lad->randomFactions = atoi(line.str() + 15); - } - else if ( lad && line.startsWith("Faction ") ) - { - AsciiString faction = line.str() + 8; - AsciiStringList outStringList; - ThePlayerTemplateStore->getAllSideStrings(&outStringList); - - AsciiStringList::iterator aIt = std::find(outStringList.begin(), outStringList.end(), faction); - if (aIt != outStringList.end()) - { - // valid faction - now check for dupes - aIt = std::find(lad->validFactions.begin(), lad->validFactions.end(), faction); - if (aIt == lad->validFactions.end()) - { - lad->validFactions.push_back(faction); - } - } - } - /* - else if ( lad && line.startsWith("QM ") ) - { - lad->validQM = atoi(line.str() + 3); - } - else if ( lad && line.startsWith("Custom ") ) - { - lad->validCustom = atoi(line.str() + 7); - } - */ - else if ( lad && line.startsWith("MinWins ") ) - { - lad->minWins = atoi(line.str() + 8); - } - else if ( lad && line.startsWith("MaxWins ") ) - { - lad->maxWins = atoi(line.str() + 8); - } - else if ( lad && line.startsWith("CryptedPass ") ) - { - lad->cryptedPassword = line.str() + 12; - } - else if ( lad && line.compare("") == 0 ) - { - DEBUG_LOG(("Saw a ladder: name=%ls, addr=%s:%d, players=%dv%d, pass=%s, replay=%d, homepage=%s", - lad->name.str(), lad->address.str(), lad->port, lad->playersPerTeam, lad->playersPerTeam, lad->cryptedPassword.str(), - lad->submitReplay, lad->homepageURL.str())); - // end of a ladder - if (lad->playersPerTeam >= 1 && lad->playersPerTeam <= MAX_SLOTS/2) - { - if (lad->validFactions.size() == 0) - { - DEBUG_LOG(("No factions specified. Using all.")); - lad->validFactions.clear(); - Int numTemplates = ThePlayerTemplateStore->getPlayerTemplateCount(); - for ( Int i = 0; i < numTemplates; ++i ) - { - const PlayerTemplate *pt = ThePlayerTemplateStore->getNthPlayerTemplate(i); - if (!pt) - continue; - - if (pt->isPlayableSide() && pt->getSide().compare("Boss") != 0 ) - lad->validFactions.push_back(pt->getSide()); - } - } - else - { - AsciiStringList validFactions = lad->validFactions; - for (AsciiStringListIterator it = validFactions.begin(); it != validFactions.end(); ++it) - { - AsciiString faction = *it; - AsciiString marker; - marker.format("INI:Faction%s", faction.str()); - DEBUG_LOG(("Faction %s has marker %s corresponding to str %ls", faction.str(), marker.str(), TheGameText->fetch(marker).str())); - } - } - - if (lad->validMaps.size() == 0) - { - DEBUG_LOG(("No maps specified. Using all.")); - std::list qmMaps = TheGameSpyConfig->getQMMaps(); - for (std::list::const_iterator it = qmMaps.begin(); it != qmMaps.end(); ++it) - { - AsciiString mapName = *it; - - // check sizes on the maps before allowing them - const MapMetaData *md = TheMapCache->findMap(mapName); - if (md && md->m_numPlayers >= lad->playersPerTeam*2) - { - lad->validMaps.push_back(mapName); - } - } - } - return lad; - } - else - { - // no maps? don't play on it! - delete lad; - lad = NULL; - return NULL; - } - } - else if ( lad && line.startsWith("Map ") ) - { - // valid map - AsciiString mapName = line.str() + 4; - mapName.trim(); - if (mapName.isNotEmpty()) - { - mapName.format("%s\\%s\\%s.map", TheMapCache->getMapDir().str(), mapName.str(), mapName.str()); - mapName = TheGameState->portableMapPathToRealMapPath(TheGameState->realMapPathToPortableMapPath(mapName)); - mapName.toLower(); - std::list qmMaps = TheGameSpyConfig->getQMMaps(); - if (std::find(qmMaps.begin(), qmMaps.end(), mapName) != qmMaps.end()) - { - // check sizes on the maps before allowing them - const MapMetaData *md = TheMapCache->findMap(mapName); - if (md && md->m_numPlayers >= lad->playersPerTeam*2) - lad->validMaps.push_back(mapName); - } - } - } - else - { - // bad ladder - kill it - delete lad; - lad = NULL; - } - } - - delete lad; - return NULL; -} - -LadderList::LadderList() -{ - //Int profile = TheGameSpyInfo->getLocalProfileID(); - - AsciiString rawMotd = TheGameSpyConfig->getLeftoverConfig(); - AsciiString line; - Bool inLadders = FALSE; - Bool inSpecialLadders = FALSE; - Bool inLadder = FALSE; - LadderInfo *lad = NULL; - Int index = 1; - AsciiString rawLadder; - - while (rawMotd.nextToken(&line, "\n")) - { - if (line.getCharAt(line.getLength()-1) == '\r') - line.removeLastChar(); // there is a trailing '\r' - - line.trim(); - - if (line.isEmpty()) - continue; - - if (!inLadders && line.compare("") == 0) - { - inLadders = TRUE; - rawLadder.clear(); - } - else if (inLadders && line.compare("") == 0) - { - inLadders = FALSE; - } - else if (!inSpecialLadders && line.compare("") == 0) - { - inSpecialLadders = TRUE; - rawLadder.clear(); - } - else if (inSpecialLadders && line.compare("") == 0) - { - inSpecialLadders = FALSE; - } - else if (inLadders || inSpecialLadders) - { - if (line.startsWith("") == 0 && inLadder) - { - inLadder = FALSE; - rawLadder.concat(line); - rawLadder.concat('\n'); - if ((lad = parseLadder(rawLadder)) != NULL) - { - lad->index = index++; - if (inLadders) - { - DEBUG_LOG(("Adding to standard ladders")); - m_standardLadders.push_back(lad); - } - else - { - DEBUG_LOG(("Adding to special ladders")); - m_specialLadders.push_back(lad); - } - } - rawLadder.clear(); - } - else if (inLadder) - { - rawLadder.concat(line); - rawLadder.concat('\n'); - } - } - } - - // look for local ladders - loadLocalLadders(); - - DEBUG_LOG(("After looking for ladders, we have %d local, %d special && %d normal", m_localLadders.size(), m_specialLadders.size(), m_standardLadders.size())); -} - -LadderList::~LadderList() -{ - LadderInfoList::iterator it; - for (it = m_specialLadders.begin(); it != m_specialLadders.end(); it = m_specialLadders.begin()) - { - delete *it; - m_specialLadders.pop_front(); - } - for (it = m_standardLadders.begin(); it != m_standardLadders.end(); it = m_standardLadders.begin()) - { - delete *it; - m_standardLadders.pop_front(); - } - for (it = m_localLadders.begin(); it != m_localLadders.end(); it = m_localLadders.begin()) - { - delete *it; - m_localLadders.pop_front(); - } -} - -const LadderInfo* LadderList::findLadder( const AsciiString& addr, UnsignedShort port ) -{ - LadderInfoList::const_iterator cit; - - for (cit = m_specialLadders.begin(); cit != m_specialLadders.end(); ++cit) - { - const LadderInfo *li = *cit; - if (li->address == addr && li->port == port) - { - return li; - } - } - - for (cit = m_standardLadders.begin(); cit != m_standardLadders.end(); ++cit) - { - const LadderInfo *li = *cit; - if (li->address == addr && li->port == port) - { - return li; - } - } - - for (cit = m_localLadders.begin(); cit != m_localLadders.end(); ++cit) - { - const LadderInfo *li = *cit; - if (li->address == addr && li->port == port) - { - return li; - } - } - - return NULL; -} - -const LadderInfo* LadderList::findLadderByIndex( Int index ) -{ - if (index == 0) - return NULL; - - LadderInfoList::const_iterator cit; - - for (cit = m_specialLadders.begin(); cit != m_specialLadders.end(); ++cit) - { - const LadderInfo *li = *cit; - if (li->index == index) - { - return li; - } - } - - for (cit = m_standardLadders.begin(); cit != m_standardLadders.end(); ++cit) - { - const LadderInfo *li = *cit; - if (li->index == index) - { - return li; - } - } - - for (cit = m_localLadders.begin(); cit != m_localLadders.end(); ++cit) - { - const LadderInfo *li = *cit; - if (li->index == index) - { - return li; - } - } - - return NULL; -} - -const LadderInfoList* LadderList::getSpecialLadders( void ) -{ - return &m_specialLadders; -} - -const LadderInfoList* LadderList::getStandardLadders( void ) -{ - return &m_standardLadders; -} - -const LadderInfoList* LadderList::getLocalLadders( void ) -{ - return &m_localLadders; -} - -void LadderList::loadLocalLadders( void ) -{ - AsciiString dirname; - dirname.format("%sGeneralsOnline\\Ladders\\", TheGlobalData->getPath_UserData().str()); - FilenameList filenameList; - TheFileSystem->getFileListInDirectory(dirname, AsciiString("*.ini"), filenameList, TRUE); - - Int index = -1; - - FilenameList::iterator it = filenameList.begin(); - while (it != filenameList.end()) - { - AsciiString filename = *it; - DEBUG_LOG(("Looking at possible ladder info file '%s'", filename.str())); - filename.toLower(); - checkLadder( filename, index-- ); - ++it; - } -} - -void LadderList::checkLadder( AsciiString fname, Int index ) -{ - File *fp = TheFileSystem->openFile(fname.str(), File::READ | File::TEXT); - char buf[1024]; - AsciiString rawData; - if (fp) - { - Int len; - while (!fp->eof()) - { - len = fp->read(buf, 1023); - buf[len] = 0; - buf[1023] = 0; - rawData.concat(buf); - } - fp->close(); - fp = NULL; - } - - DEBUG_LOG(("Read %d bytes from '%s'", rawData.getLength(), fname.str())); - if (rawData.isEmpty()) - return; - - LadderInfo *li = parseLadder(rawData); - if (!li) - { - return; - } - - // sanity check - if (li->address.isEmpty()) - { - DEBUG_LOG(("Bailing because of li->address.isEmpty()")); - delete li; - return; - } - - if (!li->port) - { - DEBUG_LOG(("Bailing because of !li->port")); - delete li; - return; - } - - if (li->validMaps.size() == 0) - { - DEBUG_LOG(("Bailing because of li->validMaps.size() == 0")); - delete li; - return; - } - - li->index = index; - - // ladders are QM-only at this point, which kinda invalidates the whole concept of local ladders. Oh well. - li->validQM = FALSE; // no local ladders in QM - li->validCustom = FALSE; - - //for (Int i=0; i<4; ++i) - // fname.removeLastChar(); // remove .lad - //li->name = UnicodeString(MultiByteToWideCharSingleLine(fname.reverseFind('\\')+1).c_str()); - - DEBUG_LOG(("Adding local ladder %ls", li->name.str())); - m_localLadders.push_back(li); -} diff --git a/Generals/Code/GameEngine/Source/GameNetwork/GameSpy/LobbyUtils.cpp b/Generals/Code/GameEngine/Source/GameNetwork/GameSpy/LobbyUtils.cpp deleted file mode 100644 index 6c11a86cd4..0000000000 --- a/Generals/Code/GameEngine/Source/GameNetwork/GameSpy/LobbyUtils.cpp +++ /dev/null @@ -1,939 +0,0 @@ -/* -** 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. // -// // -//////////////////////////////////////////////////////////////////////////////// - -/////////////////////////////////////////////////////////////////////////////////////// -// FILE: LobbyUtils.cpp -// Author: Matthew D. Campbell, Sept 2002 -// Description: GameSpy lobby utils -/////////////////////////////////////////////////////////////////////////////////////// - -// INCLUDES /////////////////////////////////////////////////////////////////////////////////////// -#include "PreRTS.h" // This must go first in EVERY cpp file in the GameEngine - -#include "Common/GameEngine.h" -#include "Common/MultiplayerSettings.h" -#include "Common/PlayerTemplate.h" -#include "Common/version.h" -#include "GameClient/AnimateWindowManager.h" -#include "GameClient/WindowLayout.h" -#include "GameClient/Gadget.h" -#include "GameClient/Image.h" -#include "GameClient/Shell.h" -#include "GameClient/KeyDefs.h" -#include "GameClient/GameWindowManager.h" -#include "GameClient/GadgetComboBox.h" -#include "GameClient/GadgetListBox.h" -#include "GameClient/GadgetTextEntry.h" -#include "GameClient/GameText.h" -#include "GameClient/MapUtil.h" -#include "GameClient/MessageBox.h" -#include "GameClient/Mouse.h" -#include "GameNetwork/GameSpyOverlay.h" - -#include "GameClient/LanguageFilter.h" -#include "GameNetwork/GameSpy/BuddyDefs.h" -#include "GameNetwork/GameSpy/LadderDefs.h" -#include "GameNetwork/GameSpy/LobbyUtils.h" -#include "GameNetwork/GameSpy/PeerDefs.h" -#include "GameNetwork/GameSpy/PeerThread.h" -#include "GameNetwork/GameSpy/PersistentStorageDefs.h" -#include "GameNetwork/GameSpy/GSConfig.h" - -#include "Common/STLTypedefs.h" - - -// PRIVATE DATA /////////////////////////////////////////////////////////////////////////////////// -// Note: if you add more columns, you must modify the .wnd files and change the listbox properties (yuck!) -enum { - COLUMN_NAME = 0, - COLUMN_MAP, - COLUMN_LADDER, - COLUMN_NUMPLAYERS, - COLUMN_PASSWORD, - COLUMN_OBSERVER, -#if !RTS_GENERALS - COLUMN_USE_STATS, -#endif - COLUMN_PING, -}; - -static NameKeyType buttonSortAlphaID = NAMEKEY_INVALID; -static NameKeyType buttonSortPingID = NAMEKEY_INVALID; -static NameKeyType buttonSortBuddiesID = NAMEKEY_INVALID; -static NameKeyType windowSortAlphaID = NAMEKEY_INVALID; -static NameKeyType windowSortPingID = NAMEKEY_INVALID; -static NameKeyType windowSortBuddiesID = NAMEKEY_INVALID; - -static GameWindow *buttonSortAlpha = NULL; -static GameWindow *buttonSortPing = NULL; -static GameWindow *buttonSortBuddies = NULL; -static GameWindow *windowSortAlpha = NULL; -static GameWindow *windowSortPing = NULL; -static GameWindow *windowSortBuddies = NULL; - -static GameSortType theGameSortType = GAMESORT_ALPHA_ASCENDING; -static Bool sortBuddies = TRUE; -static void showSortIcons(void) -{ - if (windowSortAlpha && windowSortPing) - { - switch(theGameSortType) - { - case GAMESORT_ALPHA_ASCENDING: - windowSortAlpha->winHide(FALSE); - windowSortAlpha->winEnable(TRUE); - windowSortPing->winHide(TRUE); - break; - case GAMESORT_ALPHA_DESCENDING: - windowSortAlpha->winHide(FALSE); - windowSortAlpha->winEnable(FALSE); - windowSortPing->winHide(TRUE); - break; - case GAMESORT_PING_ASCENDING: - windowSortPing->winHide(FALSE); - windowSortPing->winEnable(TRUE); - windowSortAlpha->winHide(TRUE); - break; - case GAMESORT_PING_DESCENDING: - windowSortPing->winHide(FALSE); - windowSortPing->winEnable(FALSE); - windowSortAlpha->winHide(TRUE); - break; - } - } - - if (sortBuddies) - { - if (windowSortBuddies) - { - windowSortBuddies->winHide(FALSE); - } - } - else - { - if (windowSortBuddies) - { - windowSortBuddies->winHide(TRUE); - } - } -} -void setSortMode( GameSortType sortType ) { theGameSortType = sortType; showSortIcons(); RefreshGameListBoxes(); } -void sortByBuddies( Bool doSort ) { sortBuddies = doSort; showSortIcons(); RefreshGameListBoxes(); } - -Bool HandleSortButton( NameKeyType sortButton ) -{ - if (sortButton == buttonSortBuddiesID) - { - sortByBuddies( !sortBuddies ); - return TRUE; - } - else if (sortButton == buttonSortAlphaID) - { - if (theGameSortType == GAMESORT_ALPHA_ASCENDING) - { - setSortMode(GAMESORT_ALPHA_DESCENDING); - } - else - { - setSortMode(GAMESORT_ALPHA_ASCENDING); - } - return TRUE; - } - else if (sortButton == buttonSortPingID) - { - if (theGameSortType == GAMESORT_PING_ASCENDING) - { - setSortMode(GAMESORT_PING_DESCENDING); - } - else - { - setSortMode(GAMESORT_PING_ASCENDING); - } - return TRUE; - } - return FALSE; -} - -// window ids ------------------------------------------------------------------------------ -static NameKeyType parentID = NAMEKEY_INVALID; -//static NameKeyType parentGameListSmallID = NAMEKEY_INVALID; -static NameKeyType parentGameListLargeID = NAMEKEY_INVALID; -static NameKeyType listboxLobbyGamesSmallID = NAMEKEY_INVALID; -static NameKeyType listboxLobbyGamesLargeID = NAMEKEY_INVALID; -//static NameKeyType listboxLobbyGameInfoID = NAMEKEY_INVALID; - -// Window Pointers ------------------------------------------------------------------------ -static GameWindow *parent = NULL; -//static GameWindow *parentGameListSmall = NULL; -static GameWindow *parentGameListLarge = NULL; - //GameWindow *listboxLobbyGamesSmall = NULL; - GameWindow *listboxLobbyGamesLarge = NULL; - //GameWindow *listboxLobbyGameInfo = NULL; - -static const Image *pingImages[3] = { NULL, NULL, NULL }; - -static void gameTooltip(GameWindow *window, - WinInstanceData *instData, - UnsignedInt mouse) -{ - Int x, y, row, col; - x = LOLONGTOSHORT(mouse); - y = HILONGTOSHORT(mouse); - - GadgetListBoxGetEntryBasedOnXY(window, x, y, row, col); - - if (row == -1 || col == -1) - { - TheMouse->setCursorTooltip( UnicodeString::TheEmptyString);//TheGameText->fetch("TOOLTIP:GamesBeingFormed") ); - return; - } - - Int gameID = (Int)GadgetListBoxGetItemData(window, row, 0); - GameSpyStagingRoom *room = TheGameSpyInfo->findStagingRoomByID(gameID); - if (!room) - { - TheMouse->setCursorTooltip( TheGameText->fetch("TOOLTIP:UnknownGame") ); - return; - } - - if (col == COLUMN_PING) - { -#if 0 //def DEBUG_LOGGING - UnicodeString s; - s.format(L"Ping is %d ms (cutoffs are %d ms and %d ms\n%hs local pings\n%hs remote pings", - room->getPingAsInt(), TheGameSpyConfig->getPingCutoffGood(), TheGameSpyConfig->getPingCutoffBad(), - TheGameSpyInfo->getPingString().str(), room->getPingString().str() - ); - TheMouse->setCursorTooltip( s, 10, NULL, 2.0f ); // the text and width are the only params used. the others are the default values. -#else - TheMouse->setCursorTooltip( TheGameText->fetch("TOOLTIP:PingInfo"), 10, NULL, 2.0f ); // the text and width are the only params used. the others are the default values. -#endif - return; - } - if (col == COLUMN_NUMPLAYERS) - { - TheMouse->setCursorTooltip( TheGameText->fetch("TOOLTIP:NumberOfPlayers"), 10, NULL, 2.0f ); // the text and width are the only params used. the others are the default values. - return; - } - if (col == COLUMN_PASSWORD) - { - if (room->getHasPassword()) - { - UnicodeString checkTooltip =TheGameText->fetch("TOOTIP:Password"); - if(!checkTooltip.compare(L"Password required to joing game")) - checkTooltip.set(L"Password required to join game"); - TheMouse->setCursorTooltip( checkTooltip, 10, NULL, 2.0f ); // the text and width are the only params used. the others are the default values. - } - else - TheMouse->setCursorTooltip( UnicodeString::TheEmptyString ); - return; - } -#if !RTS_GENERALS - if (col == COLUMN_USE_STATS) - { - if ( room->getUseStats() ) - { - TheMouse->setCursorTooltip( TheGameText->fetch("TOOLTIP:UseStatsOn") ); - } - else - { - TheMouse->setCursorTooltip( TheGameText->fetch("TOOLTIP:UseStatsOff") ); - } - return; - } -#endif - - UnicodeString tooltip; - - UnicodeString mapName; - const MapMetaData *md = TheMapCache->findMap(room->getMap()); - if (md) - { - mapName = md->m_displayName; - } - else - { - const char *start = room->getMap().reverseFind('\\'); - if (start) - { - ++start; - } - else - { - start = room->getMap().str(); - } - mapName.translate( start ); - } - UnicodeString tmp; - tooltip.format(TheGameText->fetch("TOOLTIP:GameInfoGameName"), room->getGameName().str()); - if (room->getLadderPort() != 0) - { - const LadderInfo *linfo = TheLadderList->findLadder(room->getLadderIP(), room->getLadderPort()); - if (linfo) - { - tmp.format(TheGameText->fetch("TOOLTIP:GameInfoLadderName"), linfo->name.str()); - tooltip.concat(tmp); - } - } - if (room->getExeCRC() != TheGlobalData->m_exeCRC || room->getIniCRC() != TheGlobalData->m_iniCRC) - { - tmp.format(TheGameText->fetch("TOOLTIP:InvalidGameVersion"), mapName.str()); - tooltip.concat(tmp); - } - tmp.format(TheGameText->fetch("TOOLTIP:GameInfoMap"), mapName.str()); - tooltip.concat(tmp); - - AsciiString aPlayer; - UnicodeString player; - Int numPlayers = 0; - for (Int i=0; igetGameSpySlot(i); - if (i == 0 && (!slot || !slot->isHuman())) - { - DEBUG_CRASH(("About to tooltip a non-hosted game!")); - } - if (slot && slot->isHuman()) - { - tmp.format(TheGameText->fetch("TOOLTIP:GameInfoPlayer"), slot->getName().str(), slot->getWins(), slot->getLosses()); - tooltip.concat(tmp); - ++numPlayers; - } - else if (slot && slot->isAI()) - { - ++numPlayers; - switch(slot->getState()) - { - case SLOT_EASY_AI: - tooltip.concat(L'\n'); - tooltip.concat(TheGameText->fetch("GUI:EasyAI")); - break; - case SLOT_MED_AI: - tooltip.concat(L'\n'); - tooltip.concat(TheGameText->fetch("GUI:MediumAI")); - break; - case SLOT_BRUTAL_AI: - tooltip.concat(L'\n'); - tooltip.concat(TheGameText->fetch("GUI:HardAI")); - break; - } - } - } - DEBUG_ASSERTCRASH(numPlayers, ("Tooltipping a 0-player game!")); - - TheMouse->setCursorTooltip( tooltip, 10, NULL, 2.0f ); // the text and width are the only params used. the others are the default values. -} - -static Bool isSmall = TRUE; - -GameWindow *GetGameListBox( void ) -{ - return listboxLobbyGamesLarge; -} - -GameWindow *GetGameInfoListBox( void ) -{ - return NULL; -} - -NameKeyType GetGameListBoxID( void ) -{ - return listboxLobbyGamesLargeID; -} - -NameKeyType GetGameInfoListBoxID( void ) -{ - return NAMEKEY_INVALID; -} - -void GrabWindowInfo( void ) -{ - isSmall = TRUE; - parentID = NAMEKEY( "WOLCustomLobby.wnd:WOLLobbyMenuParent" ); - parent = TheWindowManager->winGetWindowFromId(NULL, parentID); - - pingImages[0] = TheMappedImageCollection->findImageByName("Ping03"); - pingImages[1] = TheMappedImageCollection->findImageByName("Ping02"); - pingImages[2] = TheMappedImageCollection->findImageByName("Ping01"); - DEBUG_ASSERTCRASH(pingImages[0], ("Can't find ping image!")); - DEBUG_ASSERTCRASH(pingImages[1], ("Can't find ping image!")); - DEBUG_ASSERTCRASH(pingImages[2], ("Can't find ping image!")); - -// parentGameListSmallID = NAMEKEY( "WOLCustomLobby.wnd:ParentGameListSmall" ); -// parentGameListSmall = TheWindowManager->winGetWindowFromId(NULL, parentGameListSmallID); - - parentGameListLargeID = NAMEKEY( "WOLCustomLobby.wnd:ParentGameListLarge" ); - parentGameListLarge = TheWindowManager->winGetWindowFromId(NULL, parentGameListLargeID); - - listboxLobbyGamesSmallID = NAMEKEY( "WOLCustomLobby.wnd:ListboxGames" ); -// listboxLobbyGamesSmall = TheWindowManager->winGetWindowFromId(NULL, listboxLobbyGamesSmallID); -// listboxLobbyGamesSmall->winSetTooltipFunc(gameTooltip); - - listboxLobbyGamesLargeID = NAMEKEY( "WOLCustomLobby.wnd:ListboxGamesLarge" ); - listboxLobbyGamesLarge = TheWindowManager->winGetWindowFromId(NULL, listboxLobbyGamesLargeID); - listboxLobbyGamesLarge->winSetTooltipFunc(gameTooltip); -// -// listboxLobbyGameInfoID = NAMEKEY( "WOLCustomLobby.wnd:ListboxGameInfo" ); -// listboxLobbyGameInfo = TheWindowManager->winGetWindowFromId(NULL, listboxLobbyGameInfoID); - - buttonSortAlphaID = NAMEKEY("WOLCustomLobby.wnd:ButtonSortAlpha"); - buttonSortPingID = NAMEKEY("WOLCustomLobby.wnd:ButtonSortPing"); - buttonSortBuddiesID = NAMEKEY("WOLCustomLobby.wnd:ButtonSortBuddies"); - windowSortAlphaID = NAMEKEY("WOLCustomLobby.wnd:WindowSortAlpha"); - windowSortPingID = NAMEKEY("WOLCustomLobby.wnd:WindowSortPing"); - windowSortBuddiesID = NAMEKEY("WOLCustomLobby.wnd:WindowSortBuddies"); - - buttonSortAlpha = TheWindowManager->winGetWindowFromId(parent, buttonSortAlphaID); - buttonSortPing = TheWindowManager->winGetWindowFromId(parent, buttonSortPingID); - buttonSortBuddies = TheWindowManager->winGetWindowFromId(parent, buttonSortBuddiesID); - windowSortAlpha = TheWindowManager->winGetWindowFromId(parent, windowSortAlphaID); - windowSortPing = TheWindowManager->winGetWindowFromId(parent, windowSortPingID); - windowSortBuddies = TheWindowManager->winGetWindowFromId(parent, windowSortBuddiesID); - - showSortIcons(); -} - -void ReleaseWindowInfo( void ) -{ - isSmall = TRUE; - parent = NULL; -// parentGameListSmall = NULL; - parentGameListLarge = NULL; -// listboxLobbyGamesSmall = NULL; - listboxLobbyGamesLarge = NULL; -// listboxLobbyGameInfo = NULL; - - buttonSortAlpha = NULL; - buttonSortPing = NULL; - buttonSortBuddies = NULL; - windowSortAlpha = NULL; - windowSortPing = NULL; - windowSortBuddies = NULL; -} - -typedef std::set BuddyGameSet; -static BuddyGameSet *theBuddyGames = NULL; -static void populateBuddyGames(void) -{ - BuddyInfoMap *m = TheGameSpyInfo->getBuddyMap(); - theBuddyGames = NEW BuddyGameSet; - if (!m) - { - return; - } - for (BuddyInfoMap::const_iterator bit = m->begin(); bit != m->end(); ++bit) - { - BuddyInfo info = bit->second; - if (info.m_status == GP_STAGING) - { - StagingRoomMap *srm = TheGameSpyInfo->getStagingRoomList(); - for (StagingRoomMap::iterator srmIt = srm->begin(); srmIt != srm->end(); ++srmIt) - { - GameSpyStagingRoom *game = srmIt->second; - game->cleanUpSlotPointers(); - const GameSpyGameSlot *slot = game->getGameSpySlot(0); - if (slot && slot->getName() == info.m_locationString) - { - theBuddyGames->insert(game); - break; - } - } - } - } -} - -static void clearBuddyGames(void) -{ - delete theBuddyGames; - theBuddyGames = NULL; -} - -struct GameSortStruct -{ - bool operator()(GameSpyStagingRoom *g1, GameSpyStagingRoom *g2) const - { - // sort CRC mismatches to the bottom - Bool g1Good = (g1->getExeCRC() != TheGlobalData->m_exeCRC || g1->getIniCRC() != TheGlobalData->m_iniCRC); - Bool g2Good = (g1->getExeCRC() != TheGlobalData->m_exeCRC || g1->getIniCRC() != TheGlobalData->m_iniCRC); - if ( g1Good ^ g2Good ) - { - return g1Good; - } - - // sort games with private ladders to the bottom - Bool g1UnknownLadder = (g1->getLadderPort() && TheLadderList->findLadder(g1->getLadderIP(), g1->getLadderPort()) == NULL); - Bool g2UnknownLadder = (g2->getLadderPort() && TheLadderList->findLadder(g2->getLadderIP(), g2->getLadderPort()) == NULL); - if ( g1UnknownLadder ^ g2UnknownLadder ) - { - return g2UnknownLadder; - } - - // sort full games to the bottom - Bool g1Full = (g1->getNumNonObserverPlayers() == g1->getMaxPlayers() || g1->getNumPlayers() == MAX_SLOTS); - Bool g2Full = (g2->getNumNonObserverPlayers() == g2->getMaxPlayers() || g2->getNumPlayers() == MAX_SLOTS); - if ( g1Full ^ g2Full ) - { - return g2Full; - } - - if (sortBuddies) - { - Bool g1HasBuddies = (theBuddyGames->find(g1) != theBuddyGames->end()); - Bool g2HasBuddies = (theBuddyGames->find(g2) != theBuddyGames->end()); - if ( g1HasBuddies ^ g2HasBuddies ) - { - return g1HasBuddies; - } - } - - switch(theGameSortType) - { - case GAMESORT_ALPHA_ASCENDING: - return wcsicmp(g1->getGameName().str(), g2->getGameName().str()) < 0; - break; - case GAMESORT_ALPHA_DESCENDING: - return wcsicmp(g1->getGameName().str(),g2->getGameName().str()) > 0; - break; - case GAMESORT_PING_ASCENDING: - return g1->getPingAsInt() < g2->getPingAsInt(); - break; - case GAMESORT_PING_DESCENDING: - return g1->getPingAsInt() > g2->getPingAsInt(); - break; - } - return false; - } -}; - -static Int insertGame( GameWindow *win, GameSpyStagingRoom *game, Bool showMap ) -{ - game->cleanUpSlotPointers(); - Color gameColor = GameSpyColor[GSCOLOR_GAME]; - if (game->getNumNonObserverPlayers() == game->getMaxPlayers() || game->getNumPlayers() == MAX_SLOTS) - { - gameColor = GameSpyColor[GSCOLOR_GAME_FULL]; - } - if (game->getExeCRC() != TheGlobalData->m_exeCRC || game->getIniCRC() != TheGlobalData->m_iniCRC) - { - gameColor = GameSpyColor[GSCOLOR_GAME_CRCMISMATCH]; - } - UnicodeString gameName = game->getGameName(); - - if(TheGameSpyInfo->getDisallowAsianText()) - { - const WideChar *buff = gameName.str(); - Int length = gameName.getLength(); - for(Int i = 0; i < length; ++i) - { - if(buff[i] >= 256) - return -1; - } - } - else if(TheGameSpyInfo->getDisallowNonAsianText()) - { - const WideChar *buff = gameName.str(); - Int length = gameName.getLength(); - Bool hasUnicode = FALSE; - for(Int i = 0; i < length; ++i) - { - if(buff[i] >= 256) - { - hasUnicode = TRUE; - break; - } - } - if(!hasUnicode) - return -1; - } - - - - Int index = GadgetListBoxAddEntryText(win, game->getGameName(), gameColor, -1, COLUMN_NAME); - GadgetListBoxSetItemData(win, (void *)game->getID(), index); - - UnicodeString s; - - if (showMap) - { - UnicodeString mapName; - const MapMetaData *md = TheMapCache->findMap(game->getMap()); - if (md) - { - mapName = md->m_displayName; - } - else - { - const char *start = game->getMap().reverseFind('\\'); - if (start) - { - ++start; - } - else - { - start = game->getMap().str(); - } - mapName.translate( start ); - } - GadgetListBoxAddEntryText(win, mapName, gameColor, index, COLUMN_MAP); - - const LadderInfo * li = TheLadderList->findLadder(game->getLadderIP(), game->getLadderPort()); - if (li) - { - GadgetListBoxAddEntryText(win, li->name, gameColor, index, COLUMN_LADDER); - } - else if (game->getLadderPort()) - { - GadgetListBoxAddEntryText(win, TheGameText->fetch("GUI:UnknownLadder"), gameColor, index, COLUMN_LADDER); - } - else - { - GadgetListBoxAddEntryText(win, TheGameText->fetch("GUI:NoLadder"), gameColor, index, COLUMN_LADDER); - } - } - else - { - GadgetListBoxAddEntryText(win, UnicodeString(L" "), gameColor, index, COLUMN_MAP); - GadgetListBoxAddEntryText(win, UnicodeString(L" "), gameColor, index, COLUMN_LADDER); - } - - s.format(L"%d/%d", game->getReportedNumPlayers(), game->getReportedMaxPlayers()); - GadgetListBoxAddEntryText(win, s, gameColor, index, COLUMN_NUMPLAYERS); - - if (game->getHasPassword()) - { - const Image *img = TheMappedImageCollection->findImageByName("Password"); - Int width = 10, height = 10; - if (img) - { - width = img->getImageWidth(); - height = img->getImageHeight(); - } - GadgetListBoxAddEntryImage(win, img, index, COLUMN_PASSWORD, width, height); - } - else - { - GadgetListBoxAddEntryText(win, UnicodeString(L" "), gameColor, index, COLUMN_PASSWORD); - } - - if (game->getAllowObservers()) - { - const Image *img = TheMappedImageCollection->findImageByName("Observer"); - GadgetListBoxAddEntryImage(win, img, index, COLUMN_OBSERVER); - } - else - { - GadgetListBoxAddEntryText(win, UnicodeString(L" "), gameColor, index, COLUMN_OBSERVER); - } - -#if !RTS_GENERALS - { - if (game->getUseStats()) - { - if (const Image *img = TheMappedImageCollection->findImageByName("GoodStatsIcon")) - { - GadgetListBoxAddEntryImage(win, img, index, COLUMN_USE_STATS, img->getImageHeight(), img->getImageWidth()); - } - } - } -#endif - - s.format(L"%d", game->getPingAsInt()); - GadgetListBoxAddEntryText(win, s, gameColor, index, COLUMN_PING); - Int ping = game->getPingAsInt(); - Int width = 10, height = 10; - if (pingImages[0]) - { - width = pingImages[0]->getImageWidth(); - height = pingImages[0]->getImageHeight(); - } - // CLH picking an arbitrary number for our ping display - if (ping < TheGameSpyConfig->getPingCutoffGood()) - { - GadgetListBoxAddEntryImage(win, pingImages[0], index, COLUMN_PING, width, height); - } - else if (ping < TheGameSpyConfig->getPingCutoffBad()) - { - GadgetListBoxAddEntryImage(win, pingImages[1], index, COLUMN_PING, width, height); - } - else - { - GadgetListBoxAddEntryImage(win, pingImages[2], index, COLUMN_PING, width, height); - } - - return index; -} - -void RefreshGameListBox( GameWindow *win, Bool showMap ) -{ - if (!win) - return; - - // save off selection - Int selectedIndex = -1; - Int indexToSelect = -1; - Int selectedID = 0; - GadgetListBoxGetSelected(win, &selectedIndex); - if (selectedIndex != -1 ) - { - selectedID = (Int)GadgetListBoxGetItemData(win, selectedIndex); - } - int prevPos = GadgetListBoxGetTopVisibleEntry( win ); - - // empty listbox - GadgetListBoxReset(win); - - // sort our games - typedef std::multiset SortedGameList; - SortedGameList sgl; - StagingRoomMap *srm = TheGameSpyInfo->getStagingRoomList(); - populateBuddyGames(); - for (StagingRoomMap::iterator srmIt = srm->begin(); srmIt != srm->end(); ++srmIt) - { - sgl.insert(srmIt->second); - } - - // populate listbox - for (SortedGameList::iterator sglIt = sgl.begin(); sglIt != sgl.end(); ++sglIt) - { - GameSpyStagingRoom *game = *sglIt; - if (game) - { - Int index = insertGame(win, game, showMap); - if (game->getID() == selectedID) - { - indexToSelect = index; - } - } - } - - clearBuddyGames(); - - // restore selection - GadgetListBoxSetSelected(win, indexToSelect); // even for -1, so we can disable the 'Join Game' button -// if(prevPos > 10) - GadgetListBoxSetTopVisibleEntry( win, prevPos );//+ 1 - - if (indexToSelect < 0 && selectedID) - { - TheWindowManager->winSetLoneWindow(NULL); - } -} - -void RefreshGameInfoListBox( GameWindow *mainWin, GameWindow *win ) -{ -// if (!mainWin || !win) -// return; -// -// GadgetListBoxReset(win); -// -// Int selected = -1; -// GadgetListBoxGetSelected(mainWin, &selected); -// if (selected < 0) -// { -// return; -// } -// -// Int selectedID = (Int)GadgetListBoxGetItemData(mainWin, selected); -// if (selectedID < 0) -// { -// return; -// } -// -// StagingRoomMap *srm = TheGameSpyInfo->getStagingRoomList(); -// StagingRoomMap::iterator srmIt = srm->find(selectedID); -// if (srmIt != srm->end()) -// { -// GameSpyStagingRoom *theRoom = srmIt->second; -// theRoom->cleanUpSlotPointers(); -// -// // game name -//// GadgetListBoxAddEntryText(listboxLobbyGameInfo, theRoom->getGameName(), GameSpyColor[GSCOLOR_DEFAULT], -1); -// -// const LadderInfo * li = TheLadderList->findLadder(theRoom->getLadderIP(), theRoom->getLadderPort()); -// if (li) -// { -// UnicodeString tmp; -// tmp.format(TheGameText->fetch("TOOLTIP:LadderName"), li->name.str()); -// GadgetListBoxAddEntryText(listboxLobbyGameInfo, tmp, GameSpyColor[GSCOLOR_DEFAULT], -1); -// } -// else if (theRoom->getLadderPort()) -// { -// GadgetListBoxAddEntryText(listboxLobbyGameInfo, TheGameText->fetch("TOOLTIP:UnknownLadder"), GameSpyColor[GSCOLOR_DEFAULT], -1); -// } -// else -// { -// GadgetListBoxAddEntryText(listboxLobbyGameInfo, TheGameText->fetch("TOOLTIP:NoLadder"), GameSpyColor[GSCOLOR_DEFAULT], -1); -// } -// -// if (theRoom->getExeCRC() != TheGlobalData->m_exeCRC || theRoom->getIniCRC() != TheGlobalData->m_iniCRC) -// { -// GadgetListBoxAddEntryText(listboxLobbyGameInfo, TheGameText->fetch("TOOLTIP:InvalidGameVersionSingleLine"), GameSpyColor[GSCOLOR_DEFAULT], -1); -// } -// -// // map name -// UnicodeString mapName; -// const MapMetaData *md = TheMapCache->findMap(theRoom->getMap()); -// if (md) -// { -// mapName = md->m_displayName; -// } -// else -// { -// const char *start = theRoom->getMap().reverseFind('\\'); -// if (start) -// { -// ++start; -// } -// else -// { -// start = theRoom->getMap().str(); -// } -// mapName.translate( start ); -// } -// -// GadgetListBoxAddEntryText(listboxLobbyGameInfo, mapName, GameSpyColor[GSCOLOR_DEFAULT], -1); -// -// // player list (rank, win/loss, side) -// for (Int i=0; igetGameSpySlot(i); -// if (slot && slot->isHuman()) -// { -// UnicodeString theName, theRating, thePlayerTemplate; -// Int colorIdx = slot->getColor(); -// theName = slot->getName(); -// theRating.format(L" (%d-%d)", slot->getWins(), slot->getLosses()); -// const PlayerTemplate * pt = ThePlayerTemplateStore->getNthPlayerTemplate(slot->getPlayerTemplate()); -// if (pt) -// { -// thePlayerTemplate = pt->getDisplayName(); -// } -// else -// { -// thePlayerTemplate = TheGameText->fetch("GUI:Random"); -// } -// -// UnicodeString theText; -// theText.format(L"%ls - %ls - %ls", theName.str(), thePlayerTemplate.str(), theRating.str()); -// -// Int theColor = GameSpyColor[GSCOLOR_DEFAULT]; -// const MultiplayerColorDefinition *mcd = TheMultiplayerSettings->getColor(colorIdx); -// if (mcd) -// { -// theColor = mcd->getColor(); -// } -// -// GadgetListBoxAddEntryText(listboxLobbyGameInfo, theText, theColor, -1); -// } -// } -// } - -} - -void RefreshGameListBoxes( void ) -{ - GameWindow *main = GetGameListBox(); - GameWindow *info = GetGameInfoListBox(); - - RefreshGameListBox( main, (info == NULL) ); - - if (info) - { - RefreshGameInfoListBox( main, info ); - } -} - -void ToggleGameListType( void ) -{ - isSmall = !isSmall; - if(isSmall) - { - parentGameListLarge->winHide(TRUE); -// parentGameListSmall->winHide(FALSE); - } - else - { - parentGameListLarge->winHide(FALSE); -// parentGameListSmall->winHide(TRUE); - } - - RefreshGameListBoxes(); -} - -// for use by GameWindow::winSetTooltipFunc -// displays the Army Tooltip for the player templates -void playerTemplateComboBoxTooltip(GameWindow *wndComboBox, WinInstanceData *instData, UnsignedInt mouse) -{ - Int index = 0; - GadgetComboBoxGetSelectedPos(wndComboBox, &index); - Int templateNum = (Int)GadgetComboBoxGetItemData(wndComboBox, index); - UnicodeString ustringTooltip; - if (templateNum == -1) - { - // the "Random" template is always first - ustringTooltip = TheGameText->fetch("TOOLTIP:BioStrategyLong_Random"); - } - else - { - const PlayerTemplate *playerTemplate = ThePlayerTemplateStore->getNthPlayerTemplate(templateNum); - if (playerTemplate) - { - ustringTooltip = TheGameText->fetch(playerTemplate->getTooltip()); - } - } - TheMouse->setCursorTooltip(ustringTooltip); -} - -// ----------------------------------------------------------------------------- - -// for use by GameWindow::winSetTooltipFunc -// displays the Army Tooltip for the player templates -void playerTemplateListBoxTooltip(GameWindow *wndListBox, WinInstanceData *instData, UnsignedInt mouse) -{ - Int x, y, row, col; - x = LOLONGTOSHORT(mouse); - y = HILONGTOSHORT(mouse); - GadgetListBoxGetEntryBasedOnXY(wndListBox, x, y, row, col); - if (row == -1 || col == -1) - return; - - Int templateNum = (Int)GadgetListBoxGetItemData(wndListBox, row, col); - UnicodeString ustringTooltip; - if (templateNum == -1) - { - // the "Random" template is always first - ustringTooltip = TheGameText->fetch("TOOLTIP:BioStrategyLong_Random"); - } - else - { - const PlayerTemplate *playerTemplate = ThePlayerTemplateStore->getNthPlayerTemplate(templateNum); - if (playerTemplate) - { - ustringTooltip = TheGameText->fetch(playerTemplate->getTooltip()); - } - } - - // use no tooltip delay here - TheMouse->setCursorTooltip(ustringTooltip, 0); -} diff --git a/Generals/Code/GameEngine/Source/GameNetwork/GameSpy/MainMenuUtils.cpp b/Generals/Code/GameEngine/Source/GameNetwork/GameSpy/MainMenuUtils.cpp deleted file mode 100644 index e3db2cc3b1..0000000000 --- a/Generals/Code/GameEngine/Source/GameNetwork/GameSpy/MainMenuUtils.cpp +++ /dev/null @@ -1,885 +0,0 @@ -/* -** 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. // -// // -//////////////////////////////////////////////////////////////////////////////// - -/////////////////////////////////////////////////////////////////////////////////////// -// FILE: MainMenuUtils.cpp -// Author: Matthew D. Campbell, Sept 2002 -// Description: GameSpy version check, patch download, etc utils -/////////////////////////////////////////////////////////////////////////////////////// - -// INCLUDES /////////////////////////////////////////////////////////////////////////// -#include "PreRTS.h" // This must go first in EVERY cpp file in the GameEngine - -#include - -//#include "Common/Registry.h" -#include "Common/UserPreferences.h" -#include "Common/version.h" -#include "GameClient/GameText.h" -#include "GameClient/MessageBox.h" -#include "GameClient/Shell.h" -#include "GameLogic/ScriptEngine.h" - -#include "GameClient/ShellHooks.h" - -#include "gamespy/ghttp/ghttp.h" - -#include "GameNetwork/DownloadManager.h" -#include "GameNetwork/GameSpy/BuddyThread.h" -#include "GameNetwork/GameSpy/MainMenuUtils.h" -#include "GameNetwork/GameSpy/PeerDefs.h" -#include "GameNetwork/GameSpy/PeerThread.h" - -#include "WWDownload/Registry.h" -#include "WWDownload/urlBuilder.h" - - -/////////////////////////////////////////////////////////////////////////////////////// - -static Bool checkingForPatchBeforeGameSpy = FALSE; -static Int checksLeftBeforeOnline = 0; -static Int timeThroughOnline = 0; // used to avoid having old callbacks cause problems -static Bool mustDownloadPatch = FALSE; -static Bool cantConnectBeforeOnline = FALSE; -static std::list queuedDownloads; - -static char *MOTDBuffer = NULL; -static char *configBuffer = NULL; -GameWindow *onlineCancelWindow = NULL; - -static Bool s_asyncDNSThreadDone = TRUE; -static Bool s_asyncDNSThreadSucceeded = FALSE; -static Bool s_asyncDNSLookupInProgress = FALSE; -static HANDLE s_asyncDNSThreadHandle = NULL; -enum { - LOOKUP_INPROGRESS, - LOOKUP_FAILED, - LOOKUP_SUCCEEDED, -}; - -/////////////////////////////////////////////////////////////////////////////////////// - -static void startOnline( void ); -static void reallyStartPatchCheck( void ); - -/////////////////////////////////////////////////////////////////////////////////////// - -// someone has hit a button allowing downloads to start -void StartDownloadingPatches( void ) -{ - if (queuedDownloads.empty()) - { - HandleCanceledDownload(); - return; - } - - WindowLayout *layout; - layout = TheWindowManager->winCreateLayout( AsciiString( "Menus/DownloadMenu.wnd" ) ); - layout->runInit(); - layout->hide( FALSE ); - layout->bringForward(); - HandleCanceledDownload(FALSE); - DEBUG_ASSERTCRASH(TheDownloadManager, ("No download manager!")); - if (TheDownloadManager) - { - std::list::iterator it = queuedDownloads.begin(); - while (it != queuedDownloads.end()) - { - QueuedDownload q = *it; - TheDownloadManager->queueFileForDownload(q.server, q.userName, q.password, - q.file, q.localFile, q.regKey, q.tryResume); - queuedDownloads.pop_front(); - it = queuedDownloads.begin(); - } - TheDownloadManager->downloadNextQueuedFile(); - } -} - -/////////////////////////////////////////////////////////////////////////////////////// - -// user agrees to patch before going online -static void patchBeforeOnlineCallback( void ) -{ - StartDownloadingPatches(); -} - -// user doesn't want to patch before going online -static void noPatchBeforeOnlineCallback( void ) -{ - queuedDownloads.clear(); - if (mustDownloadPatch || cantConnectBeforeOnline) - { - // go back to normal - HandleCanceledDownload(); - } - else - { - // clear out unneeded downloads and go on - startOnline(); - } -} - -/////////////////////////////////////////////////////////////////////////////////////// - -static Bool hasWriteAccess() -{ - const char* filename = "PatchAccessTest.txt"; - - remove(filename); - - int handle = _open( filename, _O_CREAT | _O_RDWR, _S_IREAD | _S_IWRITE); - if (handle == -1) - { - return false; - } - - _close(handle); - remove(filename); - - unsigned int val; - if (!GetUnsignedIntFromRegistry("", "Version", val)) - { - return false; - } - - if (!SetUnsignedIntInRegistry("", "Version", val)) - { - return false; - } - - return true; -} - -/////////////////////////////////////////////////////////////////////////////////////// - -static void startOnline( void ) -{ - checkingForPatchBeforeGameSpy = FALSE; - - DEBUG_ASSERTCRASH(checksLeftBeforeOnline==0, ("starting online with pending callbacks")); - if (onlineCancelWindow) - { - TheWindowManager->winDestroy(onlineCancelWindow); - onlineCancelWindow = NULL; - } - - if (cantConnectBeforeOnline) - { - MessageBoxOk(TheGameText->fetch("GUI:CannotConnectToServservTitle"), - TheGameText->fetch("GUI:CannotConnectToServserv"), - noPatchBeforeOnlineCallback); - return; - } - if (queuedDownloads.size()) - { - if (!hasWriteAccess()) - { - MessageBoxOk(TheGameText->fetch("GUI:Error"), - TheGameText->fetch("GUI:MustHaveAdminRights"), - noPatchBeforeOnlineCallback); - } - else if (mustDownloadPatch) - { - MessageBoxOkCancel(TheGameText->fetch("GUI:PatchAvailable"), - TheGameText->fetch("GUI:MustPatchForOnline"), - patchBeforeOnlineCallback, noPatchBeforeOnlineCallback); - } - else - { - MessageBoxYesNo(TheGameText->fetch("GUI:PatchAvailable"), - TheGameText->fetch("GUI:CanPatchForOnline"), - patchBeforeOnlineCallback, noPatchBeforeOnlineCallback); - } - return; - } - - TheScriptEngine->signalUIInteract(TheShellHookNames[SHELL_SCRIPT_HOOK_MAIN_MENU_ONLINE_SELECTED]); - - DEBUG_ASSERTCRASH( !TheGameSpyBuddyMessageQueue, ("TheGameSpyBuddyMessageQueue exists!") ); - DEBUG_ASSERTCRASH( !TheGameSpyPeerMessageQueue, ("TheGameSpyPeerMessageQueue exists!") ); - DEBUG_ASSERTCRASH( !TheGameSpyInfo, ("TheGameSpyInfo exists!") ); - SetUpGameSpy(MOTDBuffer, configBuffer); - - delete[] MOTDBuffer; - MOTDBuffer = NULL; - - delete[] configBuffer; - configBuffer = NULL; - -#ifdef ALLOW_NON_PROFILED_LOGIN - UserPreferences pref; - pref.load("GameSpyLogin.ini"); - UserPreferences::const_iterator it = pref.find("useProfiles"); - if (it != pref.end() && it->second.compareNoCase("yes") == 0) -#endif // ALLOW_NON_PROFILED_LOGIN - TheShell->push( AsciiString("Menus/GameSpyLoginProfile.wnd") ); -#ifdef ALLOW_NON_PROFILED_LOGIN - else - TheShell->push( AsciiString("Menus/GameSpyLoginQuick.wnd") ); -#endif // ALLOW_NON_PROFILED_LOGIN -} - -/////////////////////////////////////////////////////////////////////////////////////// - -static void queuePatch(Bool mandatory, AsciiString downloadURL) -{ - QueuedDownload q; - Bool success = TRUE; - - AsciiString connectionType; - success &= downloadURL.nextToken(&connectionType, ":"); - - AsciiString server; - success &= downloadURL.nextToken(&server, ":/"); - - AsciiString user; - success &= downloadURL.nextToken(&user, ":@"); - - AsciiString pass; - success &= downloadURL.nextToken(&pass, "@/"); - - AsciiString filePath; - success &= downloadURL.nextToken(&filePath, ""); - - if (!success && user.isNotEmpty()) - { - // no user/pass combo - move the file into it's proper place - filePath = user; - user = ""; // LFeenanEA - Credentials removed as per Security requirements - pass = ""; - success = TRUE; - } - - AsciiString fileStr = filePath; - const char *s = filePath.reverseFind('/'); - if (s) - fileStr = s+1; - AsciiString fileName = "patches\\"; - fileName.concat(fileStr); - - DEBUG_LOG(("download URL split: %d [%s] [%s] [%s] [%s] [%s] [%s]", - success, connectionType.str(), server.str(), user.str(), pass.str(), - filePath.str(), fileName.str())); - - if (!success) - return; - - q.file = filePath; - q.localFile = fileName; - q.password = pass; - q.regKey = ""; - q.server = server; - q.tryResume = TRUE; - q.userName = user; - - std::list::iterator it = queuedDownloads.begin(); - while (it != queuedDownloads.end()) - { - if (it->localFile == q.localFile) - return; // don't add it if it exists already (because we can check multiple times) - ++it; - } - - queuedDownloads.push_back(q); -} - -/////////////////////////////////////////////////////////////////////////////////////// - -static GHTTPBool motdCallback( GHTTPRequest request, GHTTPResult result, - char * buffer, GHTTPByteCount bufferLen, void * param ) -{ - Int run = (Int)param; - if (run != timeThroughOnline) - { - DEBUG_CRASH(("Old callback being called!")); - return GHTTPTrue; - } - - delete[] MOTDBuffer; - MOTDBuffer = NEW char[bufferLen]; - memcpy(MOTDBuffer, buffer, bufferLen); - MOTDBuffer[bufferLen-1] = 0; - - --checksLeftBeforeOnline; - DEBUG_ASSERTCRASH(checksLeftBeforeOnline>=0, ("Too many callbacks")); - if (onlineCancelWindow && !checksLeftBeforeOnline) - { - TheWindowManager->winDestroy(onlineCancelWindow); - onlineCancelWindow = NULL; - } - - DEBUG_LOG(("------- Got MOTD before going online -------")); - DEBUG_LOG(("%s", (MOTDBuffer)?MOTDBuffer:"")); - DEBUG_LOG(("--------------------------------------------")); - - if (!checksLeftBeforeOnline) - startOnline(); - - return GHTTPTrue; -} - -/////////////////////////////////////////////////////////////////////////////////////// - -static GHTTPBool configCallback( GHTTPRequest request, GHTTPResult result, - char * buffer, GHTTPByteCount bufferLen, void * param ) -{ - Int run = (Int)param; - if (run != timeThroughOnline) - { - DEBUG_CRASH(("Old callback being called!")); - return GHTTPTrue; - } - - delete[] configBuffer; - configBuffer = NULL; - - if (result != GHTTPSuccess || bufferLen < 100) - { - if (!checkingForPatchBeforeGameSpy) - return GHTTPTrue; - --checksLeftBeforeOnline; - if (onlineCancelWindow && !checksLeftBeforeOnline) - { - TheWindowManager->winDestroy(onlineCancelWindow); - onlineCancelWindow = NULL; - } - cantConnectBeforeOnline = TRUE; - if (!checksLeftBeforeOnline) - { - startOnline(); - } - return GHTTPTrue; - } - - configBuffer = NEW char[bufferLen]; - memcpy(configBuffer, buffer, bufferLen); - configBuffer[bufferLen-1] = 0; - - AsciiString fname; - fname.format("%sGeneralsOnline\\Config.txt", TheGlobalData->getPath_UserData().str()); - FILE *fp = fopen(fname.str(), "wb"); - if (fp) - { - fwrite(configBuffer, bufferLen, 1, fp); - fclose(fp); - } - - --checksLeftBeforeOnline; - DEBUG_ASSERTCRASH(checksLeftBeforeOnline>=0, ("Too many callbacks")); - if (onlineCancelWindow && !checksLeftBeforeOnline) - { - TheWindowManager->winDestroy(onlineCancelWindow); - onlineCancelWindow = NULL; - } - - DEBUG_LOG(("Got Config before going online")); - - if (!checksLeftBeforeOnline) - startOnline(); - - return GHTTPTrue; -} - -/////////////////////////////////////////////////////////////////////////////////////// - -static GHTTPBool configHeadCallback( GHTTPRequest request, GHTTPResult result, - char * buffer, GHTTPByteCount bufferLen, void * param ) -{ - Int run = (Int)param; - if (run != timeThroughOnline) - { - DEBUG_CRASH(("Old callback being called!")); - return GHTTPTrue; - } - - DEBUG_LOG(("HTTP head resp: res=%d, len=%d, buf=[%s]", result, bufferLen, buffer)); - - if (result == GHTTPSuccess) - { - DEBUG_LOG(("Headers are [%s]", ghttpGetHeaders( request ))); - - AsciiString headers(ghttpGetHeaders( request )); - AsciiString line; - while (headers.nextToken(&line, "\n\r")) - { - AsciiString key, val; - line.nextToken(&key, ": "); - line.nextToken(&val, ": \r\n"); - - if (key.compare("Content-Length") == 0 && val.isNotEmpty()) - { - Int serverLen = atoi(val.str()); - Int fileLen = 0; - AsciiString fname; - fname.format("%sGeneralsOnline\\Config.txt", TheGlobalData->getPath_UserData().str()); - FILE *fp = fopen(fname.str(), "rb"); - if (fp) - { - fseek(fp, 0, SEEK_END); - fileLen = ftell(fp); - fclose(fp); - } - - if (serverLen == fileLen) - { - // we don't need to download the MOTD again - --checksLeftBeforeOnline; - DEBUG_ASSERTCRASH(checksLeftBeforeOnline>=0, ("Too many callbacks")); - if (onlineCancelWindow && !checksLeftBeforeOnline) - { - TheWindowManager->winDestroy(onlineCancelWindow); - onlineCancelWindow = NULL; - } - - delete[] configBuffer; - configBuffer = NULL; - - AsciiString fname; - fname.format("%sGeneralsOnline\\Config.txt", TheGlobalData->getPath_UserData().str()); - FILE *fp = fopen(fname.str(), "rb"); - if (fp) - { - configBuffer = NEW char[fileLen]; - fread(configBuffer, fileLen, 1, fp); - configBuffer[fileLen-1] = 0; - fclose(fp); - - DEBUG_LOG(("Got Config before going online")); - - if (!checksLeftBeforeOnline) - startOnline(); - - return GHTTPTrue; - } - } - } - } - } - - // we need to download the MOTD again - std::string gameURL, mapURL; - std::string configURL, motdURL; - FormatURLFromRegistry(gameURL, mapURL, configURL, motdURL); - ghttpGet( configURL.c_str(), GHTTPFalse, configCallback, param ); - - return GHTTPTrue; -} - -/////////////////////////////////////////////////////////////////////////////////////// - -static GHTTPBool gamePatchCheckCallback( GHTTPRequest request, GHTTPResult result, char * buffer, GHTTPByteCount bufferLen, void * param ) -{ - Int run = (Int)param; - if (run != timeThroughOnline) - { - DEBUG_CRASH(("Old callback being called!")); - return GHTTPTrue; - } - - --checksLeftBeforeOnline; - DEBUG_ASSERTCRASH(checksLeftBeforeOnline>=0, ("Too many callbacks")); - - DEBUG_LOG(("Result=%d, buffer=[%s], len=%d", result, buffer, bufferLen)); - if (result != GHTTPSuccess) - { - if (!checkingForPatchBeforeGameSpy) - return GHTTPTrue; - cantConnectBeforeOnline = TRUE; - if (!checksLeftBeforeOnline) - { - startOnline(); - } - return GHTTPTrue; - } - - AsciiString message = buffer; - AsciiString line; - while (message.nextToken(&line, "\r\n")) - { - AsciiString type, req, url; - Bool ok = TRUE; - ok &= line.nextToken(&type, " "); - ok &= line.nextToken(&req, " "); - ok &= line.nextToken(&url, " "); - if (ok && type == "patch") - { - DEBUG_LOG(("Saw a patch: %d/[%s]", atoi(req.str()), url.str())); - queuePatch( atoi(req.str()), url ); - if (atoi(req.str())) - { - mustDownloadPatch = TRUE; - } - } - else if (ok && type == "server") - { - } - } - - if (!checksLeftBeforeOnline) - { - startOnline(); - } - - return GHTTPTrue; -} - -/////////////////////////////////////////////////////////////////////////////////////// - -void CancelPatchCheckCallbackAndReopenDropdown( void ) -{ - HandleCanceledDownload(); - CancelPatchCheckCallback(); -} - -void CancelPatchCheckCallback( void ) -{ - s_asyncDNSLookupInProgress = FALSE; - HandleCanceledDownload(FALSE); // don't dropdown - checkingForPatchBeforeGameSpy = FALSE; - checksLeftBeforeOnline = 0; - if (onlineCancelWindow) - { - TheWindowManager->winDestroy(onlineCancelWindow); - onlineCancelWindow = NULL; - } - queuedDownloads.clear(); - - delete[] MOTDBuffer; - MOTDBuffer = NULL; - - delete[] configBuffer; - configBuffer = NULL; -} - -/////////////////////////////////////////////////////////////////////////////////////// - -static GHTTPBool overallStatsCallback( GHTTPRequest request, GHTTPResult result, char * buffer, GHTTPByteCount bufferLen, void * param ) -{ - DEBUG_LOG(("overallStatsCallback() - Result=%d, len=%d", result, bufferLen)); - if (result != GHTTPSuccess) - { - return GHTTPTrue; - } - -#if RTS_GENERALS - OverallStats USA, China, GLA; - AsciiString message = buffer; - - Int state = STATS_MAX; // STATS_MAX == none - AsciiString line; - OverallStats *stats = NULL; - while (message.nextToken(&line, "\n")) - { - line.trim(); - line.toLower(); - if (strstr(line.str(), "today")) - { - state = STATS_TODAY; - } - else if (strstr(line.str(), "yesterday")) - { - state = STATS_YESTERDAY; - } - else if (strstr(line.str(), "all time")) - { - state = STATS_ALLTIME; - } - else if (strstr(line.str(), "last week")) - { - state = STATS_LASTWEEK; - } - else if (state != STATS_MAX && strstr(line.str(), "usa")) - { - stats = &USA; - } - else if (state != STATS_MAX && strstr(line.str(), "china")) - { - stats = &China; - } - else if (state != STATS_MAX && strstr(line.str(), "gla")) - { - stats = &GLA; - } - - if (stats) - { - AsciiString totalLine, winsLine, lossesLine; - message.nextToken(&totalLine, "\n"); - message.nextToken(&winsLine, "\n"); - message.nextToken(&lossesLine, "\n"); - while (totalLine.isNotEmpty() && !isdigit(totalLine.getCharAt(0))) - { - totalLine = totalLine.str()+1; - } - while (winsLine.isNotEmpty() && !isdigit(winsLine.getCharAt(0))) - { - winsLine = winsLine.str()+1; - } - while (lossesLine.isNotEmpty() && !isdigit(lossesLine.getCharAt(0))) - { - lossesLine = lossesLine.str()+1; - } - if (totalLine.isNotEmpty() && winsLine.isNotEmpty() && lossesLine.isNotEmpty()) - { - stats->wins[state] = atoi(winsLine.str()); - stats->losses[state] = atoi(lossesLine.str()); - } - - stats = NULL; - } - } - - HandleOverallStats(USA, China, GLA); -#elif RTS_ZEROHOUR - HandleOverallStats( buffer, bufferLen ); -#endif - - return GHTTPTrue; -} - -/////////////////////////////////////////////////////////////////////////////////////// - -static GHTTPBool numPlayersOnlineCallback( GHTTPRequest request, GHTTPResult result, char * buffer, GHTTPByteCount bufferLen, void * param ) -{ - DEBUG_LOG(("numPlayersOnlineCallback() - Result=%d, buffer=[%s], len=%d", result, buffer, bufferLen)); - if (result != GHTTPSuccess) - { - return GHTTPTrue; - } - - AsciiString message = buffer; - message.trim(); - const char *s = message.reverseFind('\\'); - if (!s) - { - return GHTTPTrue; - } - - if (*s == '\\') - ++s; - - DEBUG_LOG(("Message was '%s', trimmed to '%s'=%d", buffer, s, atoi(s))); - HandleNumPlayersOnline(atoi(s)); - - return GHTTPTrue; -} - -/////////////////////////////////////////////////////////////////////////////////////// - -void CheckOverallStats( void ) -{ -#if RTS_GENERALS - const char *const url = "http://gamestats.gamespy.com/ccgenerals/display.html"; -#elif RTS_ZEROHOUR - const char *const url = "http://gamestats.gamespy.com/ccgenzh/display.html"; -#endif - ghttpGet(url, GHTTPFalse, overallStatsCallback, NULL); -} - -/////////////////////////////////////////////////////////////////////////////////////// - -void CheckNumPlayersOnline( void ) -{ -#if RTS_GENERALS - const char *const url = "http://launch.gamespyarcade.com/software/launch/arcadecount2.dll?svcname=ccgenerals"; -#elif RTS_ZEROHOUR - const char *const url = "http://launch.gamespyarcade.com/software/launch/arcadecount2.dll?svcname=ccgenzh"; -#endif - ghttpGet(url, GHTTPFalse, numPlayersOnlineCallback, NULL); -} - -/////////////////////////////////////////////////////////////////////////////////////// - -DWORD WINAPI asyncGethostbynameThreadFunc( void * szName ) -{ - HOSTENT *he = gethostbyname( (const char *)szName ); - - if (he) - { - s_asyncDNSThreadSucceeded = TRUE; - } - else - { - s_asyncDNSThreadSucceeded = FALSE; - } - - s_asyncDNSThreadDone = TRUE; - return 0; -} - -/////////////////////////////////////////////////////////////////////////////////////// - -int asyncGethostbyname(char * szName) -{ - static int stat = 0; - static unsigned long threadid; - - if( stat == 0 ) - { - /* Kick off gethostname thread */ - s_asyncDNSThreadDone = FALSE; - s_asyncDNSThreadHandle = CreateThread( NULL, 0, asyncGethostbynameThreadFunc, szName, 0, &threadid ); - - if( s_asyncDNSThreadHandle == NULL ) - { - return( LOOKUP_FAILED ); - } - stat = 1; - } - if( stat == 1 ) - { - if( s_asyncDNSThreadDone ) - { - /* Thread finished */ - stat = 0; - s_asyncDNSLookupInProgress = FALSE; - s_asyncDNSThreadHandle = NULL; - return( (s_asyncDNSThreadSucceeded)?LOOKUP_SUCCEEDED:LOOKUP_FAILED ); - } - } - - return( LOOKUP_INPROGRESS ); -} - -/////////////////////////////////////////////////////////////////////////////////////// - -// GameSpy's HTTP SDK has had at least 1 crash bug, so we're going to just bail and -// never try again if they crash us. We won't be able to get back online again (we'll -// time out) but at least we'll live. -static Bool isHttpOk = TRUE; - -void HTTPThinkWrapper( void ) -{ - if (s_asyncDNSLookupInProgress) - { - Char hostname[] = "servserv.generals.ea.com"; - Int ret = asyncGethostbyname(hostname); - switch(ret) - { - case LOOKUP_FAILED: - cantConnectBeforeOnline = TRUE; - startOnline(); - break; - case LOOKUP_SUCCEEDED: - reallyStartPatchCheck(); - break; - } - } - - if (isHttpOk) - { - try - { - ghttpThink(); - } - catch (...) - { - isHttpOk = FALSE; // we can't abort the login, since we might be done with the - // required checks and are fetching extras. If it is a required - // check, we'll time out normally. - } - } -} - -/////////////////////////////////////////////////////////////////////////////////////// - -void StopAsyncDNSCheck( void ) -{ - if (s_asyncDNSThreadHandle) - { -#ifdef DEBUG_CRASHING - Int res = -#endif - TerminateThread(s_asyncDNSThreadHandle,0); - DEBUG_ASSERTCRASH(res, ("Could not terminate the Async DNS Lookup thread!")); // Thread still not killed! - } - s_asyncDNSThreadHandle = NULL; - s_asyncDNSLookupInProgress = FALSE; -} - -/////////////////////////////////////////////////////////////////////////////////////// - -void StartPatchCheck( void ) -{ - checkingForPatchBeforeGameSpy = TRUE; - cantConnectBeforeOnline = FALSE; - timeThroughOnline++; - checksLeftBeforeOnline = 0; - - onlineCancelWindow = MessageBoxCancel(TheGameText->fetch("GUI:CheckingForPatches"), - TheGameText->fetch("GUI:CheckingForPatches"), CancelPatchCheckCallbackAndReopenDropdown); - - s_asyncDNSLookupInProgress = TRUE; - Char hostname[] = "servserv.generals.ea.com"; - Int ret = asyncGethostbyname(hostname); - switch(ret) - { - case LOOKUP_FAILED: - cantConnectBeforeOnline = TRUE; - startOnline(); - break; - case LOOKUP_SUCCEEDED: - reallyStartPatchCheck(); - break; - } -} - -/////////////////////////////////////////////////////////////////////////////////////// - -static void reallyStartPatchCheck( void ) -{ - checksLeftBeforeOnline = 4; - - std::string gameURL, mapURL; - std::string configURL, motdURL; - - FormatURLFromRegistry(gameURL, mapURL, configURL, motdURL); - - std::string proxy; - if (GetStringFromRegistry("", "Proxy", proxy)) - { - if (!proxy.empty()) - { - ghttpSetProxy(proxy.c_str()); - } - } - - // check for a patch first - DEBUG_LOG(("Game patch check: [%s]", gameURL.c_str())); - DEBUG_LOG(("Map patch check: [%s]", mapURL.c_str())); - DEBUG_LOG(("Config: [%s]", configURL.c_str())); - DEBUG_LOG(("MOTD: [%s]", motdURL.c_str())); - ghttpGet(gameURL.c_str(), GHTTPFalse, gamePatchCheckCallback, (void *)timeThroughOnline); - ghttpGet(mapURL.c_str(), GHTTPFalse, gamePatchCheckCallback, (void *)timeThroughOnline); - ghttpHead(configURL.c_str(), GHTTPFalse, configHeadCallback, (void *)timeThroughOnline); - ghttpGet(motdURL.c_str(), GHTTPFalse, motdCallback, (void *)timeThroughOnline); - - // check total game stats - CheckOverallStats(); - - // check the users online - CheckNumPlayersOnline(); -} - -/////////////////////////////////////////////////////////////////////////////////////// diff --git a/Generals/Code/GameEngine/Source/GameNetwork/GameSpy/PeerDefs.cpp b/Generals/Code/GameEngine/Source/GameNetwork/GameSpy/PeerDefs.cpp deleted file mode 100644 index fc540e9246..0000000000 --- a/Generals/Code/GameEngine/Source/GameNetwork/GameSpy/PeerDefs.cpp +++ /dev/null @@ -1,920 +0,0 @@ -/* -** 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 . -*/ - -// FILE: PeerDefs.cpp ////////////////////////////////////////////////////// -// Generals GameSpy Peer (chat) definitions -// Author: Matthew D. Campbell, June 2002 - -#include "PreRTS.h" // This must go first in EVERY cpp file in the GameEngine -#include - -#include "Common/GameState.h" -#include "Common/RandomValue.h" -#include "Common/IgnorePreferences.h" -#include "Common/CustomMatchPreferences.h" -#include "Common/GameSpyMiscPreferences.h" -#include "Common/Recorder.h" -#include "Common/Player.h" -#include "Common/PlayerList.h" -#include "Common/PlayerTemplate.h" -#include "GameClient/MapUtil.h" -#include "GameClient/ShellHooks.h" -#include "GameClient/GameText.h" -#include "GameNetwork/GameSpy/LadderDefs.h" -#include "GameNetwork/GameSpy/PeerDefsImplementation.h" -#include "GameNetwork/GameSpy/BuddyThread.h" -#include "GameNetwork/GameSpy/PeerThread.h" -#include "GameNetwork/GameSpy/PingThread.h" -#include "GameNetwork/GameSpy/PersistentStorageThread.h" -#include "GameNetwork/GameSpy/GSConfig.h" -#include "GameNetwork/GameSpyOverlay.h" -#include "GameNetwork/RankPointValue.h" -#include "GameLogic/GameLogic.h" - - -GameSpyInfoInterface *TheGameSpyInfo = NULL; -extern GameSpyStagingRoom *TheGameSpyGame = NULL; -void deleteNotificationBox( void ); - -bool AsciiComparator::operator()(AsciiString s1, AsciiString s2) const -{ - return stricmp(s1.str(), s2.str()) < 0; -} - -GameSpyInfo::GameSpyInfo() -{ - reset(); - TheGameSpyGame = &m_localStagingRoom; - m_isDisconAfterGameStart = FALSE; -} - -GameSpyInfo::~GameSpyInfo() -{ - TheGameSpyGame = NULL; - reset(); -} - -void GameSpyInfo::reset( void ) -{ - m_sawFullGameList = FALSE; - m_isDisconAfterGameStart = FALSE; - m_currentGroupRoomID = 0; - clearGroupRoomList(); - clearStagingRoomList(); - m_localStagingRoomID = 0; - m_buddyRequestMap.clear(); - m_buddyMap.clear(); - m_buddyMessages.clear(); - m_joinedStagingRoom = 0; - m_isHosting = false; - m_localStagingRoomID = 0; - m_localStagingRoom.reset(); - m_gotGroupRoomList = false; - m_localName = ""; - m_localProfileID = 0; - m_maxMessagesPerUpdate = 100; - - // Added By Sadullah Nader - // Initialization missing and needed - m_disallowAsainText = FALSE; - m_disallowNonAsianText = FALSE; - m_disconReason = 0; - m_localBaseName.clear(); - m_localEmail.clear(); - m_localPasswd.clear(); - m_pingString.clear(); - m_rawConfig.clear(); - m_rawMotd.clear(); - // - - m_internalIP = m_externalIP = 0; - - m_savedIgnoreMap.clear(); - m_preorderPlayers.clear(); - - m_cachedLocalPlayerStats.reset(); - - m_additionalDisconnects = -1; -} - -Bool GameSpyInfo::didPlayerPreorder( Int profileID ) const -{ - std::set::const_iterator it = m_preorderPlayers.find(profileID); - return (it != m_preorderPlayers.end()); -} - -void GameSpyInfo::markPlayerAsPreorder( Int profileID ) -{ - m_preorderPlayers.insert(profileID); -} - -void GameSpyInfo::setLocalIPs(UnsignedInt internalIP, UnsignedInt externalIP) -{ - m_internalIP = internalIP; - m_externalIP = externalIP; -} - -void GameSpyInfo::readAdditionalDisconnects( void ) -{ - m_additionalDisconnects = GetAdditionalDisconnectsFromUserFile(m_localProfileID); - DEBUG_LOG(("GameSpyInfo::readAdditionalDisconnects() found %d disconnects.", m_additionalDisconnects)); -} - -Int GameSpyInfo::getAdditionalDisconnects( void ) -{ - DEBUG_LOG(("GameSpyInfo::getAdditionalDisconnects() would have returned %d. Returning 0 instead.", m_additionalDisconnects)); - return 0; -} - -void GameSpyInfo::clearAdditionalDisconnects( void ) -{ - m_additionalDisconnects = 0; -} - -GameSpyInfoInterface* GameSpyInfoInterface::createNewGameSpyInfoInterface( void ) -{ - return NEW GameSpyInfo; -} - -Bool GameSpyInfo::amIHost( void ) -{ - return m_isHosting; -} - -GameSpyStagingRoom* GameSpyInfo::getCurrentStagingRoom( void ) -{ - if (m_isHosting || m_joinedStagingRoom) - return &m_localStagingRoom; - - StagingRoomMap::iterator it = m_stagingRooms.find(m_joinedStagingRoom); - if (it != m_stagingRooms.end()) - return it->second; - - return NULL; -} - -void GameSpyInfo::setGameOptions( void ) -{ - if (!m_isHosting) - return; - - // set options for game lists, and UTM players in-game - PeerRequest req; - req.peerRequestType = PeerRequest::PEERREQUEST_SETGAMEOPTIONS; - req.options = GameInfoToAsciiString(&m_localStagingRoom).str(); - - Int i; - AsciiString mapName = TheGameState->realMapPathToPortableMapPath(m_localStagingRoom.getMap()); - AsciiString newMapName; - for (i=0; igetGameSpySlot(i); - req.gameOptsPlayerNames[i] = ""; - if (!slot->isOccupied()) - { - if (slot->isOpen()) - ++numOpenSlots; - } - else - { - AsciiString playerName; - if (slot->isHuman()) - { - playerName.translate(slot->getName()); - req.gameOptsPlayerNames[i] = playerName.str(); - PlayerInfoMap::iterator it = m_playerInfoMap.find(playerName); - if (it != m_playerInfoMap.end()) - { - wins = it->second.m_wins; - losses = it->second.m_losses; - profileID = it->second.m_profileID; - } - req.gameOptions.wins[req.gameOptions.numObservers+req.gameOptions.numPlayers] = wins; - req.gameOptions.losses[req.gameOptions.numObservers+req.gameOptions.numPlayers] = losses; - req.gameOptions.profileID[req.gameOptions.numObservers+req.gameOptions.numPlayers] = profileID; - req.gameOptions.faction[req.gameOptions.numObservers+req.gameOptions.numPlayers] = slot->getPlayerTemplate(); - req.gameOptions.color[req.gameOptions.numObservers+req.gameOptions.numPlayers] = slot->getColor(); - if (slot->getPlayerTemplate() == PLAYERTEMPLATE_OBSERVER) - { - ++req.gameOptions.numObservers; - } - else - { - ++req.gameOptions.numPlayers; - } - } - else if (slot->isAI()) - { - // add in AI players - switch (slot->getState()) - { - case SLOT_EASY_AI: - playerName = "CE"; - break; - case SLOT_MED_AI: - playerName = "CM"; - break; - case SLOT_BRUTAL_AI: - playerName = "CH"; - break; - } - req.gameOptsPlayerNames[i] = playerName.str(); // name is unused - we go off of the profileID - req.gameOptions.wins[req.gameOptions.numObservers+req.gameOptions.numPlayers] = 0; - req.gameOptions.losses[req.gameOptions.numObservers+req.gameOptions.numPlayers] = 0; - req.gameOptions.profileID[req.gameOptions.numObservers+req.gameOptions.numPlayers] = slot->getState(); - req.gameOptions.faction[req.gameOptions.numObservers+req.gameOptions.numPlayers] = slot->getPlayerTemplate(); - req.gameOptions.color[req.gameOptions.numObservers+req.gameOptions.numPlayers] = slot->getColor(); - ++req.gameOptions.numPlayers; - } - } - } - req.gameOptions.maxPlayers = numOpenSlots + req.gameOptions.numPlayers + req.gameOptions.numObservers; - TheGameSpyPeerMessageQueue->addRequest(req); - - req.peerRequestType = PeerRequest::PEERREQUEST_UTMROOM; - req.UTM.isStagingRoom = TRUE; - req.id = "Pings/"; - AsciiString pings; - for (i=0; igetGameSpySlot(i); - if (slot && slot->isHuman()) - { - pings.concat(slot->getPingString()); - } - else - { - pings.concat("0"); - } - } - req.options = pings.str(); - TheGameSpyPeerMessageQueue->addRequest(req); -} - -Bool GameSpyInfo::isBuddy( Int id ) -{ - return m_buddyMap.find(id) != m_buddyMap.end(); -} - -void GameSpyInfo::addGroupRoom( GameSpyGroupRoom room ) -{ - if (room.m_groupID == 0) - { - m_gotGroupRoomList = TRUE; - - GroupRoomMap::iterator iter; - - // figure out how many good strings we've got - std::vector names; - Int numRooms = 0; - for (iter = getGroupRoomList()->begin(); iter != getGroupRoomList()->end(); ++iter) - { - GameSpyGroupRoom room = iter->second; - if (room.m_groupID != TheGameSpyConfig->getQMChannel()) - { - ++numRooms; - - AsciiString groupLabel; - groupLabel.format("GUI:%s", room.m_name.str()); - - Bool exists = FALSE; - UnicodeString groupName = TheGameText->fetch(groupLabel, &exists); - if (exists) - { - names.push_back(groupName); - } - } - } - - if (!names.empty() && names.size() != numRooms) - { - // didn't get all names. fix up - Int nameIndex = 0; - Int timesThrough = 1; // start with USA Lobby 1 - for (iter = TheGameSpyInfo->getGroupRoomList()->begin(); iter != TheGameSpyInfo->getGroupRoomList()->end(); ++iter) - { - GameSpyGroupRoom room = iter->second; - if (room.m_groupID != TheGameSpyConfig->getQMChannel()) - { - room.m_translatedName.format(L"%ls %d", names[nameIndex].str(), timesThrough); - nameIndex = (nameIndex+1)%names.size(); - m_groupRooms[room.m_groupID] = room; - if (!nameIndex) - { - // we've looped through the name list already. increment the timesThrough counter - ++timesThrough; - } - } - } - } - } - else - { - DEBUG_LOG(("Adding group room %d (%s)", room.m_groupID, room.m_name.str())); - AsciiString groupLabel; - groupLabel.format("GUI:%s", room.m_name.str()); - room.m_translatedName = TheGameText->fetch(groupLabel); - m_groupRooms[room.m_groupID] = room; - if ( !stricmp("quickmatch", room.m_name.str()) ) - { - DEBUG_LOG(("Group room %d (%s) is the QuickMatch room", room.m_groupID, room.m_name.str())); - TheGameSpyConfig->setQMChannel(room.m_groupID); - } - } -} - -void GameSpyInfo::joinGroupRoom( Int groupID ) -{ - if (groupID > 0) - { - PeerRequest req; - req.peerRequestType = PeerRequest::PEERREQUEST_JOINGROUPROOM; - req.groupRoom.id = groupID; - TheGameSpyPeerMessageQueue->addRequest(req); - m_playerInfoMap.clear(); - } -} - -void GameSpyInfo::leaveGroupRoom( void ) -{ - PeerRequest req; - req.peerRequestType = PeerRequest::PEERREQUEST_LEAVEGROUPROOM; - TheGameSpyPeerMessageQueue->addRequest(req); - setCurrentGroupRoom(0); - m_playerInfoMap.clear(); -} - -void GameSpyInfo::joinBestGroupRoom( void ) -{ - if (m_currentGroupRoomID) - { - DEBUG_LOG(("Bailing from GameSpyInfo::joinBestGroupRoom() - we were already in a room")); - m_currentGroupRoomID = 0; - return; - } - - if (m_groupRooms.size()) - { - int minID = -1; - int minPlayers = 1000; - GroupRoomMap::iterator iter = m_groupRooms.begin(); - while (iter != m_groupRooms.end()) - { - GameSpyGroupRoom room = iter->second; - DEBUG_LOG(("Group room %d: %s (%d, %d, %d, %d)", room.m_groupID, room.m_name.str(), room.m_numWaiting, room.m_maxWaiting, - room.m_numGames, room.m_numPlaying)); - - if (TheGameSpyConfig->getQMChannel() != room.m_groupID && minPlayers > 25 && room.m_numWaiting < minPlayers) - { - minID = room.m_groupID; - minPlayers = room.m_numWaiting; - } - - ++iter; - } - - if (minID > 0) - { - PeerRequest req; - req.peerRequestType = PeerRequest::PEERREQUEST_JOINGROUPROOM; - req.groupRoom.id = minID; - TheGameSpyPeerMessageQueue->addRequest(req); - m_playerInfoMap.clear(); - } - else - { - GSMessageBoxOk(TheGameText->fetch("GUI:Error"), TheGameText->fetch("GUI:GSGroupRoomJoinFail"), NULL); - } - } - else - { - GSMessageBoxOk(TheGameText->fetch("GUI:Error"), TheGameText->fetch("GUI:GSGroupRoomJoinFail"), NULL); - } -} - -void GameSpyInfo::updatePlayerInfo( PlayerInfo pi, AsciiString oldNick ) -{ - if (!oldNick.isEmpty()) - playerLeftGroupRoom(oldNick); - - m_playerInfoMap[pi.m_name] = pi; - - if (pi.m_preorder != 0) - markPlayerAsPreorder(pi.m_profileID); -} - -void GameSpyInfo::playerLeftGroupRoom( AsciiString nick ) -{ - PlayerInfoMap::iterator it = m_playerInfoMap.find(nick); - if (it != m_playerInfoMap.end()) - { - m_playerInfoMap.erase(it); - } -} - -void GameSpyInfo::clearStagingRoomList( void ) -{ - Int numRoomsRemoved = 0; - m_sawFullGameList = FALSE; - m_stagingRoomsDirty = FALSE; - - StagingRoomMap::iterator it = m_stagingRooms.begin(); - while (it != m_stagingRooms.end()) - { - ++numRoomsRemoved; - - delete it->second; - m_stagingRooms.erase(it); - it = m_stagingRooms.begin(); - } - if (numRoomsRemoved > 0) - { - //m_stagingRoomsDirty = true; // only consider ourselves dirty if we actually removed some games. - } -} - -void GameSpyInfo::addStagingRoom( GameSpyStagingRoom room ) -{ - removeStagingRoom(room); - GameSpyStagingRoom *newRoom = NEW GameSpyStagingRoom; - *newRoom = room; - newRoom->cleanUpSlotPointers(); - m_stagingRooms[room.getID()] = newRoom; - m_stagingRoomsDirty = m_sawFullGameList; -} - -void GameSpyInfo::updateStagingRoom( GameSpyStagingRoom room ) -{ - addStagingRoom(room); -} - -void GameSpyInfo::removeStagingRoom( GameSpyStagingRoom room ) -{ - StagingRoomMap::iterator it = m_stagingRooms.find(room.getID()); - if (it != m_stagingRooms.end()) - { - delete it->second; - m_stagingRooms.erase(it); - - m_stagingRoomsDirty = m_sawFullGameList; - } -} - -Bool GameSpyInfo::hasStagingRoomListChanged( void ) -{ - Bool val = m_stagingRoomsDirty; - m_stagingRoomsDirty = false; - return val; -} - -GameSpyStagingRoom* GameSpyInfo::findStagingRoomByID( Int id ) -{ - StagingRoomMap::iterator it = m_stagingRooms.find(id); - if (it != m_stagingRooms.end()) - return it->second; - - return NULL; -} - -void GameSpyInfo::leaveStagingRoom( void ) -{ - m_localStagingRoomID = 0; - PeerRequest req; - req.peerRequestType = PeerRequest::PEERREQUEST_LEAVESTAGINGROOM; - TheGameSpyPeerMessageQueue->addRequest(req); - m_playerInfoMap.clear(); - m_joinedStagingRoom = FALSE; - m_isHosting = FALSE; -} - -void GameSpyInfo::markAsStagingRoomHost( void ) -{ - m_localStagingRoomID = 0; - m_joinedStagingRoom = FALSE; m_isHosting = TRUE; - - // There are a few options we don't want to reset when we are hosting (they carry over - // from the the create game dialog). - // Interesting fact: oldFactionsOnly will be carried over correctly if I remove these - // lines. UseStats won't be. I have no idea why. - Int useStats = m_localStagingRoom.getUseStats(); - Bool oldFactionsOnly = m_localStagingRoom.oldFactionsOnly(); - - m_localStagingRoom.reset(); - m_localStagingRoom.enterGame(); - m_localStagingRoom.setSeed(GetTickCount()); - - m_localStagingRoom.setUseStats( useStats ); - m_localStagingRoom.setOldFactionsOnly( oldFactionsOnly ); - - GameSlot newSlot; - UnicodeString uName; - uName.translate(m_localName); - newSlot.setState(SLOT_PLAYER, uName); - - m_localStagingRoom.setLocalIP(m_externalIP); - newSlot.setIP(m_externalIP); - - m_localStagingRoom.setSlot(0,newSlot); - m_localStagingRoom.setLocalName(m_localName); - - TheMapCache->updateCache(); - m_localStagingRoom.setMap(getDefaultMap(TRUE)); - m_localStagingRoom.adjustSlotsForMap(); // close slots that the map can't hold. BGC -} - -void GameSpyInfo::markAsStagingRoomJoiner( Int game ) -{ - m_localStagingRoomID = game; - m_joinedStagingRoom = TRUE; m_isHosting = FALSE; - m_localStagingRoom.reset(); - m_localStagingRoom.enterGame(); - StagingRoomMap::iterator it = m_stagingRooms.find(game); - if (it != m_stagingRooms.end()) - { - GameSpyStagingRoom *info = it->second; - info->cleanUpSlotPointers(); - AsciiString options = GameInfoToAsciiString(info); -#ifdef DEBUG_CRASHING - Bool res = -#endif - ParseAsciiStringToGameInfo(&m_localStagingRoom, options); - DEBUG_ASSERTCRASH(res, ("Could not parse game info \"%s\"", options.str())); - m_localStagingRoom.setInGame(); - m_localStagingRoom.setLocalName(m_localName); - m_localStagingRoom.setExeCRC(info->getExeCRC()); - m_localStagingRoom.setIniCRC(info->getIniCRC()); - m_localStagingRoom.setAllowObservers(info->getAllowObservers()); - m_localStagingRoom.setHasPassword(info->getHasPassword()); - m_localStagingRoom.setGameName(info->getGameName()); - DEBUG_LOG(("Joining game: host is %ls", m_localStagingRoom.getConstSlot(0)->getName().str())); - } -} - -void GameSpyInfo::setMOTD( const AsciiString& motd ) -{ - m_rawMotd = motd; -} - -const AsciiString& GameSpyInfo::getMOTD( void ) -{ - return m_rawMotd; -} - -void GameSpyInfo::setConfig( const AsciiString& config ) -{ - m_rawConfig = config; -} - -const AsciiString& GameSpyInfo::getConfig( void ) -{ - return m_rawConfig; -} - -// -------------------------------------------------------------- -void SetUpGameSpy( const char *motdBuffer, const char *configBuffer ) -{ - if (!motdBuffer) - motdBuffer = ""; - if (!configBuffer) - configBuffer = ""; - TearDownGameSpy(); - - AsciiString dir = TheGlobalData->getPath_UserData(); - CreateDirectory(dir.str(), NULL); - dir.format("%sGeneralsOnline", TheGlobalData->getPath_UserData().str()); - CreateDirectory(dir.str(), NULL); - dir.format("%sGeneralsOnline\\Ladders", TheGlobalData->getPath_UserData().str()); - CreateDirectory(dir.str(), NULL); - - TheGameSpyBuddyMessageQueue = GameSpyBuddyMessageQueueInterface::createNewMessageQueue(); - TheGameSpyBuddyMessageQueue->startThread(); - - TheGameSpyPeerMessageQueue = GameSpyPeerMessageQueueInterface::createNewMessageQueue(); - TheGameSpyPeerMessageQueue->startThread(); - - TheGameSpyPSMessageQueue = GameSpyPSMessageQueueInterface::createNewMessageQueue(); - TheGameSpyPSMessageQueue->startThread(); - - /* - TheGameSpyGame = NEW GameSpyStagingRoom; - */ - - TheGameSpyInfo = GameSpyInfoInterface::createNewGameSpyInfoInterface(); - TheGameSpyInfo->setMOTD(motdBuffer); - TheGameSpyInfo->setConfig(configBuffer); - - CustomMatchPreferences pref; - TheGameSpyInfo->setDisallowAsianText(pref.getDisallowAsianText()); - TheGameSpyInfo->setDisallowNonAsianText( pref.getDisallowNonAsianText()); - - - TheGameSpyConfig = GameSpyConfigInterface::create(configBuffer); - - TheLadderList = NEW LadderList; - - ThePinger = PingerInterface::createNewPingerInterface(); - ThePinger->startThreads(); - - TheRankPointValues = NEW RankPoints; -} - -void TearDownGameSpy( void ) -{ - // save off cached stats - if (TheGameSpyInfo && TheGameSpyInfo->getLocalProfileID()) - { -// /* This was done on the score screen, so there is no need to do it now. -// * - PSPlayerStats localPSStats = TheGameSpyPSMessageQueue->findPlayerStatsByID(TheGameSpyInfo->getLocalProfileID()); - if (localPSStats.id != 0) - { - GameSpyMiscPreferences mPref; - mPref.setCachedStats(GameSpyPSMessageQueueInterface::formatPlayerKVPairs(localPSStats).c_str()); - mPref.write(); - } -// */ - } - - // End our threads before we kill off the singletons they reference. No crashy-crash for you! - if (TheGameSpyPSMessageQueue) - TheGameSpyPSMessageQueue->endThread(); - if (TheGameSpyBuddyMessageQueue) - TheGameSpyBuddyMessageQueue->endThread(); - if (TheGameSpyPeerMessageQueue) - TheGameSpyPeerMessageQueue->endThread(); - if (ThePinger) - ThePinger->endThreads(); - - delete TheRankPointValues; - TheRankPointValues = NULL; - - delete TheGameSpyPSMessageQueue; - TheGameSpyPSMessageQueue = NULL; - - delete TheGameSpyBuddyMessageQueue; - TheGameSpyBuddyMessageQueue = NULL; - - delete TheGameSpyPeerMessageQueue; - TheGameSpyPeerMessageQueue = NULL; - - if (TheGameSpyInfo) - { - if (TheGameSpyInfo->getInternalIP()) - { - // we've logged in before. mark us as logging out. - SignalUIInteraction(SHELL_SCRIPT_HOOK_GENERALS_ONLINE_LOGOUT); - } - delete TheGameSpyInfo; - TheGameSpyInfo = NULL; - } - - delete ThePinger; - ThePinger = NULL; - - delete TheLadderList; - TheLadderList = NULL; - - delete TheGameSpyConfig; - TheGameSpyConfig = NULL; - - // make sure the notification box doesn't exist - deleteNotificationBox(); -} - - -void GameSpyInfo::addToIgnoreList( AsciiString nick ) -{ - m_ignoreList.insert(nick); -} - -void GameSpyInfo::removeFromIgnoreList( AsciiString nick ) -{ - m_ignoreList.erase(nick); -} - -Bool GameSpyInfo::isIgnored( AsciiString nick ) -{ - return m_ignoreList.find(nick) != m_ignoreList.end(); -} - -IgnoreList GameSpyInfo::returnIgnoreList( void ) -{ - return m_ignoreList; -} - -void GameSpyInfo::addToSavedIgnoreList( Int profileID, AsciiString nick) -{ - m_savedIgnoreMap[profileID] = nick; - IgnorePreferences pref; - pref.setIgnore(nick, profileID, true); - pref.write(); -} - -void GameSpyInfo::removeFromSavedIgnoreList( Int profileID ) -{ - m_savedIgnoreMap.erase(profileID); - IgnorePreferences pref; - pref.setIgnore(AsciiString::TheEmptyString, profileID, false); - pref.write(); -} - -Bool GameSpyInfo::isSavedIgnored( Int profileID ) -{ - return m_savedIgnoreMap.find(profileID) != m_savedIgnoreMap.end(); -} - -SavedIgnoreMap GameSpyInfo::returnSavedIgnoreList( void ) -{ - return m_savedIgnoreMap; -} - -static Int grabHexInt(const char *s) -{ - char tmp[5] = "0xff"; - tmp[2] = s[0]; - tmp[3] = s[1]; - Int b = strtol(tmp, NULL, 16); - return b; -} - -Int GameSpyInfo::getPingValue( const AsciiString& otherPing ) -{ - if (m_pingString.getLength() != otherPing.getLength()) - { - return TheGameSpyConfig->getPingTimeoutInMs(); - } - - if (m_pingString.getLength() % 2 != 0) - { - return TheGameSpyConfig->getPingTimeoutInMs(); - } - - Int best = 255+255; - const char *myStr = m_pingString.str(); - const char *otherStr = otherPing.str(); - - while (*myStr) - { - Int myVal = grabHexInt(myStr); - Int otherVal = grabHexInt(otherStr); - Int val = myVal + otherVal; - best = (val < best) ? val : best; - myStr += 2; - otherStr += 2; - } - - return best * TheGameSpyConfig->getPingTimeoutInMs() / (255+255); -} - -Bool PlayerInfo::isIgnored( void ) -{ - return (m_profileID)?TheGameSpyInfo->isSavedIgnored(m_profileID):TheGameSpyInfo->isIgnored(m_name); -} - -void GameSpyInfo::loadSavedIgnoreList( void ) -{ - m_savedIgnoreMap.clear(); - IgnorePreferences prefs; - m_savedIgnoreMap = prefs.getIgnores(); -} - -void GameSpyInfo::setDisallowAsianText( Bool val ) -{ - m_disallowAsainText = val; -} - -void GameSpyInfo::setDisallowNonAsianText( Bool val ) -{ - m_disallowNonAsianText = val; -} - -Bool GameSpyInfo::getDisallowAsianText( void ) -{ - return m_disallowAsainText; -} -Bool GameSpyInfo::getDisallowNonAsianText(void ) -{ - return m_disallowNonAsianText; -} - -void GameSpyInfo::setMaxMessagesPerUpdate( Int num ) -{ - m_maxMessagesPerUpdate = num; -} - -Int GameSpyInfo::getMaxMessagesPerUpdate( void ) -{ - return m_maxMessagesPerUpdate; -} - -/**This function is used to force an update of player's gamespy stats with an additional -disconnection. This is used upon starting a new game so that if user disconnects prior -to finishing game, the disconnection stays on the server. If he completes the game, we -remove this extra disconnection inside of populatePlayerInfo() on the ScoreScreen. This -seems like the only secure way to handle this issue since users can abort the process -before we can detect/log disconnections.*/ -void GameSpyInfo::updateAdditionalGameSpyDisconnections(Int count) -{ - if (TheRecorder->isMultiplayer() && TheGameLogic->isInInternetGame() && TheGameSpyGame && TheGameSpyGame->getUseStats()) - { - Int localID = TheGameSpyInfo->getLocalProfileID(); - PSPlayerStats stats = TheGameSpyPSMessageQueue->findPlayerStatsByID(localID); - - Player *player=ThePlayerList->getLocalPlayer(); - - Int ptIdx; - const PlayerTemplate *myTemplate = player->getPlayerTemplate(); - DEBUG_LOG(("myTemplate = %X(%s)", myTemplate, myTemplate->getName().str())); - for (ptIdx = 0; ptIdx < ThePlayerTemplateStore->getPlayerTemplateCount(); ++ptIdx) - { - const PlayerTemplate *nthTemplate = ThePlayerTemplateStore->getNthPlayerTemplate(ptIdx); - DEBUG_LOG(("nthTemplate = %X(%s)", nthTemplate, nthTemplate->getName().str())); - if (nthTemplate == myTemplate) - { - break; - } - } - - Bool anyAI = FALSE; - for (Int i=0; igetConstSlot(i); - - if (slot->isAI()) - { - anyAI = TRUE; - } - } - - //Check for cases where we're not tracking stats. - if (anyAI || stats.id == 0 || myTemplate->isObserver() || player->getPlayerType() != PLAYER_HUMAN || player->isPlayerObserver()) - return; - - Int disCons=stats.discons[ptIdx]; - disCons += count; - if (disCons < 0) - { DEBUG_LOG(("updateAdditionalGameSpyDisconnections() - disconnection count below zero")); - return; //something is wrong here - } - stats.discons[ptIdx] = disCons; //add an additional disconnection to their stats. - - //Add an additional disconnection to player stats. - PSRequest req; - - req.requestType = PSRequest::PSREQUEST_UPDATEPLAYERSTATS; - req.email = TheGameSpyInfo->getLocalEmail().str(); - req.nick = TheGameSpyInfo->getLocalBaseName().str(); - req.password = TheGameSpyInfo->getLocalPassword().str(); - req.player = stats; - req.addDesync = FALSE; - req.addDiscon = FALSE; - req.lastHouse = ptIdx; - - TheGameSpyPSMessageQueue->addRequest(req); - TheGameSpyPSMessageQueue->trackPlayerStats(stats); - - // force an update of our shtuff - PSResponse newResp; - newResp.responseType = PSResponse::PSRESPONSE_PLAYERSTATS; - newResp.player = stats; - TheGameSpyPSMessageQueue->addResponse(newResp); - - // cache our stuff for easy reading next time - GameSpyMiscPreferences mPref; - mPref.setCachedStats(GameSpyPSMessageQueueInterface::formatPlayerKVPairs(stats).c_str()); - mPref.write(); - } -} diff --git a/Generals/Code/GameEngine/Source/GameNetwork/GameSpy/StagingRoomGameInfo.cpp b/Generals/Code/GameEngine/Source/GameNetwork/GameSpy/StagingRoomGameInfo.cpp deleted file mode 100644 index 6256aa26ba..0000000000 --- a/Generals/Code/GameEngine/Source/GameNetwork/GameSpy/StagingRoomGameInfo.cpp +++ /dev/null @@ -1,886 +0,0 @@ -/* -** 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. // -// // -//////////////////////////////////////////////////////////////////////////////// - -// FILE: StagingRoomGameInfo.cpp ////////////////////////////////////////////////////// -// Generals GameSpy GameInfo-related code -// Author: Matthew D. Campbell, July 2002 - -#include "PreRTS.h" // This must go first in EVERY cpp file in the GameEngine - -#include "Common/GameState.h" -#include "Common/Player.h" -#include "Common/PlayerList.h" -#include "Common/PlayerTemplate.h" -#include "Common/RandomValue.h" -#include "Common/ScoreKeeper.h" -#include "GameClient/GameText.h" -#include "GameClient/MapUtil.h" -#include "GameClient/Shell.h" -#include "GameLogic/GameLogic.h" -#include "GameLogic/VictoryConditions.h" -#include "GameNetwork/FileTransfer.h" -#include "GameNetwork/GameSpy/BuddyThread.h" -#include "GameNetwork/GameSpy/PeerDefs.h" -#include "GameNetwork/GameSpy/PersistentStorageThread.h" -#include "GameNetwork/GameSpy/ThreadUtils.h" -#include "GameNetwork/GameSpyOverlay.h" -#include "GameNetwork/NAT.h" -#include "GameNetwork/NetworkInterface.h" - - -// GameSpyGameSlot ------------------------------------------- - -GameSpyGameSlot::GameSpyGameSlot() - : GameSlot() -{ - m_gameSpyLogin.clear(); - m_gameSpyLocale.clear(); - m_profileID = 0; - m_wins = 0; - m_losses = 0; - m_rankPoints = 0; - m_favoriteSide = 0; - m_pingInt = 0; - // Added By Sadullah Nader - // Initializations missing and needed - m_profileID = 0; - m_pingStr.clear(); -} - -// Helper Functions ---------------------------------------- -/* -** Function definitions for the MIB-II entry points. -*/ - -BOOL (__stdcall *SnmpExtensionInitPtr)(IN DWORD dwUpTimeReference, OUT HANDLE *phSubagentTrapEvent, OUT AsnObjectIdentifier *pFirstSupportedRegion); -BOOL (__stdcall *SnmpExtensionQueryPtr)(IN BYTE bPduType, IN OUT RFC1157VarBindList *pVarBindList, OUT AsnInteger32 *pErrorStatus, OUT AsnInteger32 *pErrorIndex); -LPVOID (__stdcall *SnmpUtilMemAllocPtr)(IN DWORD bytes); -VOID (__stdcall *SnmpUtilMemFreePtr)(IN LPVOID pMem); - -typedef struct tConnInfoStruct { - unsigned int State; - unsigned long LocalIP; - unsigned short LocalPort; - unsigned long RemoteIP; - unsigned short RemotePort; -} ConnInfoStruct; - -/*********************************************************************************************** - * Get_Local_Chat_Connection_Address -- Which address are we using to talk to the chat server? * - * * - * * - * * - * INPUT: Ptr to address to return local address * * - * * - * OUTPUT: True if success * - * * - * WARNINGS: None * - * * - * HISTORY: * - * 10/27/00 3:24PM ST : Created * - *=============================================================================================*/ -Bool GetLocalChatConnectionAddress(AsciiString serverName, UnsignedShort serverPort, UnsignedInt& localIP) -{ - //return false; - /* - ** Local defines. - */ - enum { - CLOSED = 1, - LISTENING, - SYN_SENT, - SEN_RECEIVED, - ESTABLISHED, - FIN_WAIT, - FIN_WAIT2, - CLOSE_WAIT, - LAST_ACK, - CLOSING, - TIME_WAIT, - DELETE_TCB - }; - - enum { - tcpConnState = 1, - tcpConnLocalAddress, - tcpConnLocalPort, - tcpConnRemAddress, - tcpConnRemPort - }; - - - /* - ** Locals. - */ - unsigned char serverAddress[4]; - unsigned char remoteAddress[4]; - HANDLE trap_handle; - AsnObjectIdentifier first_supported_region; - std::vector connectionVector; - int last_field; - int index; - AsnInteger error_status; - AsnInteger error_index; - int conn_entry_type_index; - int conn_entry_type; - Bool found; - - /* - ** Statics. - */ - static char _conn_state[][32] = { - "?", - "CLOSED", - "LISTENING", - "SYN_SENT", - "SEN_RECEIVED", - "ESTABLISHED", - "FIN_WAIT", - "FIN_WAIT2", - "CLOSE_WAIT", - "LAST_ACK", - "CLOSING", - "TIME_WAIT", - "DELETE_TCB" - }; - - DEBUG_LOG(("Finding local address used to talk to the chat server")); - DEBUG_LOG(("Current chat server name is %s", serverName.str())); - DEBUG_LOG(("Chat server port is %d", serverPort)); - - /* - ** Get the address of the chat server. - */ - DEBUG_LOG( ("About to call gethostbyname")); - struct hostent *host_info = gethostbyname(serverName.str()); - - if (!host_info) { - DEBUG_LOG( ("gethostbyname failed! Error code %d", WSAGetLastError())); - return(false); - } - - memcpy(serverAddress, &host_info->h_addr_list[0][0], 4); - unsigned long temp = *((unsigned long*)(&serverAddress[0])); - temp = ntohl(temp); - *((unsigned long*)(&serverAddress[0])) = temp; - - DEBUG_LOG(("Host address is %d.%d.%d.%d", serverAddress[3], serverAddress[2], serverAddress[1], serverAddress[0])); - - /* - ** Load the MIB-II SNMP DLL. - */ - DEBUG_LOG(("About to load INETMIB1.DLL")); - - HINSTANCE mib_ii_dll = LoadLibrary("inetmib1.dll"); - if (mib_ii_dll == NULL) { - DEBUG_LOG(("Failed to load INETMIB1.DLL")); - return(false); - } - - DEBUG_LOG(("About to load SNMPAPI.DLL")); - - HINSTANCE snmpapi_dll = LoadLibrary("snmpapi.dll"); - if (snmpapi_dll == NULL) { - DEBUG_LOG(("Failed to load SNMPAPI.DLL")); - FreeLibrary(mib_ii_dll); - return(false); - } - - /* - ** Get the function pointers into the .dll - */ - SnmpExtensionInitPtr = (int (__stdcall *)(unsigned long,void ** ,AsnObjectIdentifier *)) GetProcAddress(mib_ii_dll, "SnmpExtensionInit"); - SnmpExtensionQueryPtr = (int (__stdcall *)(unsigned char,SnmpVarBindList *,long *,long *)) GetProcAddress(mib_ii_dll, "SnmpExtensionQuery"); - SnmpUtilMemAllocPtr = (void *(__stdcall *)(unsigned long)) GetProcAddress(snmpapi_dll, "SnmpUtilMemAlloc"); - SnmpUtilMemFreePtr = (void (__stdcall *)(void *)) GetProcAddress(snmpapi_dll, "SnmpUtilMemFree"); - if (SnmpExtensionInitPtr == NULL || SnmpExtensionQueryPtr == NULL || SnmpUtilMemAllocPtr == NULL || SnmpUtilMemFreePtr == NULL) { - DEBUG_LOG(("Failed to get proc addresses for linked functions")); - FreeLibrary(snmpapi_dll); - FreeLibrary(mib_ii_dll); - return(false); - } - - - RFC1157VarBindList *bind_list_ptr = (RFC1157VarBindList *) SnmpUtilMemAllocPtr(sizeof(RFC1157VarBindList)); - RFC1157VarBind *bind_ptr = (RFC1157VarBind *) SnmpUtilMemAllocPtr(sizeof(RFC1157VarBind)); - - /* - ** OK, here we go. Try to initialise the .dll - */ - DEBUG_LOG(("About to init INETMIB1.DLL")); - int ok = SnmpExtensionInitPtr(GetCurrentTime(), &trap_handle, &first_supported_region); - - if (!ok) { - /* - ** Aw crap. - */ - DEBUG_LOG(("Failed to init the .dll")); - SnmpUtilMemFreePtr(bind_list_ptr); - SnmpUtilMemFreePtr(bind_ptr); - FreeLibrary(snmpapi_dll); - FreeLibrary(mib_ii_dll); - return(false); - } - - /* - ** Name of mib_ii object we want to query. See RFC 1213. - ** - ** iso.org.dod.internet.mgmt.mib-2.tcp.tcpConnTable.TcpConnEntry.tcpConnState - ** 1 3 6 1 2 1 6 13 1 1 - */ - unsigned int mib_ii_name[] = {1,3,6,1,2,1,6,13,1,1}; - unsigned int *mib_ii_name_ptr = (unsigned int *) SnmpUtilMemAllocPtr(sizeof(mib_ii_name)); - memcpy(mib_ii_name_ptr, mib_ii_name, sizeof(mib_ii_name)); - - /* - ** Get the index of the conn entry data. - */ - conn_entry_type_index = ARRAY_SIZE(mib_ii_name) - 1; - - /* - ** Set up the bind list. - */ - bind_ptr->name.idLength = ARRAY_SIZE(mib_ii_name); - bind_ptr->name.ids = mib_ii_name; - bind_list_ptr->list = bind_ptr; - bind_list_ptr->len = 1; - - - /* - ** We start with the tcpConnLocalAddress field. - */ - last_field = 1; - - /* - ** First connection. - */ - index = 0; - - /* - ** Suck out that tcp connection info.... - */ - while (true) { - - if (!SnmpExtensionQueryPtr(SNMP_PDU_GETNEXT, bind_list_ptr, &error_status, &error_index)) { - //if (!SnmpExtensionQueryPtr(ASN_RFC1157_GETNEXTREQUEST, bind_list_ptr, &error_status, &error_index)) { - DEBUG_LOG(("SnmpExtensionQuery returned false")); - SnmpUtilMemFreePtr(bind_list_ptr); - SnmpUtilMemFreePtr(bind_ptr); - FreeLibrary(snmpapi_dll); - FreeLibrary(mib_ii_dll); - return(false); - } - - /* - ** If this is something new we aren't looking for then we are done. - */ - if (bind_ptr->name.idLength < ARRAY_SIZE(mib_ii_name)) { - break; - } - - /* - ** Get the type of info we are looking at. See RFC1213. - ** - ** 1 = tcpConnState - ** 2 = tcpConnLocalAddress - ** 3 = tcpConnLocalPort - ** 4 = tcpConnRemAddress - ** 5 = tcpConnRemPort - ** - ** tcpConnState is one of the following... - ** - ** 1 closed - ** 2 listen - ** 3 synSent - ** 4 synReceived - ** 5 established - ** 6 finWait1 - ** 7 finWait2 - ** 8 closeWait - ** 9 lastAck - ** 10 closing - ** 11 timeWait - ** 12 deleteTCB - */ - conn_entry_type = bind_ptr->name.ids[conn_entry_type_index]; - - if (last_field != conn_entry_type) { - index = 0; - last_field = conn_entry_type; - } - - switch (conn_entry_type) { - - /* - ** 1. First field in the entry. Need to create a new connection info struct - ** here to store this connection in. - */ - case tcpConnState: - { - ConnInfoStruct new_conn; - new_conn.State = bind_ptr->value.asnValue.number; - connectionVector.push_back(new_conn); - break; - } - - /* - ** 2. Local address field. - */ - case tcpConnLocalAddress: - DEBUG_ASSERTCRASH(index < connectionVector.size(), ("Bad connection index")); - connectionVector[index].LocalIP = *((unsigned long*)bind_ptr->value.asnValue.address.stream); - index++; - break; - - /* - ** 3. Local port field. - */ - case tcpConnLocalPort: - DEBUG_ASSERTCRASH(index < connectionVector.size(), ("Bad connection index")); - connectionVector[index].LocalPort = bind_ptr->value.asnValue.number; - //connectionVector[index]->LocalPort = ntohs(connectionVector[index]->LocalPort); - index++; - break; - - /* - ** 4. Remote address field. - */ - case tcpConnRemAddress: - DEBUG_ASSERTCRASH(index < connectionVector.size(), ("Bad connection index")); - connectionVector[index].RemoteIP = *((unsigned long*)bind_ptr->value.asnValue.address.stream); - index++; - break; - - /* - ** 5. Remote port field. - */ - case tcpConnRemPort: - DEBUG_ASSERTCRASH(index < connectionVector.size(), ("Bad connection index")); - connectionVector[index].RemotePort = bind_ptr->value.asnValue.number; - //connectionVector[index]->RemotePort = ntohs(connectionVector[index]->RemotePort); - index++; - break; - } - } - - SnmpUtilMemFreePtr(bind_list_ptr); - SnmpUtilMemFreePtr(bind_ptr); - SnmpUtilMemFreePtr(mib_ii_name_ptr); - - DEBUG_LOG(("Got %d connections in list, parsing...", connectionVector.size())); - - /* - ** Right, we got the lot. Lets see if any of them have the same address as the chat - ** server we think we are talking to. - */ - found = false; - for (size_t i=0; igetPingValue(pingStr); -} - -// GameSpyStagingRoom ---------------------------------------- - -GameSpyStagingRoom::GameSpyStagingRoom() -{ - cleanUpSlotPointers(); - - setLocalIP(0); - m_transport = NULL; - - m_localName = "localhost"; - - m_ladderIP.clear(); - m_ladderPort = 0; -} - -void GameSpyStagingRoom::cleanUpSlotPointers( void ) -{ - for (Int i = 0; i< MAX_SLOTS; ++i) - setSlotPointer(i, &m_GameSpySlot[i]); -} - -GameSpyGameSlot * GameSpyStagingRoom::getGameSpySlot( Int index ) -{ - GameSlot *slot = getSlot(index); - DEBUG_ASSERTCRASH(slot && (slot == &(m_GameSpySlot[index])), ("Bad game slot pointer")); - return (GameSpyGameSlot *)slot; -} - -void GameSpyStagingRoom::init( void ) -{ - GameInfo::init(); -} - -void GameSpyStagingRoom::setPingString( AsciiString pingStr ) -{ - m_pingStr = pingStr; - m_pingInt = TheGameSpyInfo->getPingValue(pingStr); -} - -Bool GameSpyStagingRoom::amIHost( void ) const -{ - DEBUG_ASSERTCRASH(m_inGame, ("Looking for game slot while not in game")); - if (!m_inGame) - return false; - - return getConstSlot(0)->isPlayer(m_localName); -} - -void GameSpyStagingRoom::resetAccepted( void ) -{ - GameInfo::resetAccepted(); - - if (amIHost()) - { - /* - peerStateChanged(TheGameSpyChat->getPeer()); - m_hasBeenQueried = false; - DEBUG_LOG(("resetAccepted() called peerStateChange()")); - */ - } -} - -Int GameSpyStagingRoom::getLocalSlotNum( void ) const -{ - DEBUG_ASSERTCRASH(m_inGame, ("Looking for local game slot while not in game")); - if (!m_inGame) - return -1; - - AsciiString localName = TheGameSpyInfo->getLocalName(); - - for (Int i=0; iisPlayer(localName)) - return i; - } - return -1; -} - -void GameSpyStagingRoom::startGame(Int gameID) -{ - DEBUG_ASSERTCRASH(m_inGame, ("Starting a game while not in game")); - DEBUG_LOG(("GameSpyStagingRoom::startGame - game id = %d", gameID)); - DEBUG_ASSERTCRASH(m_transport == NULL, ("m_transport is not NULL when it should be")); - DEBUG_ASSERTCRASH(TheNAT == NULL, ("TheNAT is not NULL when it should be")); - - UnsignedInt localIP = TheGameSpyInfo->getInternalIP(); - setLocalIP(localIP); - - delete TheNAT; - TheNAT = NULL; - - // fill in GS-specific info - Int numHumans = 0; - for (Int i=0; igetLocalProfileID()); // hehe - we know our own. the rest, they'll tell us. - } - else - { - PlayerInfoMap *pInfoMap = TheGameSpyInfo->getPlayerInfoMap(); - PlayerInfoMap::iterator it = pInfoMap->find(gsName); - if (it != pInfoMap->end()) - { - m_GameSpySlot[i].setProfileID(it->second.m_profileID); - m_GameSpySlot[i].setLocale(it->second.m_locale); - m_GameSpySlot[i].setSlotRankPoints(it->second.m_rankPoints); - m_GameSpySlot[i].setFavoriteSide(it->second.m_side); - } - else - { - DEBUG_CRASH(("No player info for %s", gsName.str())); - } - } - } - } - -//#if defined(RTS_DEBUG) - if (numHumans < 2) - { - launchGame(); - if (TheGameSpyInfo) - TheGameSpyInfo->leaveStagingRoom(); - } - else -//#endif // defined(RTS_DEBUG) - { - TheNAT = NEW NAT(); - TheNAT->attachSlotList(m_slot, getLocalSlotNum(), m_localIP); - TheNAT->establishConnectionPaths(); - } -} - -AsciiString GameSpyStagingRoom::generateGameSpyGameResultsPacket( void ) -{ - Int i; - Int endFrame = TheVictoryConditions->getEndFrame(); - Int localSlotNum = getLocalSlotNum(); - Int winningTeam = -1; - Int numHumans = 0; - Int numPlayers = 0; - Int numAIs = 0; - Int numTeamsAtGameEnd = 0; - Int lastTeamAtGameEnd = -1; - for (i=0; ifindPlayerWithNameKey(NAMEKEY(playerName)); - if (p) - { - ++numHumans; - if (TheVictoryConditions->hasAchievedVictory(p)) - { - winningTeam = getSlot(i)->getTeamNumber(); - } - - // check if he lasted - GameSlot *slot = getSlot(i); - if (!slot->disconnected()) - { - if (slot->getTeamNumber() != lastTeamAtGameEnd || numTeamsAtGameEnd == 0) - { - lastTeamAtGameEnd = slot->getTeamNumber(); - ++numTeamsAtGameEnd; - } - } - } - else - { - if (m_GameSpySlot[i].isAI()) - ++numAIs; - } - } - numPlayers = numHumans + numAIs; - - AsciiString mapName; - for (i=0; ifindPlayerWithNameKey(NAMEKEY(playerName)); - if (p) - { - GameSpyGameSlot *slot = &(m_GameSpySlot[i]); - AsciiString playerName = (slot->isHuman())?slot->getLoginName():"AIPlayer"; - Int gsPlayerID = slot->getProfileID(); - Bool disconnected = slot->disconnected(); - - AsciiString result = "loss"; - if (disconnected) - result = "discon"; - else if (TheNetwork->sawCRCMismatch()) - result = "desync"; - else if (TheVictoryConditions->hasAchievedVictory(p)) - result = "win"; - - AsciiString side = p->getPlayerTemplate()->getSide(); - if (side == "America") - side = "USA"; //conform to GameSpy - - AsciiString playerStr; - playerStr.format("\\player_%d\\%s\\pid_%d\\%d\\team_%d\\%d\\result_%d\\%s\\side_%d\\%s", - playerID, playerName.str(), playerID, gsPlayerID, playerID, slot->getTeamNumber(), - playerID, result.str(), playerID, side.str()); - results.concat(playerStr); - - ++playerID; - } - } - - return results; -} - -AsciiString GameSpyStagingRoom::generateLadderGameResultsPacket( void ) -{ - Int i; - Int endFrame = TheVictoryConditions->getEndFrame(); - Int localSlotNum = getLocalSlotNum(); - Bool sawGameEnd = (endFrame > 0); - Int winningTeam = -1; - Int numPlayers = 0; - Int numTeamsAtGameEnd = 0; - Int lastTeamAtGameEnd = -1; - Player* p[MAX_SLOTS]; - for (i=0; ifindPlayerWithNameKey(NAMEKEY(playerName)); - if (p[i]) - { - ++numPlayers; - if (TheVictoryConditions->hasAchievedVictory(p[i])) - { - winningTeam = getSlot(i)->getTeamNumber(); - } - - // check if he lasted - GameSlot *slot = getSlot(i); - if (!slot->disconnected()) - { - if (slot->getTeamNumber() != lastTeamAtGameEnd || numTeamsAtGameEnd == 0) - { - lastTeamAtGameEnd = slot->getTeamNumber(); - ++numTeamsAtGameEnd; - } - } - } - } - - AsciiString results; - results.format("seed=%d,slotNum=%d,sawDesync=%d,sawGameEnd=%d,winningTeam=%d,disconEnd=%d,duration=%d,numPlayers=%d,isQM=%d,map=%s", - getSeed(), localSlotNum, TheNetwork->sawCRCMismatch(), sawGameEnd, winningTeam, (numTeamsAtGameEnd < 2), - endFrame, numPlayers, m_isQM, TheGameState->realMapPathToPortableMapPath(getMap()).str()); - - AsciiString tempStr; - tempStr.format(",ladderIP=%s,ladderPort=%d", getLadderIP().str(), getLadderPort()); - results.concat(tempStr); - - Int playerID = 0; - for (i=0; igetScoreKeeper(); - AsciiString playerName = slot->getLoginName(); - Int gsPlayerID = slot->getProfileID(); - PSPlayerStats stats = TheGameSpyPSMessageQueue->findPlayerStatsByID(gsPlayerID); - Int fps = TheNetwork->getAverageFPS(); - Int unitsKilled = keeper->getTotalUnitsDestroyed(); - Int unitsLost = keeper->getTotalUnitsLost(); - Int unitsBuilt = keeper->getTotalUnitsBuilt(); - Int buildingsKilled = keeper->getTotalBuildingsDestroyed(); - Int buildingsLost = keeper->getTotalBuildingsLost(); - Int buildingsBuilt = keeper->getTotalBuildingsBuilt(); - Int earnings = keeper->getTotalMoneyEarned(); - Int techCaptured = keeper->getTotalTechBuildingsCaptured(); - Bool disconnected = slot->disconnected(); - - AsciiString playerStr; - playerStr.format(",player%d=%s,playerID%d=%d,locale%d=%d", - playerID, playerName.str(), playerID, gsPlayerID, playerID, stats.locale); - results.concat(playerStr); - playerStr.format(",unitsKilled%d=%d,unitsLost%d=%d,unitsBuilt%d=%d", - playerID, unitsKilled, playerID, unitsLost, playerID, unitsBuilt); - results.concat(playerStr); - playerStr.format(",buildingsKilled%d=%d,buildingsLost%d=%d,buildingsBuilt%d=%d", - playerID, buildingsKilled, playerID, buildingsLost, playerID, buildingsBuilt); - results.concat(playerStr); -#if RTS_GENERALS - playerStr.format(",fps%d=%d,cash%d=%d,capturedTech%d=%d,discon%d=%d,side%d=%s,team%d=%d", - playerID, fps, playerID, earnings, playerID, techCaptured, playerID, disconnected, playerID, p[i]->getPlayerTemplate()->getSide().str(), playerID, slot->getTeamNumber()); -#elif RTS_ZEROHOUR - playerStr.format(",fps%d=%d,cash%d=%d,capturedTech%d=%d,discon%d=%d,side%d=%s", - playerID, fps, playerID, earnings, playerID, techCaptured, playerID, disconnected, playerID, p[i]->getPlayerTemplate()->getSide().str()); -#endif - results.concat(playerStr); - - ++playerID; - } - } - - // Add a trailing size value (so the server can ensure it got the entire packet) - results.concat(",size="); - int resultsLen = results.getLength()+10; - AsciiString tail; - tail.format("%10.10d", resultsLen); - results.concat(tail); - - return results; -} - -void GameSpyStagingRoom::launchGame( void ) -{ - setGameInProgress(TRUE); - - for (Int i=0; iisHuman()) - { - if (TheGameSpyInfo->didPlayerPreorder(slot->getProfileID())) - markPlayerAsPreorder(i); - } - } - - // Set up the game network - AsciiString user; - AsciiString userList; - DEBUG_ASSERTCRASH(TheNetwork == NULL, ("For some reason TheNetwork isn't NULL at the start of this game. Better look into that.")); - - delete TheNetwork; - TheNetwork = NULL; - - // Time to initialize TheNetwork for this game. - TheNetwork = NetworkInterface::createNetwork(); - TheNetwork->init(); - - TheNetwork->setLocalAddress(getLocalIP(), (TheNAT)?TheNAT->getSlotPort(getLocalSlotNum()):8888); - if (TheNAT) - TheNetwork->attachTransport(TheNAT->getTransport()); - else - TheNetwork->initTransport(); - - TheNetwork->parseUserList(this); - - - if (TheGameLogic->isInGame()) { - TheGameLogic->clearGameData(); - } - - Bool filesOk = DoAnyMapTransfers(this); - - // see if we really have the map. if not, back out. - TheMapCache->updateCache(); - if (!filesOk || TheMapCache->findMap(getMap()) == NULL) - { - DEBUG_LOG(("After transfer, we didn't really have the map. Bailing...")); - - delete TheNetwork; - TheNetwork = NULL; - - GSMessageBoxOk(TheGameText->fetch("GUI:Error"), TheGameText->fetch("GUI:CouldNotTransferMap")); - - void PopBackToLobby( void ); - PopBackToLobby(); - return; - } - - - // shutdown the top, but do not pop it off the stack -// TheShell->hideShell(); - // setup the Global Data with the Map and Seed - TheWritableGlobalData->m_pendingFile = TheGameSpyGame->getMap(); - - // send a message to the logic for a new game - GameMessage *msg = TheMessageStream->appendMessage( GameMessage::MSG_NEW_GAME ); - msg->appendIntegerArgument(GAME_INTERNET); - - TheWritableGlobalData->m_useFpsLimit = false; - - // Set the random seed - InitGameLogicRandom( getSeed() ); - DEBUG_LOG(("InitGameLogicRandom( %d )", getSeed())); - - // mark us as "Loading" in the buddy list - BuddyRequest req; - req.buddyRequestType = BuddyRequest::BUDDYREQUEST_SETSTATUS; - req.arg.status.status = GP_PLAYING; - strcpy(req.arg.status.statusString, "Loading"); - sprintf(req.arg.status.locationString, "%s", WideCharStringToMultiByte(TheGameSpyGame->getGameName().str()).c_str()); - TheGameSpyBuddyMessageQueue->addRequest(req); - - delete TheNAT; - TheNAT = NULL; -} - -void GameSpyStagingRoom::reset(void) -{ -#ifdef DEBUG_LOGGING - if (this == TheGameSpyGame) - { - WindowLayout *theLayout = TheShell->findScreenByFilename("Menus/GameSpyGameOptionsMenu.wnd"); - if (theLayout) - { - DEBUG_LOG(("Resetting TheGameSpyGame on the game options menu!")); - } - } -#endif - GameInfo::reset(); -} diff --git a/Generals/Code/GameEngine/Source/GameNetwork/GameSpy/Thread/BuddyThread.cpp b/Generals/Code/GameEngine/Source/GameNetwork/GameSpy/Thread/BuddyThread.cpp deleted file mode 100644 index 8af5511a63..0000000000 --- a/Generals/Code/GameEngine/Source/GameNetwork/GameSpy/Thread/BuddyThread.cpp +++ /dev/null @@ -1,683 +0,0 @@ -/* -** 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. // -// // -//////////////////////////////////////////////////////////////////////////////// - -// FILE: BuddyThread.cpp ////////////////////////////////////////////////////// -// GameSpy Presence & Messaging (Buddy) thread -// This thread communicates with GameSpy's buddy server -// and talks through a message queue with the rest of -// the game. -// Author: Matthew D. Campbell, June 2002 - -#include "PreRTS.h" // This must go first in EVERY cpp file in the GameEngine - -#include "GameNetwork/GameSpy/BuddyThread.h" -#include "GameNetwork/GameSpy/PeerThread.h" -#include "GameNetwork/GameSpy/PersistentStorageThread.h" -#include "GameNetwork/GameSpy/ThreadUtils.h" - -#include "mutex.h" -#include "thread.h" - - -//------------------------------------------------------------------------- - -typedef std::queue RequestQueue; -typedef std::queue ResponseQueue; -class BuddyThreadClass; - -class GameSpyBuddyMessageQueue : public GameSpyBuddyMessageQueueInterface -{ -public: - virtual ~GameSpyBuddyMessageQueue(); - GameSpyBuddyMessageQueue(); - virtual void startThread( void ); - virtual void endThread( void ); - virtual Bool isThreadRunning( void ); - virtual Bool isConnected( void ); - virtual Bool isConnecting( void ); - - virtual void addRequest( const BuddyRequest& req ); - virtual Bool getRequest( BuddyRequest& req ); - - virtual void addResponse( const BuddyResponse& resp ); - virtual Bool getResponse( BuddyResponse& resp ); - - virtual GPProfile getLocalProfileID( void ); - - BuddyThreadClass* getThread( void ); - -private: - MutexClass m_requestMutex; - MutexClass m_responseMutex; - RequestQueue m_requests; - ResponseQueue m_responses; - BuddyThreadClass *m_thread; -}; - -GameSpyBuddyMessageQueueInterface* GameSpyBuddyMessageQueueInterface::createNewMessageQueue( void ) -{ - return NEW GameSpyBuddyMessageQueue; -} - -GameSpyBuddyMessageQueueInterface *TheGameSpyBuddyMessageQueue; -#define MESSAGE_QUEUE ((GameSpyBuddyMessageQueue *)TheGameSpyBuddyMessageQueue) - -//------------------------------------------------------------------------- - -class BuddyThreadClass : public ThreadClass -{ - -public: - BuddyThreadClass() : ThreadClass() { m_isNewAccount = m_isdeleting = m_isConnecting = m_isConnected = false; m_profileID = 0; m_lastErrorCode = 0; } - - void Thread_Function(); - - void errorCallback( GPConnection *con, GPErrorArg *arg ); - void messageCallback( GPConnection *con, GPRecvBuddyMessageArg *arg ); - void connectCallback( GPConnection *con, GPConnectResponseArg *arg ); - void requestCallback( GPConnection *con, GPRecvBuddyRequestArg *arg ); - void statusCallback( GPConnection *con, GPRecvBuddyStatusArg *arg ); - - Bool isConnecting( void ) { return m_isConnecting; } - Bool isConnected( void ) { return m_isConnected; } - - GPProfile getLocalProfileID( void ) { return m_profileID; } - -private: - Bool m_isNewAccount; - Bool m_isConnecting; - Bool m_isConnected; - GPProfile m_profileID; - Int m_lastErrorCode; - Bool m_isdeleting; - std::string m_nick, m_email, m_pass; -}; - -enum CallbackType -{ - CALLBACK_CONNECT, - CALLBACK_ERROR, - CALLBACK_RECVMESSAGE, - CALLBACK_RECVREQUEST, - CALLBACK_RECVSTATUS, -}; - -void callbackWrapper( GPConnection *con, void *arg, void *param ) -{ - CallbackType info = (CallbackType)(Int)param; - BuddyThreadClass *thread = MESSAGE_QUEUE->getThread() ? MESSAGE_QUEUE->getThread() : NULL /*(TheGameSpyBuddyMessageQueue)?TheGameSpyBuddyMessageQueue->getThread():NULL*/; - if (!thread) - return; - - switch (info) - { - case CALLBACK_CONNECT: - thread->connectCallback( con, (GPConnectResponseArg *)arg ); - break; - case CALLBACK_ERROR: - thread->errorCallback( con, (GPErrorArg *)arg ); - break; - case CALLBACK_RECVMESSAGE: - thread->messageCallback( con, (GPRecvBuddyMessageArg *)arg ); - break; - case CALLBACK_RECVREQUEST: - thread->requestCallback( con, (GPRecvBuddyRequestArg *)arg ); - break; - case CALLBACK_RECVSTATUS: - thread->statusCallback( con, (GPRecvBuddyStatusArg *)arg ); - break; - } -} - -//------------------------------------------------------------------------- - -GameSpyBuddyMessageQueue::GameSpyBuddyMessageQueue() -{ - m_thread = NULL; -} - -GameSpyBuddyMessageQueue::~GameSpyBuddyMessageQueue() -{ - endThread(); -} - -void GameSpyBuddyMessageQueue::startThread( void ) -{ - if (!m_thread) - { - m_thread = NEW BuddyThreadClass; - m_thread->Execute(); - } - else - { - if (!m_thread->Is_Running()) - { - m_thread->Execute(); - } - } -} - -void GameSpyBuddyMessageQueue::endThread( void ) -{ - delete m_thread; - m_thread = NULL; -} - -Bool GameSpyBuddyMessageQueue::isThreadRunning( void ) -{ - return (m_thread) ? m_thread->Is_Running() : false; -} - -Bool GameSpyBuddyMessageQueue::isConnected( void ) -{ - return (m_thread) ? m_thread->isConnected() : false; -} - -Bool GameSpyBuddyMessageQueue::isConnecting( void ) -{ - return (m_thread) ? m_thread->isConnecting() : false; -} - -void GameSpyBuddyMessageQueue::addRequest( const BuddyRequest& req ) -{ - MutexClass::LockClass m(m_requestMutex); - if (m.Failed()) - return; - - m_requests.push(req); -} - -Bool GameSpyBuddyMessageQueue::getRequest( BuddyRequest& req ) -{ - MutexClass::LockClass m(m_requestMutex, 0); - if (m.Failed()) - return false; - - if (m_requests.empty()) - return false; - req = m_requests.front(); - m_requests.pop(); - return true; -} - -void GameSpyBuddyMessageQueue::addResponse( const BuddyResponse& resp ) -{ - MutexClass::LockClass m(m_responseMutex); - if (m.Failed()) - return; - - m_responses.push(resp); -} - -Bool GameSpyBuddyMessageQueue::getResponse( BuddyResponse& resp ) -{ - MutexClass::LockClass m(m_responseMutex, 0); - if (m.Failed()) - return false; - - if (m_responses.empty()) - return false; - resp = m_responses.front(); - m_responses.pop(); - return true; -} - -BuddyThreadClass* GameSpyBuddyMessageQueue::getThread( void ) -{ - return m_thread; -} - -GPProfile GameSpyBuddyMessageQueue::getLocalProfileID( void ) -{ - return (m_thread) ? m_thread->getLocalProfileID() : 0; -} - -//------------------------------------------------------------------------- - -void BuddyThreadClass::Thread_Function() -{ - try { - GPConnection gpCon; - GPConnection *con = &gpCon; -#if RTS_GENERALS - const int productID = 675; -#elif RTS_ZEROHOUR - const int productID = 823; -#endif - gpInitialize( con, productID, 0, GP_PARTNERID_GAMESPY ); - m_isConnected = m_isConnecting = false; - - gpSetCallback( con, GP_ERROR, callbackWrapper, (void *)CALLBACK_ERROR ); - gpSetCallback( con, GP_RECV_BUDDY_MESSAGE, callbackWrapper, (void *)CALLBACK_RECVMESSAGE ); - gpSetCallback( con, GP_RECV_BUDDY_REQUEST, callbackWrapper, (void *)CALLBACK_RECVREQUEST ); - gpSetCallback( con, GP_RECV_BUDDY_STATUS, callbackWrapper, (void *)CALLBACK_RECVSTATUS ); - - GPEnum lastStatus = GP_OFFLINE; - std::string lastStatusString; - - BuddyRequest incomingRequest; - while ( running ) - { - // deal with requests - if (TheGameSpyBuddyMessageQueue->getRequest(incomingRequest)) - { - switch (incomingRequest.buddyRequestType) - { - case BuddyRequest::BUDDYREQUEST_LOGIN: - m_isConnecting = true; - m_nick = incomingRequest.arg.login.nick; - m_email = incomingRequest.arg.login.email; - m_pass = incomingRequest.arg.login.password; - m_isConnected = (gpConnect( con, incomingRequest.arg.login.nick, incomingRequest.arg.login.email, - incomingRequest.arg.login.password, (incomingRequest.arg.login.hasFirewall)?GP_FIREWALL:GP_NO_FIREWALL, - GP_BLOCKING, callbackWrapper, (void *)CALLBACK_CONNECT ) == GP_NO_ERROR); - m_isConnecting = false; - break; - - case BuddyRequest::BUDDYREQUEST_RELOGIN: - m_isConnecting = true; - m_isConnected = (gpConnect( con, m_nick.c_str(), m_email.c_str(), m_pass.c_str(), GP_FIREWALL, - GP_BLOCKING, callbackWrapper, (void *)CALLBACK_CONNECT ) == GP_NO_ERROR); - m_isConnecting = false; - break; - case BuddyRequest::BUDDYREQUEST_DELETEACCT: - m_isdeleting = true; - // TheSuperHackers @tweak OmniBlade API was updated since Generals released to require a callback. Passing -1 will make our wrapper ignore this. - gpDeleteProfile( con, callbackWrapper, (void *)(-1) ); - break; - case BuddyRequest::BUDDYREQUEST_LOGOUT: - m_isConnecting = m_isConnected = false; - gpDisconnect( con ); - break; - case BuddyRequest::BUDDYREQUEST_MESSAGE: - { - std::string s = WideCharStringToMultiByte( incomingRequest.arg.message.text ); - DEBUG_LOG(("Sending a buddy message to %d [%s]", incomingRequest.arg.message.recipient, s.c_str())); - gpSendBuddyMessage( con, incomingRequest.arg.message.recipient, s.c_str() ); - } - break; - case BuddyRequest::BUDDYREQUEST_LOGINNEW: - { - m_isConnecting = true; - m_nick = incomingRequest.arg.login.nick; - m_email = incomingRequest.arg.login.email; - m_pass = incomingRequest.arg.login.password; - m_isNewAccount = TRUE; - // TheSuperHackers @tweak OmniBlade API was updated since Generals release to require uniquenick which is the same as nick and cdkey is an empty string here. - m_isConnected = (gpConnectNewUser( con, incomingRequest.arg.login.nick, incomingRequest.arg.login.nick, incomingRequest.arg.login.email, - incomingRequest.arg.login.password, "", (incomingRequest.arg.login.hasFirewall)?GP_FIREWALL:GP_NO_FIREWALL, - GP_BLOCKING, callbackWrapper, (void *)CALLBACK_CONNECT ) == GP_NO_ERROR); - if (m_isNewAccount) // if we didn't re-login - { - gpSetInfoMask( con, GP_MASK_NONE ); // don't share info - } - m_isConnecting = false; - } - break; - case BuddyRequest::BUDDYREQUEST_ADDBUDDY: - { - std::string s = WideCharStringToMultiByte( incomingRequest.arg.addbuddy.text ); - gpSendBuddyRequest( con, incomingRequest.arg.addbuddy.id, s.c_str() ); - } - break; - case BuddyRequest::BUDDYREQUEST_DELBUDDY: - { - gpDeleteBuddy( con, incomingRequest.arg.profile.id ); - } - break; - case BuddyRequest::BUDDYREQUEST_OKADD: - { - gpAuthBuddyRequest( con, incomingRequest.arg.profile.id ); - } - break; - case BuddyRequest::BUDDYREQUEST_DENYADD: - { - gpDenyBuddyRequest( con, incomingRequest.arg.profile.id ); - } - break; - case BuddyRequest::BUDDYREQUEST_SETSTATUS: - { - //don't blast our 'Loading' status with 'Online'. - if (lastStatus == GP_PLAYING && lastStatusString == "Loading" && incomingRequest.arg.status.status == GP_ONLINE) - break; - - DEBUG_LOG(("BUDDYREQUEST_SETSTATUS: status is now %d:%s/%s", - incomingRequest.arg.status.status, incomingRequest.arg.status.statusString, incomingRequest.arg.status.locationString)); - gpSetStatus( con, incomingRequest.arg.status.status, incomingRequest.arg.status.statusString, - incomingRequest.arg.status.locationString ); - lastStatus = incomingRequest.arg.status.status; - lastStatusString = incomingRequest.arg.status.statusString; - } - break; - } - } - - // update the network - GPEnum isConnected = GP_CONNECTED; - GPResult res = GP_NO_ERROR; - res = gpIsConnected( con, &isConnected ); - if ( isConnected == GP_CONNECTED && res == GP_NO_ERROR ) - gpProcess( con ); - - // end our timeslice - Switch_Thread(); - } - - gpDestroy( con ); - } catch ( ... ) { - DEBUG_CRASH(("Exception in buddy thread!")); - } -} - -void BuddyThreadClass::errorCallback( GPConnection *con, GPErrorArg *arg ) -{ - // log the error - DEBUG_LOG(("GPErrorCallback")); - m_lastErrorCode = arg->errorCode; - - char errorCodeString[256]; - char resultString[256]; - - #define RESULT(x) case x: strcpy(resultString, #x); break; - switch(arg->result) - { - RESULT(GP_NO_ERROR) - RESULT(GP_MEMORY_ERROR) - RESULT(GP_PARAMETER_ERROR) - RESULT(GP_NETWORK_ERROR) - RESULT(GP_SERVER_ERROR) - default: - strcpy(resultString, "Unknown result!"); - } - #undef RESULT - - #define ERRORCODE(x) case x: strcpy(errorCodeString, #x); break; - switch(arg->errorCode) - { - ERRORCODE(GP_GENERAL) - ERRORCODE(GP_PARSE) - ERRORCODE(GP_NOT_LOGGED_IN) - ERRORCODE(GP_BAD_SESSKEY) - ERRORCODE(GP_DATABASE) - ERRORCODE(GP_NETWORK) - ERRORCODE(GP_FORCED_DISCONNECT) - ERRORCODE(GP_CONNECTION_CLOSED) - ERRORCODE(GP_LOGIN) - ERRORCODE(GP_LOGIN_TIMEOUT) - ERRORCODE(GP_LOGIN_BAD_NICK) - ERRORCODE(GP_LOGIN_BAD_EMAIL) - ERRORCODE(GP_LOGIN_BAD_PASSWORD) - ERRORCODE(GP_LOGIN_BAD_PROFILE) - ERRORCODE(GP_LOGIN_PROFILE_DELETED) - ERRORCODE(GP_LOGIN_CONNECTION_FAILED) - ERRORCODE(GP_LOGIN_SERVER_AUTH_FAILED) - ERRORCODE(GP_NEWUSER) - ERRORCODE(GP_NEWUSER_BAD_NICK) - ERRORCODE(GP_NEWUSER_BAD_PASSWORD) - ERRORCODE(GP_UPDATEUI) - ERRORCODE(GP_UPDATEUI_BAD_EMAIL) - ERRORCODE(GP_NEWPROFILE) - ERRORCODE(GP_NEWPROFILE_BAD_NICK) - ERRORCODE(GP_NEWPROFILE_BAD_OLD_NICK) - ERRORCODE(GP_UPDATEPRO) - ERRORCODE(GP_UPDATEPRO_BAD_NICK) - ERRORCODE(GP_ADDBUDDY) - ERRORCODE(GP_ADDBUDDY_BAD_FROM) - ERRORCODE(GP_ADDBUDDY_BAD_NEW) - ERRORCODE(GP_ADDBUDDY_ALREADY_BUDDY) - ERRORCODE(GP_AUTHADD) - ERRORCODE(GP_AUTHADD_BAD_FROM) - ERRORCODE(GP_AUTHADD_BAD_SIG) - ERRORCODE(GP_STATUS) - ERRORCODE(GP_BM) - ERRORCODE(GP_BM_NOT_BUDDY) - ERRORCODE(GP_GETPROFILE) - ERRORCODE(GP_GETPROFILE_BAD_PROFILE) - ERRORCODE(GP_DELBUDDY) - ERRORCODE(GP_DELBUDDY_NOT_BUDDY) - ERRORCODE(GP_DELPROFILE) - ERRORCODE(GP_DELPROFILE_LAST_PROFILE) - ERRORCODE(GP_SEARCH) - ERRORCODE(GP_SEARCH_CONNECTION_FAILED) - default: - strcpy(errorCodeString, "Unknown error code!"); - } - #undef ERRORCODE - - if(arg->fatal) - { - DEBUG_LOG(( "-----------")); - DEBUG_LOG(( "GP FATAL ERROR")); - DEBUG_LOG(( "-----------")); - } - else - { - DEBUG_LOG(( "-----")); - DEBUG_LOG(( "GP ERROR")); - DEBUG_LOG(( "-----")); - } - DEBUG_LOG(( "RESULT: %s (%d)", resultString, arg->result)); - DEBUG_LOG(( "ERROR CODE: %s (0x%X)", errorCodeString, arg->errorCode)); - DEBUG_LOG(( "ERROR STRING: %s", arg->errorString)); - - if (arg->fatal == GP_FATAL) - { - BuddyResponse errorResponse; - errorResponse.buddyResponseType = BuddyResponse::BUDDYRESPONSE_DISCONNECT; - errorResponse.result = arg->result; - errorResponse.arg.error.errorCode = arg->errorCode; - errorResponse.arg.error.fatal = arg->fatal; - strlcpy(errorResponse.arg.error.errorString, arg->errorString, MAX_BUDDY_CHAT_LEN); - m_isConnecting = m_isConnected = false; - TheGameSpyBuddyMessageQueue->addResponse( errorResponse ); - if (m_isdeleting) - { - PeerRequest req; - req.peerRequestType = PeerRequest::PEERREQUEST_LOGOUT; - TheGameSpyPeerMessageQueue->addRequest( req ); - m_isdeleting = false; - } - } -} - -static void getNickForMessage( GPConnection *con, GPGetInfoResponseArg *arg, void *param ) -{ - BuddyResponse *resp = (BuddyResponse *)param; - static_assert(ARRAY_SIZE(resp->arg.message.nick) >= ARRAY_SIZE(arg->nick), "Incorrect array size"); - strcpy(resp->arg.message.nick, arg->nick); -} - -void BuddyThreadClass::messageCallback( GPConnection *con, GPRecvBuddyMessageArg *arg ) -{ - BuddyResponse messageResponse; - messageResponse.buddyResponseType = BuddyResponse::BUDDYRESPONSE_MESSAGE; - messageResponse.profile = arg->profile; - - // get info about the person asking to be our buddy - gpGetInfo( con, arg->profile, GP_CHECK_CACHE, GP_BLOCKING, (GPCallback)getNickForMessage, &messageResponse); - - std::wstring s = MultiByteToWideCharSingleLine( arg->message ); - wcslcpy(messageResponse.arg.message.text, s.c_str(), MAX_BUDDY_CHAT_LEN); - messageResponse.arg.message.date = arg->date; - DEBUG_LOG(("Got a buddy message from %d [%ls]", arg->profile, s.c_str())); - TheGameSpyBuddyMessageQueue->addResponse( messageResponse ); -} - -void BuddyThreadClass::connectCallback( GPConnection *con, GPConnectResponseArg *arg ) -{ - BuddyResponse loginResponse; - if (arg->result == GP_NO_ERROR) - { - loginResponse.buddyResponseType = BuddyResponse::BUDDYRESPONSE_LOGIN; - loginResponse.result = arg->result; - loginResponse.profile = arg->profile; - TheGameSpyBuddyMessageQueue->addResponse( loginResponse ); - m_profileID = arg->profile; - - if (!TheGameSpyPeerMessageQueue->isConnected() && !TheGameSpyPeerMessageQueue->isConnecting()) - { - DEBUG_LOG(("Buddy connect: trying chat connect")); - PeerRequest req; - req.peerRequestType = PeerRequest::PEERREQUEST_LOGIN; - req.nick = m_nick; - req.password = m_pass; - req.email = m_email; - req.login.profileID = arg->profile; - TheGameSpyPeerMessageQueue->addRequest(req); - } - } - else - { - if (!TheGameSpyPeerMessageQueue->isConnected() && !TheGameSpyPeerMessageQueue->isConnecting()) - { - if (m_lastErrorCode == GP_NEWUSER_BAD_NICK) - { - m_isNewAccount = FALSE; - // they just hit 'create account' instead of 'log in'. Fix them. - DEBUG_LOG(("User Error: Create Account instead of Login. Fixing them...")); - BuddyRequest req; - req.buddyRequestType = BuddyRequest::BUDDYREQUEST_LOGIN; - strlcpy(req.arg.login.nick, m_nick.c_str(), ARRAY_SIZE(req.arg.login.nick)); - strlcpy(req.arg.login.email, m_email.c_str(), ARRAY_SIZE(req.arg.login.email)); - strlcpy(req.arg.login.password, m_pass.c_str(), ARRAY_SIZE(req.arg.login.password)); - req.arg.login.hasFirewall = true; - TheGameSpyBuddyMessageQueue->addRequest( req ); - return; - } - DEBUG_LOG(("Buddy connect failed (%d/%d): posting a failed chat connect", arg->result, m_lastErrorCode)); - PeerResponse resp; - resp.peerResponseType = PeerResponse::PEERRESPONSE_DISCONNECT; - resp.discon.reason = DISCONNECT_COULDNOTCONNECT; - switch (m_lastErrorCode) - { - case GP_LOGIN_TIMEOUT: - resp.discon.reason = DISCONNECT_GP_LOGIN_TIMEOUT; - break; - case GP_LOGIN_BAD_NICK: - resp.discon.reason = DISCONNECT_GP_LOGIN_BAD_NICK; - break; - case GP_LOGIN_BAD_EMAIL: - resp.discon.reason = DISCONNECT_GP_LOGIN_BAD_EMAIL; - break; - case GP_LOGIN_BAD_PASSWORD: - resp.discon.reason = DISCONNECT_GP_LOGIN_BAD_PASSWORD; - break; - case GP_LOGIN_BAD_PROFILE: - resp.discon.reason = DISCONNECT_GP_LOGIN_BAD_PROFILE; - break; - case GP_LOGIN_PROFILE_DELETED: - resp.discon.reason = DISCONNECT_GP_LOGIN_PROFILE_DELETED; - break; - case GP_LOGIN_CONNECTION_FAILED: - resp.discon.reason = DISCONNECT_GP_LOGIN_CONNECTION_FAILED; - break; - case GP_LOGIN_SERVER_AUTH_FAILED: - resp.discon.reason = DISCONNECT_GP_LOGIN_SERVER_AUTH_FAILED; - break; - case GP_NEWUSER_BAD_NICK: - resp.discon.reason = DISCONNECT_GP_NEWUSER_BAD_NICK; - break; - case GP_NEWUSER_BAD_PASSWORD: - resp.discon.reason = DISCONNECT_GP_NEWUSER_BAD_PASSWORD; - break; - case GP_NEWPROFILE_BAD_NICK: - resp.discon.reason = DISCONNECT_GP_NEWPROFILE_BAD_NICK; - break; - case GP_NEWPROFILE_BAD_OLD_NICK: - resp.discon.reason = DISCONNECT_GP_NEWPROFILE_BAD_OLD_NICK; - break; - } - TheGameSpyPeerMessageQueue->addResponse(resp); - } - } -} - -// ----------------------- - -static void getInfoResponseForRequest( GPConnection *con, GPGetInfoResponseArg *arg, void *param ) -{ - BuddyResponse *resp = (BuddyResponse *)param; - resp->profile = arg->profile; - static_assert(ARRAY_SIZE(resp->arg.request.nick) >= ARRAY_SIZE(arg->nick), "Incorrect array size"); - static_assert(ARRAY_SIZE(resp->arg.request.email) >= ARRAY_SIZE(arg->email), "Incorrect array size"); - static_assert(ARRAY_SIZE(resp->arg.request.countrycode) >= ARRAY_SIZE(arg->countrycode), "Incorrect array size"); - strcpy(resp->arg.request.nick, arg->nick); - strcpy(resp->arg.request.email, arg->email); - strcpy(resp->arg.request.countrycode, arg->countrycode); -} - -void BuddyThreadClass::requestCallback( GPConnection *con, GPRecvBuddyRequestArg *arg ) -{ - BuddyResponse response; - response.buddyResponseType = BuddyResponse::BUDDYRESPONSE_REQUEST; - response.profile = arg->profile; - - // get info about the person asking to be our buddy - gpGetInfo( con, arg->profile, GP_CHECK_CACHE, GP_BLOCKING, (GPCallback)getInfoResponseForRequest, &response); - - std::wstring s = MultiByteToWideCharSingleLine( arg->reason ); - wcslcpy(response.arg.request.text, s.c_str(), GP_REASON_LEN); - - TheGameSpyBuddyMessageQueue->addResponse( response ); -} - -// ----------------------- - -static void getInfoResponseForStatus(GPConnection * connection, GPGetInfoResponseArg * arg, void * param) -{ - BuddyResponse *resp = (BuddyResponse *)param; - resp->profile = arg->profile; - static_assert(ARRAY_SIZE(resp->arg.status.nick) >= ARRAY_SIZE(arg->nick), "Incorrect array size"); - static_assert(ARRAY_SIZE(resp->arg.status.email) >= ARRAY_SIZE(arg->email), "Incorrect array size"); - static_assert(ARRAY_SIZE(resp->arg.status.countrycode) >= ARRAY_SIZE(arg->countrycode), "Incorrect array size"); - strcpy(resp->arg.status.nick, arg->nick); - strcpy(resp->arg.status.email, arg->email); - strcpy(resp->arg.status.countrycode, arg->countrycode); -} - -void BuddyThreadClass::statusCallback( GPConnection *con, GPRecvBuddyStatusArg *arg ) -{ - BuddyResponse response; - - // get user's name - response.buddyResponseType = BuddyResponse::BUDDYRESPONSE_STATUS; - gpGetInfo( con, arg->profile, GP_CHECK_CACHE, GP_BLOCKING, (GPCallback)getInfoResponseForStatus, &response); - - // get user's status - GPBuddyStatus status; - gpGetBuddyStatus( con, arg->index, &status ); - static_assert(ARRAY_SIZE(response.arg.status.location) >= ARRAY_SIZE(status.locationString), "Incorrect array size"); - static_assert(ARRAY_SIZE(response.arg.status.statusString) >= ARRAY_SIZE(status.statusString), "Incorrect array size"); - strcpy(response.arg.status.location, status.locationString); - strcpy(response.arg.status.statusString, status.statusString); - response.arg.status.status = status.status; - DEBUG_LOG(("Got buddy status for %d(%s) - status %d", status.profile, response.arg.status.nick, status.status)); - - // relay to UI - TheGameSpyBuddyMessageQueue->addResponse( response ); -} - - -//------------------------------------------------------------------------- - diff --git a/Generals/Code/GameEngine/Source/GameNetwork/GameSpy/Thread/GameResultsThread.cpp b/Generals/Code/GameEngine/Source/GameNetwork/GameSpy/Thread/GameResultsThread.cpp deleted file mode 100644 index 062997e806..0000000000 --- a/Generals/Code/GameEngine/Source/GameNetwork/GameSpy/Thread/GameResultsThread.cpp +++ /dev/null @@ -1,392 +0,0 @@ -/* -** 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. // -// // -//////////////////////////////////////////////////////////////////////////////// - -// FILE: PingThread.cpp ////////////////////////////////////////////////////// -// Ping thread -// Author: Matthew D. Campbell, August 2002 - -#include "PreRTS.h" // This must go first in EVERY cpp file in the GameEngine - -#include // This one has to be here. Prevents collisions with winsock2.h - -#include "GameNetwork/GameSpy/GameResultsThread.h" -#include "mutex.h" -#include "thread.h" - -#include "Common/SubsystemInterface.h" - -//------------------------------------------------------------------------- - -static const Int NumWorkerThreads = 1; - -typedef std::queue RequestQueue; -typedef std::queue ResponseQueue; -class GameResultsThreadClass; - -class GameResultsQueue : public GameResultsInterface -{ -public: - virtual ~GameResultsQueue(); - GameResultsQueue(); - - virtual void init() {} - virtual void reset() {} - virtual void update() {} - - virtual void startThreads( void ); - virtual void endThreads( void ); - virtual Bool areThreadsRunning( void ); - - virtual void addRequest( const GameResultsRequest& req ); - virtual Bool getRequest( GameResultsRequest& resp ); - - virtual void addResponse( const GameResultsResponse& resp ); - virtual Bool getResponse( GameResultsResponse& resp ); - - virtual Bool areGameResultsBeingSent( void ); - -private: - MutexClass m_requestMutex; - MutexClass m_responseMutex; - RequestQueue m_requests; - ResponseQueue m_responses; - Int m_requestCount; - Int m_responseCount; - - GameResultsThreadClass *m_workerThreads[NumWorkerThreads]; -}; - -GameResultsInterface* GameResultsInterface::createNewGameResultsInterface( void ) -{ - return NEW GameResultsQueue; -} - -GameResultsInterface *TheGameResultsQueue; - -//------------------------------------------------------------------------- - -class GameResultsThreadClass : public ThreadClass -{ - -public: - GameResultsThreadClass() : ThreadClass() {} - - void Thread_Function(); - -private: - Int sendGameResults( UnsignedInt IP, UnsignedShort port, const std::string& results ); -}; - - -//------------------------------------------------------------------------- - -GameResultsQueue::GameResultsQueue() : m_requestCount(0), m_responseCount(0) -{ - for (Int i=0; iExecute(); - } -} - -void GameResultsQueue::endThreads( void ) -{ - for (Int i=0; iIs_Running()) - return true; - } - } - return false; -} - -void GameResultsQueue::addRequest( const GameResultsRequest& req ) -{ - MutexClass::LockClass m(m_requestMutex); - - ++m_requestCount; - m_requests.push(req); -} - -Bool GameResultsQueue::getRequest( GameResultsRequest& req ) -{ - MutexClass::LockClass m(m_requestMutex, 0); - if (m.Failed()) - return false; - - if (m_requests.empty()) - return false; - req = m_requests.front(); - m_requests.pop(); - return true; -} - -void GameResultsQueue::addResponse( const GameResultsResponse& resp ) -{ - { - MutexClass::LockClass m(m_responseMutex); - - ++m_responseCount; - m_responses.push(resp); - } -} - -Bool GameResultsQueue::getResponse( GameResultsResponse& resp ) -{ - MutexClass::LockClass m(m_responseMutex, 0); - if (m.Failed()) - return false; - - if (m_responses.empty()) - return false; - resp = m_responses.front(); - m_responses.pop(); - return true; -} - -Bool GameResultsQueue::areGameResultsBeingSent( void ) -{ - MutexClass::LockClass m(m_requestMutex, 0); - if (m.Failed()) - return true; - - return m_requestCount > 0; -} - -//------------------------------------------------------------------------- - -void GameResultsThreadClass::Thread_Function() -{ - try { - GameResultsRequest req; - - WSADATA wsaData; - - // Fire up winsock (prob already done, but doesn't matter) - WORD wVersionRequested = MAKEWORD(1, 1); - WSAStartup( wVersionRequested, &wsaData ); - - while ( running ) - { - // deal with requests - if (TheGameResultsQueue && TheGameResultsQueue->getRequest(req)) - { - // resolve the hostname - const char *hostnameBuffer = req.hostname.c_str(); - UnsignedInt IP = 0xFFFFFFFF; - if (isdigit(hostnameBuffer[0])) - { - IP = inet_addr(hostnameBuffer); - in_addr hostNode; - hostNode.s_addr = IP; - DEBUG_LOG(("sending game results to %s - IP = %s", hostnameBuffer, inet_ntoa(hostNode) )); - } - else - { - HOSTENT *hostStruct; - in_addr *hostNode; - hostStruct = gethostbyname(hostnameBuffer); - if (hostStruct == NULL) - { - DEBUG_LOG(("sending game results to %s - host lookup failed", hostnameBuffer)); - - // Even though this failed to resolve IP, still need to send a - // callback. - IP = 0xFFFFFFFF; // flag for IP resolve failed - } - else - { - hostNode = (in_addr *) hostStruct->h_addr; - IP = hostNode->s_addr; - DEBUG_LOG(("sending game results to %s IP = %s", hostnameBuffer, inet_ntoa(*hostNode) )); - } - } - - int result = sendGameResults( IP, req.port, req.results ); - GameResultsResponse resp; - resp.hostname = req.hostname; - resp.port = req.port; - resp.sentOk = (result == req.results.length()); - - } - - // end our timeslice - Switch_Thread(); - } - - WSACleanup(); - } catch ( ... ) { - DEBUG_CRASH(("Exception in results thread!")); - } -} - -//------------------------------------------------------------------------- - -#ifdef DEBUG_LOGGING -#define CASE(x) case (x): return #x; - -static const char *getWSAErrorString( Int error ) -{ - switch (error) - { - CASE(WSABASEERR) - CASE(WSAEINTR) - CASE(WSAEBADF) - CASE(WSAEACCES) - CASE(WSAEFAULT) - CASE(WSAEINVAL) - CASE(WSAEMFILE) - CASE(WSAEWOULDBLOCK) - CASE(WSAEINPROGRESS) - CASE(WSAEALREADY) - CASE(WSAENOTSOCK) - CASE(WSAEDESTADDRREQ) - CASE(WSAEMSGSIZE) - CASE(WSAEPROTOTYPE) - CASE(WSAENOPROTOOPT) - CASE(WSAEPROTONOSUPPORT) - CASE(WSAESOCKTNOSUPPORT) - CASE(WSAEOPNOTSUPP) - CASE(WSAEPFNOSUPPORT) - CASE(WSAEAFNOSUPPORT) - CASE(WSAEADDRINUSE) - CASE(WSAEADDRNOTAVAIL) - CASE(WSAENETDOWN) - CASE(WSAENETUNREACH) - CASE(WSAENETRESET) - CASE(WSAECONNABORTED) - CASE(WSAECONNRESET) - CASE(WSAENOBUFS) - CASE(WSAEISCONN) - CASE(WSAENOTCONN) - CASE(WSAESHUTDOWN) - CASE(WSAETOOMANYREFS) - CASE(WSAETIMEDOUT) - CASE(WSAECONNREFUSED) - CASE(WSAELOOP) - CASE(WSAENAMETOOLONG) - CASE(WSAEHOSTDOWN) - CASE(WSAEHOSTUNREACH) - CASE(WSAENOTEMPTY) - CASE(WSAEPROCLIM) - CASE(WSAEUSERS) - CASE(WSAEDQUOT) - CASE(WSAESTALE) - CASE(WSAEREMOTE) - CASE(WSAEDISCON) - CASE(WSASYSNOTREADY) - CASE(WSAVERNOTSUPPORTED) - CASE(WSANOTINITIALISED) - CASE(WSAHOST_NOT_FOUND) - CASE(WSATRY_AGAIN) - CASE(WSANO_RECOVERY) - CASE(WSANO_DATA) - default: - return "Not a Winsock error"; - } -} - -#undef CASE - -#endif -//------------------------------------------------------------------------- - -Int GameResultsThreadClass::sendGameResults( UnsignedInt IP, UnsignedShort port, const std::string& results ) -{ - int error = 0; - - // create the socket - Int sock = socket( AF_INET, SOCK_STREAM, 0 ); - if (sock < 0) - { - DEBUG_LOG(("GameResultsThreadClass::sendGameResults() - socket() returned %d(%s)", sock, getWSAErrorString(sock))); - return sock; - } - - // fill in address info - struct sockaddr_in sockAddr; - memset( &sockAddr, 0, sizeof( sockAddr ) ); - sockAddr.sin_family = AF_INET; - sockAddr.sin_addr.s_addr = IP; - sockAddr.sin_port = htons(port); - - // Start the connection process.... - if( connect( sock, (struct sockaddr *)&sockAddr, sizeof( sockAddr ) ) == -1 ) - { - error = WSAGetLastError(); - DEBUG_LOG(("GameResultsThreadClass::sendGameResults() - connect() returned %d(%s)", error, getWSAErrorString(error))); - if( ( error == WSAEWOULDBLOCK ) || ( error == WSAEINVAL ) || ( error == WSAEALREADY ) ) - { - return( -1 ); - } - - if( error != WSAEISCONN ) - { - closesocket( sock ); - return( -1 ); - } - } - - if (send( sock, results.c_str(), results.length(), 0 ) == SOCKET_ERROR) - { - error = WSAGetLastError(); - DEBUG_LOG(("GameResultsThreadClass::sendGameResults() - send() returned %d(%s)", error, getWSAErrorString(error))); - closesocket(sock); - return WSAGetLastError(); - } - - closesocket(sock); - - return results.length(); -} - - -//------------------------------------------------------------------------- diff --git a/Generals/Code/GameEngine/Source/GameNetwork/GameSpy/Thread/PeerThread.cpp b/Generals/Code/GameEngine/Source/GameNetwork/GameSpy/Thread/PeerThread.cpp deleted file mode 100644 index 92ae388c5a..0000000000 --- a/Generals/Code/GameEngine/Source/GameNetwork/GameSpy/Thread/PeerThread.cpp +++ /dev/null @@ -1,2999 +0,0 @@ -/* -** 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. // -// // -//////////////////////////////////////////////////////////////////////////////// - -// FILE: PeerThread.cpp ////////////////////////////////////////////////////// -// GameSpy Peer (chat) thread -// This thread communicates with GameSpy's chat server -// and talks through a message queue with the rest of -// the game. -// Author: Matthew D. Campbell, June 2002 - -#include "PreRTS.h" // This must go first in EVERY cpp file in the GameEngine - -#include "Common/Registry.h" -#include "Common/UserPreferences.h" -#include "Common/version.h" -#include "GameNetwork/IPEnumeration.h" -#include "GameNetwork/GameSpy/BuddyThread.h" -#include "GameNetwork/GameSpy/PeerDefs.h" -#include "GameNetwork/GameSpy/PeerThread.h" -#include "GameNetwork/GameSpy/PersistentStorageThread.h" -#include "GameNetwork/GameSpy/ThreadUtils.h" - -#include "strtok_r.h" -#include "mutex.h" -#include "thread.h" - -#include "Common/MiniLog.h" - - -// enable this for trying to track down why SBServers are losing their keyvals -MDC 2/20/2003 -#undef SERVER_DEBUGGING -#ifdef SERVER_DEBUGGING -void CheckServers(PEER peer); -#endif // SERVER_DEBUGGING - -#ifdef DEBUG_LOGGING -//#define PING_TEST -static LogClass s_pingLog("Ping.txt"); -#define PING_LOG(x) s_pingLog.log x -#else // DEBUG_LOGGING -#define PING_LOG(x) {} -#endif // DEBUG_LOGGING - -#ifdef DEBUG_LOGGING -static LogClass s_stateChangedLog("StateChanged.txt"); - -#define STATECHANGED_LOG(x) s_stateChangedLog.log x - -#else // DEBUG_LOGGING - -#define STATECHANGED_LOG(x) {} - -#endif // DEBUG_LOGGING - -// we should always be using broadcast keys from now on. Remove the old code sometime when -// we're not in a rush, ok? -// -MDC 2/14/2003 -#define USE_BROADCAST_KEYS - - -int isThreadHosting = 0; -static UnsignedInt s_lastStateChangedHeartbeat = 0; -static Bool s_wantStateChangedHeartbeat = FALSE; -static UnsignedInt s_heartbeatInterval = 10000; - -static SOCKET qr2Sock = INVALID_SOCKET; - -enum -{ - EXECRC_KEY = NUM_RESERVED_KEYS + 1, - INICRC_KEY, - PW_KEY, - OBS_KEY, -#if !RTS_GENERALS - USE_STATS_KEY, -#endif - LADIP_KEY, - LADPORT_KEY, - PINGSTR_KEY, - NUMPLAYER_KEY, - MAXPLAYER_KEY, - NUMOBS_KEY, - NAME__KEY, - FACTION__KEY, - COLOR__KEY, - WINS__KEY, - LOSSES__KEY -}; - -#define EXECRC_STR "exeCRC" -#define INICRC_STR "iniCRC" -#define PW_STR "pw" -#define OBS_STR "obs" -#define USE_STATS_STR "stat" -#define LADIP_STR "ladIP" -#define LADPORT_STR "ladPort" -#define PINGSTR_STR "pings" -#define NUMPLAYER_STR "numRealPlayers" -#define MAXPLAYER_STR "maxRealPlayers" -#define NUMOBS_STR "numObservers" -#define NAME__STR "name" -#define FACTION__STR "faction" -#define COLOR__STR "color" -#define WINS__STR "wins" -#define LOSSES__STR "losses" - -//------------------------------------------------------------------------- - -typedef std::queue RequestQueue; -typedef std::queue ResponseQueue; -class PeerThreadClass; - -class GameSpyPeerMessageQueue : public GameSpyPeerMessageQueueInterface -{ -public: - virtual ~GameSpyPeerMessageQueue(); - GameSpyPeerMessageQueue(); - virtual void startThread( void ); - virtual void endThread( void ); - virtual Bool isThreadRunning( void ); - virtual Bool isConnected( void ); - virtual Bool isConnecting( void ); - - virtual void addRequest( const PeerRequest& req ); - virtual Bool getRequest( PeerRequest& req ); - - virtual void addResponse( const PeerResponse& resp ); - virtual Bool getResponse( PeerResponse& resp ); - - virtual SerialAuthResult getSerialAuthResult( void ) { return m_serialAuth; } - void setSerialAuthResult( SerialAuthResult result ) { m_serialAuth = result; } - - PeerThreadClass* getThread( void ); - -private: - MutexClass m_requestMutex; - MutexClass m_responseMutex; - RequestQueue m_requests; - ResponseQueue m_responses; - PeerThreadClass *m_thread; - - SerialAuthResult m_serialAuth; -}; - -GameSpyPeerMessageQueueInterface* GameSpyPeerMessageQueueInterface::createNewMessageQueue( void ) -{ - return NEW GameSpyPeerMessageQueue; -} - -GameSpyPeerMessageQueueInterface *TheGameSpyPeerMessageQueue; -#define MESSAGE_QUEUE ((GameSpyPeerMessageQueue *)TheGameSpyPeerMessageQueue) - -//------------------------------------------------------------------------- - -class PeerThreadClass : public ThreadClass -{ - -public: - PeerThreadClass() : ThreadClass() - { - //Added By Sadullah Nader - //Initializations inserted - m_roomJoined = m_allowObservers = m_hasPassword = FALSE; - m_useStats = TRUE; - m_exeCRC = m_iniCRC = 0; - m_gameVersion = 0; - m_ladderPort = 0; - m_localRoomID = 0; - m_maxPlayers = 0; - m_numObservers = 0; - m_maxPlayers = 0; - m_qmGroupRoom = 0; - m_sawEndOfEnumPlayers = m_sawMatchbot = FALSE; - m_sawCompleteGameList = FALSE; - // - m_isConnecting = m_isConnected = false; - m_groupRoomID = m_profileID = 0; - m_nextStagingServer = 1; m_stagingServers.clear(); - m_pingStr = ""; m_mapName = ""; m_ladderIP = ""; m_isHosting = false; - for (Int i=0; i PlayerStatMap; - PlayerStatMap m_groupRoomStats; - PlayerStatMap m_stagingRoomStats; - std::string packStatKey(const char *nick, const char *key); -#endif // USE_BROADCAST_KEYS - - // game-hosting info for GOA callbacks - Bool m_isHosting; - Bool m_hasPassword; - std::string m_mapName; - std::string m_playerNames[MAX_SLOTS]; - UnsignedInt m_exeCRC; - UnsignedInt m_iniCRC; - UnsignedInt m_gameVersion; - Bool m_allowObservers; - Bool m_useStats; - std::string m_pingStr; - std::string m_ladderIP; - UnsignedShort m_ladderPort; - Int m_playerWins[MAX_SLOTS]; - Int m_playerLosses[MAX_SLOTS]; - Int m_playerProfileID[MAX_SLOTS]; - Int m_playerColors[MAX_SLOTS]; - Int m_playerFactions[MAX_SLOTS]; - Int m_numPlayers; - Int m_maxPlayers; - Int m_numObservers; - - Int m_nextStagingServer; - std::map m_stagingServers; - std::wstring m_localStagingServerName; - Int m_localRoomID; - - void doQuickMatch( PEER peer ); - QMStatus m_qmStatus; - PeerRequest m_qmInfo; - Bool m_roomJoined; - Int m_qmGroupRoom; - Bool m_sawEndOfEnumPlayers; - Bool m_sawMatchbot; - std::string m_matchbotName; -}; - -#ifdef USE_BROADCAST_KEYS -const char* PeerThreadClass::s_keys[6] = { "b_locale", "b_wins", "b_losses", "b_points", "b_side", "b_pre" }; -char PeerThreadClass::s_valueBuffers[6][20] = { "", "", "", "", "", "" }; -const char* PeerThreadClass::s_values[6] = { s_valueBuffers[0], s_valueBuffers[1], s_valueBuffers[2], - s_valueBuffers[3], s_valueBuffers[4], s_valueBuffers[5]}; - -void PeerThreadClass::trackStatsForPlayer(RoomType roomType, const char *nick, const char *key, const char *val) -{ - switch (roomType) - { - case GroupRoom: - m_groupRoomStats[packStatKey(nick, key)] = atoi(val); - break; - case StagingRoom: - m_stagingRoomStats[packStatKey(nick, key)] = atoi(val); - break; - } -} - -std::string PeerThreadClass::packStatKey(const char *nick, const char *key) -{ - std::string s = nick; - s.append(key); - return s; -} - -int PeerThreadClass::lookupStatForPlayer(RoomType roomType, const char *nick, const char *key) -{ - std::string fullKey = packStatKey(nick, key); - PlayerStatMap::const_iterator it; - switch (roomType) - { - case GroupRoom: - it = m_groupRoomStats.find(fullKey); - if (it != m_groupRoomStats.end()) - return it->second; - break; - case StagingRoom: - it = m_stagingRoomStats.find(fullKey); - if (it != m_stagingRoomStats.end()) - return it->second; - break; - } - return 0; -} - -void PeerThreadClass::clearPlayerStats(RoomType roomType) -{ - switch (roomType) - { - case GroupRoom: - m_groupRoomStats.clear(); - break; - case StagingRoom: - m_stagingRoomStats.clear(); - break; - } -} - -void PeerThreadClass::pushStatsToRoom(PEER peer) -{ - DEBUG_LOG(("PeerThreadClass::pushStatsToRoom(): stats are %s=%s,%s=%s,%s=%s,%s=%s,%s=%s,%s=%s", - s_keys[0], s_values[0], - s_keys[1], s_values[1], - s_keys[2], s_values[2], - s_keys[3], s_values[3], - s_keys[4], s_values[4], - s_keys[5], s_values[5])); - peerSetRoomKeys(peer, GroupRoom, m_loginName.c_str(), 6, s_keys, s_values); - peerSetRoomKeys(peer, StagingRoom, m_loginName.c_str(), 6, s_keys, s_values); -} - -void getRoomKeysCallback(PEER peer, PEERBool success, RoomType roomType, const char *nick, int num, char **keys, char **values, void *param); -void PeerThreadClass::getStatsFromRoom(PEER peer, RoomType roomType) -{ - peerGetRoomKeys(peer, GroupRoom, "*", NumKeys, s_keys, getRoomKeysCallback, this, PEERFalse); -} -#endif // USE_BROADCAST_KEYS - -Int PeerThreadClass::addServerToMap( SBServer server ) -{ - Int val = m_nextStagingServer++; - m_stagingServers[val] = server; - return val; -} - -Int PeerThreadClass::removeServerFromMap( SBServer server ) -{ - for (std::map::iterator it = m_stagingServers.begin(); it != m_stagingServers.end(); ++it) - { - if (it->second == server) - { - Int val = it->first; - m_stagingServers.erase(it); - return val; - } - } - - return 0; -} - -void PeerThreadClass::clearServers( void ) -{ - m_stagingServers.clear(); -} - -SBServer PeerThreadClass::findServerByID( Int id ) -{ - std::map::iterator it = m_stagingServers.find(id); - if (it != m_stagingServers.end()) - { - SBServer server = it->second; - if (server && !server->keyvals) - { - DEBUG_CRASH(("Referencing a missing server!")); - return 0; - } - return it->second; - } - return 0; -} - -Int PeerThreadClass::findServer( SBServer server ) -{ - char tmp[10] = ""; - const char *newName = SBServerGetStringValue(server, "gamename", tmp); - UnsignedInt newPrivateIP = SBServerGetPrivateInetAddress(server); - UnsignedShort newPrivatePort = SBServerGetPrivateQueryPort(server); - UnsignedInt newPublicIP = SBServerGetPublicInetAddress(server); - - SBServer serverToRemove = NULL; - - for (std::map::iterator it = m_stagingServers.begin(); it != m_stagingServers.end(); ++it) - { - if (it->second == server) - { - return it->first; - } - else - { - const char *oldName = SBServerGetStringValue(it->second, "gamename", tmp); - UnsignedInt oldPrivateIP = SBServerGetPrivateInetAddress(it->second); - UnsignedShort oldPrivatePort = SBServerGetPrivateQueryPort(it->second); - UnsignedInt oldPublicIP = SBServerGetPublicInetAddress(it->second); - if (!strcmp(oldName, newName) && - oldPrivateIP == newPrivateIP && - oldPublicIP == newPublicIP && - oldPrivatePort == newPrivatePort) - { - serverToRemove = it->second; - } - } - } - - if (serverToRemove) - { - // this is the same as another game - it has just migrated to another port. Remove the old and replace it. - PeerResponse resp; - resp.peerResponseType = PeerResponse::PEERRESPONSE_STAGINGROOM; - resp.stagingRoom.id = removeServerFromMap( serverToRemove ); - resp.stagingRoom.action = PEER_REMOVE; - resp.stagingRoom.isStaging = TRUE; - resp.stagingRoom.percentComplete = -1; - TheGameSpyPeerMessageQueue->addResponse(resp); - } - - return addServerToMap(server); -} - -enum CallbackType -{ - CALLBACK_CONNECT, - CALLBACK_ERROR, - CALLBACK_RECVMESSAGE, - CALLBACK_RECVREQUEST, - CALLBACK_RECVSTATUS, -}; - -void connectCallbackWrapper( PEER peer, PEERBool success, int failureReason, void *param ) -{ -#ifdef SERVER_DEBUGGING - DEBUG_LOG(("In connectCallbackWrapper()")); - CheckServers(peer); -#endif // SERVER_DEBUGGING - if (param != NULL) - { - ((PeerThreadClass *)param)->connectCallback( peer, success ); - } -} - -void nickErrorCallbackWrapper( PEER peer, Int type, const char *nick, int numSuggestedNicks, const gsi_char** suggestedNicks, void *param ) -{ - if (param != NULL) - { - ((PeerThreadClass *)param)->nickErrorCallback( peer, type, nick ); - } -} - -static void joinRoomCallback(PEER peer, PEERBool success, PEERJoinResult result, RoomType roomType, void *param); - -//------------------------------------------------------------------------- - -GameSpyPeerMessageQueue::GameSpyPeerMessageQueue() -{ - m_thread = NULL; - m_serialAuth = SERIAL_OK; -} - -GameSpyPeerMessageQueue::~GameSpyPeerMessageQueue() -{ - endThread(); -} - -void GameSpyPeerMessageQueue::startThread( void ) -{ - if (!m_thread) - { - m_thread = NEW PeerThreadClass; - m_thread->Execute(); - } - else - { - if (!m_thread->Is_Running()) - { - m_thread->Execute(); - } - } -} - -void GameSpyPeerMessageQueue::endThread( void ) -{ - delete m_thread; - m_thread = NULL; -} - -Bool GameSpyPeerMessageQueue::isThreadRunning( void ) -{ - return (m_thread) ? m_thread->Is_Running() : false; -} - -Bool GameSpyPeerMessageQueue::isConnected( void ) -{ - return (m_thread) ? m_thread->isConnected() : false; -} - -Bool GameSpyPeerMessageQueue::isConnecting( void ) -{ - return (m_thread) ? m_thread->isConnecting() : false; -} - -void GameSpyPeerMessageQueue::addRequest( const PeerRequest& req ) -{ - MutexClass::LockClass m(m_requestMutex); - if (m.Failed()) - return; - - m_requests.push(req); -} - -//PeerRequest GameSpyPeerMessageQueue::getRequest( void ) -Bool GameSpyPeerMessageQueue::getRequest( PeerRequest& req ) -{ - MutexClass::LockClass m(m_requestMutex, 0); - if (m.Failed()) - return false; - - if (m_requests.empty()) - return false; - req = m_requests.front(); - m_requests.pop(); - return true; -} - -void GameSpyPeerMessageQueue::addResponse( const PeerResponse& resp ) -{ - if (resp.nick == "(END)") - return; - - MutexClass::LockClass m(m_responseMutex); - if (m.Failed()) - return; - - m_responses.push(resp); -} - -//PeerResponse GameSpyPeerMessageQueue::getResponse( void ) -Bool GameSpyPeerMessageQueue::getResponse( PeerResponse& resp ) -{ - MutexClass::LockClass m(m_responseMutex, 0); - if (m.Failed()) - return false; - - if (m_responses.empty()) - return false; - resp = m_responses.front(); - m_responses.pop(); - return true; -} - -PeerThreadClass* GameSpyPeerMessageQueue::getThread( void ) -{ - return m_thread; -} - -//------------------------------------------------------------------------- -static void disconnectedCallback(PEER peer, const char * reason, void * param); -static void roomMessageCallback(PEER peer, RoomType roomType, const char * nick, const char * message, MessageType messageType, void * param); -static void playerMessageCallback(PEER peer, const char * nick, const char * message, MessageType messageType, void * param); -static void playerJoinedCallback(PEER peer, RoomType roomType, const char * nick, void * param); -static void playerLeftCallback(PEER peer, RoomType roomType, const char * nick, const char * reason, void * param); -static void playerChangedNickCallback(PEER peer, RoomType roomType, const char * oldNick, const char * newNick, void * param); -static void playerInfoCallback(PEER peer, RoomType roomType, const char * nick, unsigned int IP, int profileID, void * param); -static void playerFlagsChangedCallback(PEER peer, RoomType roomType, const char * nick, int oldFlags, int newFlags, void * param); -static void listingGamesCallback(PEER peer, PEERBool success, const char * name, SBServer server, PEERBool staging, int msg, Int percentListed, void * param); -static void roomUTMCallback(PEER peer, RoomType roomType, const char * nick, const char * command, const char * parameters, PEERBool authenticated, void * param); -static void playerUTMCallback(PEER peer, const char * nick, const char * command, const char * parameters, PEERBool authenticated, void * param); -static void gameStartedCallback(PEER peer, SBServer server, const char *message, void *param); -static void globalKeyChangedCallback(PEER peer, const char *nick, const char *key, const char *val, void *param); -static void roomKeyChangedCallback(PEER peer, RoomType roomType, const char *nick, const char *key, const char *val, void *param); - -// convenience function to set buddy status -static void updateBuddyStatus( GameSpyBuddyStatus status, Int groupRoom = 0, std::string gameName = "" ) -{ - if (!TheGameSpyBuddyMessageQueue) - return; - - BuddyRequest req; - req.buddyRequestType = BuddyRequest::BUDDYREQUEST_SETSTATUS; - switch(status) - { - case BUDDY_OFFLINE: - req.arg.status.status = GP_OFFLINE; - strcpy(req.arg.status.statusString, "Offline"); - strcpy(req.arg.status.locationString, ""); - break; - case BUDDY_ONLINE: - req.arg.status.status = GP_ONLINE; - strcpy(req.arg.status.statusString, "Online"); - strcpy(req.arg.status.locationString, ""); - break; - case BUDDY_LOBBY: - req.arg.status.status = GP_CHATTING; - strcpy(req.arg.status.statusString, "Chatting"); - sprintf(req.arg.status.locationString, "%d", groupRoom); - break; - case BUDDY_STAGING: - req.arg.status.status = GP_STAGING; - strcpy(req.arg.status.statusString, "Staging"); - sprintf(req.arg.status.locationString, "%s", gameName.c_str()); - break; - case BUDDY_LOADING: - req.arg.status.status = GP_PLAYING; - strcpy(req.arg.status.statusString, "Loading"); - sprintf(req.arg.status.locationString, "%s", gameName.c_str()); - break; - case BUDDY_PLAYING: - req.arg.status.status = GP_PLAYING; - strcpy(req.arg.status.statusString, "Playing"); - sprintf(req.arg.status.locationString, "%s", gameName.c_str()); - break; - case BUDDY_MATCHING: - req.arg.status.status = GP_ONLINE; - strcpy(req.arg.status.statusString, "Matching"); - strcpy(req.arg.status.locationString, ""); - break; - } - DEBUG_LOG(("updateBuddyStatus %d:%s", req.arg.status.status, req.arg.status.statusString)); - TheGameSpyBuddyMessageQueue->addRequest(req); -} - -static void createRoomCallback(PEER peer, PEERBool success, PEERJoinResult result, RoomType roomType, void *param) -{ - Int *s = (Int *)param; - if (s) - *s = result; -} - -static const char * KeyTypeToString(qr2_key_type type) -{ - switch(type) - { - case key_server: - return "server"; - case key_player: - return "player"; - case key_team: - return "team"; - } - - return "Unkown key type"; -} - -static const char * ErrorTypeToString(qr2_error_t error) -{ - switch(error) - { - case e_qrnoerror: - return "noerror"; - case e_qrwsockerror: - return "wsockerror"; - case e_qrbinderror: - return "rbinderror"; - case e_qrdnserror: - return "dnserror"; - case e_qrconnerror: - return "connerror"; - } - - return "Unknown error type"; -} - -static void QRServerKeyCallback -( - PEER peer, - int key, - qr2_buffer_t buffer, - void * param -) -{ - //DEBUG_LOG(("QR_SERVER_KEY | %d (%s)", key, qr2_registered_key_list[key])); - PeerThreadClass *t = (PeerThreadClass *)param; - if (!t) - { - DEBUG_LOG(("QRServerKeyCallback: bailing because of no thread info")); - return; - } - - if (!t->isHosting()) - t->stopHostingAlready(peer); - -#ifdef DEBUG_LOGGING - AsciiString val = ""; -#define ADD(x) { qr2_buffer_add(buffer, x); val = x; } -#define ADDINT(x) { qr2_buffer_add_int(buffer, x); val.format("%d",x); } -#else -#define ADD(x) { qr2_buffer_add(buffer, x); } -#define ADDINT(x) { qr2_buffer_add_int(buffer, x); } -#endif - - switch(key) - { - case HOSTNAME_KEY: - ADD(t->getPlayerName(0).c_str()); - break; - case GAMEVER_KEY: - ADDINT(t->gameVersion()); - break; - case EXECRC_KEY: - ADDINT(t->exeCRC()); - break; - case INICRC_KEY: - ADDINT(t->iniCRC()); - break; - case GAMENAME_KEY: - { - std::string tmp = t->getPlayerName(0); - tmp.append(" "); - tmp.append(WideCharStringToMultiByte(t->getLocalStagingServerName().c_str())); - ADD(tmp.c_str()); - } - break; - case MAPNAME_KEY: - ADD(t->getMapName().c_str()); - break; - case PW_KEY: - ADDINT(t->hasPassword()); - break; - case OBS_KEY: - ADDINT(t->allowObservers()); - break; -#if !RTS_GENERALS - case USE_STATS_KEY: - ADDINT(t->useStats()); - break; -#endif - case LADIP_KEY: - ADD(t->ladderIP().c_str()); - break; - case LADPORT_KEY: - ADDINT(t->ladderPort()); - break; - case PINGSTR_KEY: - ADD(t->pingStr().c_str()); - break; - case NUMPLAYER_KEY: - ADDINT(t->getNumPlayers()); - break; - case MAXPLAYER_KEY: - ADDINT(t->getMaxPlayers()); - break; - case NUMOBS_KEY: - ADDINT(t->getNumObservers()); - break; - default: - ADD(""); - //DEBUG_LOG(("QR_SERVER_KEY | %d (%s)", key, qr2_registered_key_list[key])); - break; - } - - DEBUG_LOG(("QR_SERVER_KEY | %d (%s) = [%s]", key, qr2_registered_key_list[key], val.str())); -} - -static void QRPlayerKeyCallback -( - PEER peer, - int key, - int index, - qr2_buffer_t buffer, - void * param -) -{ - //DEBUG_LOG(("QR_PLAYER_KEY | %d | %d (%s)", key, index, qr2_registered_key_list[key])); - PeerThreadClass *t = (PeerThreadClass *)param; - if (!t) - { - DEBUG_LOG(("QRPlayerKeyCallback: bailing because of no thread info")); - return; - } - - if (!t->isHosting()) - t->stopHostingAlready(peer); - -#undef ADD -#undef ADDINT -#ifdef DEBUG_LOGGING - AsciiString val = ""; -#define ADD(x) { qr2_buffer_add(buffer, x); val = x; } -#define ADDINT(x) { qr2_buffer_add_int(buffer, x); val.format("%d",x); } -#else -#define ADD(x) { qr2_buffer_add(buffer, x); } -#define ADDINT(x) { qr2_buffer_add_int(buffer, x); } -#endif - - switch(key) - { - case NAME__KEY: - ADD(t->getPlayerName(index).c_str()); - break; - case WINS__KEY: - ADDINT(t->getPlayerWins(index)); - break; - case LOSSES__KEY: - ADDINT(t->getPlayerLosses(index)); - break; - case PID__KEY: - ADDINT(t->getPlayerProfileID(index)); - break; - case FACTION__KEY: - ADDINT(t->getPlayerLosses(index)); - break; - case COLOR__KEY: - ADDINT(t->getPlayerLosses(index)); - break; - default: - ADD(""); - //DEBUG_LOG(("QR_PLAYER_KEY | %d | %d (%s)", key, index, qr2_registered_key_list[key])); - break; - } - - DEBUG_LOG(("QR_PLAYER_KEY | %d | %d (%s) = [%s]", key, index, qr2_registered_key_list[key], val.str())); -} - -static void QRTeamKeyCallback -( - PEER peer, - int key, - int index, - qr2_buffer_t buffer, - void * param -) -{ - //DEBUG_LOG(("QR_TEAM_KEY | %d | %d", key, index)); - - PeerThreadClass *t = (PeerThreadClass *)param; - if (!t) - { - DEBUG_LOG(("QRTeamKeyCallback: bailing because of no thread info")); - return; - } - if (!t->isHosting()) - t->stopHostingAlready(peer); - - // we don't report teams, so this shouldn't get called - qr2_buffer_add(buffer, ""); -} - -static void QRKeyListCallback -( - PEER peer, - qr2_key_type type, - qr2_keybuffer_t keyBuffer, - void * param -) -{ - DEBUG_LOG(("QR_KEY_LIST | %s", KeyTypeToString(type))); - - /* - PeerThreadClass *t = (PeerThreadClass *)param; - if (!t) - { - DEBUG_LOG(("QRKeyListCallback: bailing because of no thread info")); - return; - } - if (!t->isHosting()) - t->stopHostingAlready(peer); - */ - - // register the keys we use - switch(type) - { - case key_server: - qr2_keybuffer_add(keyBuffer, HOSTNAME_KEY); - qr2_keybuffer_add(keyBuffer, GAMEVER_KEY); - //qr2_keybuffer_add(keyBuffer, GAMENAME_KEY); - qr2_keybuffer_add(keyBuffer, MAPNAME_KEY); - qr2_keybuffer_add(keyBuffer, EXECRC_KEY); - qr2_keybuffer_add(keyBuffer, INICRC_KEY); - qr2_keybuffer_add(keyBuffer, PW_KEY); - qr2_keybuffer_add(keyBuffer, OBS_KEY); -#if !RTS_GENERALS - qr2_keybuffer_add(keyBuffer, USE_STATS_KEY); -#endif - qr2_keybuffer_add(keyBuffer, LADIP_KEY); - qr2_keybuffer_add(keyBuffer, LADPORT_KEY); - qr2_keybuffer_add(keyBuffer, PINGSTR_KEY); - qr2_keybuffer_add(keyBuffer, NUMPLAYER_KEY); - qr2_keybuffer_add(keyBuffer, MAXPLAYER_KEY); - qr2_keybuffer_add(keyBuffer, NUMOBS_KEY); - break; - case key_player: - qr2_keybuffer_add(keyBuffer, NAME__KEY); - qr2_keybuffer_add(keyBuffer, WINS__KEY); - qr2_keybuffer_add(keyBuffer, LOSSES__KEY); - qr2_keybuffer_add(keyBuffer, PID__KEY); - qr2_keybuffer_add(keyBuffer, FACTION__KEY); - qr2_keybuffer_add(keyBuffer, COLOR__KEY); - break; - case key_team: - // no custom team keys - break; - } -} - -static int QRCountCallback -( - PEER peer, - qr2_key_type type, - void * param -) -{ - PeerThreadClass *t = (PeerThreadClass *)param; - if (!t) - { - DEBUG_LOG(("QRCountCallback: bailing because of no thread info")); - return 0; - } - if (!t->isHosting()) - t->stopHostingAlready(peer); - - if(type == key_player) - { - DEBUG_LOG(("QR_COUNT | %s = %d", KeyTypeToString(type), t->getNumPlayers() + t->getNumObservers())); - return t->getNumPlayers() + t->getNumObservers(); - } - else if(type == key_team) - { - DEBUG_LOG(("QR_COUNT | %s = %d", KeyTypeToString(type), 0)); - return 0; - } - - DEBUG_LOG(("QR_COUNT | %s = %d", KeyTypeToString(type), 0)); - return 0; -} - -void PeerThreadClass::stopHostingAlready(PEER peer) -{ - isThreadHosting = 0; // debugging - s_lastStateChangedHeartbeat = 0; - s_wantStateChangedHeartbeat = FALSE; - peerStopGame(peer); - if (qr2Sock != INVALID_SOCKET) - { - closesocket(qr2Sock); - qr2Sock = INVALID_SOCKET; - } -} - -static void QRAddErrorCallback -( - PEER peer, - qr2_error_t error, - char * errorString, - void * param -) -{ - DEBUG_LOG(("QR_ADD_ERROR | %s | %s", ErrorTypeToString(error), errorString)); - PeerResponse resp; - resp.peerResponseType = PeerResponse::PEERRESPONSE_FAILEDTOHOST; - TheGameSpyPeerMessageQueue->addResponse(resp); -} - -static void QRNatNegotiateCallback -( - PEER peer, - int cookie, - void * param -) -{ - DEBUG_LOG(("QR_NAT_NEGOTIATE | 0x%08X", cookie)); -} - -static void KickedCallback -( - PEER peer, - RoomType roomType, - const char * nick, - const char * reason, - void * param -) -{ - DEBUG_LOG(("Kicked from %d by %s: \"%s\"", roomType, nick, reason)); -} - -static void NewPlayerListCallback -( - PEER peer, - RoomType roomType, - void * param -) -{ - DEBUG_LOG(("NewPlayerListCallback")); -} - -static void AuthenticateCDKeyCallback -( - PEER peer, - int result, - const char * message, - void * param -) -{ - DEBUG_LOG(("CD Key Result: %s (%d) %X", message, result, param)); -#ifdef SERVER_DEBUGGING - CheckServers(peer); -#endif // SERVER_DEBUGGING - SerialAuthResult *val = (SerialAuthResult *)param; - if (val) - { - if (result >= 1) - { - *val = SERIAL_OK; - } - else - { - *val = SERIAL_AUTHFAILED; - } - } -#ifdef SERVER_DEBUGGING - CheckServers(peer); -#endif // SERVER_DEBUGGING -} - -static SerialAuthResult doCDKeyAuthentication( PEER peer ) -{ - SerialAuthResult retval = SERIAL_NONEXISTENT; - if (!peer) - return retval; - - AsciiString s = ""; - if (GetStringFromRegistry("\\ergc", "", s) && s.isNotEmpty()) - { -#ifdef SERVER_DEBUGGING - DEBUG_LOG(("Before peerAuthenticateCDKey()")); - CheckServers(peer); -#endif // SERVER_DEBUGGING - peerAuthenticateCDKey(peer, s.str(), AuthenticateCDKeyCallback, &retval, PEERTrue); -#ifdef SERVER_DEBUGGING - DEBUG_LOG(("After peerAuthenticateCDKey()")); - CheckServers(peer); -#endif // SERVER_DEBUGGING - } - - if (retval == SERIAL_OK) - { - PSRequest req; - req.requestType = PSRequest::PSREQUEST_READCDKEYSTATS; - req.cdkey = s.str(); - TheGameSpyPSMessageQueue->addRequest(req); - } - - return retval; -} - -#define INBUF_LEN 256 -void checkQR2Queries( PEER peer, SOCKET sock ) -{ - static char indata[INBUF_LEN]; - struct sockaddr_in saddr; - int saddrlen = sizeof(struct sockaddr_in); - fd_set set; - struct timeval timeout = {0,0}; - int error; - - FD_ZERO ( &set ); - FD_SET ( sock, &set ); - - while (1) - { - error = select(FD_SETSIZE, &set, NULL, NULL, &timeout); - if (SOCKET_ERROR == error || 0 == error) - return; - //else we have data - error = recvfrom(sock, indata, INBUF_LEN - 1, 0, (struct sockaddr *)&saddr, &saddrlen); - if (error != SOCKET_ERROR) - { - indata[error] = '\0'; - peerParseQuery( peer, indata, error, (sockaddr *)&saddr ); - } - } -} - -static UnsignedInt localIP = 0; - -void PeerThreadClass::Thread_Function() -{ - try { - - PEER peer; - - // Setup the callbacks. - /////////////////////// - PEERCallbacks callbacks; - memset(&callbacks, 0, sizeof(PEERCallbacks)); - callbacks.disconnected = disconnectedCallback; - //callbacks.readyChanged = readyChangedCallback; - callbacks.roomMessage = roomMessageCallback; - callbacks.playerMessage = playerMessageCallback; - callbacks.gameStarted = gameStartedCallback; - callbacks.playerJoined = playerJoinedCallback; - callbacks.playerLeft = playerLeftCallback; - callbacks.playerChangedNick = playerChangedNickCallback; - callbacks.playerFlagsChanged = playerFlagsChangedCallback; - callbacks.playerInfo = playerInfoCallback; - callbacks.roomUTM = roomUTMCallback; - callbacks.playerUTM = playerUTMCallback; - callbacks.globalKeyChanged = globalKeyChangedCallback; - callbacks.roomKeyChanged = roomKeyChangedCallback; - - callbacks.qrServerKey = QRServerKeyCallback; - callbacks.qrPlayerKey = QRPlayerKeyCallback; - callbacks.qrTeamKey = QRTeamKeyCallback; - callbacks.qrKeyList = QRKeyListCallback; - callbacks.qrCount = QRCountCallback; - callbacks.qrAddError = QRAddErrorCallback; - callbacks.qrNatNegotiateCallback = QRNatNegotiateCallback; - - callbacks.kicked = KickedCallback; - callbacks.newPlayerList = NewPlayerListCallback; - - callbacks.param = this; - - m_qmGroupRoom = 0; - - peer = peerInitialize( &callbacks ); - DEBUG_ASSERTCRASH( peer != NULL, ("NULL peer!") ); - m_isConnected = m_isConnecting = false; - - qr2_register_key(EXECRC_KEY, EXECRC_STR); - qr2_register_key(INICRC_KEY, INICRC_STR); - qr2_register_key(PW_KEY, PW_STR); - qr2_register_key(OBS_KEY, OBS_STR); -#if !RTS_GENERALS - qr2_register_key(USE_STATS_KEY, USE_STATS_STR); -#endif - qr2_register_key(LADIP_KEY, LADIP_STR); - qr2_register_key(LADPORT_KEY, LADPORT_STR); - qr2_register_key(PINGSTR_KEY, PINGSTR_STR); - qr2_register_key(NUMOBS_KEY, NUMOBS_STR); - qr2_register_key(NUMPLAYER_KEY, NUMPLAYER_STR); - qr2_register_key(MAXPLAYER_KEY, MAXPLAYER_STR); - qr2_register_key(NAME__KEY, NAME__STR "_"); - qr2_register_key(WINS__KEY, WINS__STR "_"); - qr2_register_key(LOSSES__KEY, LOSSES__STR "_"); - qr2_register_key(FACTION__KEY, FACTION__STR "_"); - qr2_register_key(COLOR__KEY, COLOR__STR "_"); - -#if RTS_GENERALS - const Int NumKeys = 14; -#else - const Int NumKeys = 15; -#endif - unsigned char allKeysArray[NumKeys] = { - /* - PID__KEY, - NAME__KEY, - WINS__KEY, - LOSSES__KEY, - FACTION__KEY, - COLOR__KEY, - */ - MAPNAME_KEY, - GAMEVER_KEY, - GAMENAME_KEY, - EXECRC_KEY, - INICRC_KEY, - PW_KEY, - OBS_KEY, -#if !RTS_GENERALS - USE_STATS_KEY, -#endif - LADIP_KEY, - LADPORT_KEY, - PINGSTR_KEY, - NUMOBS_KEY, - NUMPLAYER_KEY, - MAXPLAYER_KEY, - HOSTNAME_KEY - }; - - /* - const char *allKeys = "\\pid_\\mapname\\gamever\\gamename" \ - "\\" EXECRC_STR "\\" INICRC_STR \ - "\\" PW_STR "\\" OBS_STR "\\" USE_STATS_STR "\\" LADIP_STR "\\" LADPORT_STR \ - "\\" PINGSTR_STR "\\" NUMOBS_STR \ - "\\" NUMPLAYER_STR "\\" MAXPLAYER_STR \ - "\\" NAME__STR "_" "\\" WINS__STR "_" "\\" LOSSES__STR "_" "\\" FACTION__STR "_" "\\" COLOR__STR "_"; - */ - - const char * key = "username"; - peerSetRoomWatchKeys(peer, StagingRoom, 1, &key, PEERTrue); - peerSetRoomWatchKeys(peer, GroupRoom, 1, &key, PEERTrue); - - m_localRoomID = 0; - m_localStagingServerName = L""; - - m_qmStatus = QM_IDLE; - - // Setup which rooms to do pings and cross-pings in. - //////////////////////////////////////////////////// - PEERBool pingRooms[NumRooms]; - PEERBool crossPingRooms[NumRooms]; - pingRooms[TitleRoom] = PEERFalse; - pingRooms[GroupRoom] = PEERFalse; - pingRooms[StagingRoom] = PEERFalse; - crossPingRooms[TitleRoom] = PEERFalse; - crossPingRooms[GroupRoom] = PEERFalse; - crossPingRooms[StagingRoom] = PEERFalse; - - /********* - First step, set our game authentication info - We could do: - Generals: - strcpy(gcd_gamename,"ccgenerals"); - strcpy(gcd_secret_key,"h5T2f6"); - ZeroHour: - strcpy(gcd_gamename,"ccgenzh"); - strcpy(gcd_secret_key,"D6s9k3"); - or - Generals: - strcpy(gcd_gamename,"ccgeneralsb"); - strcpy(gcd_secret_key,"g3T9s2"); - ZeroHour: - strcpy(gcd_gamename,"ccgeneralsb"); - strcpy(gcd_secret_key,"whatever the key is"); - ...but this is more secure: - **********/ - char gameName[12] = {0}; - char secretKey[7] = {0}; - /** - gameName[0]='c';gameName[1]='c';gameName[2]='g';gameName[3]='e'; - gameName[4]='n';gameName[5]='e';gameName[6]='r';gameName[7]='a'; - gameName[8]='l';gameName[9]='s';gameName[10]='b';gameName[11]='\0'; - secretKey[0]='g';secretKey[1]='3';secretKey[2]='T';secretKey[3]='9'; - secretKey[4]='s';secretKey[5]='2';secretKey[6]='\0'; - /**/ -#if RTS_GENERALS - gameName[0]='c';gameName[1]='c';gameName[2]='g';gameName[3]='e'; - gameName[4]='n';gameName[5]='e';gameName[6]='r';gameName[7]='a'; - gameName[8]='l';gameName[9]='s';gameName[10]='\0'; - secretKey[0]='h';secretKey[1]='5';secretKey[2]='T';secretKey[3]='2'; - secretKey[4]='f';secretKey[5]='6';secretKey[6]='\0'; -#elif RTS_ZEROHOUR - gameName[0]='c';gameName[1]='c';gameName[2]='g';gameName[3]='e'; - gameName[4]='n';gameName[5]='z';gameName[6]='h';gameName[7]='\0'; - secretKey[0]='D';secretKey[1]='6';secretKey[2]='s';secretKey[3]='9'; - secretKey[4]='k';secretKey[5]='3';secretKey[6]='\0'; -#endif - /**/ - - // Set the title. - ///////////////// - if(!peerSetTitle( peer , gameName, secretKey, gameName, secretKey, GetRegistryVersion(), 30, PEERTrue, pingRooms, crossPingRooms)) - { - DEBUG_CRASH(("Error setting title")); - peerShutdown( peer ); - peer = NULL; - return; - } - - OptionPreferences pref; - UnsignedInt preferredIP = INADDR_ANY; - UnsignedInt selectedIP = pref.getOnlineIPAddress(); - DEBUG_LOG(("Looking for IP %X", selectedIP)); - IPEnumeration IPs; - EnumeratedIP *IPlist = IPs.getAddresses(); - while (IPlist) - { - DEBUG_LOG(("Looking at IP %s", IPlist->getIPstring().str())); - if (selectedIP == IPlist->getIP()) - { - preferredIP = IPlist->getIP(); - DEBUG_LOG(("Connecting to GameSpy chat server via IP address %8.8X", preferredIP)); - break; - } - IPlist = IPlist->getNext(); - } - chatSetLocalIP(preferredIP); - - UnsignedInt preferredQRPort = 0; - AsciiString selectedQRPort = pref["GameSpyQRPort"]; - if (selectedQRPort.isNotEmpty()) - { - preferredQRPort = atoi(selectedQRPort.str()); - } - - PeerRequest incomingRequest; - while ( running ) - { - // deal with requests - if (TheGameSpyPeerMessageQueue->getRequest(incomingRequest)) - { - DEBUG_LOG(("TheGameSpyPeerMessageQueue->getRequest() got request of type %d", incomingRequest.peerRequestType)); - switch (incomingRequest.peerRequestType) - { - case PeerRequest::PEERREQUEST_LOGIN: - { - m_isConnecting = true; - m_originalName = incomingRequest.nick; - m_loginName = incomingRequest.nick; - m_profileID = incomingRequest.login.profileID; - m_password = incomingRequest.password; - m_email = incomingRequest.email; - peerConnect( peer, incomingRequest.nick.c_str(), incomingRequest.login.profileID, nickErrorCallbackWrapper, connectCallbackWrapper, this, PEERTrue ); -#ifdef SERVER_DEBUGGING - DEBUG_LOG(("After peerConnect()")); - CheckServers(peer); -#endif // SERVER_DEBUGGING - if (m_isConnected) - { - SerialAuthResult ret = doCDKeyAuthentication( peer ); - if (ret != SERIAL_OK) - { - m_isConnecting = m_isConnected = false; - MESSAGE_QUEUE->setSerialAuthResult( ret ); - peerDisconnect( peer ); - } - } - m_isConnecting = false; - - // check our connection - //if (m_isConnected) - //{ - // GetLocalChatConnectionAddress("peerchat.gamespy.com", 6667, localIP); - //} - } - - break; - - case PeerRequest::PEERREQUEST_LOGOUT: - m_isConnecting = m_isConnected = false; - peerDisconnect( peer ); - break; - - case PeerRequest::PEERREQUEST_JOINGROUPROOM: - m_groupRoomID = incomingRequest.groupRoom.id; - isThreadHosting = 0; // debugging - s_lastStateChangedHeartbeat = 0; - s_wantStateChangedHeartbeat = FALSE; - peerStopGame( peer ); - peerLeaveRoom( peer, GroupRoom, NULL ); - peerLeaveRoom( peer, StagingRoom, NULL ); - if (qr2Sock != INVALID_SOCKET) - { - closesocket(qr2Sock); - qr2Sock = INVALID_SOCKET; - } - m_isHosting = false; - m_localRoomID = m_groupRoomID; - DEBUG_LOG(("Requesting to join room %d in thread %X", m_localRoomID, this)); - peerJoinGroupRoom( peer, incomingRequest.groupRoom.id, joinRoomCallback, (void *)this, PEERTrue ); - break; - - case PeerRequest::PEERREQUEST_LEAVEGROUPROOM: - m_groupRoomID = 0; - updateBuddyStatus( BUDDY_ONLINE ); - peerLeaveRoom( peer, GroupRoom, NULL ); - peerLeaveRoom( peer, StagingRoom, NULL ); m_isHosting = false; - break; - - case PeerRequest::PEERREQUEST_JOINSTAGINGROOM: - { - m_groupRoomID = 0; - updateBuddyStatus( BUDDY_ONLINE ); - peerLeaveRoom( peer, GroupRoom, NULL ); - peerLeaveRoom( peer, StagingRoom, NULL ); m_isHosting = false; - SBServer server = findServerByID(incomingRequest.stagingRoom.id); - m_localStagingServerName = incomingRequest.text; - DEBUG_LOG(("Setting m_localStagingServerName to [%ls]", m_localStagingServerName.c_str())); - m_localRoomID = incomingRequest.stagingRoom.id; - DEBUG_LOG(("Requesting to join room %d", m_localRoomID)); - if (server) - { - peerJoinStagingRoom( peer, server, incomingRequest.password.c_str(), joinRoomCallback, (void *)this, PEERTrue ); - } - else - { - PeerResponse resp; - resp.peerResponseType = PeerResponse::PEERRESPONSE_JOINSTAGINGROOM; - resp.joinStagingRoom.id = incomingRequest.stagingRoom.id; - resp.joinStagingRoom.ok = FALSE; - resp.joinStagingRoom.result = PEERJoinFailed; - TheGameSpyPeerMessageQueue->addResponse(resp); - } - } - break; - - case PeerRequest::PEERREQUEST_LEAVESTAGINGROOM: - m_groupRoomID = 0; - updateBuddyStatus( BUDDY_ONLINE ); - peerLeaveRoom( peer, GroupRoom, NULL ); - peerLeaveRoom( peer, StagingRoom, NULL ); - isThreadHosting = 0; // debugging - s_lastStateChangedHeartbeat = 0; - s_wantStateChangedHeartbeat = FALSE; - if (m_isHosting) - { - peerStopGame( peer ); - if (qr2Sock != INVALID_SOCKET) - { - closesocket(qr2Sock); - qr2Sock = INVALID_SOCKET; - } - m_isHosting = false; - } - break; - - case PeerRequest::PEERREQUEST_MESSAGEPLAYER: - { - std::string s = WideCharStringToMultiByte(incomingRequest.text.c_str()); - peerMessagePlayer( peer, incomingRequest.nick.c_str(), s.c_str(), (incomingRequest.message.isAction)?ActionMessage:NormalMessage ); - } - break; - - case PeerRequest::PEERREQUEST_MESSAGEROOM: - { - std::string s = WideCharStringToMultiByte(incomingRequest.text.c_str()); - peerMessageRoom( peer, (m_groupRoomID)?GroupRoom:StagingRoom, s.c_str(), (incomingRequest.message.isAction)?ActionMessage:NormalMessage ); - } - break; - - case PeerRequest::PEERREQUEST_PUSHSTATS: - { - DEBUG_LOG(("PEERREQUEST_PUSHSTATS: stats are %d,%d,%d,%d,%d,%d", - incomingRequest.statsToPush.locale, incomingRequest.statsToPush.wins, incomingRequest.statsToPush.losses, incomingRequest.statsToPush.rankPoints, incomingRequest.statsToPush.side, incomingRequest.statsToPush.preorder)); - - // Testing alternate way to push stats -#ifdef USE_BROADCAST_KEYS - snprintf(s_valueBuffers[0], 20, "%d", incomingRequest.statsToPush.locale); - snprintf(s_valueBuffers[1], 20, "%d", incomingRequest.statsToPush.wins); - snprintf(s_valueBuffers[2], 20, "%d", incomingRequest.statsToPush.losses); - snprintf(s_valueBuffers[3], 20, "%d", incomingRequest.statsToPush.rankPoints); - snprintf(s_valueBuffers[4], 20, "%d", incomingRequest.statsToPush.side); - snprintf(s_valueBuffers[5], 20, "%d", incomingRequest.statsToPush.preorder); - pushStatsToRoom(peer); -#else - const char *keys[6] = { "locale", "wins", "losses", "points", "side", "pre" }; - char valueStrings[6][20]; - char *values[6] = { valueStrings[0], valueStrings[1], valueStrings[2], - valueStrings[3], valueStrings[4], valueStrings[5]}; - snprintf(values[0], 20, "%d", incomingRequest.statsToPush.locale); - snprintf(values[1], 20, "%d", incomingRequest.statsToPush.wins); - snprintf(values[2], 20, "%d", incomingRequest.statsToPush.losses); - snprintf(values[3], 20, "%d", incomingRequest.statsToPush.rankPoints); - snprintf(values[4], 20, "%d", incomingRequest.statsToPush.side); - snprintf(values[5], 20, "%d", incomingRequest.statsToPush.preorder); - peerSetGlobalKeys(peer, 6, (const char **)keys, (const char **)values); - peerSetGlobalWatchKeys(peer, GroupRoom, 0, NULL, PEERFalse); - peerSetGlobalWatchKeys(peer, StagingRoom, 0, NULL, PEERFalse); - peerSetGlobalWatchKeys(peer, GroupRoom, 6, keys, PEERTrue); - peerSetGlobalWatchKeys(peer, StagingRoom, 6, keys, PEERTrue); -#endif - } - break; - - case PeerRequest::PEERREQUEST_SETGAMEOPTIONS: - { - m_mapName = incomingRequest.gameOptsMapName; - m_numPlayers = incomingRequest.gameOptions.numPlayers; - m_numObservers = incomingRequest.gameOptions.numObservers; - m_maxPlayers = incomingRequest.gameOptions.maxPlayers; - DEBUG_LOG(("peerStateChanged(): Marking game options state as changed - %d players, %d observers", m_numPlayers, m_numObservers)); - for (Int i=0; iaddResponse(resp); - - if (res != PEERJoinSuccess && res != PEERAlreadyInRoom) - { - m_localRoomID = oldGroupID; - DEBUG_LOG(("Requesting to join room %d", m_localRoomID)); - if (incomingRequest.stagingRoomCreation.restrictGameList) - { - peerLeaveRoom( peer, StagingRoom, NULL ); - } - else - { - peerJoinGroupRoom( peer, oldGroupID, joinRoomCallback, (void *)this, PEERTrue ); - } - m_isHosting = FALSE; - m_localStagingServerName = L""; - m_playerNames[0] = ""; - } - else - { - if (incomingRequest.stagingRoomCreation.restrictGameList) - { - peerLeaveRoom( peer, GroupRoom, NULL ); - } - isThreadHosting = 1; // debugging - s_lastStateChangedHeartbeat = timeGetTime(); // wait the full interval before updating state - s_wantStateChangedHeartbeat = FALSE; - m_isHosting = TRUE; - m_allowObservers = incomingRequest.stagingRoomCreation.allowObservers; - m_useStats = incomingRequest.stagingRoomCreation.useStats; - m_mapName = ""; - for (Int i=0; i 0) - m_hasPassword = true; - else - m_hasPassword = false; - m_playerNames[0] = m_loginName; - m_exeCRC = incomingRequest.stagingRoomCreation.exeCRC; - m_iniCRC = incomingRequest.stagingRoomCreation.iniCRC; - m_gameVersion = incomingRequest.stagingRoomCreation.gameVersion; - m_localStagingServerName = incomingRequest.text; - m_ladderIP = incomingRequest.ladderIP; - m_pingStr = incomingRequest.hostPingStr; - m_ladderPort = incomingRequest.stagingRoomCreation.ladPort; - -#ifdef USE_BROADCAST_KEYS - pushStatsToRoom(peer); -#endif // USE_BROADCAST_KEYS - - DEBUG_LOG(("Setting m_localStagingServerName to [%ls]", m_localStagingServerName.c_str())); - updateBuddyStatus( BUDDY_STAGING, 0, WideCharStringToMultiByte(m_localStagingServerName.c_str()) ); - } - } - break; - - case PeerRequest::PEERREQUEST_STARTGAMELIST: - { - m_sawCompleteGameList = FALSE; - PeerResponse resp; - resp.peerResponseType = PeerResponse::PEERRESPONSE_STAGINGROOM; - resp.stagingRoom.action = PEER_CLEAR; - resp.stagingRoom.isStaging = TRUE; - resp.stagingRoom.percentComplete = 0; - clearServers(); - TheGameSpyPeerMessageQueue->addResponse(resp); - peerStartListingGames( peer, allKeysArray, NumKeys, (incomingRequest.gameList.restrictGameList?"~":NULL), listingGamesCallback, this ); - } - break; - - case PeerRequest::PEERREQUEST_STOPGAMELIST: - { - peerStopListingGames( peer ); - } - break; - - case PeerRequest::PEERREQUEST_STARTGAME: - { - peerStartGame( peer, NULL, PEER_STOP_REPORTING); - } - break; - - case PeerRequest::PEERREQUEST_UTMPLAYER: - { - if (incomingRequest.nick.length() > 0) - { - peerUTMPlayer( peer, incomingRequest.nick.c_str(), incomingRequest.id.c_str(), incomingRequest.options.c_str(), PEERFalse ); - } - } - break; - - case PeerRequest::PEERREQUEST_UTMROOM: - { - peerUTMRoom( peer, (incomingRequest.UTM.isStagingRoom)?StagingRoom:GroupRoom, incomingRequest.id.c_str(), incomingRequest.options.c_str(), PEERFalse ); - } - break; - - case PeerRequest::PEERREQUEST_STARTQUICKMATCH: - { - m_qmInfo = incomingRequest; - doQuickMatch( peer ); - } - break; - - } - } - - if (isThreadHosting && s_wantStateChangedHeartbeat) - { - UnsignedInt now = timeGetTime(); - if (now > s_lastStateChangedHeartbeat + s_heartbeatInterval) - { - s_lastStateChangedHeartbeat = now; - s_wantStateChangedHeartbeat = FALSE; - peerStateChanged( peer ); - -#ifdef DEBUG_LOGGING - static UnsignedInt prev = 0; - UnsignedInt now = timeGetTime(); - UnsignedInt diff = now - prev; - prev = now; -#endif - STATECHANGED_LOG(("peerStateChanged() at time %d (difference of %d ms)", now, diff)); - } - } - - // update the network - PEERBool isConnected = PEERTrue; - isConnected = peerIsConnected( peer ); - if ( isConnected == PEERTrue ) - { - if (qr2Sock != INVALID_SOCKET) - { - // check hosting activity - checkQR2Queries( peer, qr2Sock ); - } - peerThink( peer ); - } - - // end our timeslice - Switch_Thread(); - } - - DEBUG_LOG(("voluntarily ending peer thread %d", running)); - peerShutdown( peer ); - - } catch ( ... ) { - DEBUG_CRASH(("Exception in peer thread!")); - - try { - PeerResponse resp; - resp.peerResponseType = PeerResponse::PEERRESPONSE_DISCONNECT; - resp.discon.reason = DISCONNECT_LOSTCON; - TheGameSpyPeerMessageQueue->addResponse(resp); - } - catch (...) - { - } - } -} - -static void qmProfileIDCallback( PEER peer, PEERBool success, const char *nick, int profileID, void *param ) -{ - Int *i = (Int *)param; - if (!i || !success || !nick) - return; - - *i = profileID; -} - -static Int matchbotProfileID = 0; -void quickmatchEnumPlayersCallback( PEER peer, PEERBool success, RoomType roomType, int index, const char * nick, int flags, void * param ) -{ - PeerThreadClass *t = (PeerThreadClass *)param; - if (!t || !success || nick == NULL || nick[0] == '\0') - { - t->sawEndOfEnumPlayers(); - return; - } - - Int id = 0; - peerGetPlayerProfileID(peer, nick, qmProfileIDCallback, &id, PEERTrue); - DEBUG_LOG(("Saw player %s with id %d (looking for %d)", nick, id, matchbotProfileID)); - if (id == matchbotProfileID) - { - t->sawMatchbot(nick); - } - - PeerResponse resp; - resp.peerResponseType = PeerResponse::PEERRESPONSE_PLAYERJOIN; - resp.nick = nick; - resp.player.roomType = roomType; - resp.player.IP = 0; - - TheGameSpyPeerMessageQueue->addResponse(resp); -} - -void PeerThreadClass::handleQMMatch(PEER peer, Int mapIndex, Int seed, - char *playerName[MAX_SLOTS], - char *playerIP[MAX_SLOTS], - char *playerSide[MAX_SLOTS], - char *playerColor[MAX_SLOTS], - char *playerNAT[MAX_SLOTS]) -{ - if (m_qmStatus == QM_WORKING) - { - m_qmStatus = QM_MATCHED; - peerLeaveRoom(peer, GroupRoom, ""); - - Int i=0; - for (; iaddResponse(resp); - } -} - -void PeerThreadClass::doQuickMatch( PEER peer ) -{ - m_qmStatus = QM_JOININGQMCHANNEL; - Bool done = false; - matchbotProfileID = m_qmInfo.QM.botID; - setQMGroupRoom( m_qmInfo.QM.roomID ); - m_sawMatchbot = false; - updateBuddyStatus( BUDDY_MATCHING ); - while (!done && running) - { - if (!peerIsConnected( peer )) - { - done = true; - } - else - { - // update the network - peerThink( peer ); - - // end our timeslice - Switch_Thread(); - - PeerRequest incomingRequest; - if (TheGameSpyPeerMessageQueue->getRequest(incomingRequest)) - { - switch (incomingRequest.peerRequestType) - { - case PeerRequest::PEERREQUEST_WIDENQUICKMATCHSEARCH: - { - if (m_qmStatus != QM_IDLE && m_qmStatus != QM_STOPPED && m_sawMatchbot) - { - peerMessagePlayer( peer, m_matchbotName.c_str(), "\\WIDEN", NormalMessage ); - } - } - break; - case PeerRequest::PEERREQUEST_STOPQUICKMATCH: - { - m_qmStatus = QM_STOPPED; - peerLeaveRoom(peer, GroupRoom, ""); - done = true; - } - break; - case PeerRequest::PEERREQUEST_LOGOUT: - { - m_qmStatus = QM_STOPPED; - peerLeaveRoom(peer, GroupRoom, ""); - done = true; - } - break; - case PeerRequest::PEERREQUEST_LEAVEGROUPROOM: - { - m_qmStatus = QM_STOPPED; - peerLeaveRoom(peer, GroupRoom, ""); - done = true; - } - break; - case PeerRequest::PEERREQUEST_UTMPLAYER: - { - peerUTMPlayer( peer, incomingRequest.nick.c_str(), incomingRequest.id.c_str(), incomingRequest.options.c_str(), PEERFalse ); - } - break; - default: - { - DEBUG_CRASH(("Unanticipated request %d to peer thread!", incomingRequest.peerRequestType)); - } - break; - } - } - - if (!done) - { - // do the next bit of QM - switch (m_qmStatus) - { - case QM_JOININGQMCHANNEL: - { - PeerResponse resp; - resp.peerResponseType = PeerResponse::PEERRESPONSE_QUICKMATCHSTATUS; - resp.qmStatus.status = QM_JOININGQMCHANNEL; - TheGameSpyPeerMessageQueue->addResponse(resp); - - m_groupRoomID = m_qmGroupRoom; - peerLeaveRoom( peer, GroupRoom, NULL ); - peerLeaveRoom( peer, StagingRoom, NULL ); m_isHosting = false; - m_localRoomID = m_groupRoomID; - m_roomJoined = false; - DEBUG_LOG(("Requesting to join room %d in thread %X", m_localRoomID, this)); - peerJoinGroupRoom( peer, m_localRoomID, joinRoomCallback, (void *)this, PEERTrue ); - if (m_roomJoined) - { - resp.peerResponseType = PeerResponse::PEERRESPONSE_QUICKMATCHSTATUS; - resp.qmStatus.status = QM_LOOKINGFORBOT; - TheGameSpyPeerMessageQueue->addResponse(resp); - - m_qmStatus = QM_LOOKINGFORBOT; - m_sawMatchbot = false; - m_sawEndOfEnumPlayers = false; - peerEnumPlayers( peer, GroupRoom, quickmatchEnumPlayersCallback, this ); - } - else - { - resp.peerResponseType = PeerResponse::PEERRESPONSE_QUICKMATCHSTATUS; - resp.qmStatus.status = QM_COULDNOTFINDBOT; - TheGameSpyPeerMessageQueue->addResponse(resp); - done = true; - m_qmStatus = QM_STOPPED; - } - } - break; - case QM_LOOKINGFORBOT: - { - if (m_sawEndOfEnumPlayers) - { - if (m_sawMatchbot) - { - char buf[64]; - std::string msg = "\\CINFO"; - snprintf(buf, 64, "\\Widen\\%d", m_qmInfo.QM.widenTime); - msg.append(buf); - snprintf(buf, 64, "\\LadID\\%d", m_qmInfo.QM.ladderID); - msg.append(buf); - snprintf(buf, 64, "\\LadPass\\%d", m_qmInfo.QM.ladderPassCRC); - msg.append(buf); - snprintf(buf, 64, "\\PointsMin\\%d", m_qmInfo.QM.minPointPercentage); - msg.append(buf); - snprintf(buf, 64, "\\PointsMax\\%d", m_qmInfo.QM.maxPointPercentage); - msg.append(buf); - snprintf(buf, 64, "\\Points\\%d", m_qmInfo.QM.points); - msg.append(buf); - snprintf(buf, 64, "\\Discons\\%d", m_qmInfo.QM.discons); - msg.append(buf); - snprintf(buf, 64, "\\DisconMax\\%d", m_qmInfo.QM.maxDiscons); - msg.append(buf); - snprintf(buf, 64, "\\NumPlayers\\%d", m_qmInfo.QM.numPlayers); - msg.append(buf); - snprintf(buf, 64, "\\Pings\\%s", m_qmInfo.QM.pings); - msg.append(buf); - snprintf(buf, 64, "\\IP\\%d", ntohl(peerGetLocalIP(peer)));// not ntohl(localIP), as we need EXTERNAL address for proper NAT negotiation! - msg.append(buf); - snprintf(buf, 64, "\\Side\\%d", m_qmInfo.QM.side); - msg.append(buf); - snprintf(buf, 64, "\\Color\\%d", m_qmInfo.QM.color); - msg.append(buf); - snprintf(buf, 64, "\\NAT\\%d", m_qmInfo.QM.NAT); - msg.append(buf); - snprintf(buf, 64, "\\EXE\\%d", m_qmInfo.QM.exeCRC); - msg.append(buf); - snprintf(buf, 64, "\\INI\\%d", m_qmInfo.QM.iniCRC); - msg.append(buf); - buf[0] = 0; - msg.append("\\Maps\\"); - for (size_t i=0; iaddResponse(resp); - } - else - { - // no QM bot. Bail. - PeerResponse resp; - resp.peerResponseType = PeerResponse::PEERRESPONSE_QUICKMATCHSTATUS; - resp.qmStatus.status = QM_COULDNOTFINDBOT; - TheGameSpyPeerMessageQueue->addResponse(resp); - - m_qmStatus = QM_STOPPED; - peerLeaveRoom(peer, GroupRoom, ""); - done = true; - } - } - } - break; - case QM_WORKING: - { - } - break; - case QM_MATCHED: - { - // leave QM channel, and clean up. Our work here is done. - peerLeaveRoom( peer, GroupRoom, NULL ); - peerLeaveRoom( peer, StagingRoom, NULL ); m_isHosting = false; - - m_qmStatus = QM_STOPPED; - peerLeaveRoom(peer, GroupRoom, ""); - done = true; - } - break; - case QM_INCHANNEL: - { - } - break; - case QM_NEGOTIATINGFIREWALLS: - { - } - break; - case QM_STARTINGGAME: - { - } - break; - case QM_COULDNOTFINDCHANNEL: - { - } - break; - case QM_COULDNOTNEGOTIATEFIREWALLS: - { - } - break; - } - } - } - } - updateBuddyStatus( BUDDY_ONLINE ); -} - -static void getPlayerProfileIDCallback(PEER peer, PEERBool success, const char * nick, int profileID, void * param) -{ - if (success && param != NULL) - { - *((Int *)param) = profileID; - } -} - -static void stagingRoomPlayerEnum( PEER peer, PEERBool success, RoomType roomType, int index, const char * nick, int flags, void * param ) -{ - DEBUG_LOG(("Enum: success=%d, index=%d, nick=%s, flags=%d", success, index, nick, flags)); - if (!nick || !success) - return; - - Int id = 0; - peerGetPlayerProfileID(peer, nick, getPlayerProfileIDCallback, &id, PEERTrue); - DEBUG_ASSERTCRASH(id != 0, ("Failed to fetch player ID!")); - - PeerResponse *resp = (PeerResponse *)param; - if (flags & PEER_FLAG_OP) - { - resp->joinStagingRoom.isHostPresent = TRUE; - } - if (index < MAX_SLOTS) - { - resp->stagingRoomPlayerNames[index] = nick; - } - - if (id) - { - PSRequest req; - req.requestType = PSRequest::PSREQUEST_READPLAYERSTATS; - req.player.id = id; - TheGameSpyPSMessageQueue->addRequest(req); - } -} - -static void joinRoomCallback(PEER peer, PEERBool success, PEERJoinResult result, RoomType roomType, void *param) -{ - DEBUG_LOG(("JoinRoomCallback: success==%d, result==%d", success, result)); - PeerThreadClass *t = (PeerThreadClass *)param; - if (!t) - return; - DEBUG_LOG(("Room id was %d from thread %X", t->getLocalRoomID(), t)); - DEBUG_LOG(("Current staging server name is [%ls]", t->getLocalStagingServerName().c_str())); - DEBUG_LOG(("Room type is %d (GroupRoom=%d, StagingRoom=%d, TitleRoom=%d)", roomType, GroupRoom, StagingRoom, TitleRoom)); - -#ifdef USE_BROADCAST_KEYS - if (success) - { - t->pushStatsToRoom(peer); - t->getStatsFromRoom(peer, roomType); - } -#endif // USE_BROADCAST_KEYS - - switch (roomType) - { - case GroupRoom: - { -#ifdef USE_BROADCAST_KEYS - t->clearPlayerStats(GroupRoom); -#endif // USE_BROADCAST_KEYS - PeerResponse resp; - resp.peerResponseType = PeerResponse::PEERRESPONSE_JOINGROUPROOM; - resp.joinGroupRoom.id = t->getLocalRoomID(); - resp.joinGroupRoom.ok = success; - TheGameSpyPeerMessageQueue->addResponse(resp); - t->roomJoined(success == PEERTrue); - DEBUG_LOG(("Entered group room %d, qm is %d", t->getLocalRoomID(), t->getQMGroupRoom())); - if ((!t->getQMGroupRoom()) || (t->getQMGroupRoom() != t->getLocalRoomID())) - { - DEBUG_LOG(("Updating buddy status")); - updateBuddyStatus( BUDDY_LOBBY, t->getLocalRoomID() ); - } - } - break; - case StagingRoom: - { -#ifdef USE_BROADCAST_KEYS - t->clearPlayerStats(StagingRoom); -#endif // USE_BROADCAST_KEYS - PeerResponse resp; - resp.peerResponseType = PeerResponse::PEERRESPONSE_JOINSTAGINGROOM; - resp.joinStagingRoom.id = t->getLocalRoomID(); - resp.joinStagingRoom.ok = success; - resp.joinStagingRoom.result = result; - if (success) - { - DEBUG_LOG(("joinRoomCallback() - game name is now '%ls'", t->getLocalStagingServerName().c_str())); - updateBuddyStatus( BUDDY_STAGING, 0, WideCharStringToMultiByte(t->getLocalStagingServerName().c_str()) ); - } - - resp.joinStagingRoom.isHostPresent = FALSE; - DEBUG_LOG(("Enum of staging room players")); - peerEnumPlayers(peer, StagingRoom, stagingRoomPlayerEnum, &resp); - DEBUG_LOG(("Host %s present", (resp.joinStagingRoom.isHostPresent)?"is":"is not")); - - TheGameSpyPeerMessageQueue->addResponse(resp); - } - break; - } -} - -// Gets called once for each group room when listing group rooms. -// After this has been called for each group room, it will be -// called one more time with groupID==0 and name==NULL. -///////////////////////////////////////////////////////////////// -static void listGroupRoomsCallback(PEER peer, PEERBool success, - int groupID, SBServer server, - const char * name, int numWaiting, - int maxWaiting, int numGames, - int numPlaying, void * param) -{ - DEBUG_LOG(("listGroupRoomsCallback, success=%d, server=%X, groupID=%d", success, server, groupID)); -#ifdef SERVER_DEBUGGING - CheckServers(peer); -#endif // SERVER_DEBUGGING - PeerThreadClass *t = (PeerThreadClass *)param; - if (!t) - { - DEBUG_LOG(("No thread! Bailing!")); - return; - } - - if (success) - { - DEBUG_LOG(("Saw group room of %d (%s) at address %X %X", groupID, name, server, (server)?server->keyvals:0)); - PeerResponse resp; - resp.peerResponseType = PeerResponse::PEERRESPONSE_GROUPROOM; - resp.groupRoom.id = groupID; - resp.groupRoom.numWaiting = numWaiting; - resp.groupRoom.maxWaiting = maxWaiting; - resp.groupRoom.numGames = numGames; - resp.groupRoom.numPlaying = numPlaying; - if (name) - { - resp.groupRoomName = name; - //t->setQMGroupRoom(groupID); - } - TheGameSpyPeerMessageQueue->addResponse(resp); -#ifdef SERVER_DEBUGGING - CheckServers(peer); - DEBUG_LOG(("")); -#endif // SERVER_DEBUGGING - } - else - { - DEBUG_LOG(("Failure!")); - } -} - -void PeerThreadClass::connectCallback( PEER peer, PEERBool success ) -{ - PeerResponse resp; - if(!success) - { - //updateBuddyStatus( BUDDY_OFFLINE ); - resp.peerResponseType = PeerResponse::PEERRESPONSE_DISCONNECT; - resp.discon.reason = DISCONNECT_COULDNOTCONNECT; - TheGameSpyPeerMessageQueue->addResponse(resp); - return; - } - - updateBuddyStatus( BUDDY_ONLINE ); - - m_isConnected = true; - DEBUG_LOG(("Connected as profile %d (%s)", m_profileID, m_loginName.c_str())); - resp.peerResponseType = PeerResponse::PEERRESPONSE_LOGIN; - resp.player.profileID = m_profileID; - resp.nick = m_loginName; - GetLocalChatConnectionAddress("peerchat.gamespy.com", 6667, localIP); - chatSetLocalIP(localIP); - resp.player.internalIP = ntohl(localIP); - resp.player.externalIP = ntohl(peerGetLocalIP(peer)); - TheGameSpyPeerMessageQueue->addResponse(resp); - - PSRequest psReq; - psReq.requestType = PSRequest::PSREQUEST_READPLAYERSTATS; - psReq.player.id = m_profileID; - psReq.nick = m_originalName; - psReq.email = m_email; - psReq.password = m_password; - TheGameSpyPSMessageQueue->addRequest(psReq); - -#ifdef SERVER_DEBUGGING - DEBUG_LOG(("Before peerListGroupRooms()")); - CheckServers(peer); -#endif // SERVER_DEBUGGING - peerListGroupRooms( peer, NULL, listGroupRoomsCallback, this, PEERTrue ); -#ifdef SERVER_DEBUGGING - DEBUG_LOG(("After peerListGroupRooms()")); - CheckServers(peer); -#endif // SERVER_DEBUGGING -} - -void PeerThreadClass::nickErrorCallback( PEER peer, Int type, const char *nick ) -{ - if(type == PEER_IN_USE) - { - Int len = strlen(nick); - std::string nickStr = nick; - Int newVal = 0; - if (nick[len-1] == '}' && nick[len-3] == '{' && isdigit(nick[len-2])) - { - newVal = nick[len-2] - '0' + 1; - nickStr.erase(len-3, 3); - } - - DEBUG_LOG(("Nickname taken: was %s, new val = %d, new nick = %s", nick, newVal, nickStr.c_str())); - - if (newVal < 10) - { - nickStr.append("{"); - char tmp[2]; - tmp[0] = '0'+newVal; - tmp[1] = '\0'; - nickStr.append(tmp); - nickStr.append("}"); - // Retry the connect with a similar nick. - m_loginName = nickStr; - peerRetryWithNick(peer, nickStr.c_str()); - } - else - { - PeerResponse resp; - resp.peerResponseType = PeerResponse::PEERRESPONSE_DISCONNECT; - resp.discon.reason = DISCONNECT_NICKTAKEN; - TheGameSpyPeerMessageQueue->addResponse(resp); - - // Cancel the connect. - peerRetryWithNick(peer, NULL); - } - } - else - { - PeerResponse resp; - resp.peerResponseType = PeerResponse::PEERRESPONSE_DISCONNECT; - resp.discon.reason = DISCONNECT_BADNICK; - TheGameSpyPeerMessageQueue->addResponse(resp); - - // Cancel the connect. - peerRetryWithNick(peer, NULL); - } -} - -void disconnectedCallback(PEER peer, const char * reason, void * param) -{ - DEBUG_LOG(("disconnectedCallback(): reason was '%s'", reason)); - PeerThreadClass *t = (PeerThreadClass *)param; - DEBUG_ASSERTCRASH(t, ("No Peer thread!")); - if (t) - t->markAsDisconnected(); - //updateBuddyStatus( BUDDY_OFFLINE ); - PeerResponse resp; - resp.peerResponseType = PeerResponse::PEERRESPONSE_DISCONNECT; - resp.discon.reason = DISCONNECT_LOSTCON; - SerialAuthResult res = TheGameSpyPeerMessageQueue->getSerialAuthResult(); - switch (res) - { - case SERIAL_NONEXISTENT: - resp.discon.reason = DISCONNECT_SERIAL_NOT_PRESENT; - break; - case SERIAL_AUTHFAILED: - resp.discon.reason = DISCONNECT_SERIAL_INVALID; - break; - case SERIAL_BANNED: - resp.discon.reason = DISCONNECT_SERIAL_BANNED; - break; - } - TheGameSpyPeerMessageQueue->addResponse(resp); -} - -void roomMessageCallback(PEER peer, RoomType roomType, const char * nick, const char * message, MessageType messageType, void * param) -{ - PeerResponse resp; - resp.peerResponseType = PeerResponse::PEERRESPONSE_MESSAGE; - resp.nick = nick; - resp.text = MultiByteToWideCharSingleLine(message); - resp.message.isPrivate = FALSE; - resp.message.isAction = (messageType == ActionMessage); - TheGameSpyPeerMessageQueue->addResponse(resp); - DEBUG_LOG(("Saw text [%hs] (%ls) %d chars Orig was %s (%d chars)", nick, resp.text.c_str(), resp.text.length(), message, strlen(message))); - - UnsignedInt IP; - peerGetPlayerInfoNoWait(peer, nick, &IP, &resp.message.profileID); - - PeerThreadClass *t = (PeerThreadClass *)param; - DEBUG_ASSERTCRASH(t, ("No Peer thread!")); - if (t && (t->getQMStatus() != QM_IDLE && t->getQMStatus() != QM_STOPPED)) - { - if (resp.message.profileID == matchbotProfileID) - { - char *lastStr = NULL; - char *cmd = strtok_r((char *)message, " ", &lastStr); - if ( cmd && strcmp(cmd, "MBOT:POOLSIZE") == 0 ) - { - Int poolSize = 0; - - while (1) - { - char *poolStr = strtok_r(NULL, " ", &lastStr); - char *sizeStr = strtok_r(NULL, " ", &lastStr); - if (poolStr && sizeStr) - { - Int pool = atoi(poolStr); - Int size = atoi(sizeStr); - if (pool == t->getQMLadder()) - { - poolSize = size; - break; - } - } - else - break; - } - - PeerResponse resp; - resp.peerResponseType = PeerResponse::PEERRESPONSE_QUICKMATCHSTATUS; - resp.qmStatus.status = QM_POOLSIZE; - resp.qmStatus.poolSize = poolSize; - TheGameSpyPeerMessageQueue->addResponse(resp); - } - } - } -} - -void gameStartedCallback( PEER peer, SBServer server, const char *message, void *param ) -{ - PeerResponse resp; - resp.peerResponseType = PeerResponse::PEERRESPONSE_GAMESTART; - TheGameSpyPeerMessageQueue->addResponse(resp); -} - -void playerMessageCallback(PEER peer, const char * nick, const char * message, MessageType messageType, void * param) -{ - PeerResponse resp; - resp.peerResponseType = PeerResponse::PEERRESPONSE_MESSAGE; - resp.nick = nick; - resp.text = MultiByteToWideCharSingleLine(message); - resp.message.isPrivate = TRUE; - resp.message.isAction = (messageType == ActionMessage); - UnsignedInt IP; - peerGetPlayerInfoNoWait(peer, nick, &IP, &resp.message.profileID); - TheGameSpyPeerMessageQueue->addResponse(resp); - - - PeerThreadClass *t = (PeerThreadClass *)param; - DEBUG_ASSERTCRASH(t, ("No Peer thread!")); - if (t && (t->getQMStatus() != QM_IDLE && t->getQMStatus() != QM_STOPPED)) - { - if (resp.message.isPrivate && resp.message.profileID == matchbotProfileID) - { - char *lastStr = NULL; - char *cmd = strtok_r((char *)message, " ", &lastStr); - if ( cmd && strcmp(cmd, "MBOT:MATCHED") == 0 ) - { - char *mapNumStr = strtok_r(NULL, " ", &lastStr); - char *seedStr = strtok_r(NULL, " ", &lastStr); - char *playerStr[MAX_SLOTS]; - char *playerIPStr[MAX_SLOTS]; - char *playerSideStr[MAX_SLOTS]; - char *playerColorStr[MAX_SLOTS]; - char *playerNATStr[MAX_SLOTS]; - Int numPlayers = 0; - for (Int i=0; i 1) - { - // woohoo! got everything needed for a match! - DEBUG_LOG(("Saw %d-player QM match: map index = %s, seed = %s", numPlayers, mapNumStr, seedStr)); - t->handleQMMatch(peer, atoi(mapNumStr), atoi(seedStr), playerStr, playerIPStr, playerSideStr, playerColorStr, playerNATStr); - } - } - else if ( cmd && strcmp(cmd, "MBOT:WORKING") == 0 ) - { - Int poolSize = 0; - char *poolStr = strtok_r(NULL, " ", &lastStr); - if (poolStr) - poolSize = atoi(poolStr); - PeerResponse resp; - resp.peerResponseType = PeerResponse::PEERRESPONSE_QUICKMATCHSTATUS; - resp.qmStatus.status = QM_WORKING; - resp.qmStatus.poolSize = poolSize; - TheGameSpyPeerMessageQueue->addResponse(resp); - } - else if ( cmd && strcmp(cmd, "MBOT:WIDENINGSEARCH") == 0 ) - { - PeerResponse resp; - resp.peerResponseType = PeerResponse::PEERRESPONSE_QUICKMATCHSTATUS; - resp.qmStatus.status = QM_WIDENINGSEARCH; - TheGameSpyPeerMessageQueue->addResponse(resp); - } - } - } -} - -void roomUTMCallback(PEER peer, RoomType roomType, const char * nick, const char * command, const char * parameters, PEERBool authenticated, void * param) -{ - DEBUG_LOG(("roomUTMCallback: %s says %s = [%s]", nick, command, parameters)); - if (roomType != StagingRoom) - return; - PeerResponse resp; - resp.peerResponseType = PeerResponse::PEERRESPONSE_ROOMUTM; - resp.nick = nick; - resp.command = command; - resp.commandOptions = parameters; - TheGameSpyPeerMessageQueue->addResponse(resp); -} - -void playerUTMCallback(PEER peer, const char * nick, const char * command, const char * parameters, PEERBool authenticated, void * param) -{ - DEBUG_LOG(("playerUTMCallback: %s says %s = [%s]", nick, command, parameters)); - PeerResponse resp; - resp.peerResponseType = PeerResponse::PEERRESPONSE_PLAYERUTM; - resp.nick = nick; - resp.command = command; - resp.commandOptions = parameters; - TheGameSpyPeerMessageQueue->addResponse(resp); -} - -static void getPlayerInfo(PeerThreadClass *t, PEER peer, const char *nick, Int& id, UnsignedInt& IP, - std::string& locale, Int& wins, Int& losses, Int& rankPoints, Int& side, Int& preorder, - RoomType roomType, Int& flags) -{ - if (!t || !nick) - return; - peerGetPlayerInfoNoWait(peer, nick, &IP, &id); -#ifdef USE_BROADCAST_KEYS - //locale.printf - Int localeIndex = t->lookupStatForPlayer(roomType, nick, "b_locale"); - AsciiString tmp; - tmp.format("%d", localeIndex); - locale = tmp.str(); - - wins = t->lookupStatForPlayer(roomType, nick, "b_wins"); - losses = t->lookupStatForPlayer(roomType, nick, "b_losses"); - rankPoints = t->lookupStatForPlayer(roomType, nick, "b_points"); - side = t->lookupStatForPlayer(roomType, nick, "b_side"); - preorder = t->lookupStatForPlayer(roomType, nick, "b_pre"); -#else // USE_BROADCAST_KEYS - const char *s; - s = peerGetGlobalWatchKey(peer, nick, "locale"); - locale = (s)?s:""; - s = peerGetGlobalWatchKey(peer, nick, "wins"); - wins = atoi((s)?s:""); - s = peerGetGlobalWatchKey(peer, nick, "losses"); - losses = atoi((s)?s:""); - s = peerGetGlobalWatchKey(peer, nick, "points"); - rankPoints = atoi((s)?s:""); - s = peerGetGlobalWatchKey(peer, nick, "side"); - side = atoi((s)?s:""); - s = peerGetGlobalWatchKey(peer, nick, "pre"); - preorder = atoi((s)?s:""); -#endif // USE_BROADCAST_KEYS - flags = 0; - peerGetPlayerFlags(peer, nick, roomType, &flags); - DEBUG_LOG(("getPlayerInfo(%d) - %s has locale %s, wins:%d, losses:%d, rankPoints:%d, side:%d, preorder:%d", - id, nick, locale.c_str(), wins, losses, rankPoints, side, preorder)); -} - -static void roomKeyChangedCallback(PEER peer, RoomType roomType, const char *nick, const char *key, const char *val, void *param) -{ -#ifdef USE_BROADCAST_KEYS - PeerThreadClass *t = (PeerThreadClass *)param; - DEBUG_ASSERTCRASH(t, ("No Peer thread!")); - if (!t || !nick || !key || !val) - { - DEBUG_ASSERTCRASH(nick && strcmp(nick,"(END)")==0, ("roomKeyChangedCallback bad values = nick:%X:%s, key:%X:%s, val:%X:%s", nick, nick, key, key, val, val)); - return; - } - -#ifdef DEBUG_LOGGING - if (strcmp(key, "username") && strcmp(key, "b_flags")) - { - DEBUG_LOG(("roomKeyChangedCallback() - %s set %s=%s", nick, key, val)); - } -#endif - - t->trackStatsForPlayer(roomType, nick, key, val); - - PeerResponse resp; - resp.peerResponseType = PeerResponse::PEERRESPONSE_PLAYERINFO; - resp.nick = nick; - resp.player.roomType = roomType; - - getPlayerInfo(t, peer, nick, resp.player.profileID, resp.player.IP, - resp.locale, resp.player.wins, resp.player.losses, - resp.player.rankPoints, resp.player.side, resp.player.preorder, - resp.player.roomType, resp.player.flags); - TheGameSpyPeerMessageQueue->addResponse(resp); -#endif // USE_BROADCAST_KEYS -} - -#ifdef USE_BROADCAST_KEYS -void getRoomKeysCallback(PEER peer, PEERBool success, RoomType roomType, const char *nick, int num, char **keys, char **values, void *param) -{ - PeerThreadClass *t = (PeerThreadClass *)param; - DEBUG_ASSERTCRASH(t, ("No Peer thread!")); - if (!t || !nick || !num || !success || !keys || !values) - { - DEBUG_ASSERTCRASH(!nick || strcmp(nick,"(END)")==0, ("getRoomKeysCallback bad key/value %X/%X, nick=%s", keys, values, nick)); - return; - } - - for (Int i=0; itrackStatsForPlayer(roomType, nick, keys[i], values[i]); - } - - PeerResponse resp; - resp.peerResponseType = PeerResponse::PEERRESPONSE_PLAYERINFO; - resp.nick = nick; - resp.player.roomType = roomType; - - getPlayerInfo(t, peer, nick, resp.player.profileID, resp.player.IP, - resp.locale, resp.player.wins, resp.player.losses, - resp.player.rankPoints, resp.player.side, resp.player.preorder, - resp.player.roomType, resp.player.flags); - TheGameSpyPeerMessageQueue->addResponse(resp); -} -#endif // USE_BROADCAST_KEYS - -static void globalKeyChangedCallback(PEER peer, const char *nick, const char *key, const char *val, void *param) -{ - if (!nick) - return; - - PeerThreadClass *t = (PeerThreadClass *)param; - DEBUG_ASSERTCRASH(t, ("No Peer thread!")); - if (!t) - return; - - PeerResponse resp; - resp.peerResponseType = PeerResponse::PEERRESPONSE_PLAYERINFO; - resp.nick = nick; - resp.player.roomType = t->getCurrentGroupRoom()?GroupRoom:StagingRoom; - - getPlayerInfo(t, peer, nick, resp.player.profileID, resp.player.IP, - resp.locale, resp.player.wins, resp.player.losses, - resp.player.rankPoints, resp.player.side, resp.player.preorder, - resp.player.roomType, resp.player.flags); - TheGameSpyPeerMessageQueue->addResponse(resp); -} - -void playerJoinedCallback(PEER peer, RoomType roomType, const char * nick, void * param) -{ - if (!nick) - return; - - PeerThreadClass *t = (PeerThreadClass *)param; - DEBUG_ASSERTCRASH(t, ("No Peer thread!")); - if (!t) - return; - - PeerResponse resp; - resp.peerResponseType = PeerResponse::PEERRESPONSE_PLAYERJOIN; - resp.nick = nick; - resp.player.roomType = roomType; - - getPlayerInfo(t, peer, nick, resp.player.profileID, resp.player.IP, - resp.locale, resp.player.wins, resp.player.losses, - resp.player.rankPoints, resp.player.side, resp.player.preorder, - roomType, resp.player.flags); - TheGameSpyPeerMessageQueue->addResponse(resp); -} - -void playerLeftCallback(PEER peer, RoomType roomType, const char * nick, const char * reason, void * param) -{ - PeerResponse resp; - resp.peerResponseType = PeerResponse::PEERRESPONSE_PLAYERLEFT; - resp.nick = nick; - resp.player.roomType = roomType; - resp.player.profileID = 0; - - PeerThreadClass *t = (PeerThreadClass *)param; - DEBUG_ASSERTCRASH(t, ("No Peer thread!")); - if (!t) - return; - - getPlayerInfo(t, peer, nick, resp.player.profileID, resp.player.IP, - resp.locale, resp.player.wins, resp.player.losses, - resp.player.rankPoints, resp.player.side, resp.player.preorder, - roomType, resp.player.flags); - TheGameSpyPeerMessageQueue->addResponse(resp); - - if (t->getQMStatus() != QM_IDLE && t->getQMStatus() != QM_STOPPED) - { - if (!stricmp(t->getQMBotName().c_str(), nick)) - { - // matchbot left - bail - PeerResponse resp; - resp.peerResponseType = PeerResponse::PEERRESPONSE_QUICKMATCHSTATUS; - resp.qmStatus.status = QM_COULDNOTFINDBOT; - TheGameSpyPeerMessageQueue->addResponse(resp); - - PeerRequest req; - req.peerRequestType = PeerRequest::PEERREQUEST_STOPQUICKMATCH; - TheGameSpyPeerMessageQueue->addRequest(req); - } - } -} - -void playerChangedNickCallback(PEER peer, RoomType roomType, const char * oldNick, const char * newNick, void * param) -{ - PeerResponse resp; - resp.peerResponseType = PeerResponse::PEERRESPONSE_PLAYERCHANGEDNICK; - resp.nick = newNick; - resp.oldNick = oldNick; - resp.player.roomType = roomType; - - PeerThreadClass *t = (PeerThreadClass *)param; - DEBUG_ASSERTCRASH(t, ("No Peer thread!")); - if (!t) - return; - - getPlayerInfo(t, peer, newNick, resp.player.profileID, resp.player.IP, - resp.locale, resp.player.wins, resp.player.losses, - resp.player.rankPoints, resp.player.side, resp.player.preorder, - roomType, resp.player.flags); - TheGameSpyPeerMessageQueue->addResponse(resp); -} - -static void playerInfoCallback(PEER peer, RoomType roomType, const char * nick, unsigned int IP, int profileID, void * param) -{ - if (!nick) - return; - PeerResponse resp; - resp.peerResponseType = PeerResponse::PEERRESPONSE_PLAYERINFO; - resp.nick = nick; - resp.player.roomType = roomType; - - PeerThreadClass *t = (PeerThreadClass *)param; - DEBUG_ASSERTCRASH(t, ("No Peer thread!")); - if (!t) - return; - - getPlayerInfo(t, peer, nick, resp.player.profileID, resp.player.IP, - resp.locale, resp.player.wins, resp.player.losses, - resp.player.rankPoints, resp.player.side, resp.player.preorder, - roomType, resp.player.flags); -DEBUG_LOG(("**GS playerInfoCallback name=%s, local=%s", nick, resp.locale.c_str() )); - TheGameSpyPeerMessageQueue->addResponse(resp); -} - -static void playerFlagsChangedCallback(PEER peer, RoomType roomType, const char * nick, int oldFlags, int newFlags, void * param) -{ - if (!nick) - return; - PeerResponse resp; - resp.peerResponseType = PeerResponse::PEERRESPONSE_PLAYERCHANGEDFLAGS; - resp.nick = nick; - resp.player.roomType = roomType; - - PeerThreadClass *t = (PeerThreadClass *)param; - DEBUG_ASSERTCRASH(t, ("No Peer thread!")); - if (!t) - return; - - getPlayerInfo(t, peer, nick, resp.player.profileID, resp.player.IP, - resp.locale, resp.player.wins, resp.player.losses, - resp.player.rankPoints, resp.player.side, resp.player.preorder, - roomType, resp.player.flags); - TheGameSpyPeerMessageQueue->addResponse(resp); -} - -#ifdef DEBUG_LOGGING -/* -static void enumFunc(char *key, char *val, void *param) -{ - DEBUG_LOG((" [%s] = [%s]", key, val)); -} -*/ -#endif - -static void listingGamesCallback(PEER peer, PEERBool success, const char * name, SBServer server, PEERBool staging, int msg, Int percentListed, void * param) -{ - PeerThreadClass *t = (PeerThreadClass *)param; - if (!t || !success) - return; - -#ifdef DEBUG_LOGGING - AsciiString cmdStr = ""; - switch(msg) - { - case PEER_ADD: - cmdStr = "PEER_ADD"; - break; - case PEER_UPDATE: - cmdStr = "PEER_UPDATE"; - break; - case PEER_REMOVE: - cmdStr = "PEER_REMOVE"; - break; - case PEER_CLEAR: - cmdStr = "PEER_CLEAR"; - break; - case PEER_COMPLETE: - cmdStr = "PEER_COMPLETE"; - break; - } - DEBUG_LOG(("listingGamesCallback() - doing command %s on server %X", cmdStr.str(), server)); -#endif // DEBUG_LOGGING - -// PeerThreadClass *t = (PeerThreadClass *)param; - DEBUG_ASSERTCRASH(name || msg==PEER_CLEAR || msg==PEER_COMPLETE, ("Game has no name!")); - if (!t || !success || (!name && (msg == PEER_ADD || msg == PEER_UPDATE))) - { - DEBUG_LOG(("Bailing from listingGamesCallback() - success=%d, name=%X, server=%X, msg=%X", success, name, server, msg)); - return; - } - if (!name) - name = "bogus"; - - if (server && (msg == PEER_ADD || msg == PEER_UPDATE)) - { - DEBUG_ASSERTCRASH(server->keyvals, ("Looking at an already-freed server for msg type %d!", msg)); - if (!server->keyvals) - { - msg = PEER_REMOVE; - } - } - - if (server && success && (msg == PEER_ADD || msg == PEER_UPDATE)) - { - DEBUG_LOG(("Game name is '%s'", name)); - const char *newname = SBServerGetStringValue(server, "gamename", (char *)name); -#if RTS_GENERALS - if (strcmp(newname, "ccgenerals")) -#elif RTS_ZEROHOUR - if (strcmp(newname, "ccgenzh")) -#endif - name = newname; - DEBUG_LOG(("Game name is now '%s'", name)); - } - - DEBUG_LOG(("listingGamesCallback - got percent complete %d", percentListed)); - if (percentListed == 100) - { - if (!t->getSawCompleteGameList()) - { - t->setSawCompleteGameList(TRUE); - PeerResponse completeResp; - completeResp.peerResponseType = PeerResponse::PEERRESPONSE_STAGINGROOMLISTCOMPLETE; - TheGameSpyPeerMessageQueue->addResponse(completeResp); - } - } - - AsciiString gameName = name; - AsciiString tmp = gameName; - AsciiString hostName; - tmp.nextToken(&hostName, " "); - const char *firstSpace = gameName.find(' '); - if(firstSpace) - { - gameName.set(firstSpace + 1); - //gameName.trim(); - DEBUG_LOG(("Hostname/Gamename split leaves '%s' hosting '%s'", hostName.str(), gameName.str())); - } - PeerResponse resp; - resp.peerResponseType = PeerResponse::PEERRESPONSE_STAGINGROOM; - resp.stagingRoom.action = msg; - resp.stagingRoom.isStaging = staging; - resp.stagingRoom.percentComplete = percentListed; - - if (server && (msg == PEER_ADD || msg == PEER_UPDATE)) - { - Bool hasPassword = (Bool)SBServerGetIntValue(server, PW_STR, FALSE); - Bool allowObservers = (Bool)SBServerGetIntValue(server, OBS_STR, FALSE); - Bool usesStats = (Bool)SBServerGetIntValue(server, USE_STATS_STR, TRUE); - const char *verStr = SBServerGetStringValue(server, "gamever", "000000"); - const char *exeStr = SBServerGetStringValue(server, EXECRC_STR, "000000"); - const char *iniStr = SBServerGetStringValue(server, INICRC_STR, "000000"); - const char *ladIPStr = SBServerGetStringValue(server, LADIP_STR, "000000"); - const char *pingStr = SBServerGetStringValue(server, PINGSTR_STR, "FFFFFFFFFFFFFFFF"); - UnsignedShort ladPort = (UnsignedShort)SBServerGetIntValue(server, LADPORT_STR, 0); - UnsignedInt verVal = strtoul(verStr, NULL, 10); - UnsignedInt exeVal = strtoul(exeStr, NULL, 10); - UnsignedInt iniVal = strtoul(iniStr, NULL, 10); - resp.stagingRoom.requiresPassword = hasPassword; - resp.stagingRoom.allowObservers = allowObservers; - resp.stagingRoom.useStats = usesStats; - resp.stagingRoom.version = verVal; - resp.stagingRoom.exeCRC = exeVal; - resp.stagingRoom.iniCRC = iniVal; - resp.stagingServerLadderIP = ladIPStr; - resp.stagingServerPingString = pingStr; - resp.stagingRoom.ladderPort = ladPort; - resp.stagingRoom.numPlayers = SBServerGetIntValue(server, NUMPLAYER_STR, 0); - resp.stagingRoom.numObservers = SBServerGetIntValue(server, NUMOBS_STR, 0); - resp.stagingRoom.maxPlayers = SBServerGetIntValue(server, MAXPLAYER_STR, 8); - resp.stagingRoomMapName = SBServerGetStringValue(server, "mapname", ""); - for (Int i=0; ifindServer( server ); - DEBUG_LOG(("Add/update a 0/0 server %X (%d, %s) - requesting full update to see if that helps.", - server, resp.stagingRoom.id, gameName.str())); - TheGameSpyPeerMessageQueue->addRequest(req); - } - return; // don't actually try to list it. - } - } - - switch (msg) - { - case PEER_CLEAR: - t->clearServers(); - break; - case PEER_ADD: - case PEER_UPDATE: - resp.stagingRoom.id = t->findServer( server ); - DEBUG_LOG(("Add/update on server %X (%d, %s)", server, resp.stagingRoom.id, gameName.str())); - resp.stagingServerName = MultiByteToWideCharSingleLine( gameName.str() ); - DEBUG_LOG(("Server had basic=%d, full=%d", SBServerHasBasicKeys(server), SBServerHasFullKeys(server))); -#ifdef DEBUG_LOGGING - //SBServerEnumKeys(server, enumFunc, NULL); -#endif - break; - case PEER_REMOVE: - DEBUG_LOG(("Removing server %X (%d)", server, resp.stagingRoom.id)); - resp.stagingRoom.id = t->removeServerFromMap( server ); - break; - } - - TheGameSpyPeerMessageQueue->addResponse(resp); -} - -//------------------------------------------------------------------------- - diff --git a/Generals/Code/GameEngine/Source/GameNetwork/GameSpy/Thread/PersistentStorageThread.cpp b/Generals/Code/GameEngine/Source/GameNetwork/GameSpy/Thread/PersistentStorageThread.cpp deleted file mode 100644 index 34ff36f3a1..0000000000 --- a/Generals/Code/GameEngine/Source/GameNetwork/GameSpy/Thread/PersistentStorageThread.cpp +++ /dev/null @@ -1,1488 +0,0 @@ -/* -** 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. // -// // -//////////////////////////////////////////////////////////////////////////////// - -// FILE: PersistentStorageThread.cpp ////////////////////////////////////////////////////// -// GameSpy Persistent Storage thread -// This thread communicates with GameSpy's persistent storage server -// and talks through a message queue with the rest of -// the game. -// Author: Matthew D. Campbell, July 2002 - -#include "PreRTS.h" // This must go first in EVERY cpp file in the GameEngine - -#include "Common/UserPreferences.h" -#include "Common/PlayerTemplate.h" -#include "GameNetwork/GameSpy/PersistentStorageThread.h" -#include "GameNetwork/GameSpy/PeerDefs.h" - -#include "mutex.h" -#include "thread.h" - -#include "Common/SubsystemInterface.h" - - -//------------------------------------------------------------------------- - -PSRequest::PSRequest() -{ - player.reset(); - requestType = PSREQUEST_READPLAYERSTATS; - addDiscon = addDesync = FALSE; - lastHouse = -1; -} - -//------------------------------------------------------------------------- - -#define DEBUG_MAP(x) for (it = stats.x.begin(); it != stats.x.end(); ++it) \ -{ \ - if (it->second > 0) \ - { \ - DEBUG_LOG(("%s(%d): %d", #x, it->first, it->second)); \ - } \ -} - -static void debugDumpPlayerStats( const PSPlayerStats& stats ) -{ - DEBUG_LOG(("-----------------------------------------")); - DEBUG_LOG(("Tracking player stats for player %d:", stats.id)); - PerGeneralMap::const_iterator it; - DEBUG_MAP(wins); - DEBUG_MAP(losses); - DEBUG_MAP(games); - DEBUG_MAP(duration); - DEBUG_MAP(unitsKilled); - DEBUG_MAP(unitsLost); - DEBUG_MAP(unitsBuilt); - DEBUG_MAP(buildingsKilled); - DEBUG_MAP(buildingsLost); - DEBUG_MAP(buildingsBuilt); - DEBUG_MAP(earnings); - DEBUG_MAP(techCaptured); - DEBUG_MAP(discons); - DEBUG_MAP(desyncs); - DEBUG_MAP(surrenders); - DEBUG_MAP(gamesOf2p); - DEBUG_MAP(gamesOf3p); - DEBUG_MAP(gamesOf4p); - DEBUG_MAP(gamesOf5p); - DEBUG_MAP(gamesOf6p); - DEBUG_MAP(gamesOf7p); - DEBUG_MAP(gamesOf8p); - DEBUG_MAP(customGames); - DEBUG_MAP(QMGames); - - if (stats.locale > 0) - { - DEBUG_LOG(("Locale: %d", stats.locale)); - } - - if (stats.gamesAsRandom > 0) - { - DEBUG_LOG(("gamesAsRandom: %d", stats.gamesAsRandom)); - } - - if (stats.options.length()) - { - DEBUG_LOG(("Options: %s", stats.options.c_str())); - } - - if (stats.systemSpec.length()) - { - DEBUG_LOG(("systemSpec: %s", stats.systemSpec.c_str())); - } - - if (stats.lastFPS > 0.0f) - { - DEBUG_LOG(("lastFPS: %g", stats.lastFPS)); - } - - if (stats.battleHonors > 0) - { - DEBUG_LOG(("battleHonors: %x", stats.battleHonors)); - } - if (stats.challengeMedals > 0) - { - DEBUG_LOG(("challengeMedals: %x", stats.challengeMedals)); - } - if (stats.lastGeneral >= 0) - { - DEBUG_LOG(("lastGeneral: %d", stats.lastGeneral)); - } - if (stats.gamesInRowWithLastGeneral >= 0) - { - DEBUG_LOG(("gamesInRowWithLastGeneral: %d", stats.gamesInRowWithLastGeneral)); - } - if (stats.builtSCUD >= 0) - { - DEBUG_LOG(("builtSCUD: %d", stats.builtSCUD)); - } - if (stats.builtNuke >= 0) - { - DEBUG_LOG(("builtNuke: %d", stats.builtNuke)); - } - if (stats.builtParticleCannon >= 0) - { - DEBUG_LOG(("builtParticleCannon: %d", stats.builtParticleCannon)); - } - - if (stats.winsInARow >= 0) - { - DEBUG_LOG(("winsInARow: %d", stats.winsInARow)); - } - if (stats.maxWinsInARow >= 0) - { - DEBUG_LOG(("maxWinsInARow: %d", stats.maxWinsInARow)); - } - if (stats.disconsInARow >= 0) - { - DEBUG_LOG(("disconsInARow: %d", stats.disconsInARow)); - } - if (stats.maxDisconsInARow >= 0) - { - DEBUG_LOG(("maxDisconsInARow: %d", stats.maxDisconsInARow)); - } - if (stats.lossesInARow >= 0) - { - DEBUG_LOG(("lossesInARow: %d", stats.lossesInARow)); - } - if (stats.maxLossesInARow >= 0) - { - DEBUG_LOG(("maxLossesInARow: %d", stats.maxLossesInARow)); - } - if (stats.desyncsInARow >= 0) - { - DEBUG_LOG(("desyncsInARow: %d", stats.desyncsInARow)); - } - if (stats.maxDesyncsInARow >= 0) - { - DEBUG_LOG(("maxDesyncsInARow: %d", stats.maxDesyncsInARow)); - } - - if (stats.lastLadderPort >= 0) - { - DEBUG_LOG(("lastLadderPort: %d", stats.lastLadderPort)); - } - - if (stats.lastLadderHost.length()) - { - DEBUG_LOG(("lastLadderHost: %s", stats.lastLadderHost.c_str())); - } - - - -} - -//------------------------------------------------------------------------- - -#define INCORPORATE_MAP(x) for (it = other.x.begin(); it != other.x.end(); ++it) \ -{ \ - if (it->second > 0) \ - { \ - x[it->first] = it->second; \ - } \ -} - -void PSPlayerStats::incorporate( const PSPlayerStats& other ) -{ - PerGeneralMap::const_iterator it; - INCORPORATE_MAP(wins); - INCORPORATE_MAP(losses); - INCORPORATE_MAP(games); - INCORPORATE_MAP(duration); - INCORPORATE_MAP(unitsKilled); - INCORPORATE_MAP(unitsLost); - INCORPORATE_MAP(unitsBuilt); - INCORPORATE_MAP(buildingsKilled); - INCORPORATE_MAP(buildingsLost); - INCORPORATE_MAP(buildingsBuilt); - INCORPORATE_MAP(earnings); - INCORPORATE_MAP(techCaptured); - - //GS Clear all disconnects so that we don't retain any that were - //previously reported as 1 by updateAdditionalGameSpyDisconnections - discons.clear(); - INCORPORATE_MAP(discons); - - INCORPORATE_MAP(desyncs); - INCORPORATE_MAP(surrenders); - INCORPORATE_MAP(gamesOf2p); - INCORPORATE_MAP(gamesOf3p); - INCORPORATE_MAP(gamesOf4p); - INCORPORATE_MAP(gamesOf5p); - INCORPORATE_MAP(gamesOf6p); - INCORPORATE_MAP(gamesOf7p); - INCORPORATE_MAP(gamesOf8p); - INCORPORATE_MAP(customGames); - INCORPORATE_MAP(QMGames); - - if (other.locale > 0) - { - locale = other.locale; - } - - if (other.gamesAsRandom > 0) - { - gamesAsRandom = other.gamesAsRandom; - } - - if (other.options.length()) - { - options = other.options; - } - - if (other.systemSpec.length()) - { - systemSpec = other.systemSpec; - } - - if (other.lastFPS > 0.0f) - { - lastFPS = other.lastFPS; - } - - if (other.battleHonors > 0) - { - battleHonors |= other.battleHonors; - } - if (other.challengeMedals > 0) - { - challengeMedals |= other.challengeMedals; - } - if (other.lastGeneral >= 0) - { - lastGeneral = other.lastGeneral; - } - if (other.gamesInRowWithLastGeneral >= 0) - { - gamesInRowWithLastGeneral = other.gamesInRowWithLastGeneral; - } - if (other.builtParticleCannon >= 0) - { - builtParticleCannon = other.builtParticleCannon; - } - if (other.builtNuke >= 0) - { - builtNuke = other.builtNuke; - } - if (other.builtSCUD >= 0) - { - builtSCUD = other.builtSCUD; - } - if (other.winsInARow >= 0) - { - winsInARow = other.winsInARow; - } - if (other.maxWinsInARow >= 0) - { - maxWinsInARow = other.maxWinsInARow; - } - if (other.lossesInARow >= 0) - { - lossesInARow = other.lossesInARow; - } - if (other.maxLossesInARow >= 0) - { - maxLossesInARow = other.maxLossesInARow; - } - if (other.disconsInARow >= 0) - { - disconsInARow = other.disconsInARow; - } - if (other.maxDisconsInARow >= 0) - { - maxDisconsInARow = other.maxDisconsInARow; - } - if (other.desyncsInARow >= 0) - { - desyncsInARow = other.desyncsInARow; - } - if (other.maxDesyncsInARow >= 0) - { - maxDesyncsInARow = other.maxDesyncsInARow; - } - if (other.lastLadderPort >= 0) - { - lastLadderPort = other.lastLadderPort; - } - if (other.lastLadderHost.length()) - { - lastLadderHost = other.lastLadderHost; - } -} - -PSPlayerStats::PSPlayerStats( const PSPlayerStats& other ) -{ - incorporate(other); - id = other.id; - locale = other.locale; - gamesAsRandom = other.gamesAsRandom; - options = other.options; - systemSpec = other.systemSpec; - lastFPS = other.lastFPS; - lastGeneral = other.lastGeneral; - gamesInRowWithLastGeneral = other.gamesInRowWithLastGeneral; - builtParticleCannon = other.builtParticleCannon; - builtNuke = other.builtNuke; - builtSCUD = other.builtSCUD; - challengeMedals = other.challengeMedals; - battleHonors = other.battleHonors; - winsInARow = other.winsInARow; - maxWinsInARow = other.maxWinsInARow; - lossesInARow = other.lossesInARow; - maxLossesInARow = other.maxLossesInARow; - disconsInARow = other.disconsInARow; - maxDisconsInARow = other.maxDisconsInARow; - desyncsInARow = other.desyncsInARow; - maxDesyncsInARow = other.maxDesyncsInARow; - lastLadderHost = other.lastLadderHost; - lastLadderPort = other.lastLadderPort; -} - -//------------------------------------------------------------------------- - -typedef std::queue RequestQueue; -typedef std::queue ResponseQueue; -class PSThreadClass; - -class GameSpyPSMessageQueue : public GameSpyPSMessageQueueInterface -{ -public: - virtual ~GameSpyPSMessageQueue(); - GameSpyPSMessageQueue(); - virtual void startThread( void ); - virtual void endThread( void ); - virtual Bool isThreadRunning( void ); - - virtual void addRequest( const PSRequest& req ); - virtual Bool getRequest( PSRequest& req ); - - virtual void addResponse( const PSResponse& resp ); - virtual Bool getResponse( PSResponse& resp ); - - virtual void trackPlayerStats( PSPlayerStats stats ); - virtual PSPlayerStats findPlayerStatsByID( Int id ); - - PSThreadClass* getThread( void ); - - Int getLocalPlayerID(void) { return m_localPlayerID; } - void setLocalPlayerID(Int localPlayerID) { m_localPlayerID = localPlayerID; } - - std::string getEmail() { return m_email; } - std::string getNick() { return m_nick; } - std::string getPassword() { return m_password; } - - void setEmail(std::string email) { m_email = email; } - void setNick(std::string nick) { m_nick = nick; } - void setPassword(std::string password) { m_password = password; } - -private: - MutexClass m_requestMutex; - MutexClass m_responseMutex; - RequestQueue m_requests; - ResponseQueue m_responses; - PSThreadClass *m_thread; - Int m_localPlayerID; - - std::string m_email; - std::string m_nick; - std::string m_password; - - std::map m_playerStats; -}; - -GameSpyPSMessageQueueInterface* GameSpyPSMessageQueueInterface::createNewMessageQueue( void ) -{ - return NEW GameSpyPSMessageQueue; -} - -GameSpyPSMessageQueueInterface *TheGameSpyPSMessageQueue = NULL; -#define MESSAGE_QUEUE ((GameSpyPSMessageQueue *)TheGameSpyPSMessageQueue) - -//------------------------------------------------------------------------- - -class PSThreadClass : public ThreadClass -{ - -public: - PSThreadClass() : ThreadClass() - { - m_loginOK = m_sawLocalData = m_doneTryingToLogin = false; - m_opCount = 0; - } - - void Thread_Function(); - - void persAuthCallback( Bool val ) { m_loginOK = val; m_doneTryingToLogin = true; } - void decrOpCount( void ) { --m_opCount; } - void incrOpCount( void ) { ++m_opCount; } - Int getOpCount( void ) { return m_opCount; } - Bool sawLocalPlayerData( void ) { return m_sawLocalData; } - void gotLocalPlayerData( void ) { m_sawLocalData = TRUE; } - -private: - Bool tryConnect( void ); - Bool tryLogin( Int id, std::string nick, std::string password, std::string email ); - Bool m_loginOK; - Bool m_doneTryingToLogin; - Int m_opCount; - Bool m_sawLocalData; -}; - - -//------------------------------------------------------------------------- - -GameSpyPSMessageQueue::GameSpyPSMessageQueue() -{ - m_thread = NULL; - m_localPlayerID = 0; -} - -GameSpyPSMessageQueue::~GameSpyPSMessageQueue() -{ - endThread(); -} - -void GameSpyPSMessageQueue::startThread( void ) -{ - if (!m_thread) - { - m_thread = NEW PSThreadClass; - m_thread->Execute(); - } - else - { - if (!m_thread->Is_Running()) - { - m_thread->Execute(); - } - } -} - -void GameSpyPSMessageQueue::endThread( void ) -{ - delete m_thread; - m_thread = NULL; -} - -Bool GameSpyPSMessageQueue::isThreadRunning( void ) -{ - return (m_thread) ? m_thread->Is_Running() : false; -} - -void GameSpyPSMessageQueue::addRequest( const PSRequest& req ) -{ - MutexClass::LockClass m(m_requestMutex); - if (m.Failed()) - return; - - m_requests.push(req); -} - -Bool GameSpyPSMessageQueue::getRequest( PSRequest& req ) -{ - MutexClass::LockClass m(m_requestMutex, 0); - if (m.Failed()) - return false; - - if (m_requests.empty()) - return false; - req = m_requests.front(); - m_requests.pop(); - return true; -} - -void GameSpyPSMessageQueue::addResponse( const PSResponse& resp ) -{ - MutexClass::LockClass m(m_responseMutex); - if (m.Failed()) - return; - - m_responses.push(resp); -} - -Bool GameSpyPSMessageQueue::getResponse( PSResponse& resp ) -{ - MutexClass::LockClass m(m_responseMutex, 0); - if (m.Failed()) - return false; - - if (m_responses.empty()) - return false; - resp = m_responses.front(); - m_responses.pop(); - return true; -} - -PSThreadClass* GameSpyPSMessageQueue::getThread( void ) -{ - return m_thread; -} - -void GameSpyPSMessageQueue::trackPlayerStats( PSPlayerStats stats ) -{ -#ifdef DEBUG_LOGGING - debugDumpPlayerStats( stats ); - DEBUG_ASSERTCRASH(stats.id != 0, ("Tracking stats with ID of 0")); -#endif - PSPlayerStats newStats; - std::map::iterator it = m_playerStats.find(stats.id); - if (it != m_playerStats.end()) - { - newStats = it->second; - newStats.incorporate(stats); - m_playerStats[stats.id] = newStats; - } - else - { - m_playerStats[stats.id] = stats; - } -} - -PSPlayerStats GameSpyPSMessageQueue::findPlayerStatsByID( Int id ) -{ - std::map::iterator it = m_playerStats.find(id); - if (it != m_playerStats.end()) - { - return it->second; - } - - PSPlayerStats empty; - empty.id = 0; - return empty; -} - -//------------------------------------------------------------------------- - -Bool PSThreadClass::tryConnect( void ) -{ - Int result; - - DEBUG_LOG(("m_opCount = %d - opening connection", m_opCount)); - - if (IsStatsConnected()) - { - DEBUG_LOG(("connection already open!")); - return true; - } - - // this may block for 1-2 seconds (according to GS) so it's nice we're not in the UI thread :) - result = InitStatsConnection(0); - - if (result != GE_NOERROR) - { - DEBUG_LOG(("InitStatsConnection() returned %d", result)); - return false; - } - - return true; -} - -static void persAuthCallback(int localid, int profileid, int authenticated, char *errmsg, void *instance) -{ - PSThreadClass *t = (PSThreadClass *)instance; - DEBUG_LOG(("Auth callback: localid: %d profileid: %d auth: %d err: %s",localid, profileid, authenticated, errmsg)); - if (t) - t->persAuthCallback(authenticated != 0); -} - -Bool PSThreadClass::tryLogin( Int id, std::string nick, std::string password, std::string email ) -{ - char validate[33]; - DEBUG_LOG(("PSThreadClass::tryLogin id = %d, nick = %s, password = %s, email = %s", id, nick.c_str(), password.c_str(), email.c_str())); - /*********** - We'll go ahead and start the authentication, using a Presence & Messaging SDK - profileid / password. To generate the new validation token, we'll need to pass - in the password for the profile we are authenticating. - Again, if this is done in a client/server setting, with the Persistent Storage - access being done on the server, and the P&M SDK is used on the client, the - server will need to send the challenge (GetChallenge(NULL)) to the client, the - client will create the validation token using GenerateAuth, and send it - back to the server for use in PreAuthenticatePlayerPM - ***********/ - char *munkeeHack = strdup(password.c_str()); // GenerateAuth takes a char*, not a const char* :P - GenerateAuth(GetChallenge(NULL), munkeeHack, validate); - free (munkeeHack); - - /************ - After we get the validation token, we pass it and the profileid of the user - we are authenticating into PreAuthenticatePlayerPM. - We pass the same authentication callback as for the first user, but a different - localid this time. - ************/ - m_loginOK = false; - m_doneTryingToLogin = false; - PreAuthenticatePlayerPM(id, id, validate, ::persAuthCallback, this); - while (!m_doneTryingToLogin && IsStatsConnected()) - PersistThink(); - DEBUG_LOG(("Persistant Storage Login success %d", m_loginOK)); - return m_loginOK; -} - -static void getPersistentDataCallback(int localid, int profileid, persisttype_t type, int index, int success, time_t modified, char *data, int len, void *instance) -{ - DEBUG_LOG(("Data get callback: localid: %d profileid: %d success: %d len: %d data: %s",localid, profileid, success, len, data)); - PSThreadClass *t = (PSThreadClass *)instance; - if (!t) - return; - - t->decrOpCount(); - - PSResponse resp; - - if (!success) - { - resp.responseType = PSResponse::PSRESPONSE_COULDNOTCONNECT; - resp.player.id = profileid; - TheGameSpyPSMessageQueue->addResponse(resp); - if (!t->getOpCount() && !t->sawLocalPlayerData()) - { - // we haven't gotten stats for ourselves - try again - PSRequest req; - req.requestType = PSRequest::PSREQUEST_READPLAYERSTATS; - req.player.id = MESSAGE_QUEUE->getLocalPlayerID(); - TheGameSpyPSMessageQueue->addRequest(req); - } - return; - } - - if (profileid == MESSAGE_QUEUE->getLocalPlayerID() && TheGameSpyGame && TheGameSpyGame->getUseStats()) - { - t->gotLocalPlayerData(); - DEBUG_LOG(("getPersistentDataCallback() - got local player info")); - - // check if we have discons we should update on the server - UserPreferences pref; - AsciiString userPrefFilename; - userPrefFilename.format("GeneralsOnline\\MiscPref%d.ini", MESSAGE_QUEUE->getLocalPlayerID()); - DEBUG_LOG(("using the file %s", userPrefFilename.str())); - pref.load(userPrefFilename); - Int addedInDesyncs2 = pref.getInt("0", 0); - DEBUG_LOG(("addedInDesyncs2 = %d", addedInDesyncs2)); - if (addedInDesyncs2 < 0) - addedInDesyncs2 = 10; - Int addedInDesyncs3 = pref.getInt("1", 0); - DEBUG_LOG(("addedInDesyncs3 = %d", addedInDesyncs3)); - if (addedInDesyncs3 < 0) - addedInDesyncs3 = 10; - Int addedInDesyncs4 = pref.getInt("2", 0); - DEBUG_LOG(("addedInDesyncs4 = %d", addedInDesyncs4)); - if (addedInDesyncs4 < 0) - addedInDesyncs4 = 10; - Int addedInDiscons2 = pref.getInt("3", 0); - DEBUG_LOG(("addedInDiscons2 = %d", addedInDiscons2)); - if (addedInDiscons2 < 0) - addedInDiscons2 = 10; - Int addedInDiscons3 = pref.getInt("4", 0); - DEBUG_LOG(("addedInDiscons3 = %d", addedInDiscons3)); - if (addedInDiscons3 < 0) - addedInDiscons3 = 10; - Int addedInDiscons4 = pref.getInt("5", 0); - DEBUG_LOG(("addedInDiscons4 = %d", addedInDiscons4)); - if (addedInDiscons4 < 0) - addedInDiscons4 = 10; - - DEBUG_LOG(("addedInDesync=%d,%d,%d, addedInDiscon=%d,%d,%d", - addedInDesyncs2, addedInDesyncs3, addedInDesyncs4, - addedInDiscons2, addedInDiscons3, addedInDiscons4)); - - if (addedInDesyncs2 || addedInDesyncs3 || addedInDesyncs4 || addedInDiscons2 || addedInDiscons3 || addedInDiscons4) - { - DEBUG_LOG(("We have a previous discon we can attempt to update! Bummer...")); - - PSRequest req; - req.requestType = PSRequest::PSREQUEST_UPDATEPLAYERSTATS; - req.email = MESSAGE_QUEUE->getEmail(); - req.nick = MESSAGE_QUEUE->getNick(); - req.password = MESSAGE_QUEUE->getPassword(); - req.player = GameSpyPSMessageQueueInterface::parsePlayerKVPairs((len)?data:""); - req.player.id = profileid; - req.addDesync = FALSE; - req.addDiscon = FALSE; - req.lastHouse = 0; - TheGameSpyPSMessageQueue->addRequest(req); - } - } - - resp.responseType = PSResponse::PSRESPONSE_PLAYERSTATS; - resp.player = GameSpyPSMessageQueueInterface::parsePlayerKVPairs((len)?data:""); - resp.player.id = profileid; - - TheGameSpyPSMessageQueue->addResponse(resp); -} - -static void setPersistentDataLocaleCallback(int localid, int profileid, persisttype_t type, int index, int success, time_t modified, void *instance) -{ - DEBUG_LOG(("Data save callback: localid: %d profileid: %d success: %d", localid, profileid, success)); - - PSThreadClass *t = (PSThreadClass *)instance; - if (!t) - return; - - t->decrOpCount(); -} - -static void setPersistentDataCallback(int localid, int profileid, persisttype_t type, int index, int success, time_t modified, void *instance) -{ - DEBUG_LOG(("Data save callback: localid: %d profileid: %d success: %d", localid, profileid, success)); - - PSThreadClass *t = (PSThreadClass *)instance; - if (!t) - return; - - if (success) - { - UserPreferences pref; - AsciiString userPrefFilename; - userPrefFilename.format("GeneralsOnline\\MiscPref%d.ini", profileid); - DEBUG_LOG(("setPersistentDataCallback - writing stats to file %s", userPrefFilename.str())); - pref.load(userPrefFilename); - pref.clear(); - pref.write(); - } - t->decrOpCount(); -} - -struct CDAuthInfo -{ - Bool success; - Bool done; - Int id; -}; - -void preAuthCDCallback(int localid, int profileid, int authenticated, char *errmsg, void *instance) -{ - DEBUG_LOG(("preAuthCDCallback(): profileid: %d auth: %d err: %s", profileid, authenticated, errmsg)); - - CDAuthInfo *authInfo = (CDAuthInfo *)instance; - authInfo->success = authenticated; - authInfo->done = TRUE; - authInfo->id = profileid; -} - -static void getPreorderCallback(int localid, int profileid, persisttype_t type, int index, int success, time_t modified, char *data, int len, void *instance) -{ - PSThreadClass *t = (PSThreadClass *)instance; - if (!t) - return; - - t->decrOpCount(); - - PSResponse resp; - - if (!success) - { - DEBUG_LOG(("Failed getPreorderCallback()")); - return; - } - - resp.responseType = PSResponse::PSRESPONSE_PREORDER; - resp.preorder = (data && strcmp(data, "\\preorder\\1") == 0); - DEBUG_LOG(("getPreorderCallback() - data was '%s'", data)); - - TheGameSpyPSMessageQueue->addResponse(resp); -} - -void PSThreadClass::Thread_Function() -{ - try { - /********* - First step, set our game authentication info - We could do: - Generals: - strcpy(gcd_gamename,"ccgenerals"); - strcpy(gcd_secret_key,"h5T2f6"); - ZeroHour: - strcpy(gcd_gamename,"ccgenzh"); - strcpy(gcd_secret_key,"D6s9k3"); - or - Generals: - strcpy(gcd_gamename,"ccgeneralsb"); - strcpy(gcd_secret_key,"g3T9s2"); - ZeroHour: - strcpy(gcd_gamename,"ccgeneralsb"); - strcpy(gcd_secret_key,"whatever the key is"); - ...but this is more secure: - **********/ - /** - gcd_gamename[0]='c';gcd_gamename[1]='c';gcd_gamename[2]='g';gcd_gamename[3]='e'; - gcd_gamename[4]='n';gcd_gamename[5]='e';gcd_gamename[6]='r';gcd_gamename[7]='a'; - gcd_gamename[8]='l';gcd_gamename[9]='s';gcd_gamename[10]='b';gcd_gamename[11]='\0'; - gcd_secret_key[0]='g';gcd_secret_key[1]='3';gcd_secret_key[2]='T';gcd_secret_key[3]='9'; - gcd_secret_key[4]='s';gcd_secret_key[5]='2';gcd_secret_key[6]='\0'; - /**/ -#if RTS_GENERALS - gcd_gamename[0]='c';gcd_gamename[1]='c';gcd_gamename[2]='g';gcd_gamename[3]='e'; - gcd_gamename[4]='n';gcd_gamename[5]='e';gcd_gamename[6]='r';gcd_gamename[7]='a'; - gcd_gamename[8]='l';gcd_gamename[9]='s';gcd_gamename[10]='\0'; - gcd_secret_key[0]='h';gcd_secret_key[1]='5';gcd_secret_key[2]='T';gcd_secret_key[3]='2'; - gcd_secret_key[4]='f';gcd_secret_key[5]='6';gcd_secret_key[6]='\0'; -#elif RTS_ZEROHOUR - gcd_gamename[0]='c';gcd_gamename[1]='c';gcd_gamename[2]='g';gcd_gamename[3]='e'; - gcd_gamename[4]='n';gcd_gamename[5]='z';gcd_gamename[6]='h';gcd_gamename[7]='\0'; - gcd_secret_key[0]='D';gcd_secret_key[1]='6';gcd_secret_key[2]='s';gcd_secret_key[3]='9'; - gcd_secret_key[4]='k';gcd_secret_key[5]='3';gcd_secret_key[6]='\0'; -#endif - /**/ - - //strcpy(StatsServerHostname, "sdkdev.gamespy.com"); - - PSRequest req; - while ( running ) - { - // deal with requests - if (TheGameSpyPSMessageQueue->getRequest(req)) - { - switch (req.requestType) - { - case PSRequest::PSREQUEST_SENDGAMERESTOGAMESPY: - { - if (tryConnect()) - { - NewGame(0); -#ifdef DEBUG_LOGGING - Int res = -#endif // DEBUG_LOGGING - SendGameSnapShot(NULL, req.results.c_str(), SNAP_FINAL); - DEBUG_LOG(("Just sent game results - res was %d", res)); - FreeGame(NULL); - } - } - break; - case PSRequest::PSREQUEST_READPLAYERSTATS: - { - if (!MESSAGE_QUEUE->getLocalPlayerID()) - { - MESSAGE_QUEUE->setLocalPlayerID(req.player.id); // first request is for ourselves - MESSAGE_QUEUE->setEmail(req.email); - MESSAGE_QUEUE->setNick(req.nick); - MESSAGE_QUEUE->setPassword(req.password); - DEBUG_LOG(("Setting email/nick/password = %s/%s/%s", req.email.c_str(), req.nick.c_str(), req.password.c_str())); - } - DEBUG_LOG(("Processing PSRequest::PSREQUEST_READPLAYERSTATS")); - if (tryConnect()) - { - incrOpCount(); - gsi_char keys[] = ""; - GetPersistDataValues(0, req.player.id, pd_public_rw, 0, keys, getPersistentDataCallback, this); - } - } - break; - case PSRequest::PSREQUEST_UPDATEPLAYERLOCALE: - { - DEBUG_LOG(("Processing PSRequest::PSREQUEST_UPDATEPLAYERLOCALE")); - if (tryConnect() && tryLogin(req.player.id, req.nick, req.password, req.email)) - { - char kvbuf[256]; - sprintf(kvbuf, "\\locale\\%d", req.player.locale); - incrOpCount(); - SetPersistDataValues(0, req.player.id, pd_public_rw, 0, kvbuf, setPersistentDataLocaleCallback, this); - } - } - break; - case PSRequest::PSREQUEST_UPDATEPLAYERSTATS: - { - /* - ** NOTE THAT THIS IS HIGHLY DEPENDENT ON INI ORDERING FOR THE PLAYERTEMPLATES!!! - */ - DEBUG_LOG(("Processing PSRequest::PSREQUEST_UPDATEPLAYERSTATS")); - UserPreferences pref; - AsciiString userPrefFilename; - userPrefFilename.format("GeneralsOnline\\MiscPref%d.ini", MESSAGE_QUEUE->getLocalPlayerID()); - DEBUG_LOG(("using the file %s", userPrefFilename.str())); - pref.load(userPrefFilename); - Int addedInDesyncs2 = pref.getInt("0", 0); - DEBUG_LOG(("addedInDesyncs2 = %d", addedInDesyncs2)); - if (addedInDesyncs2 < 0) - addedInDesyncs2 = 10; - Int addedInDesyncs3 = pref.getInt("1", 0); - DEBUG_LOG(("addedInDesyncs3 = %d", addedInDesyncs3)); - if (addedInDesyncs3 < 0) - addedInDesyncs3 = 10; - Int addedInDesyncs4 = pref.getInt("2", 0); - DEBUG_LOG(("addedInDesyncs4 = %d", addedInDesyncs4)); - if (addedInDesyncs4 < 0) - addedInDesyncs4 = 10; - Int addedInDiscons2 = pref.getInt("3", 0); - DEBUG_LOG(("addedInDiscons2 = %d", addedInDiscons2)); - if (addedInDiscons2 < 0) - addedInDiscons2 = 10; - Int addedInDiscons3 = pref.getInt("4", 0); - DEBUG_LOG(("addedInDiscons3 = %d", addedInDiscons3)); - if (addedInDiscons3 < 0) - addedInDiscons3 = 10; - Int addedInDiscons4 = pref.getInt("5", 0); - DEBUG_LOG(("addedInDiscons4 = %d", addedInDiscons4)); - if (addedInDiscons4 < 0) - addedInDiscons4 = 10; - - DEBUG_LOG(("req.addDesync=%d, req.addDiscon=%d, addedInDesync=%d,%d,%d, addedInDiscon=%d,%d,%d", - req.addDesync, req.addDiscon, addedInDesyncs2, addedInDesyncs3, addedInDesyncs4, - addedInDiscons2, addedInDiscons3, addedInDiscons4)); - - if (req.addDesync || req.addDiscon) - { - AsciiString val; - if (req.lastHouse == 2) - { - val.format("%d", addedInDesyncs2 + req.addDesync); - pref["0"] = val; - val.format("%d", addedInDiscons2 + req.addDiscon); - pref["3"] = val; - DEBUG_LOG(("house 2 req.addDesync || req.addDiscon: %d %d", - addedInDesyncs2 + req.addDesync, addedInDiscons2 + req.addDiscon)); - } - else if (req.lastHouse == 3) - { - val.format("%d", addedInDesyncs3 + req.addDesync); - pref["1"] = val; - val.format("%d", addedInDiscons3 + req.addDiscon); - pref["4"] = val; - DEBUG_LOG(("house 3 req.addDesync || req.addDiscon: %d %d", - addedInDesyncs3 + req.addDesync, addedInDiscons3 + req.addDiscon)); - } - else - { - val.format("%d", addedInDesyncs4 + req.addDesync); - pref["2"] = val; - val.format("%d", addedInDiscons4 + req.addDiscon); - pref["5"] = val; - DEBUG_LOG(("house 4 req.addDesync || req.addDiscon: %d %d", - addedInDesyncs4 + req.addDesync, addedInDiscons4 + req.addDiscon)); - } - pref.write(); - if (req.password.size() == 0) - return; - } - if (!req.player.id) - { - DEBUG_LOG(("Bailing because ID is NULL!")); - return; - } - req.player.desyncs[2] += addedInDesyncs2; - req.player.games[2] += addedInDesyncs2; - req.player.discons[2] += addedInDiscons2; - req.player.games[2] += addedInDiscons2; - req.player.desyncs[3] += addedInDesyncs3; - req.player.games[3] += addedInDesyncs3; - req.player.discons[3] += addedInDiscons3; - req.player.games[3] += addedInDiscons3; - req.player.desyncs[4] += addedInDesyncs4; - req.player.games[4] += addedInDesyncs4; - req.player.discons[4] += addedInDiscons4; - req.player.games[4] += addedInDiscons4; - DEBUG_LOG(("House2: %d/%d/%d, House3: %d/%d/%d, House4: %d/%d/%d", - req.player.desyncs[2], req.player.discons[2], req.player.games[2], - req.player.desyncs[3], req.player.discons[3], req.player.games[3], - req.player.desyncs[4], req.player.discons[4], req.player.games[4] - )); - if (tryConnect() && tryLogin(req.player.id, req.nick, req.password, req.email)) - { - DEBUG_LOG(("Logged in!")); - if (TheGameSpyPSMessageQueue) - TheGameSpyPSMessageQueue->trackPlayerStats(req.player); - - char *munkeeHack = strdup(GameSpyPSMessageQueueInterface::formatPlayerKVPairs(req.player).c_str()); // GS takes a char* for some reason - incrOpCount(); - DEBUG_LOG(("Setting values %s", munkeeHack)); - SetPersistDataValues(0, req.player.id, pd_public_rw, 0, munkeeHack, setPersistentDataCallback, this); - free(munkeeHack); - } - else - { - DEBUG_LOG(("Cannot connect!")); - //if (IsStatsConnected()) - //CloseStatsConnection(); - } - } - break; - case PSRequest::PSREQUEST_READCDKEYSTATS: - { - DEBUG_LOG(("Processing PSRequest::PSREQUEST_READCDKEYSTATS")); - if (tryConnect()) - { - incrOpCount(); - CDAuthInfo cdAuthInfo; - cdAuthInfo.done = FALSE; - cdAuthInfo.success = FALSE; - cdAuthInfo.id = 0; - char cdkeyHash[33] = ""; - char validationToken[33] = ""; - char *munkeeHack = strdup(req.cdkey.c_str()); // GenerateAuth takes a char*, not a const char* :P - - GenerateAuth(GetChallenge(NULL), munkeeHack, validationToken); // validation token - GenerateAuth("", munkeeHack, cdkeyHash); // cdkey hash - - free (munkeeHack); - - PreAuthenticatePlayerCD( 0, "preorder", cdkeyHash, validationToken, preAuthCDCallback , &cdAuthInfo); - - while (running && IsStatsConnected() && !cdAuthInfo.done) - PersistThink(); - - DEBUG_LOG(("Looking for preorder status for %d (success=%d, done=%d) from CDKey %s with hash %s", - cdAuthInfo.id, cdAuthInfo.success, cdAuthInfo.done, req.cdkey.c_str(), cdkeyHash)); - if (cdAuthInfo.done && cdAuthInfo.success) - { - gsi_char keys[] = "\\preorder"; - GetPersistDataValues(0, cdAuthInfo.id, pd_public_ro, 0, keys, getPreorderCallback, this); - } - else - decrOpCount(); - } - } - break; - } - } - - // update the network - if (IsStatsConnected()) - { - PersistThink(); - if (m_opCount <= 0) - { - DEBUG_ASSERTCRASH(m_opCount == 0, ("Negative operations pending!!!")); - DEBUG_LOG(("m_opCount = %d - closing connection", m_opCount)); - CloseStatsConnection(); - m_opCount = 0; - } - } - - // end our timeslice - Switch_Thread(); - } - - if (IsStatsConnected()) - CloseStatsConnection(); - } catch ( ... ) { - DEBUG_CRASH(("Exception in storage thread!")); - } -} - -//------------------------------------------------------------------------- -PSPlayerStats::PSPlayerStats( void ) -{ - reset(); -} - -void PSPlayerStats::reset( void ) -{ - id = 0; - locale = 0; - gamesAsRandom = 0; - lastFPS = 0; - lastGeneral = 0; - gamesInRowWithLastGeneral = 0; - builtNuke = 0; - builtSCUD = 0; - builtParticleCannon = 0; - challengeMedals = 0; - battleHonors = 0; - winsInARow = 0; - maxWinsInARow = 0; - lossesInARow = 0; - maxLossesInARow = 0; - disconsInARow = 0; - maxDisconsInARow = 0; - desyncsInARow = 0; - maxDesyncsInARow = 0; - lastLadderPort = 0; - - //Added By Sadullah Nader - maxQMwinsInARow = 0; - QMwinsInARow = 0; - // -} - -//------------------------------------------------------------------------- -#define CHECK(x) if (k == #x && generalMarker >= 0) { s.x[generalMarker] = atoi(v.c_str()); continue; } - -PSPlayerStats GameSpyPSMessageQueueInterface::parsePlayerKVPairs( std::string kvPairs ) -{ - PSPlayerStats s; - kvPairs.append("\\"); - - Int offset = 0; - while (1) - { - Int firstMarker = kvPairs.find_first_of('\\', offset); - if (firstMarker < 0) - break; - Int secondMarker = kvPairs.find_first_of('\\', firstMarker + 1); - if (secondMarker < 0) - break; - Int thirdMarker = kvPairs.find_first_of('\\', secondMarker + 1); - if (thirdMarker < 0) - break; - Int generalMarker = kvPairs.find_last_not_of("0123456789", secondMarker - 1); - std::string k, v, g; - if (generalMarker == secondMarker - 1) - { - k = kvPairs.substr(firstMarker + 1, secondMarker - firstMarker - 1); - generalMarker = -1; - } - else - { - k = kvPairs.substr(firstMarker + 1, generalMarker - firstMarker); - g = kvPairs.substr(generalMarker + 1, secondMarker - generalMarker - 1); - generalMarker = atoi(g.c_str()); - } - v = kvPairs.substr(secondMarker + 1, thirdMarker - secondMarker - 1); - //DEBUG_LOG(("%d [%s] [%s]", generalMarker, k.c_str(), v.c_str())); - offset = thirdMarker - 1; - - CHECK(wins); - CHECK(losses); - CHECK(games); - CHECK(duration); - CHECK(unitsKilled); - CHECK(unitsLost); - CHECK(unitsBuilt); - CHECK(buildingsKilled); - CHECK(buildingsLost); - CHECK(buildingsBuilt); - CHECK(earnings); - CHECK(techCaptured); - CHECK(discons); - CHECK(desyncs); - CHECK(surrenders); - CHECK(gamesOf2p); - CHECK(gamesOf3p); - CHECK(gamesOf4p); - CHECK(gamesOf5p); - CHECK(gamesOf6p); - CHECK(gamesOf7p); - CHECK(gamesOf8p); - CHECK(customGames); - CHECK(QMGames); - - if (k == "locale" && generalMarker < 0) - { - s.locale = atoi(v.c_str()); - continue; - } - - if (k == "random" && generalMarker < 0) - { - s.gamesAsRandom = atoi(v.c_str()); - continue; - } - - if (k == "options" && generalMarker < 0) - { - s.options = v; - continue; - } - - if (k == "systemSpec" && generalMarker < 0) - { - s.systemSpec = v; - continue; - } - - if (k == "fps" && generalMarker < 0) - { - s.lastFPS = atof(v.c_str()); - continue; - } - - if (k == "lastGeneral" && generalMarker < 0) - { - s.lastGeneral = atoi(v.c_str()); - continue; - } - if (k == "genInRow" && generalMarker < 0) - { - s.gamesInRowWithLastGeneral = atoi(v.c_str()); - continue; - } - if (k == "builtNuke" && generalMarker < 0) - { - s.builtNuke = atoi(v.c_str()); - continue; - } - if (k == "builtSCUD" && generalMarker < 0) - { - s.builtSCUD = atoi(v.c_str()); - continue; - } - if (k == "builtCannon" && generalMarker < 0) - { - s.builtParticleCannon = atoi(v.c_str()); - continue; - } - if (k == "challenge" && generalMarker < 0) - { - s.challengeMedals = atoi(v.c_str()); - continue; - } - if (k == "battle" && generalMarker < 0) - { - s.battleHonors = atoi(v.c_str()); - continue; - } - - if (k == "WinRow" && generalMarker < 0) - { - s.winsInARow = atoi(v.c_str()); - continue; - } - if (k == "WinRowMax" && generalMarker < 0) - { - s.maxWinsInARow = atoi(v.c_str()); - continue; - } - - if (k == "LossRow" && generalMarker < 0) - { - s.lossesInARow = atoi(v.c_str()); - continue; - } - if (k == "LossRowMax" && generalMarker < 0) - { - s.maxLossesInARow = atoi(v.c_str()); - continue; - } - - if (k == "DSRow" && generalMarker < 0) - { - s.desyncsInARow = atoi(v.c_str()); - continue; - } - if (k == "DSRowMax" && generalMarker < 0) - { - s.maxDesyncsInARow = atoi(v.c_str()); - continue; - } - - if (k == "DCRow" && generalMarker < 0) - { - s.disconsInARow = atoi(v.c_str()); - continue; - } - if (k == "DCRowMax" && generalMarker < 0) - { - s.maxDisconsInARow = atoi(v.c_str()); - continue; - } - - if (k == "ladderPort" && generalMarker < 0) - { - s.lastLadderPort = atoi(v.c_str()); - continue; - } - if (k == "ladderHost" && generalMarker < 0) - { - s.lastLadderHost = v; - continue; - } - - //DEBUG_ASSERTCRASH(generalMarker >= 0, ("Unknown KV Pair in persistent storage: [%s] = [%s]", k.c_str(), v.c_str())); - //DEBUG_ASSERTCRASH(generalMarker < 0, ("Unknown KV Pair in persistent storage for PlayerTemplate %d: [%s] = [%s]", generalMarker, k.c_str(), v.c_str())); - } - - return s; -} - -#define ITERATE_OVER(x) for (it = stats.x.begin(); it != stats.x.end(); ++it) \ -{ \ - if (it->second > 0) \ - { \ - sprintf(kvbuf, "\\" #x "%d\\%d", it->first, it->second); \ - s.append(kvbuf); \ - } \ -} - -#include "Common/PlayerTemplate.h" - -std::string GameSpyPSMessageQueueInterface::formatPlayerKVPairs( PSPlayerStats stats ) -{ - char kvbuf[256]; - std::string s = ""; - PerGeneralMap::iterator it; - - ITERATE_OVER(wins); - ITERATE_OVER(losses); - ITERATE_OVER(games); - ITERATE_OVER(duration); - ITERATE_OVER(unitsKilled); - ITERATE_OVER(unitsLost); - ITERATE_OVER(unitsBuilt); - ITERATE_OVER(buildingsKilled); - ITERATE_OVER(buildingsLost); - ITERATE_OVER(buildingsBuilt); - ITERATE_OVER(earnings); - ITERATE_OVER(techCaptured); - - //GS Report all disconnects, even if zero, because might have been - //previously reported as 1 by updateAdditionalGameSpyDisconnections -// ITERATE_OVER(discons); - for (Int ptIdx = 0; ptIdx < ThePlayerTemplateStore->getPlayerTemplateCount(); ++ptIdx) - { -// const PlayerTemplate* pTemplate = ThePlayerTemplateStore->getNthPlayerTemplate(ptIdx); -// const GeneralPersona* pGeneral = TheChallengeGenerals->getGeneralByTemplateName(pTemplate->getName()); -// BOOL isReported = pGeneral ? pGeneral->isStartingEnabled() : FALSE; -// if( !isReported ) -// continue; //don't report unplayable templates (observer, boss, etc.) - - sprintf(kvbuf, "\\discons%d\\%d", ptIdx, stats.discons[ptIdx]); - s.append(kvbuf); - } - - ITERATE_OVER(desyncs); - ITERATE_OVER(surrenders); - ITERATE_OVER(gamesOf2p); - ITERATE_OVER(gamesOf3p); - ITERATE_OVER(gamesOf4p); - ITERATE_OVER(gamesOf5p); - ITERATE_OVER(gamesOf6p); - ITERATE_OVER(gamesOf7p); - ITERATE_OVER(gamesOf8p); - ITERATE_OVER(customGames); - ITERATE_OVER(QMGames); - - if (stats.locale > 0) - { - sprintf(kvbuf, "\\locale\\%d", stats.locale); - s.append(kvbuf); - } - - if (stats.gamesAsRandom > 0) - { - sprintf(kvbuf, "\\random\\%d", stats.gamesAsRandom); - s.append(kvbuf); - } - - if (stats.options.length()) - { - snprintf(kvbuf, 256, "\\options\\%s", stats.options.c_str()); - s.append(kvbuf); - } - - if (stats.systemSpec.length()) - { - snprintf(kvbuf, 256, "\\systemSpec\\%s", stats.systemSpec.c_str()); - s.append(kvbuf); - } - - if (stats.lastFPS > 0.0f) - { - sprintf(kvbuf, "\\fps\\%g", stats.lastFPS); - s.append(kvbuf); - } - if (stats.lastGeneral >= 0) - { - sprintf(kvbuf, "\\lastGeneral\\%d", stats.lastGeneral); - s.append(kvbuf); - } - if (stats.gamesInRowWithLastGeneral >= 0) - { - sprintf(kvbuf, "\\genInRow\\%d", stats.gamesInRowWithLastGeneral); - s.append(kvbuf); - } - if (stats.builtParticleCannon >= 0) - { - sprintf(kvbuf, "\\builtCannon\\%d", stats.builtParticleCannon); - s.append(kvbuf); - } - if (stats.builtNuke >= 0) - { - sprintf(kvbuf, "\\builtNuke\\%d", stats.builtNuke); - s.append(kvbuf); - } - if (stats.builtSCUD >= 0) - { - sprintf(kvbuf, "\\builtSCUD\\%d", stats.builtSCUD); - s.append(kvbuf); - } - if (stats.challengeMedals > 0) - { - sprintf(kvbuf, "\\challenge\\%d", stats.challengeMedals); - s.append(kvbuf); - } - if (stats.battleHonors > 0) - { - sprintf(kvbuf, "\\battle\\%d", stats.battleHonors); - s.append(kvbuf); - } - - //if (stats.winsInARow > 0) - { - sprintf(kvbuf, "\\WinRow\\%d", stats.winsInARow); - s.append(kvbuf); - } - if (stats.maxWinsInARow > 0) - { - sprintf(kvbuf, "\\WinRowMax\\%d", stats.maxWinsInARow); - s.append(kvbuf); - } - - //if (stats.lossesInARow > 0) - { - sprintf(kvbuf, "\\LossRow\\%d", stats.lossesInARow); - s.append(kvbuf); - } - if (stats.maxLossesInARow > 0) - { - sprintf(kvbuf, "\\LossRowMax\\%d", stats.maxLossesInARow); - s.append(kvbuf); - } - - //if (stats.disconsInARow > 0) - { - sprintf(kvbuf, "\\DCRow\\%d", stats.disconsInARow); - s.append(kvbuf); - } - if (stats.maxDisconsInARow > 0) - { - sprintf(kvbuf, "\\DCRowMax\\%d", stats.maxDisconsInARow); - s.append(kvbuf); - } - - //if (stats.desyncsInARow > 0) - { - sprintf(kvbuf, "\\DSRow\\%d", stats.desyncsInARow); - s.append(kvbuf); - } - if (stats.maxDesyncsInARow > 0) - { - sprintf(kvbuf, "\\DSRowMax\\%d", stats.maxDesyncsInARow); - s.append(kvbuf); - } - - if (stats.lastLadderPort > 0) - { - sprintf(kvbuf, "\\ladderPort\\%d", stats.lastLadderPort); - s.append(kvbuf); - } - if (stats.lastLadderHost.length()) - { - snprintf(kvbuf, 256, "\\ladderHost\\%s", stats.lastLadderHost.c_str()); - s.append(kvbuf); - } - - DEBUG_LOG(("Formatted persistent values as '%s'", s.c_str())); - return s; -} - -//------------------------------------------------------------------------- diff --git a/Generals/Code/GameEngine/Source/GameNetwork/GameSpy/Thread/PingThread.cpp b/Generals/Code/GameEngine/Source/GameNetwork/GameSpy/Thread/PingThread.cpp deleted file mode 100644 index b084e9a8c5..0000000000 --- a/Generals/Code/GameEngine/Source/GameNetwork/GameSpy/Thread/PingThread.cpp +++ /dev/null @@ -1,573 +0,0 @@ -/* -** 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. // -// // -//////////////////////////////////////////////////////////////////////////////// - -// FILE: PingThread.cpp ////////////////////////////////////////////////////// -// Ping thread -// Author: Matthew D. Campbell, August 2002 - -#include "PreRTS.h" // This must go first in EVERY cpp file in the GameEngine - -#include // This one has to be here. Prevents collisions with windsock2.h - -#include "GameNetwork/GameSpy/PingThread.h" -#include "mutex.h" -#include "thread.h" - -#include "Common/SubsystemInterface.h" - -//------------------------------------------------------------------------- - -static const Int NumWorkerThreads = 10; - -typedef std::queue RequestQueue; -typedef std::queue ResponseQueue; -class PingThreadClass; - -class Pinger : public PingerInterface -{ -public: - virtual ~Pinger(); - Pinger(); - virtual void startThreads( void ); - virtual void endThreads( void ); - virtual Bool areThreadsRunning( void ); - - virtual void addRequest( const PingRequest& req ); - virtual Bool getRequest( PingRequest& resp ); - - virtual void addResponse( const PingResponse& resp ); - virtual Bool getResponse( PingResponse& resp ); - - virtual Bool arePingsInProgress( void ); - virtual Int getPing( AsciiString hostname ); - - virtual void clearPingMap( void ); - virtual AsciiString getPingString( Int timeout ); - -private: - MutexClass m_requestMutex; - MutexClass m_responseMutex; - MutexClass m_pingMapMutex; - RequestQueue m_requests; - ResponseQueue m_responses; - Int m_requestCount; - Int m_responseCount; - - std::map m_pingMap; - - PingThreadClass *m_workerThreads[NumWorkerThreads]; -}; - -PingerInterface* PingerInterface::createNewPingerInterface( void ) -{ - return NEW Pinger; -} - -PingerInterface *ThePinger; - -//------------------------------------------------------------------------- - -class PingThreadClass : public ThreadClass -{ - -public: - PingThreadClass() : ThreadClass() {} - - void Thread_Function(); - -private: - Int doPing( UnsignedInt IP, Int timeout ); -}; - - -//------------------------------------------------------------------------- - -Pinger::Pinger() : m_requestCount(0), m_responseCount(0) -{ - for (Int i=0; iExecute(); - } -} - -void Pinger::endThreads( void ) -{ - for (Int i=0; iIs_Running()) - return true; - } - } - return false; -} - -void Pinger::addRequest( const PingRequest& req ) -{ - MutexClass::LockClass m(m_requestMutex); - - ++m_requestCount; - m_requests.push(req); -} - -Bool Pinger::getRequest( PingRequest& req ) -{ - MutexClass::LockClass m(m_requestMutex, 0); - if (m.Failed()) - return false; - - if (m_requests.empty()) - return false; - req = m_requests.front(); - m_requests.pop(); - return true; -} - -void Pinger::addResponse( const PingResponse& resp ) -{ - { - MutexClass::LockClass m(m_pingMapMutex); - - m_pingMap[resp.hostname] = resp.avgPing; - } - { - MutexClass::LockClass m(m_responseMutex); - - ++m_responseCount; - m_responses.push(resp); - } -} - -Bool Pinger::getResponse( PingResponse& resp ) -{ - MutexClass::LockClass m(m_responseMutex, 0); - if (m.Failed()) - return false; - - if (m_responses.empty()) - return false; - resp = m_responses.front(); - m_responses.pop(); - return true; -} - -Bool Pinger::arePingsInProgress( void ) -{ - return (m_requestCount != m_responseCount); -} - -Int Pinger::getPing( AsciiString hostname ) -{ - MutexClass::LockClass m(m_pingMapMutex, 0); - if (m.Failed()) - return false; - - std::map::const_iterator it = m_pingMap.find(hostname.str()); - if (it != m_pingMap.end()) - return it->second; - - return -1; -} - -void Pinger::clearPingMap( void ) -{ - MutexClass::LockClass m(m_pingMapMutex); - m_pingMap.clear(); -} - -AsciiString Pinger::getPingString( Int timeout ) -{ - MutexClass::LockClass m(m_pingMapMutex); - - AsciiString pingString; - AsciiString tmp; - for (std::map::const_iterator it = m_pingMap.begin(); it != m_pingMap.end(); ++it) - { - Int ping = it->second; - if (ping < 0 || ping > timeout) - ping = timeout; - ping = ping * 255 / timeout; - tmp.format("%2.2X", ping); - pingString.concat(tmp); - } - return pingString; -} - -//------------------------------------------------------------------------- - -void PingThreadClass::Thread_Function() -{ - try { - PingRequest req; - - WSADATA wsaData; - - // Fire up winsock (prob already done, but doesn't matter) - WORD wVersionRequested = MAKEWORD(1, 1); - WSAStartup( wVersionRequested, &wsaData ); - - while ( running ) - { - // deal with requests - if (ThePinger->getRequest(req)) - { - // resolve the hostname - const char *hostnameBuffer = req.hostname.c_str(); - UnsignedInt IP = 0xFFFFFFFF; - if (isdigit(hostnameBuffer[0])) - { - IP = inet_addr(hostnameBuffer); - in_addr hostNode; - hostNode.s_addr = IP; - DEBUG_LOG(("pinging %s - IP = %s", hostnameBuffer, inet_ntoa(hostNode) )); - } - else - { - HOSTENT *hostStruct; - in_addr *hostNode; - hostStruct = gethostbyname(hostnameBuffer); - if (hostStruct == NULL) - { - DEBUG_LOG(("pinging %s - host lookup failed", hostnameBuffer)); - - // Even though this failed to resolve IP, still need to send a - // callback. - IP = 0xFFFFFFFF; // flag for IP resolve failed - } - else - { - hostNode = (in_addr *) hostStruct->h_addr; - IP = hostNode->s_addr; - DEBUG_LOG(("pinging %s IP = %s", hostnameBuffer, inet_ntoa(*hostNode) )); - } - } - - // do ping - Int totalPing = 0; - Int goodReps = 0; - Int reps = req.repetitions; - while (reps-- && running && IP != 0xFFFFFFFF) - { - Int ping = doPing(IP, req.timeout); - if (ping >= 0) - { - totalPing += ping; - ++goodReps; - } - - // end our timeslice - Switch_Thread(); - } - if (!goodReps) - totalPing = -1; - else - totalPing = totalPing / goodReps; - - PingResponse resp; - resp.hostname = req.hostname; - resp.avgPing = totalPing; - resp.repetitions = goodReps; - ThePinger->addResponse(resp); - } - - // end our timeslice - Switch_Thread(); - } - - WSACleanup(); - } catch ( ... ) { - DEBUG_CRASH(("Exception in ping thread!")); - } -} - -//------------------------------------------------------------------------- -//------------------------------------------------------------------------- -//------------------------------------------------------------------------- -//------------------------------------------------------------------------- -//------------------------------------------------------------------------- -//------------------------------------------------------------------------- - -HANDLE WINAPI IcmpCreateFile(VOID); /* INVALID_HANDLE_VALUE on error */ -BOOL WINAPI IcmpCloseHandle(HANDLE IcmpHandle); /* FALSE on error */ - -/* Note 2: For the most part, you can refer to RFC 791 for detials - * on how to fill in values for the IP option information structure. - */ -typedef struct ip_option_information -{ - UnsignedByte Ttl; /* Time To Live (used for traceroute) */ - UnsignedByte Tos; /* Type Of Service (usually 0) */ - UnsignedByte Flags; /* IP header flags (usually 0) */ - UnsignedByte OptionsSize; /* Size of options data (usually 0, max 40) */ - UnsignedByte FAR *OptionsData; /* Options data buffer */ -} -IPINFO, *PIPINFO, FAR *LPIPINFO; - - -/* Note 1: The Reply Buffer will have an array of ICMP_ECHO_REPLY - * structures, followed by options and the data in ICMP echo reply - * datagram received. You must have room for at least one ICMP - * echo reply structure, plus 8 bytes for an ICMP header. - */ -typedef struct icmp_echo_reply -{ - UnsignedInt Address; /* source address */ - ////////UnsignedInt Status; /* IP status value (see below) */ - UnsignedInt RTTime; /* Round Trip Time in milliseconds */ - UnsignedShort DataSize; /* reply data size */ - UnsignedShort Reserved; /* */ - void FAR *Data; /* reply data buffer */ - struct ip_option_information Options; /* reply options */ -} -ICMPECHO, *PICMPECHO, FAR *LPICMPECHO; - - -DWORD WINAPI IcmpSendEcho( - HANDLE IcmpHandle, /* handle returned from IcmpCreateFile() */ - UnsignedInt DestAddress, /* destination IP address (in network order) */ - LPVOID RequestData, /* pointer to buffer to send */ - WORD RequestSize, /* length of data in buffer */ - LPIPINFO RequestOptns, /* see Note 2 */ - LPVOID ReplyBuffer, /* see Note 1 */ - DWORD ReplySize, /* length of reply (must allow at least 1 reply) */ - DWORD Timeout /* time in milliseconds to wait for reply */ -); - - -#define IP_STATUS_BASE 11000 -#define IP_SUCCESS 0 -#define IP_BUF_TOO_SMALL (IP_STATUS_BASE + 1) -#define IP_DEST_NET_UNREACHABLE (IP_STATUS_BASE + 2) -#define IP_DEST_HOST_UNREACHABLE (IP_STATUS_BASE + 3) -#define IP_DEST_PROT_UNREACHABLE (IP_STATUS_BASE + 4) -#define IP_DEST_PORT_UNREACHABLE (IP_STATUS_BASE + 5) -#define IP_NO_RESOURCES (IP_STATUS_BASE + 6) -#define IP_BAD_OPTION (IP_STATUS_BASE + 7) -#define IP_HW_ERROR (IP_STATUS_BASE + 8) -#define IP_PACKET_TOO_BIG (IP_STATUS_BASE + 9) -#define IP_REQ_TIMED_OUT (IP_STATUS_BASE + 10) -#define IP_BAD_REQ (IP_STATUS_BASE + 11) -#define IP_BAD_ROUTE (IP_STATUS_BASE + 12) -#define IP_TTL_EXPIRED_TRANSIT (IP_STATUS_BASE + 13) -#define IP_TTL_EXPIRED_REASSEM (IP_STATUS_BASE + 14) -#define IP_PARAM_PROBLEM (IP_STATUS_BASE + 15) -#define IP_SOURCE_QUENCH (IP_STATUS_BASE + 16) -#define IP_OPTION_TOO_BIG (IP_STATUS_BASE + 17) -#define IP_BAD_DESTINATION (IP_STATUS_BASE + 18) -#define IP_ADDR_DELETED (IP_STATUS_BASE + 19) -#define IP_SPEC_MTU_CHANGE (IP_STATUS_BASE + 20) -#define IP_MTU_CHANGE (IP_STATUS_BASE + 21) -#define IP_UNLOAD (IP_STATUS_BASE + 22) -#define IP_GENERAL_FAILURE (IP_STATUS_BASE + 50) -#define MAX_IP_STATUS IP_GENERAL_FAILURE -#define IP_PENDING (IP_STATUS_BASE + 255) - - -#define BUFSIZE 8192 -#define DEFAULT_LEN 32 -#define LOOPLIMIT 4 -#define DEFAULT_TTL 64 - -Int PingThreadClass::doPing(UnsignedInt IP, Int timeout) -{ - /* - * Initialize default settings - */ - - IPINFO stIPInfo, *lpstIPInfo; - HANDLE hICMP, hICMP_DLL; - int i, j, nDataLen, nLoopLimit, nTimeOut, nTTL, nTOS; - DWORD dwReplyCount; - ///////IN_ADDR stDestAddr; - BOOL fRet, fDontStop; - ///BOOL fTraceRoute; - - nDataLen = DEFAULT_LEN; - nLoopLimit = LOOPLIMIT; - nTimeOut = timeout; - fDontStop = FALSE; - lpstIPInfo = NULL; - nTTL = DEFAULT_TTL; - nTOS = 0; - - Int pingTime = -1; // in case of error - - char achReqData[BUFSIZE]; - char achRepData[sizeof(ICMPECHO) + BUFSIZE]; - - - HANDLE ( WINAPI *lpfnIcmpCreateFile )( VOID ) = NULL; - BOOL ( WINAPI *lpfnIcmpCloseHandle )( HANDLE ) = NULL; - DWORD (WINAPI *lpfnIcmpSendEcho)(HANDLE, DWORD, LPVOID, WORD, LPVOID, - LPVOID, DWORD, DWORD) = NULL; - - - /* - * Load the ICMP.DLL - */ - hICMP_DLL = LoadLibrary("ICMP.DLL"); - if (hICMP_DLL == 0) - { - DEBUG_LOG(("LoadLibrary() failed: Unable to locate ICMP.DLL!")); - goto cleanup; - } - - /* - * Get pointers to ICMP.DLL functions - */ - lpfnIcmpCreateFile = (void * (__stdcall *)(void))GetProcAddress( (HINSTANCE)hICMP_DLL, "IcmpCreateFile"); - lpfnIcmpCloseHandle = (int (__stdcall *)(void *))GetProcAddress( (HINSTANCE)hICMP_DLL, "IcmpCloseHandle"); - lpfnIcmpSendEcho = (unsigned long (__stdcall *)(void *, unsigned long, void *, unsigned short, - void *, void *, unsigned long, unsigned long))GetProcAddress( (HINSTANCE)hICMP_DLL, "IcmpSendEcho" ); - - if ((!lpfnIcmpCreateFile) || - (!lpfnIcmpCloseHandle) || - (!lpfnIcmpSendEcho)) - { - DEBUG_LOG(("GetProcAddr() failed for at least one function.")); - goto cleanup; - } - - - /* - * IcmpCreateFile() - Open the ping service - */ - hICMP = (HANDLE) lpfnIcmpCreateFile(); - if (hICMP == INVALID_HANDLE_VALUE) - { - DEBUG_LOG(("IcmpCreateFile() failed")); - goto cleanup; - } - - /* - * Init data buffer printable ASCII - * 32 (space) through 126 (tilde) - */ - for (j = 0, i = 32; j < nDataLen; j++, i++) - { - if (i >= 126) - i = 32; - achReqData[j] = i; - } - - /* - * Init IPInfo structure - */ - lpstIPInfo = &stIPInfo; - stIPInfo.Ttl = nTTL; - stIPInfo.Tos = nTOS; - stIPInfo.Flags = 0; - stIPInfo.OptionsSize = 0; - stIPInfo.OptionsData = NULL; - - - - /* - * IcmpSendEcho() - Send the ICMP Echo Request - * and read the Reply - */ - dwReplyCount = lpfnIcmpSendEcho( - hICMP, - IP, - achReqData, - nDataLen, - lpstIPInfo, - achRepData, - sizeof(achRepData), - nTimeOut); - if (dwReplyCount != 0) - { - //////////IN_ADDR stDestAddr; - DWORD dwStatus; - - pingTime = (*(UnsignedInt *) & (achRepData[8])); - - // I've seen the ping time bigger than the timeout by a little - // bit. How lame. - if (pingTime > timeout) - pingTime = timeout; - - dwStatus = *(DWORD *) & (achRepData[4]); - if (dwStatus != IP_SUCCESS) - { - DEBUG_LOG(("ICMPERR: %d", dwStatus)); - } - - } - else - { - DEBUG_LOG(("IcmpSendEcho() failed: %d", dwReplyCount)); - // Ok we didn't get a packet, just say everything's OK - // and the time was -1 - pingTime = -1; - goto cleanup; - } - - - /* - * IcmpCloseHandle - Close the ICMP handle - */ - fRet = lpfnIcmpCloseHandle(hICMP); - if (fRet == FALSE) - { - DEBUG_LOG(("Error closing ICMP handle")); - } - - // Say what you will about goto's but it's handy for stuff like this -cleanup: - - // Shut down... - if (hICMP_DLL) - FreeLibrary((HINSTANCE)hICMP_DLL); - - return pingTime; -} - - -//------------------------------------------------------------------------- diff --git a/Generals/Code/GameEngine/Source/GameNetwork/GameSpy/Thread/ThreadUtils.cpp b/Generals/Code/GameEngine/Source/GameNetwork/GameSpy/Thread/ThreadUtils.cpp deleted file mode 100644 index 4ddc8c0ead..0000000000 --- a/Generals/Code/GameEngine/Source/GameNetwork/GameSpy/Thread/ThreadUtils.cpp +++ /dev/null @@ -1,81 +0,0 @@ -/* -** 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. // -// // -//////////////////////////////////////////////////////////////////////////////// - -// FILE: ThreadUtils.cpp ////////////////////////////////////////////////////// -// GameSpy thread utils -// Author: Matthew D. Campbell, July 2002 - -#include "PreRTS.h" // This must go first in EVERY cpp file in the GameEngine - -//------------------------------------------------------------------------- - -std::wstring MultiByteToWideCharSingleLine( const char *orig ) -{ - Int len = strlen(orig); - WideChar *dest = NEW WideChar[len+1]; - - MultiByteToWideChar(CP_UTF8, 0, orig, -1, dest, len); - WideChar *c = NULL; - do - { - c = wcschr(dest, L'\n'); - if (c) - { - *c = L' '; - } - } - while ( c != NULL ); - do - { - c = wcschr(dest, L'\r'); - if (c) - { - *c = L' '; - } - } - while ( c != NULL ); - - dest[len] = 0; - std::wstring ret = dest; - delete[] dest; - return ret; -} - -std::string WideCharStringToMultiByte( const WideChar *orig ) -{ - std::string ret; - Int len = WideCharToMultiByte( CP_UTF8, 0, orig, wcslen(orig), NULL, 0, NULL, NULL ) + 1; - if (len > 0) - { - char *dest = NEW char[len]; - WideCharToMultiByte( CP_UTF8, 0, orig, -1, dest, len, NULL, NULL ); - dest[len-1] = 0; - ret = dest; - delete[] dest; - } - return ret; -} - -//------------------------------------------------------------------------- - diff --git a/Generals/Code/GameEngine/Source/GameNetwork/GameSpyChat.cpp b/Generals/Code/GameEngine/Source/GameNetwork/GameSpyChat.cpp deleted file mode 100644 index a567fd126c..0000000000 --- a/Generals/Code/GameEngine/Source/GameNetwork/GameSpyChat.cpp +++ /dev/null @@ -1,455 +0,0 @@ -/* -** 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. // -// // -//////////////////////////////////////////////////////////////////////////////// - -// FILE: GameSpyChat.cpp ////////////////////////////////////////////////////// -// GameSpy chat handlers -// Author: Matthew D. Campbell, February 2002 - -#include "PreRTS.h" // This must go first in EVERY cpp file in the GameEngine - -#include "GameClient/GameText.h" -#include "GameClient/GadgetListBox.h" -#include "GameClient/LanguageFilter.h" -#include "GameNetwork/GameSpy.h" -#include "GameNetwork/GameSpyChat.h" -#include "Common/QuotedPrintable.h" - -typedef set::const_iterator AsciiSetIter; - -/** - * handleSlashCommands looks for slash ccommands and handles them, - * returning true if it found one, false otherwise. - * /i,/ignore list ignored players - * /i,/ignore +name1 -name2 ignore name1, stop ignoring name2 - * /m,/me: shorthand for an action - * /o,/on: find command to look up a user's location - * /f,/find: find command to look up a user's location - * /p,/page: page user(s) - * /r,/reply: reply to last page - * /raw: raw IRC command (only in debug & internal) - * /oper: become an IRC op (only in debug & internal) - * /quit: send the IRC quit command to exit WOL - */ -static Bool handleSlashCommands( UnicodeString message, Bool isAction, GameWindow *playerListbox ) -{ - /* - if (message.getCharAt(0) == L'/') - { - UnicodeString remainder = UnicodeString(message.str() + 1); - UnicodeString token; - - switch (message.getCharAt(1)) - { - case L'i': - case L'I': - remainder.nextToken(&token); - if (token.compareNoCase(L"i") == 0 || token.compareNoCase(L"ignore") == 0) - { - if (remainder.isEmpty()) - { - // List the people we're ignoring - TheWOL->addText(TheGameText->fetch("WOL:BeginIgnoreList")); - set *ignoreList = getIgnoreList(); - if (ignoreList) - { - UnicodeString msg; - UnicodeString uName; - AsciiSetIter iter = ignoreList->begin(); - while (iter != ignoreList->end()) - { - uName.translate(*iter); - msg.format(TheGameText->fetch("WOL:IgnoredUser"), uName.str()); - TheWOL->addText(msg); - iter++; - } - } - TheWOL->addText(TheGameText->fetch("WOL:EndIgnoreList")); - } - - while ( remainder.nextToken(&token) ) - { - AsciiString name; - int doIgnore = 0; - if (token.getCharAt(0) == L'+') - { - // Ignore somebody - token = UnicodeString(token.str() + 1); - name.translate(token); - doIgnore = 1; - } - else if (token.getCharAt(0) == L'-') - { - // Listen to someone again - token = UnicodeString(token.str() + 1); - name.translate(token); - doIgnore = 0; - } - else - { - // Ignore somebody - token = UnicodeString(token.str()); - name.translate(token); - doIgnore = 1; - } - IChat *ichat = TheWOL->getIChat(); - User user; - strncpy((char *)user.name, name.str(), 9); - user.name[9] = 0; - ichat->SetSquelch(&user, doIgnore); - - if (doIgnore) - addIgnore(name); - else - removeIgnore(name); - - UnicodeString msg; - UnicodeString uName; - uName.translate(name); - msg.format(TheGameText->fetch("WOL:IgnoredUser"), uName.str()); - TheWOL->addText(msg); - } - return true; - } - break; - case L'r': - case L'R': - remainder.nextToken(&token); -#if defined(RTS_DEBUG) - if (token.compareNoCase(L"raw") == 0) - { - // Send raw IRC commands (Ascii only) - AsciiString str; - str.translate(remainder); - str.concat('\n'); - IChat *ichat = TheWOL->getIChat(); - ichat->RequestRawMessage(str.str()); - TheWOL->addText(remainder); - return true; // show it anyway - } -#endif - break; -#if defined(RTS_DEBUG) - case L'k': - case L'K': - remainder.nextToken(&token); - if (token.compareNoCase(L"kick") == 0) - { - - while ( remainder.nextToken(&token) ) - { - AsciiString name; - name.translate(token); - IChat *ichat = TheWOL->getIChat(); - User user; - strncpy((char *)user.name, name.str(), 9); - user.name[9] = 0; - ichat->RequestUserKick(&user); - } - return true; - } - break; -#endif - case L'o': - case L'O': - remainder.nextToken(&token); - if (token.compareNoCase(L"on") == 0 || token.compareNoCase(L"o") == 0) - { - remainder.nextToken(&token); - AsciiString userName; - userName.translate(token); - User user; - strncpy((char *)user.name, userName.str(), 10); - user.name[9] = 0; - if (user.name[0] == 0) - { - // didn't enter a name - TheWOL->addText(message); - } - else - { - // Send find command - IChat *ichat = TheWOL->getIChat(); - ichat->RequestGlobalFind(&user); - } - return true; // show it anyway - } -#if defined(RTS_DEBUG) - else if (token.compareNoCase(L"oper") == 0) - { - // Send raw IRC oper command - AsciiString str; - str.translate(message); - str.concat('\n'); - IChat *ichat = TheWOL->getIChat(); - ichat->RequestRawMessage(str.str()); - TheWOL->addText(message); - return true; // show it anyway - } -#endif - break; - case L'p': - case L'P': - remainder.nextToken(&token); - if (token.compareNoCase(L"page") == 0 || token.compareNoCase(L"p") == 0) - { - remainder.nextToken(&token); - AsciiString userName; - userName.translate(token); - User user; - strncpy((char *)user.name, userName.str(), 10); - user.name[9] = 0; - remainder.trim(); - if (user.name[0] == 0 || remainder.isEmpty()) - { - // didn't enter a name or message - TheWOL->addText(message); - } - else - { - // Send page command - IChat *ichat = TheWOL->getIChat(); - ichat->RequestGlobalUnicodePage(&user, remainder.str()); - } - return true; // show it anyway - } - break; - case L'q': - case L'Q': - remainder.nextToken(&token); - if (token.compareNoCase(L"quit") == 0) - { - TheWOL->setState(WOLAPI_LOGIN); - TheWOL->addCommand(WOLCOMMAND_LOGOUT); - //TheWOL->setScreen(WOLAPI_MENU_WELCOME); - return true; // show it anyway - } - break; -#if defined(RTS_DEBUG) - case L'c': - case L'C': - remainder.nextToken(&token); - if (token.compareNoCase(L"colortest") == 0) - { - addColorText(token, 0xDD, 0xE2, 0x0D, 0xff); - addColorText(token, 0xFF, 0x19, 0x19, 0xff); - addColorText(token, 0x2A, 0x74, 0xE2, 0xff); - addColorText(token, 0x3E, 0xD1, 0x2E, 0xff); - addColorText(token, 0xFF, 0xA0, 0x19, 0xff); - addColorText(token, 0x32, 0xD7, 0xE6, 0xff); - addColorText(token, 0x95, 0x28, 0xBD, 0xff); - addColorText(token, 0xFF, 0x9A, 0xEB, 0xff); - return true; // show it anyway - } - break; -#endif // RTS_DEBUG - } - } - */ - return false; -} - -static handleUnicodeMessage( const char *nick, UnicodeString msg, Bool isPublic, Bool isAction ); - -Bool GameSpySendChat( UnicodeString message, Bool isAction, GameWindow *playerListbox ) -{ - RoomType roomType = StagingRoom; - if (TheGameSpyChat->getCurrentGroupRoomID()) - roomType = GroupRoom; - - message.trim(); - // Echo the user's input to the chat window - if (!message.isEmpty()) - { - // Check for slash commands - if (handleSlashCommands(message, isAction, playerListbox)) - { - return false; // already handled - } - - if (!playerListbox) - { - // Public message - if (isAction) - { - peerMessageRoom(TheGameSpyChat->getPeer(), roomType, UnicodeStringToQuotedPrintable(message).str(), ActionMessage); - //if (roomType == StagingRoom) - //handleUnicodeMessage(TheGameSpyChat->getloginName().str(), message, true, true); - } - else - { - peerMessageRoom(TheGameSpyChat->getPeer(), roomType, UnicodeStringToQuotedPrintable(message).str(), NormalMessage); - //if (roomType == StagingRoom) - //handleUnicodeMessage(TheGameSpyChat->getloginName().str(), message, true, false); - } - return false; - } - - // Get the selections (is this a private message?) - Int maxSel = GadgetListBoxGetListLength(playerListbox); - Int *selections; - GadgetListBoxGetSelected(playerListbox, (Int *)&selections); - - if (selections[0] == -1) - { - // Public message - if (isAction) - { - peerMessageRoom(TheGameSpyChat->getPeer(), roomType, UnicodeStringToQuotedPrintable(message).str(), ActionMessage); - //if (roomType == StagingRoom) - //handleUnicodeMessage(TheGameSpyChat->getloginName().str(), message, true, true); - } - else - { - peerMessageRoom(TheGameSpyChat->getPeer(), roomType, UnicodeStringToQuotedPrintable(message).str(), NormalMessage); - //if (roomType == StagingRoom) - //handleUnicodeMessage(TheGameSpyChat->getloginName().str(), message, true, false); - } - return false; - } - else - { - // Private message - - // Construct a list - AsciiString names = AsciiString::TheEmptyString; - AsciiString tmp = AsciiString::TheEmptyString; - AsciiString aStr; // AsciiString buf for translating Unicode entries - names.format("%s", TheGameSpyChat->getLoginName().str()); - for (int i=0; igetLoginName())) - { - tmp.format(",%s", aStr.str()); - names.concat(tmp); - } - } - else - { - break; - } - } - - if (!names.isEmpty()) - { - if (isAction) - { - peerMessagePlayer(TheGameSpyChat->getPeer(), names.str(), UnicodeStringToQuotedPrintable(message).str(), ActionMessage); - } - else - { - peerMessagePlayer(TheGameSpyChat->getPeer(), names.str(), UnicodeStringToQuotedPrintable(message).str(), NormalMessage); - } - } - - return true; - } - } - return false; -} - -void RoomMessageCallback(PEER peer, RoomType roomType, - const char * nick, const char * message, - MessageType messageType, void * param) -{ - DEBUG_LOG(("RoomMessageCallback")); - handleUnicodeMessage(nick, QuotedPrintableToUnicodeString(message), true, (messageType == ActionMessage)); -} - -void PlayerMessageCallback(PEER peer, - const char * nick, const char * message, - MessageType messageType, void * param) -{ - DEBUG_LOG(("PlayerMessageCallback")); - handleUnicodeMessage(nick, QuotedPrintableToUnicodeString(message), false, (messageType == ActionMessage)); -} - -static handleUnicodeMessage( const char *nick, UnicodeString msg, Bool isPublic, Bool isAction ) -{ - GameSpyColors style; - - Bool isOwner = false; - Int flags = 0; - if (TheGameSpyChat->getCurrentGroupRoomID()) - peerGetPlayerFlags(TheGameSpyChat->getPeer(), nick, GroupRoom, &flags); - else - peerGetPlayerFlags(TheGameSpyChat->getPeer(), nick, StagingRoom, &flags); - isOwner = flags & PEER_FLAG_OP; - - if (isPublic && isAction) - { - style = (isOwner)?GSCOLOR_CHAT_OWNER_EMOTE:GSCOLOR_CHAT_EMOTE; - } - else if (isPublic) - { - style = (isOwner)?GSCOLOR_CHAT_OWNER:GSCOLOR_CHAT_NORMAL; - } - else if (isAction) - { - style = (isOwner)?GSCOLOR_CHAT_PRIVATE_OWNER_EMOTE:GSCOLOR_CHAT_PRIVATE_EMOTE; - } - else - { - style = (isOwner)?GSCOLOR_CHAT_PRIVATE_OWNER:GSCOLOR_CHAT_PRIVATE; - } - - UnicodeString name; - name.translate(nick); - - // filters language -// if( TheGlobalData->m_languageFilterPref ) -// { - TheLanguageFilter->filterLine(msg); -// } - - UnicodeString fullMsg; - if (isAction) - { - fullMsg.format( L"%ls %ls", name.str(), msg.str() ); - } - else - { - fullMsg.format( L"[%ls] %ls", name.str(), msg.str() ); - } - GameSpyAddText(fullMsg, style); -} - -void GameSpyAddText( UnicodeString message, GameSpyColors color ) -{ - GameWindow *textWindow = NULL; - - if (!textWindow) - textWindow = listboxLobbyChat; - if (!textWindow) - textWindow = listboxGameSetupChat; - - if (!textWindow) - return; - - GadgetListBoxAddEntryText(textWindow, message, GameSpyColor[color], -1, -1); - -} - diff --git a/Generals/Code/GameEngine/Source/GameNetwork/GameSpyGP.cpp b/Generals/Code/GameEngine/Source/GameNetwork/GameSpyGP.cpp deleted file mode 100644 index be309ddae3..0000000000 --- a/Generals/Code/GameEngine/Source/GameNetwork/GameSpyGP.cpp +++ /dev/null @@ -1,162 +0,0 @@ -/* -** 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. // -// // -//////////////////////////////////////////////////////////////////////////////// - -// FILE: GameSpyGP.cpp ////////////////////////////////////////////////////// -// GameSpy GP callbacks, utils, etc -// Author: Matthew D. Campbell, February 2002 - -#include "PreRTS.h" // This must go first in EVERY cpp file in the GameEngine - -#include "GameClient/GameText.h" -#include "GameNetwork/GameSpy.h" -#include "GameNetwork/GameSpyGP.h" -#include "GameNetwork/GameSpyOverlay.h" - -GPConnection TheGPConnectionObj; -GPConnection *TheGPConnection = &TheGPConnectionObj; -GPProfile GameSpyLocalProfile = 0; -char GameSpyProfilePassword[64]; - -void GPRecvBuddyMessageCallback(GPConnection * pconnection, GPRecvBuddyMessageArg * arg, void * param) -{ - DEBUG_LOG(("GPRecvBuddyMessageCallback: message from %d is %s", arg->profile, arg->message)); - - //gpGetInfo(pconn, arg->profile, GP_DONT_CHECK_CACHE, GP_BLOCKING, (GPCallback)Whois, NULL); - //printf("MESSAGE (%d): %s: %s\n", msgCount,whois, arg->message); -} - -static void buddyTryReconnect( void ) -{ - TheGameSpyChat->reconnectProfile(); -} - -void GPErrorCallback(GPConnection * pconnection, GPErrorArg * arg, void * param) -{ - DEBUG_LOG(("GPErrorCallback")); - - AsciiString errorCodeString; - AsciiString resultString; - - #define RESULT(x) case x: resultString = #x; break; - switch(arg->result) - { - RESULT(GP_NO_ERROR) - RESULT(GP_MEMORY_ERROR) - RESULT(GP_PARAMETER_ERROR) - RESULT(GP_NETWORK_ERROR) - RESULT(GP_SERVER_ERROR) - default: - resultString = "Unknown result!"; - } - #undef RESULT - - #define ERRORCODE(x) case x: errorCodeString = #x; break; - switch(arg->errorCode) - { - ERRORCODE(GP_GENERAL) - ERRORCODE(GP_PARSE) - ERRORCODE(GP_NOT_LOGGED_IN) - ERRORCODE(GP_BAD_SESSKEY) - ERRORCODE(GP_DATABASE) - ERRORCODE(GP_NETWORK) - ERRORCODE(GP_FORCED_DISCONNECT) - ERRORCODE(GP_CONNECTION_CLOSED) - ERRORCODE(GP_LOGIN) - ERRORCODE(GP_LOGIN_TIMEOUT) - ERRORCODE(GP_LOGIN_BAD_NICK) - ERRORCODE(GP_LOGIN_BAD_EMAIL) - ERRORCODE(GP_LOGIN_BAD_PASSWORD) - ERRORCODE(GP_LOGIN_BAD_PROFILE) - ERRORCODE(GP_LOGIN_PROFILE_DELETED) - ERRORCODE(GP_LOGIN_CONNECTION_FAILED) - ERRORCODE(GP_LOGIN_SERVER_AUTH_FAILED) - ERRORCODE(GP_NEWUSER) - ERRORCODE(GP_NEWUSER_BAD_NICK) - ERRORCODE(GP_NEWUSER_BAD_PASSWORD) - ERRORCODE(GP_UPDATEUI) - ERRORCODE(GP_UPDATEUI_BAD_EMAIL) - ERRORCODE(GP_NEWPROFILE) - ERRORCODE(GP_NEWPROFILE_BAD_NICK) - ERRORCODE(GP_NEWPROFILE_BAD_OLD_NICK) - ERRORCODE(GP_UPDATEPRO) - ERRORCODE(GP_UPDATEPRO_BAD_NICK) - ERRORCODE(GP_ADDBUDDY) - ERRORCODE(GP_ADDBUDDY_BAD_FROM) - ERRORCODE(GP_ADDBUDDY_BAD_NEW) - ERRORCODE(GP_ADDBUDDY_ALREADY_BUDDY) - ERRORCODE(GP_AUTHADD) - ERRORCODE(GP_AUTHADD_BAD_FROM) - ERRORCODE(GP_AUTHADD_BAD_SIG) - ERRORCODE(GP_STATUS) - ERRORCODE(GP_BM) - ERRORCODE(GP_BM_NOT_BUDDY) - ERRORCODE(GP_GETPROFILE) - ERRORCODE(GP_GETPROFILE_BAD_PROFILE) - ERRORCODE(GP_DELBUDDY) - ERRORCODE(GP_DELBUDDY_NOT_BUDDY) - ERRORCODE(GP_DELPROFILE) - ERRORCODE(GP_DELPROFILE_LAST_PROFILE) - ERRORCODE(GP_SEARCH) - ERRORCODE(GP_SEARCH_CONNECTION_FAILED) - default: - errorCodeString = "Unknown error code!"; - } - #undef ERRORCODE - - if(arg->fatal) - { - DEBUG_LOG(( "-----------")); - DEBUG_LOG(( "GP FATAL ERROR")); - DEBUG_LOG(( "-----------")); - - // if we're still connected to the chat server, tell the user. He can always hit the buddy - // button to try reconnecting. Oh yes, also hide the buddy popup. - GameSpyCloseOverlay(GSOVERLAY_BUDDY); - if (TheGameSpyChat->isConnected()) - { - GSMessageBoxYesNo(TheGameText->fetch("GUI:GPErrorTitle"), TheGameText->fetch("GUI:GPDisconnected"), buddyTryReconnect, NULL); - } - } - else - { - DEBUG_LOG(( "-----")); - DEBUG_LOG(( "GP ERROR")); - DEBUG_LOG(( "-----")); - } - DEBUG_LOG(( "RESULT: %s (%d)", resultString.str(), arg->result)); - DEBUG_LOG(( "ERROR CODE: %s (0x%X)", errorCodeString.str(), arg->errorCode)); - DEBUG_LOG(( "ERROR STRING: %s", arg->errorString)); -} - -void GPRecvBuddyStatusCallback(GPConnection * connection, GPRecvBuddyStatusArg * arg, void * param) -{ - DEBUG_LOG(("GPRecvBuddyStatusCallback: info on %d is in %d", arg->profile, arg->index)); - - //GameSpyUpdateBuddyOverlay(); -} - -void GPRecvBuddyRequestCallback(GPConnection * connection, GPRecvBuddyRequestArg * arg, void * param) -{ - DEBUG_LOG(("GPRecvBuddyRequestCallback: %d wants to be our buddy because '%s'", arg->profile, arg->reason)); -} diff --git a/Generals/Code/GameEngine/Source/GameNetwork/GameSpyGameInfo.cpp b/Generals/Code/GameEngine/Source/GameNetwork/GameSpyGameInfo.cpp deleted file mode 100644 index 92dc5ddd07..0000000000 --- a/Generals/Code/GameEngine/Source/GameNetwork/GameSpyGameInfo.cpp +++ /dev/null @@ -1,751 +0,0 @@ -/* -** 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. // -// // -//////////////////////////////////////////////////////////////////////////////// - -// FILE: GameSpyGameInfo.cpp ////////////////////////////////////////////////////// -// GameSpy game setup state info -// Author: Matthew D. Campbell, December 2001 - -#include "PreRTS.h" // This must go first in EVERY cpp file in the GameEngine - -#include "Common/GameEngine.h" -#include "Common/Player.h" -#include "Common/PlayerList.h" -#include "Common/RandomValue.h" -#include "Common/ScoreKeeper.h" -#include "GameClient/Shell.h" -#include "GameClient/GameText.h" -#include "GameNetwork/GameSpy/PeerDefs.h" -#include "GameNetwork/GameSpyGameInfo.h" -#include "GameNetwork/NetworkInterface.h" -#include "GameNetwork/networkutil.h" -#include "GameNetwork/NetworkDefs.h" -#include "GameNetwork/NAT.h" -#include "GameLogic/GameLogic.h" -#include "GameLogic/VictoryConditions.h" - -// Singleton ------------------------------------------ - -GameSpyGameInfo *TheGameSpyGame = NULL; - -// Helper Functions ---------------------------------------- - -GameSpyGameSlot::GameSpyGameSlot() -{ - GameSlot(); - m_gameSpyLogin.clear(); - m_gameSpyLocale.clear(); - m_profileID = 0; -} - -// Helper Functions ---------------------------------------- -/* -** Function definitions for the MIB-II entry points. -*/ - -BOOL (__stdcall *SnmpExtensionInitPtr)(IN DWORD dwUpTimeReference, OUT HANDLE *phSubagentTrapEvent, OUT AsnObjectIdentifier *pFirstSupportedRegion); -BOOL (__stdcall *SnmpExtensionQueryPtr)(IN BYTE bPduType, IN OUT RFC1157VarBindList *pVarBindList, OUT AsnInteger32 *pErrorStatus, OUT AsnInteger32 *pErrorIndex); -LPVOID (__stdcall *SnmpUtilMemAllocPtr)(IN DWORD bytes); -VOID (__stdcall *SnmpUtilMemFreePtr)(IN LPVOID pMem); - -typedef struct tConnInfoStruct { - unsigned int State; - unsigned long LocalIP; - unsigned short LocalPort; - unsigned long RemoteIP; - unsigned short RemotePort; -} ConnInfoStruct; - -#ifndef ARRAY_SIZE -#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0])) -#endif - -/*********************************************************************************************** - * Get_Local_Chat_Connection_Address -- Which address are we using to talk to the chat server? * - * * - * * - * * - * INPUT: Ptr to address to return local address * * - * * - * OUTPUT: True if success * - * * - * WARNINGS: None * - * * - * HISTORY: * - * 10/27/00 3:24PM ST : Created * - *=============================================================================================*/ -Bool GetLocalChatConnectionAddress(AsciiString serverName, UnsignedShort serverPort, UnsignedInt& localIP) -{ - //return false; - /* - ** Local defines. - */ - enum { - CLOSED = 1, - LISTENING, - SYN_SENT, - SEN_RECEIVED, - ESTABLISHED, - FIN_WAIT, - FIN_WAIT2, - CLOSE_WAIT, - LAST_ACK, - CLOSING, - TIME_WAIT, - DELETE_TCB - }; - - enum { - tcpConnState = 1, - tcpConnLocalAddress, - tcpConnLocalPort, - tcpConnRemAddress, - tcpConnRemPort - }; - - - /* - ** Locals. - */ - unsigned char serverAddress[4]; - unsigned char remoteAddress[4]; - HANDLE trap_handle; - AsnObjectIdentifier first_supported_region; - std::vector connectionVector; - int last_field; - int index; - AsnInteger error_status; - AsnInteger error_index; - int conn_entry_type_index; - int conn_entry_type; - Bool found; - - /* - ** Statics. - */ - static char _conn_state[][32] = { - "?", - "CLOSED", - "LISTENING", - "SYN_SENT", - "SEN_RECEIVED", - "ESTABLISHED", - "FIN_WAIT", - "FIN_WAIT2", - "CLOSE_WAIT", - "LAST_ACK", - "CLOSING", - "TIME_WAIT", - "DELETE_TCB" - }; - - DEBUG_LOG(("Finding local address used to talk to the chat server")); - DEBUG_LOG(("Current chat server name is %s", serverName.str())); - DEBUG_LOG(("Chat server port is %d", serverPort)); - - /* - ** Get the address of the chat server. - */ - DEBUG_LOG( ("About to call gethostbyname")); - struct hostent *host_info = gethostbyname(serverName.str()); - - if (!host_info) { - DEBUG_LOG( ("gethostbyname failed! Error code %d", WSAGetLastError())); - return(false); - } - - memcpy(serverAddress, &host_info->h_addr_list[0][0], 4); - unsigned long temp = *((unsigned long*)(&serverAddress[0])); - temp = ntohl(temp); - *((unsigned long*)(&serverAddress[0])) = temp; - - DEBUG_LOG(("Host address is %d.%d.%d.%d", serverAddress[3], serverAddress[2], serverAddress[1], serverAddress[0])); - - /* - ** Load the MIB-II SNMP DLL. - */ - DEBUG_LOG(("About to load INETMIB1.DLL")); - - HINSTANCE mib_ii_dll = LoadLibrary("inetmib1.dll"); - if (mib_ii_dll == NULL) { - DEBUG_LOG(("Failed to load INETMIB1.DLL")); - return(false); - } - - DEBUG_LOG(("About to load SNMPAPI.DLL")); - - HINSTANCE snmpapi_dll = LoadLibrary("snmpapi.dll"); - if (snmpapi_dll == NULL) { - DEBUG_LOG(("Failed to load SNMPAPI.DLL")); - FreeLibrary(mib_ii_dll); - return(false); - } - - /* - ** Get the function pointers into the .dll - */ - SnmpExtensionInitPtr = (int (__stdcall *)(unsigned long,void ** ,AsnObjectIdentifier *)) GetProcAddress(mib_ii_dll, "SnmpExtensionInit"); - SnmpExtensionQueryPtr = (int (__stdcall *)(unsigned char,SnmpVarBindList *,long *,long *)) GetProcAddress(mib_ii_dll, "SnmpExtensionQuery"); - SnmpUtilMemAllocPtr = (void *(__stdcall *)(unsigned long)) GetProcAddress(snmpapi_dll, "SnmpUtilMemAlloc"); - SnmpUtilMemFreePtr = (void (__stdcall *)(void *)) GetProcAddress(snmpapi_dll, "SnmpUtilMemFree"); - if (SnmpExtensionInitPtr == NULL || SnmpExtensionQueryPtr == NULL || SnmpUtilMemAllocPtr == NULL || SnmpUtilMemFreePtr == NULL) { - DEBUG_LOG(("Failed to get proc addresses for linked functions")); - FreeLibrary(snmpapi_dll); - FreeLibrary(mib_ii_dll); - return(false); - } - - - RFC1157VarBindList *bind_list_ptr = (RFC1157VarBindList *) SnmpUtilMemAllocPtr(sizeof(RFC1157VarBindList)); - RFC1157VarBind *bind_ptr = (RFC1157VarBind *) SnmpUtilMemAllocPtr(sizeof(RFC1157VarBind)); - - /* - ** OK, here we go. Try to initialise the .dll - */ - DEBUG_LOG(("About to init INETMIB1.DLL")); - int ok = SnmpExtensionInitPtr(GetCurrentTime(), &trap_handle, &first_supported_region); - - if (!ok) { - /* - ** Aw crap. - */ - DEBUG_LOG(("Failed to init the .dll")); - SnmpUtilMemFreePtr(bind_list_ptr); - SnmpUtilMemFreePtr(bind_ptr); - FreeLibrary(snmpapi_dll); - FreeLibrary(mib_ii_dll); - return(false); - } - - /* - ** Name of mib_ii object we want to query. See RFC 1213. - ** - ** iso.org.dod.internet.mgmt.mib-2.tcp.tcpConnTable.TcpConnEntry.tcpConnState - ** 1 3 6 1 2 1 6 13 1 1 - */ - unsigned int mib_ii_name[] = {1,3,6,1,2,1,6,13,1,1}; - unsigned int *mib_ii_name_ptr = (unsigned int *) SnmpUtilMemAllocPtr(sizeof(mib_ii_name)); - memcpy(mib_ii_name_ptr, mib_ii_name, sizeof(mib_ii_name)); - - /* - ** Get the index of the conn entry data. - */ - conn_entry_type_index = ARRAY_SIZE(mib_ii_name) - 1; - - /* - ** Set up the bind list. - */ - bind_ptr->name.idLength = ARRAY_SIZE(mib_ii_name); - bind_ptr->name.ids = mib_ii_name; - bind_list_ptr->list = bind_ptr; - bind_list_ptr->len = 1; - - - /* - ** We start with the tcpConnLocalAddress field. - */ - last_field = 1; - - /* - ** First connection. - */ - index = 0; - - /* - ** Suck out that tcp connection info.... - */ - while (true) { - - if (!SnmpExtensionQueryPtr(SNMP_PDU_GETNEXT, bind_list_ptr, &error_status, &error_index)) { - //if (!SnmpExtensionQueryPtr(ASN_RFC1157_GETNEXTREQUEST, bind_list_ptr, &error_status, &error_index)) { - DEBUG_LOG(("SnmpExtensionQuery returned false")); - SnmpUtilMemFreePtr(bind_list_ptr); - SnmpUtilMemFreePtr(bind_ptr); - FreeLibrary(snmpapi_dll); - FreeLibrary(mib_ii_dll); - return(false); - } - - /* - ** If this is something new we aren't looking for then we are done. - */ - if (bind_ptr->name.idLength < ARRAY_SIZE(mib_ii_name)) { - break; - } - - /* - ** Get the type of info we are looking at. See RFC1213. - ** - ** 1 = tcpConnState - ** 2 = tcpConnLocalAddress - ** 3 = tcpConnLocalPort - ** 4 = tcpConnRemAddress - ** 5 = tcpConnRemPort - ** - ** tcpConnState is one of the following... - ** - ** 1 closed - ** 2 listen - ** 3 synSent - ** 4 synReceived - ** 5 established - ** 6 finWait1 - ** 7 finWait2 - ** 8 closeWait - ** 9 lastAck - ** 10 closing - ** 11 timeWait - ** 12 deleteTCB - */ - conn_entry_type = bind_ptr->name.ids[conn_entry_type_index]; - - if (last_field != conn_entry_type) { - index = 0; - last_field = conn_entry_type; - } - - switch (conn_entry_type) { - - /* - ** 1. First field in the entry. Need to create a new connection info struct - ** here to store this connection in. - */ - case tcpConnState: - { - ConnInfoStruct new_conn; - new_conn.State = bind_ptr->value.asnValue.number; - connectionVector.push_back(new_conn); - break; - } - - /* - ** 2. Local address field. - */ - case tcpConnLocalAddress: - DEBUG_ASSERTCRASH(index < connectionVector.size(), ("Bad connection index")); - connectionVector[index].LocalIP = *((unsigned long*)bind_ptr->value.asnValue.address.stream); - index++; - break; - - /* - ** 3. Local port field. - */ - case tcpConnLocalPort: - DEBUG_ASSERTCRASH(index < connectionVector.size(), ("Bad connection index")); - connectionVector[index].LocalPort = bind_ptr->value.asnValue.number; - //connectionVector[index]->LocalPort = ntohs(connectionVector[index]->LocalPort); - index++; - break; - - /* - ** 4. Remote address field. - */ - case tcpConnRemAddress: - DEBUG_ASSERTCRASH(index < connectionVector.size(), ("Bad connection index")); - connectionVector[index].RemoteIP = *((unsigned long*)bind_ptr->value.asnValue.address.stream); - index++; - break; - - /* - ** 5. Remote port field. - */ - case tcpConnRemPort: - DEBUG_ASSERTCRASH(index < connectionVector.size(), ("Bad connection index")); - connectionVector[index].RemotePort = bind_ptr->value.asnValue.number; - //connectionVector[index]->RemotePort = ntohs(connectionVector[index]->RemotePort); - index++; - break; - } - } - - SnmpUtilMemFreePtr(bind_list_ptr); - SnmpUtilMemFreePtr(bind_ptr); - SnmpUtilMemFreePtr(mib_ii_name_ptr); - - DEBUG_LOG(("Got %d connections in list, parsing...", connectionVector.size())); - - /* - ** Right, we got the lot. Lets see if any of them have the same address as the chat - ** server we think we are talking to. - */ - found = false; - for (Int i=0; igetSlot(i); - if (slot && slot->isOccupied()) - numUsers++; - } - - if (numUsers < 2) - { - if (TheGameSpyGame->amIHost()) - { - UnicodeString text; - text.format(TheGameText->fetch("LAN:NeedMorePlayers"),numUsers); - TheGameSpyInfo->addText(text, GSCOLOR_DEFAULT, NULL); - } - return; - } - - TheGameSpyGame->startGame(0); - } -} - -void GameSpyLaunchGame( void ) -{ - if (TheGameSpyGame) - { - - // Set up the game network - AsciiString user; - AsciiString userList; - DEBUG_ASSERTCRASH(TheNetwork == NULL, ("For some reason TheNetwork isn't NULL at the start of this game. Better look into that.")); - - if (TheNetwork != NULL) { - delete TheNetwork; - TheNetwork = NULL; - } - - // Time to initialize TheNetwork for this game. - TheNetwork = NetworkInterface::createNetwork(); - TheNetwork->init(); - /* - if (!TheGameSpyGame->amIHost()) - TheNetwork->setLocalAddress((207<<24) | (138<<16) | (47<<8) | 15, 8088); - else - */ - TheNetwork->setLocalAddress(TheGameSpyGame->getLocalIP(), TheNAT->getSlotPort(TheGameSpyGame->getLocalSlotNum())); - TheNetwork->attachTransport(TheNAT->getTransport()); - - user = TheGameSpyInfo->getLocalName(); - for (Int i=0; igetSlot(i); - if (!slot) - { - DEBUG_CRASH(("No GameSlot[%d]!", i)); - delete TheNetwork; - TheNetwork = NULL; - return; - } - -// UnsignedInt ip = htonl(slot->getIP()); - UnsignedInt ip = slot->getIP(); - AsciiString tmpUserName; - tmpUserName.translate(slot->getName()); - if (ip) - { - /* - if (i == 1) - { - user.format(",%s@207.138.47.15:8088", tmpUserName.str()); - } - else - */ - { - user.format(",%s@%d.%d.%d.%d:%d", tmpUserName.str(), - PRINTF_IP_AS_4_INTS(ip), - TheNAT->getSlotPort(i) - ); - } - userList.concat(user); - } - } - userList.trim(); - - TheNetwork->parseUserList(TheGameSpyGame); - - // shutdown the top, but do not pop it off the stack -// TheShell->hideShell(); - // setup the Global Data with the Map and Seed - TheGlobalData->m_pendingFile = TheGameSpyGame->getMap(); - - if (TheGameLogic->isInGame()) { - TheGameLogic->clearGameData(); - } - // send a message to the logic for a new game - GameMessage *msg = TheMessageStream->appendMessage( GameMessage::MSG_NEW_GAME ); - msg->appendIntegerArgument(GAME_INTERNET); - - TheGlobalData->m_useFpsLimit = false; - - // Set the random seed - InitGameLogicRandom( TheGameSpyGame->getSeed() ); - DEBUG_LOG(("InitGameLogicRandom( %d )", TheGameSpyGame->getSeed())); - - if (TheNAT != NULL) { - delete TheNAT; - TheNAT = NULL; - } - } -} - -void GameSpyGameInfo::init( void ) -{ - GameInfo::init(); - - m_hasBeenQueried = false; -} - -void GameSpyGameInfo::resetAccepted( void ) -{ - GameInfo::resetAccepted(); - - if (m_hasBeenQueried && amIHost()) - { - // ANCIENTMUNKEE peerStateChanged(TheGameSpyChat->getPeer()); - m_hasBeenQueried = false; - DEBUG_LOG(("resetAccepted() called peerStateChange()")); - } -} - -Int GameSpyGameInfo::getLocalSlotNum( void ) const -{ - DEBUG_ASSERTCRASH(m_inGame, ("Looking for local game slot while not in game")); - if (!m_inGame) - return -1; - - AsciiString localName = TheGameSpyInfo->getLocalName(); - - for (Int i=0; iisPlayer(localName)) - return i; - } - return -1; -} - -void GameSpyGameInfo::gotGOACall( void ) -{ - DEBUG_LOG(("gotGOACall()")); - m_hasBeenQueried = true; -} - -void GameSpyGameInfo::startGame(Int gameID) -{ - DEBUG_LOG(("GameSpyGameInfo::startGame - game id = %d", gameID)); - DEBUG_ASSERTCRASH(m_transport == NULL, ("m_transport is not NULL when it should be")); - DEBUG_ASSERTCRASH(TheNAT == NULL, ("TheNAT is not NULL when it should be")); - - // fill in GS-specific info - for (Int i=0; igetPlayerInfoMap(); - PlayerInfoMap::iterator it = pInfoMap->find(gsName); - if (it != pInfoMap->end()) - { - m_GameSpySlot[i].setProfileID(it->second.m_profileID); - m_GameSpySlot[i].setLocale(it->second.m_locale); - } - else - { - DEBUG_CRASH(("No player info for %s", gsName.str())); - } - } - } - - if (TheNAT != NULL) { - delete TheNAT; - TheNAT = NULL; - } - TheNAT = NEW NAT(); - TheNAT->attachSlotList(m_slot, getLocalSlotNum(), m_localIP); - TheNAT->establishConnectionPaths(); -} - -AsciiString GameSpyGameInfo::generateGameResultsPacket( void ) -{ - Int i; - Int endFrame = TheVictoryConditions->getEndFrame(); - Int localSlotNum = getLocalSlotNum(); - //GameSlot *localSlot = getSlot(localSlotNum); - Bool sawGameEnd = (endFrame > 0);// && localSlot->lastFrameInGame() <= endFrame); - Int winningTeam = -1; - Int numPlayers = 0; - Int numTeamsAtGameEnd = 0; - Int lastTeamAtGameEnd = -1; - for (i=0; ifindPlayerWithNameKey(NAMEKEY(playerName)); - if (p) - { - ++numPlayers; - if (TheVictoryConditions->hasAchievedVictory(p)) - { - winningTeam = getSlot(i)->getTeamNumber(); - } - - // check if he lasted - GameSlot *slot = getSlot(i); - if (!slot->disconnected()) - { - if (slot->getTeamNumber() != lastTeamAtGameEnd || numTeamsAtGameEnd == 0) - { - lastTeamAtGameEnd = slot->getTeamNumber(); - ++numTeamsAtGameEnd; - } - } - } - } - - AsciiString results; - results.format("seed=%d,slotNum=%d,sawDesync=%d,sawGameEnd=%d,winningTeam=%d,disconEnd=%d,duration=%d,numPlayers=%d,isQM=%d", - getSeed(), localSlotNum, TheNetwork->sawCRCMismatch(), sawGameEnd, winningTeam, (numTeamsAtGameEnd != 0), - endFrame, numPlayers, m_isQM); - - Int playerID = 0; - for (i=0; ifindPlayerWithNameKey(NAMEKEY(playerName)); - if (p) - { - GameSpyGameSlot *slot = &(m_GameSpySlot[i]); - ScoreKeeper *keeper = p->getScoreKeeper(); - AsciiString playerName = slot->getLoginName(); - Int gsPlayerID = slot->getProfileID(); - AsciiString locale = slot->getLocale(); - Int fps = TheNetwork->getAverageFPS(); - Int unitsKilled = keeper->getTotalUnitsDestroyed(); - Int unitsLost = keeper->getTotalUnitsLost(); - Int unitsBuilt = keeper->getTotalUnitsBuilt(); - Int buildingsKilled = keeper->getTotalBuildingsDestroyed(); - Int buildingsLost = keeper->getTotalBuildingsLost(); - Int buildingsBuilt = keeper->getTotalBuildingsBuilt(); - Int earnings = keeper->getTotalMoneyEarned(); - Int techCaptured = keeper->getTotalTechBuildingsCaptured(); - Bool disconnected = slot->disconnected(); - - AsciiString playerStr; - playerStr.format(",player%d=%s,playerID%d=%d,locale%d=%s", - playerID, playerName.str(), playerID, gsPlayerID, playerID, locale.str()); - results.concat(playerStr); - playerStr.format(",unitsKilled%d=%d,unitsLost%d=%d,unitsBuilt%d=%d", - playerID, unitsKilled, playerID, unitsLost, playerID, unitsBuilt); - results.concat(playerStr); - playerStr.format(",buildingsKilled%d=%d,buildingsLost%d=%d,buildingsBuilt%d=%d", - playerID, buildingsKilled, playerID, buildingsLost, playerID, buildingsBuilt); - results.concat(playerStr); - playerStr.format(",fps%d=%d,cash%d=%d,capturedTech%d=%d,discon%d=%d", - playerID, fps, playerID, earnings, playerID, techCaptured, playerID, disconnected); - results.concat(playerStr); - - ++playerID; - } - } - - // Add a trailing size value (so the server can ensure it got the entire packet) - int resultsLen = results.getLength()+10; - AsciiString tail; - tail.format("%10.10d", resultsLen); - results.concat(tail); - - return results; -} - diff --git a/Generals/Code/GameEngine/Source/GameNetwork/GameSpyOverlay.cpp b/Generals/Code/GameEngine/Source/GameNetwork/GameSpyOverlay.cpp deleted file mode 100644 index 329f5c79c5..0000000000 --- a/Generals/Code/GameEngine/Source/GameNetwork/GameSpyOverlay.cpp +++ /dev/null @@ -1,333 +0,0 @@ -/* -** 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. // -// // -//////////////////////////////////////////////////////////////////////////////// - -// FILE: wolscreens.cpp ////////////////////////////////////////////////////// -// Westwood Online screen setup/teardown -// Author: Matthew D. Campbell, November 2001 - -#include "PreRTS.h" // This must go first in EVERY cpp file in the GameEngine -#include "Common/AudioEventRTS.h" - -#include "GameClient/GadgetListBox.h" -#include "GameClient/GameText.h" -#include "GameClient/MessageBox.h" -#include "GameClient/ShellHooks.h" -//#include "GameNetwork/GameSpy.h" -//#include "GameNetwork/GameSpyGP.h" - -#include "GameNetwork/GameSpyOverlay.h" -//#include "GameNetwork/GameSpy/PeerDefs.h" -#include "GameNetwork/GameSpy/BuddyThread.h" - -void deleteNotificationBox( void ); -static void raiseOverlays( void ); - -// Message boxes ------------------------------------- -static GameWindow *messageBoxWindow = NULL; -static GameWinMsgBoxFunc okFunc = NULL; -static GameWinMsgBoxFunc cancelFunc = NULL; -static Bool reOpenPlayerInfoFlag = FALSE; -/** - * messageBoxOK is called when a message box is destroyed - * by way of an OK button, so we can clear our pointers to it. - */ -static void messageBoxOK( void ) -{ - DEBUG_ASSERTCRASH(messageBoxWindow, ("Message box window went away without being there in the first place!")); - messageBoxWindow = NULL; - if (okFunc) - { - okFunc(); - okFunc = NULL; - } -} - -/** - * messageBoxCancel is called when a message box is destroyed - * by way of a Cancel button, so we can clear our pointers to it. - */ -static void messageBoxCancel( void ) -{ - DEBUG_ASSERTCRASH(messageBoxWindow, ("Message box window went away without being there in the first place!")); - messageBoxWindow = NULL; - if (cancelFunc) - { - cancelFunc(); - cancelFunc = NULL; - } -} - -/** - * clearGSMessageBoxes removes the current message box if - * one is present. This is usually done when putting up a - * second messageBox. - */ -void ClearGSMessageBoxes( void ) -{ - if (messageBoxWindow) - { - TheWindowManager->winDestroy(messageBoxWindow); - messageBoxWindow = NULL; - } - - if (okFunc) - { - okFunc = NULL; - } - - if (cancelFunc) - { - cancelFunc = NULL; - } -} - -/** - * GSMessageBoxOk puts up an OK dialog box and saves the - * pointers to it and its callbacks. - */ -void GSMessageBoxOk(UnicodeString title, UnicodeString message, GameWinMsgBoxFunc newOkFunc) -{ - ClearGSMessageBoxes(); - messageBoxWindow = MessageBoxOk(title, message, messageBoxOK); - okFunc = newOkFunc; -} - -/** - * GSMessageBoxOkCancel puts up an OK/Cancel dialog box and saves the - * pointers to it and its callbacks. - */ -void GSMessageBoxOkCancel(UnicodeString title, UnicodeString message, GameWinMsgBoxFunc newOkFunc, GameWinMsgBoxFunc newCancelFunc) -{ - ClearGSMessageBoxes(); - messageBoxWindow = MessageBoxOkCancel(title, message, messageBoxOK, messageBoxCancel); - okFunc = newOkFunc; - cancelFunc = newCancelFunc; -} - -/** - * GSMessageBoxYesNo puts up a Yes/No dialog box and saves the - * pointers to it and its callbacks. - */ -void GSMessageBoxYesNo(UnicodeString title, UnicodeString message, GameWinMsgBoxFunc newYesFunc, GameWinMsgBoxFunc newNoFunc) -{ - ClearGSMessageBoxes(); - messageBoxWindow = MessageBoxYesNo(title, message, messageBoxOK, messageBoxCancel); - okFunc = newYesFunc; - cancelFunc = newNoFunc; -} - -/** - * If the screen transitions underneath the dialog box, we - * need to raise it to keep it visible. - */ -void RaiseGSMessageBox( void ) -{ - raiseOverlays(); - - if (!messageBoxWindow) - return; - - messageBoxWindow->winBringToTop(); -} - -// Overlay screens ------------------------------------- - -/** - * gsOverlays holds a list of the .wnd files used in GS overlays. - * The entries *MUST* be in the same order as the GSOverlayType enum. - */ -static const char * gsOverlays[GSOVERLAY_MAX] = -{ - "Menus/PopupPlayerInfo.wnd", // Player info (right-click) - "Menus/WOLMapSelectMenu.wnd", // Map select - "Menus/WOLBuddyOverlay.wnd", // Buddy list - "Menus/WOLPageOverlay.wnd", // Find/page - "Menus/PopupHostGame.wnd", // Hosting options (game name, password, etc) - "Menus/PopupJoinGame.wnd", // Joining options (password, etc) - "Menus/PopupLadderSelect.wnd",// LadderSelect - "Menus/PopupLocaleSelect.wnd",// Prompt for user's locale - "Menus/OptionsMenu.wnd", // popup options -}; - -static WindowLayout *overlayLayouts[GSOVERLAY_MAX] = -{ - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, -}; - -static void buddyTryReconnect( void ) -{ - BuddyRequest req; - req.buddyRequestType = BuddyRequest::BUDDYREQUEST_RELOGIN; - TheGameSpyBuddyMessageQueue->addRequest( req ); -} - -void GameSpyOpenOverlay( GSOverlayType overlay ) -{ - if (overlay == GSOVERLAY_BUDDY) - { - if (!TheGameSpyBuddyMessageQueue->isConnected()) - { - // not connected - is it because we were disconnected? - if (TheGameSpyBuddyMessageQueue->getLocalProfileID()) - { - // used to be connected - GSMessageBoxYesNo(TheGameText->fetch("GUI:GPErrorTitle"), TheGameText->fetch("GUI:GPDisconnected"), buddyTryReconnect, NULL); - } - else - { - // no profile - GSMessageBoxOk(TheGameText->fetch("GUI:GPErrorTitle"), TheGameText->fetch("GUI:GPNoProfile"), NULL); - } - return; - } - AudioEventRTS buttonClick("GUICommunicatorOpen"); - - if( TheAudio ) - { - TheAudio->addAudioEvent( &buttonClick ); - } - } - if (overlayLayouts[overlay]) - { - overlayLayouts[overlay]->hide( FALSE ); - overlayLayouts[overlay]->bringForward(); - } - else - { - overlayLayouts[overlay] = TheWindowManager->winCreateLayout( AsciiString( gsOverlays[overlay] ) ); - overlayLayouts[overlay]->runInit(); - overlayLayouts[overlay]->hide( FALSE ); - overlayLayouts[overlay]->bringForward(); - } -} - -void GameSpyCloseOverlay( GSOverlayType overlay ) -{ - switch(overlay) - { - case GSOVERLAY_PLAYERINFO: - DEBUG_LOG(("Closing overlay GSOVERLAY_PLAYERINFO")); - break; - case GSOVERLAY_MAPSELECT: - DEBUG_LOG(("Closing overlay GSOVERLAY_MAPSELECT")); - break; - case GSOVERLAY_BUDDY: - DEBUG_LOG(("Closing overlay GSOVERLAY_BUDDY")); - break; - case GSOVERLAY_PAGE: - DEBUG_LOG(("Closing overlay GSOVERLAY_PAGE")); - break; - case GSOVERLAY_GAMEOPTIONS: - DEBUG_LOG(("Closing overlay GSOVERLAY_GAMEOPTIONS")); - break; - case GSOVERLAY_GAMEPASSWORD: - DEBUG_LOG(("Closing overlay GSOVERLAY_GAMEPASSWORD")); - break; - case GSOVERLAY_LADDERSELECT: - DEBUG_LOG(("Closing overlay GSOVERLAY_LADDERSELECT")); - break; - case GSOVERLAY_OPTIONS: - DEBUG_LOG(("Closing overlay GSOVERLAY_OPTIONS")); - if( overlayLayouts[overlay] ) - { - SignalUIInteraction(SHELL_SCRIPT_HOOK_OPTIONS_CLOSED); - } - break; - } - if( overlayLayouts[overlay] ) - { - overlayLayouts[overlay]->runShutdown(); - overlayLayouts[overlay]->destroyWindows(); - deleteInstance(overlayLayouts[overlay]); - overlayLayouts[overlay] = NULL; - } -} - -Bool GameSpyIsOverlayOpen( GSOverlayType overlay ) -{ - return (overlayLayouts[overlay] != NULL); -} - -void GameSpyToggleOverlay( GSOverlayType overlay ) -{ - if (GameSpyIsOverlayOpen(overlay)) - GameSpyCloseOverlay(overlay); - else - GameSpyOpenOverlay(overlay); -} - -void raiseOverlays( void ) -{ - for (int i=0; ibringForward(); - } - } -} - -void GameSpyCloseAllOverlays( void ) -{ - for (int i=0; irunUpdate(); - } - } -} - -void ReOpenPlayerInfo( void ) -{ - reOpenPlayerInfoFlag = TRUE; -} -void CheckReOpenPlayerInfo(void ) -{ - if(!reOpenPlayerInfoFlag) - return; - - GameSpyOpenOverlay(GSOVERLAY_PLAYERINFO); - reOpenPlayerInfoFlag = FALSE; - -} diff --git a/Generals/Code/GameEngine/Source/GameNetwork/IPEnumeration.cpp b/Generals/Code/GameEngine/Source/GameNetwork/IPEnumeration.cpp deleted file mode 100644 index 53ae8eecd0..0000000000 --- a/Generals/Code/GameEngine/Source/GameNetwork/IPEnumeration.cpp +++ /dev/null @@ -1,196 +0,0 @@ -/* -** 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 in the GameEngine - -#include "GameNetwork/IPEnumeration.h" -#include "GameNetwork/networkutil.h" -#include "GameClient/ClientInstance.h" - -IPEnumeration::IPEnumeration( void ) -{ - m_IPlist = NULL; - m_isWinsockInitialized = false; -} - -IPEnumeration::~IPEnumeration( void ) -{ - if (m_isWinsockInitialized) - { - WSACleanup(); - m_isWinsockInitialized = false; - } - - EnumeratedIP *ip = m_IPlist; - while (ip) - { - ip = ip->getNext(); - deleteInstance(m_IPlist); - m_IPlist = ip; - } -} - -EnumeratedIP * IPEnumeration::getAddresses( void ) -{ - if (m_IPlist) - return m_IPlist; - - if (!m_isWinsockInitialized) - { - WORD verReq = MAKEWORD(2, 2); - WSADATA wsadata; - - int err = WSAStartup(verReq, &wsadata); - if (err != 0) { - return NULL; - } - - if ((LOBYTE(wsadata.wVersion) != 2) || (HIBYTE(wsadata.wVersion) !=2)) { - WSACleanup(); - return NULL; - } - m_isWinsockInitialized = true; - } - - // get the local machine's host name - char hostname[256]; - if (gethostname(hostname, sizeof(hostname))) - { - DEBUG_LOG(("Failed call to gethostname; WSAGetLastError returned %d", WSAGetLastError())); - return NULL; - } - DEBUG_LOG(("Hostname is '%s'", hostname)); - - // get host information from the host name - HOSTENT* hostEnt = gethostbyname(hostname); - if (hostEnt == NULL) - { - DEBUG_LOG(("Failed call to gethostbyname; WSAGetLastError returned %d", WSAGetLastError())); - return NULL; - } - - // sanity-check the length of the IP adress - if (hostEnt->h_length != 4) - { - DEBUG_LOG(("gethostbyname returns oddly-sized IP addresses!")); - return NULL; - } - - // TheSuperHackers @feature Add one unique local host IP address for each multi client instance. - if (rts::ClientInstance::isMultiInstance()) - { - const UnsignedInt id = rts::ClientInstance::getInstanceId(); - addNewIP( - 127, - (UnsignedByte)(id >> 16), - (UnsignedByte)(id >> 8), - (UnsignedByte)(id)); - } - - // construct a list of addresses - int numAddresses = 0; - char *entry; - while ( (entry = hostEnt->h_addr_list[numAddresses++]) != 0 ) - { - addNewIP( - (UnsignedByte)entry[0], - (UnsignedByte)entry[1], - (UnsignedByte)entry[2], - (UnsignedByte)entry[3]); - } - - return m_IPlist; -} - -void IPEnumeration::addNewIP( UnsignedByte a, UnsignedByte b, UnsignedByte c, UnsignedByte d ) -{ - EnumeratedIP *newIP = newInstance(EnumeratedIP); - - AsciiString str; - str.format("%d.%d.%d.%d", (int)a, (int)b, (int)c, (int)d); - - UnsignedInt ip = AssembleIp(a, b, c, d); - - newIP->setIPstring(str); - newIP->setIP(ip); - - DEBUG_LOG(("IP: 0x%8.8X (%s)", ip, str.str())); - - // Add the IP to the list in ascending order - if (!m_IPlist) - { - m_IPlist = newIP; - newIP->setNext(NULL); - } - else - { - if (newIP->getIP() < m_IPlist->getIP()) - { - newIP->setNext(m_IPlist); - m_IPlist = newIP; - } - else - { - EnumeratedIP *p = m_IPlist; - while (p->getNext() && p->getNext()->getIP() < newIP->getIP()) - { - p = p->getNext(); - } - newIP->setNext(p->getNext()); - p->setNext(newIP); - } - } -} - -AsciiString IPEnumeration::getMachineName( void ) -{ - if (!m_isWinsockInitialized) - { - WORD verReq = MAKEWORD(2, 2); - WSADATA wsadata; - - int err = WSAStartup(verReq, &wsadata); - if (err != 0) { - return NULL; - } - - if ((LOBYTE(wsadata.wVersion) != 2) || (HIBYTE(wsadata.wVersion) !=2)) { - WSACleanup(); - return NULL; - } - m_isWinsockInitialized = true; - } - - // get the local machine's host name - char hostname[256]; - if (gethostname(hostname, sizeof(hostname))) - { - DEBUG_LOG(("Failed call to gethostname; WSAGetLastError returned %d", WSAGetLastError())); - return NULL; - } - - return AsciiString(hostname); -} - - diff --git a/Generals/Code/GameEngine/Source/GameNetwork/LANAPI.cpp b/Generals/Code/GameEngine/Source/GameNetwork/LANAPI.cpp deleted file mode 100644 index 5398c52ad0..0000000000 --- a/Generals/Code/GameEngine/Source/GameNetwork/LANAPI.cpp +++ /dev/null @@ -1,1283 +0,0 @@ -/* -** 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 in the GameEngine - -#define WIN32_LEAN_AND_MEAN // only bare bones windows stuff wanted - -#include "Common/crc.h" -#include "Common/GameState.h" -#include "Common/Registry.h" -#include "GameNetwork/LANAPI.h" -#include "GameNetwork/networkutil.h" -#include "Common/GlobalData.h" -#include "Common/RandomValue.h" -#include "GameClient/GameText.h" -#include "GameClient/MapUtil.h" -#include "Common/UserPreferences.h" -#include "GameLogic/GameLogic.h" - - -static const UnsignedShort lobbyPort = 8086; ///< This is the UDP port used by all LANAPI communication - -AsciiString GetMessageTypeString(UnsignedInt type); - -const UnsignedInt LANAPI::s_resendDelta = 10 * 1000; ///< This is how often we announce ourselves to the world -/* -LANGame::LANGame( void ) -{ - m_gameName = L""; - - int player; - for (player = 0; player < MAX_SLOTS; ++player) - { - m_playerName[player] = L""; - m_playerIP[player]= 0; - m_playerAccepted[player] = false; - } - m_lastHeard = 0; - m_inProgress = false; - m_next = NULL; -} -*/ - - - - -LANAPI::LANAPI( void ) : m_transport(NULL) -{ - DEBUG_LOG(("LANAPI::LANAPI() - max game option size is %d, sizeof(LANMessage)=%d, MAX_PACKET_SIZE=%d", - m_lanMaxOptionsLength, sizeof(LANMessage), MAX_PACKET_SIZE)); - - m_lastResendTime = 0; - // - m_lobbyPlayers = NULL; - m_games = NULL; - m_name = L""; // safe default? - m_pendingAction = ACT_NONE; - m_expiration = 0; - m_localIP = 0; - m_inLobby = true; - m_isInLANMenu = TRUE; - m_currentGame = NULL; - m_broadcastAddr = INADDR_BROADCAST; - m_directConnectRemoteIP = 0; - m_actionTimeout = 5000; // ms - m_lastUpdate = 0; - m_transport = new Transport; - m_isActive = TRUE; -} - -LANAPI::~LANAPI( void ) -{ - reset(); - delete m_transport; -} - -void LANAPI::init( void ) -{ - m_gameStartTime = 0; - m_gameStartSeconds = 0; - m_transport->reset(); - m_transport->init(m_localIP, lobbyPort); - m_transport->allowBroadcasts(true); - - m_pendingAction = ACT_NONE; - m_expiration = 0; - m_inLobby = true; - m_isInLANMenu = TRUE; - m_currentGame = NULL; - m_directConnectRemoteIP = 0; - - m_lastGameopt = ""; - -#if TELL_COMPUTER_IDENTITY_IN_LAN_LOBBY - char userName[UNLEN + 1]; - DWORD bufSize = ARRAY_SIZE(userName); - if (GetUserNameA(userName, &bufSize)) - { - m_userName.set(userName, bufSize - 1); - } - else - { - m_userName = "unknown"; - } - - char computerName[MAX_COMPUTERNAME_LENGTH + 1]; - bufSize = ARRAY_SIZE(computerName); - if (GetComputerNameA(computerName, &bufSize)) - { - m_hostName.set(computerName, bufSize - 1); - } - else - { - m_hostName = "unknown"; - } -#endif -} - -void LANAPI::reset( void ) -{ - if (m_inLobby) - { - LANMessage msg; - fillInLANMessage( &msg ); - msg.messageType = LANMessage::MSG_REQUEST_LOBBY_LEAVE; - sendMessage(&msg); - } - m_transport->update(); - - LANGameInfo *theGame = m_games; - LANGameInfo *deletableGame = NULL; - - while (theGame) - { - deletableGame = theGame; - theGame = theGame->getNext(); - delete deletableGame; - } - - LANPlayer *thePlayer = m_lobbyPlayers; - LANPlayer *deletablePlayer = NULL; - - while (thePlayer) - { - deletablePlayer = thePlayer; - thePlayer = thePlayer->getNext(); - delete deletablePlayer; - } - - m_games = NULL; - m_lobbyPlayers = NULL; - m_directConnectRemoteIP = 0; - m_pendingAction = ACT_NONE; - m_expiration = 0; - m_inLobby = true; - m_isInLANMenu = TRUE; - m_currentGame = NULL; - -} - -void LANAPI::sendMessage(LANMessage *msg, UnsignedInt ip /* = 0 */) -{ - if (ip != 0) - { - m_transport->queueSend(ip, lobbyPort, (unsigned char *)msg, sizeof(LANMessage) /*, 0, 0 */); - } - else if ((m_currentGame != NULL) && (m_currentGame->getIsDirectConnect())) - { - Int localSlot = m_currentGame->getLocalSlotNum(); - for (Int i = 0; i < MAX_SLOTS; ++i) - { - if (i != localSlot) { - GameSlot *slot = m_currentGame->getSlot(i); - if ((slot != NULL) && (slot->isHuman())) { - m_transport->queueSend(slot->getIP(), lobbyPort, (unsigned char *)msg, sizeof(LANMessage) /*, 0, 0 */); - } - } - } - } - else - { - m_transport->queueSend(m_broadcastAddr, lobbyPort, (unsigned char *)msg, sizeof(LANMessage) /*, 0, 0 */); - } -} - - -AsciiString GetMessageTypeString(UnsignedInt type) -{ - AsciiString returnString; - - switch (type) - { - case LANMessage::MSG_REQUEST_LOCATIONS: - returnString.format( "Request Locations (%d)",type); - break; - case LANMessage::MSG_GAME_ANNOUNCE: - returnString.format("Game Announce (%d)",type); - break; - case LANMessage::MSG_LOBBY_ANNOUNCE: - returnString.format("Lobby Announce (%d)",type); - break; - case LANMessage::MSG_REQUEST_JOIN: - returnString.format("Request Join (%d)",type); - break; - case LANMessage::MSG_JOIN_ACCEPT: - returnString.format("Join Accept (%d)",type); - break; - case LANMessage::MSG_JOIN_DENY: - returnString.format("Join Deny (%d)",type); - break; - case LANMessage::MSG_REQUEST_GAME_LEAVE: - returnString.format("Request Game Leave (%d)",type); - break; - case LANMessage::MSG_REQUEST_LOBBY_LEAVE: - returnString.format("Request Lobby Leave (%d)",type); - break; - case LANMessage::MSG_SET_ACCEPT: - returnString.format("Set Accept(%d)",type); - break; - case LANMessage::MSG_CHAT: - returnString.format("Chat (%d)",type); - break; - case LANMessage::MSG_GAME_START: - returnString.format("Game Start (%d)",type); - break; - case LANMessage::MSG_GAME_START_TIMER: - returnString.format("Game Start Timer (%d)",type); - break; - case LANMessage::MSG_GAME_OPTIONS: - returnString.format("Game Options (%d)",type); - break; - case LANMessage::MSG_REQUEST_GAME_INFO: - returnString.format("Request GameInfo (%d)", type); - break; - case LANMessage::MSG_INACTIVE: - returnString.format("Inactive (%d)", type); - break; - default: - returnString.format("Unknown Message (%d)",type); - } - return returnString; -} - - -void LANAPI::checkMOTD( void ) -{ -#if defined(RTS_DEBUG) - if (TheGlobalData->m_useLocalMOTD) - { - // for a playtest, let's log some play statistics, eh? - if (TheGlobalData->m_playStats <= 0) - TheWritableGlobalData->m_playStats = 30; - - static UnsignedInt oldMOTDCRC = 0; - UnsignedInt newMOTDCRC = 0; - AsciiString asciiMOTD; - char buf[4096]; - FILE *fp = fopen(TheGlobalData->m_MOTDPath.str(), "r"); - Int len; - if (fp) - { - while( (len = fread(buf, 1, 4096, fp)) > 0 ) - { - buf[len] = 0; - asciiMOTD.concat(buf); - } - fclose(fp); - CRC crcObj; - crcObj.computeCRC(asciiMOTD.str(), asciiMOTD.getLength()); - newMOTDCRC = crcObj.get(); - } - - if (oldMOTDCRC != newMOTDCRC) - { - // different MOTD... display it - oldMOTDCRC = newMOTDCRC; - AsciiString line; - while (asciiMOTD.nextToken(&line, "\n")) - { - if (line.getCharAt(line.getLength()-1) == '\r') - line.removeLastChar(); // there is a trailing '\r' - - if (line.isEmpty()) - { - line = " "; - } - - UnicodeString uniLine; - uniLine.translate(line); - OnChat( UnicodeString(L"MOTD"), 0, uniLine, LANCHAT_SYSTEM ); - } - } - } -#endif -} - -extern Bool LANbuttonPushed; -extern Bool LANSocketErrorDetected; -void LANAPI::update( void ) -{ - if(LANbuttonPushed) - return; - static const UnsignedInt LANAPIUpdateDelay = 200; - UnsignedInt now = timeGetTime(); - - if( now > m_lastUpdate + LANAPIUpdateDelay) - { - m_lastUpdate = now; - } - else - { - return; - } - - // Let the UDP socket breathe - if ((m_transport->update() == FALSE) && (LANSocketErrorDetected == FALSE)) { - if (m_isInLANMenu == TRUE) { - LANSocketErrorDetected = TRUE; - } - } - - // Handle any new messages - int i; - for (i=0; im_inBuffer[i].length > 0) - { - // Process the new message - UnsignedInt senderIP = m_transport->m_inBuffer[i].addr; - if (senderIP == m_localIP) - { - m_transport->m_inBuffer[i].length = 0; - continue; - } - - LANMessage *msg = (LANMessage *)(m_transport->m_inBuffer[i].data); - //DEBUG_LOG(("LAN message type %s from %ls (%s@%s)", GetMessageTypeString(msg->messageType).str(), - // msg->name, msg->userName, msg->hostName)); - switch (msg->messageType) - { - // Location specification - case LANMessage::MSG_REQUEST_LOCATIONS: // Hey, where is everybody? - DEBUG_LOG(("LANAPI::update - got a MSG_REQUEST_LOCATIONS from %d.%d.%d.%d", PRINTF_IP_AS_4_INTS(senderIP))); - handleRequestLocations( msg, senderIP ); - break; - case LANMessage::MSG_GAME_ANNOUNCE: // Here someone is, and here's his game info! - DEBUG_LOG(("LANAPI::update - got a MSG_GAME_ANNOUNCE from %d.%d.%d.%d", PRINTF_IP_AS_4_INTS(senderIP))); - handleGameAnnounce( msg, senderIP ); - break; - case LANMessage::MSG_LOBBY_ANNOUNCE: // Hey, I'm in the lobby! - DEBUG_LOG(("LANAPI::update - got a MSG_LOBBY_ANNOUNCE from %d.%d.%d.%d", PRINTF_IP_AS_4_INTS(senderIP))); - handleLobbyAnnounce( msg, senderIP ); - break; - case LANMessage::MSG_REQUEST_GAME_INFO: - DEBUG_LOG(("LANAPI::update - got a MSG_REQUEST_GAME_INFO from %d.%d.%d.%d", PRINTF_IP_AS_4_INTS(senderIP))); - handleRequestGameInfo( msg, senderIP ); - break; - - // Joining games - case LANMessage::MSG_REQUEST_JOIN: // Let me in! Let me in! - DEBUG_LOG(("LANAPI::update - got a MSG_REQUEST_JOIN from %d.%d.%d.%d", PRINTF_IP_AS_4_INTS(senderIP))); - handleRequestJoin( msg, senderIP ); - break; - case LANMessage::MSG_JOIN_ACCEPT: // Okay, you can join. - DEBUG_LOG(("LANAPI::update - got a MSG_JOIN_ACCEPT from %d.%d.%d.%d", PRINTF_IP_AS_4_INTS(senderIP))); - handleJoinAccept( msg, senderIP ); - break; - case LANMessage::MSG_JOIN_DENY: // Go away! We don't want any! - DEBUG_LOG(("LANAPI::update - got a MSG_JOIN_DENY from %d.%d.%d.%d", PRINTF_IP_AS_4_INTS(senderIP))); - handleJoinDeny( msg, senderIP ); - break; - - // Leaving games, lobby - case LANMessage::MSG_REQUEST_GAME_LEAVE: // I'm outa here! - DEBUG_LOG(("LANAPI::update - got a MSG_REQUEST_GAME_LEAVE from %d.%d.%d.%d", PRINTF_IP_AS_4_INTS(senderIP))); - handleRequestGameLeave( msg, senderIP ); - break; - case LANMessage::MSG_REQUEST_LOBBY_LEAVE: // I'm outa here! - DEBUG_LOG(("LANAPI::update - got a MSG_REQUEST_LOBBY_LEAVE from %d.%d.%d.%d", PRINTF_IP_AS_4_INTS(senderIP))); - handleRequestLobbyLeave( msg, senderIP ); - break; - - // Game options, chat, etc - case LANMessage::MSG_SET_ACCEPT: // I'm cool with everything as is. - handleSetAccept( msg, senderIP ); - break; - case LANMessage::MSG_MAP_AVAILABILITY: // Map status - handleHasMap( msg, senderIP ); - break; - case LANMessage::MSG_CHAT: // Just spouting my mouth off. - handleChat( msg, senderIP ); - break; - case LANMessage::MSG_GAME_START: // Hold on; we're starting! - handleGameStart( msg, senderIP ); - break; - case LANMessage::MSG_GAME_START_TIMER: - handleGameStartTimer( msg, senderIP ); - break; - case LANMessage::MSG_GAME_OPTIONS: // Here's some info about the game. - DEBUG_LOG(("LANAPI::update - got a MSG_GAME_OPTIONS from %d.%d.%d.%d", PRINTF_IP_AS_4_INTS(senderIP))); - handleGameOptions( msg, senderIP ); - break; - case LANMessage::MSG_INACTIVE: // someone is telling us that we're inactive. - handleInActive( msg, senderIP ); - break; - - default: - DEBUG_LOG(("Unknown LAN message type %d", msg->messageType)); - } - - // Mark it as read - m_transport->m_inBuffer[i].length = 0; - } - } - if(LANbuttonPushed) - return; - // Send out periodic I'm Here messages - if (now > s_resendDelta + m_lastResendTime) - { - m_lastResendTime = now; - - if (m_inLobby) - { - RequestSetName(m_name); - } - else if (m_currentGame && !m_currentGame->isGameInProgress()) - { - if (AmIHost()) - { - RequestGameOptions( GenerateGameOptionsString(), true ); - RequestGameAnnounce( ); - } - else - { -#if TELL_COMPUTER_IDENTITY_IN_LAN_LOBBY - AsciiString text; - text.format("User=%s", m_userName.str()); - RequestGameOptions( text, true ); - text.format("Host=%s", m_hostName.str()); - RequestGameOptions( text, true ); -#endif - RequestGameOptions( "HELLO", false ); - } - } - else if (m_currentGame) - { - // game is in progress - RequestGameAnnounce will check if we should send it - RequestGameAnnounce(); - } - } - - Bool playerListChanged = false; - Bool gameListChanged = false; - - // Weed out people we haven't heard from in a while - LANPlayer *player = m_lobbyPlayers; - while (player) - { - if (player->getLastHeard() + s_resendDelta*2 < now) - { - // He's gone! - removePlayer(player); - LANPlayer *nextPlayer = player->getNext(); - delete player; - player = nextPlayer; - playerListChanged = true; - } - else - { - player = player->getNext(); - } - } - - // Weed out people we haven't heard from in a while - LANGameInfo *game = m_games; - while (game) - { - if (game != m_currentGame && game->getLastHeard() + s_resendDelta*2 < now) - { - // He's gone! - removeGame(game); - LANGameInfo *nextGame = game->getNext(); - delete game; - game = nextGame; - gameListChanged = true; - } - else - { - game = game->getNext(); - } - } - if ( m_currentGame && !m_currentGame->isGameInProgress() ) - { - if ( !AmIHost() && (m_currentGame->getLastHeard() + s_resendDelta*16 < now) ) - { - // We haven't heard from the host in a while. Bail. - // Actually, fake a host leaving message. :) - LANMessage msg; - fillInLANMessage( &msg ); - msg.messageType = LANMessage::MSG_REQUEST_GAME_LEAVE; - wcslcpy(msg.name, m_currentGame->getPlayerName(0).str(), ARRAY_SIZE(msg.name)); - handleRequestGameLeave(&msg, m_currentGame->getIP(0)); - UnicodeString text; - text = TheGameText->fetch("LAN:HostNotResponding"); - OnChat(UnicodeString::TheEmptyString, m_localIP, text, LANCHAT_SYSTEM); - } - else if ( AmIHost() ) - { - // Check each player for timeouts - for (int p=1; pgetIP(p) && m_currentGame->getPlayerLastHeard(p) + s_resendDelta*8 < now) - { - LANMessage msg; - fillInLANMessage( &msg ); - UnicodeString theStr; - theStr.format(TheGameText->fetch("LAN:PlayerDropped"), m_currentGame->getPlayerName(p).str()); - msg.messageType = LANMessage::MSG_REQUEST_GAME_LEAVE; - wcslcpy(msg.name, m_currentGame->getPlayerName(p).str(), ARRAY_SIZE(msg.name)); - handleRequestGameLeave(&msg, m_currentGame->getIP(p)); - OnChat(UnicodeString::TheEmptyString, m_localIP, theStr, LANCHAT_SYSTEM); - } - } - } - } - - if (playerListChanged) - { - OnPlayerList(m_lobbyPlayers); - } - - if (gameListChanged) - { - OnGameList(m_games); - } - - // Time out old actions - if (m_pendingAction != ACT_NONE && now > m_expiration) - { - switch (m_pendingAction) - { - case ACT_JOIN: - OnGameJoin(RET_TIMEOUT, NULL); - m_pendingAction = ACT_NONE; - m_currentGame = NULL; - m_inLobby = true; - break; - case ACT_LEAVE: - OnPlayerLeave(m_name); - m_pendingAction = ACT_NONE; - m_currentGame = NULL; - m_inLobby = true; - break; - case ACT_JOINDIRECTCONNECT: - OnGameJoin(RET_TIMEOUT, NULL); - m_pendingAction = ACT_NONE; - m_currentGame = NULL; - m_inLobby = true; - break; - default: - m_pendingAction = ACT_NONE; - } - } - - // send out "game starting" messages - if ( m_gameStartTime && m_gameStartSeconds && m_gameStartTime <= now ) - { - // m_gameStartTime is when the next message goes out - // m_gameStartSeconds is how many seconds remain in the message - - RequestGameStartTimer( m_gameStartSeconds ); - } - else if (m_gameStartTime && m_gameStartTime <= now) - { -// DEBUG_LOG(("m_gameStartTime=%d, now=%d, m_gameStartSeconds=%d", m_gameStartTime, now, m_gameStartSeconds)); - ResetGameStartTimer(); - RequestGameStart(); - } - - // Check for an MOTD every few seconds - static UnsignedInt lastMOTDCheck = 0; - static const UnsignedInt motdInterval = 30000; - if (now > lastMOTDCheck + motdInterval) - { - checkMOTD(); - lastMOTDCheck = now; - } -} - -// Request functions generate network traffic -void LANAPI::RequestLocations( void ) -{ - LANMessage msg; - msg.messageType = LANMessage::MSG_REQUEST_LOCATIONS; - fillInLANMessage( &msg ); - sendMessage(&msg); -} - -void LANAPI::RequestGameJoin( LANGameInfo *game, UnsignedInt ip /* = 0 */ ) -{ - if ((m_pendingAction != ACT_NONE) && (m_pendingAction != ACT_JOINDIRECTCONNECT)) - { - OnGameJoin( RET_BUSY, NULL ); - return; - } - - if (!game) - { - OnGameJoin( RET_GAME_GONE, NULL ); - return; - } - - LANMessage msg; - msg.messageType = LANMessage::MSG_REQUEST_JOIN; - fillInLANMessage( &msg ); - msg.GameToJoin.gameIP = game->getSlot(0)->getIP(); - msg.GameToJoin.exeCRC = TheGlobalData->m_exeCRC; - msg.GameToJoin.iniCRC = TheGlobalData->m_iniCRC; - - AsciiString s = ""; - GetStringFromRegistry("\\ergc", "", s); - strlcpy(msg.GameToJoin.serial, s.str(), ARRAY_SIZE(msg.GameToJoin.serial)); - - sendMessage(&msg, ip); - - m_pendingAction = ACT_JOIN; - m_expiration = timeGetTime() + m_actionTimeout; -} - -void LANAPI::RequestGameJoinDirectConnect(UnsignedInt ipaddress) -{ - if (m_pendingAction != ACT_NONE) - { - OnGameJoin( RET_BUSY, NULL ); - return; - } - - if (ipaddress == 0) - { - OnGameJoin( RET_GAME_GONE, NULL ); - return; - } - - m_directConnectRemoteIP = ipaddress; - - LANMessage msg; - msg.messageType = LANMessage::MSG_REQUEST_GAME_INFO; - fillInLANMessage(&msg); - msg.PlayerInfo.ip = GetLocalIP(); - wcslcpy(msg.PlayerInfo.playerName, m_name.str(), ARRAY_SIZE(msg.PlayerInfo.playerName)); - - sendMessage(&msg, ipaddress); - - m_pendingAction = ACT_JOINDIRECTCONNECT; - m_expiration = timeGetTime() + m_actionTimeout; -} - -void LANAPI::RequestGameLeave( void ) -{ - LANMessage msg; - msg.messageType = LANMessage::MSG_REQUEST_GAME_LEAVE; - fillInLANMessage( &msg ); - wcslcpy(msg.PlayerInfo.playerName, m_name.str(), ARRAY_SIZE(msg.PlayerInfo.playerName)); - sendMessage(&msg); - m_transport->update(); // Send immediately, before OnPlayerLeave below resets everything. - - if (m_currentGame && m_currentGame->getIP(0) == m_localIP) - { - // Exit out immediately if we're hosting - OnPlayerLeave(m_name); - removeGame(m_currentGame); - m_currentGame = NULL; - m_inLobby = true; - } - else - { - m_pendingAction = ACT_LEAVE; - m_expiration = timeGetTime() + m_actionTimeout; - } -} - -void LANAPI::RequestGameAnnounce( void ) -{ - // In game - are we a game host? - if (m_currentGame && !(m_currentGame->getIsDirectConnect())) - { - if (m_currentGame->getIP(0) == m_localIP || (m_currentGame->isGameInProgress() && TheNetwork && TheNetwork->isPacketRouter())) // if we're in game we should reply if we're the packet router - { - LANMessage reply; - fillInLANMessage( &reply ); - reply.messageType = LANMessage::MSG_GAME_ANNOUNCE; - - AsciiString gameOpts = GameInfoToAsciiString(m_currentGame); - strlcpy(reply.GameInfo.options,gameOpts.str(), ARRAY_SIZE(reply.GameInfo.options)); - wcslcpy(reply.GameInfo.gameName, m_currentGame->getName().str(), ARRAY_SIZE(reply.GameInfo.gameName)); - reply.GameInfo.inProgress = m_currentGame->isGameInProgress(); - reply.GameInfo.isDirectConnect = m_currentGame->getIsDirectConnect(); - - sendMessage(&reply); - } - } -} - -void LANAPI::RequestAccept( void ) -{ - if (m_inLobby || !m_currentGame) - return; - - LANMessage msg; - fillInLANMessage( &msg ); - msg.messageType = LANMessage::MSG_SET_ACCEPT; - msg.Accept.isAccepted = true; - wcslcpy(msg.Accept.gameName, m_currentGame->getName().str(), ARRAY_SIZE(msg.Accept.gameName)); - sendMessage(&msg); -} - -void LANAPI::RequestHasMap( void ) -{ - if (m_inLobby || !m_currentGame) - return; - - LANMessage msg; - fillInLANMessage( &msg ); - msg.messageType = LANMessage::MSG_MAP_AVAILABILITY; - msg.MapStatus.hasMap = m_currentGame->getSlot(m_currentGame->getLocalSlotNum())->hasMap(); - wcslcpy(msg.MapStatus.gameName, m_currentGame->getName().str(), ARRAY_SIZE(msg.MapStatus.gameName)); - CRC mapNameCRC; -//mapNameCRC.computeCRC(m_currentGame->getMap().str(), m_currentGame->getMap().getLength()); - AsciiString portableMapName = TheGameState->realMapPathToPortableMapPath(m_currentGame->getMap()); - mapNameCRC.computeCRC(portableMapName.str(), portableMapName.getLength()); - msg.MapStatus.mapCRC = mapNameCRC.get(); - sendMessage(&msg); - - if (!msg.MapStatus.hasMap) - { - UnicodeString text; - UnicodeString mapDisplayName; - const MapMetaData *mapData = TheMapCache->findMap( m_currentGame->getMap() ); - Bool willTransfer = TRUE; - if (mapData) - { - mapDisplayName.format(L"%ls", mapData->m_displayName.str()); - if (mapData->m_isOfficial) - willTransfer = FALSE; - } - else - { - mapDisplayName.format(L"%hs", TheGameState->getMapLeafName(m_currentGame->getMap()).str()); - willTransfer = WouldMapTransfer(m_currentGame->getMap()); - } - if (willTransfer) - text.format(TheGameText->fetch("GUI:LocalPlayerNoMapWillTransfer"), mapDisplayName.str()); - else - text.format(TheGameText->fetch("GUI:LocalPlayerNoMap"), mapDisplayName.str()); - OnChat(UnicodeString(L"SYSTEM"), m_localIP, text, LANCHAT_SYSTEM); - } -} - -void LANAPI::RequestChat( UnicodeString message, ChatType format ) -{ - LANMessage msg; - fillInLANMessage( &msg ); - wcslcpy(msg.Chat.gameName, (m_currentGame) ? m_currentGame->getName().str() : L"", ARRAY_SIZE(msg.Chat.gameName)); - msg.messageType = LANMessage::MSG_CHAT; - msg.Chat.chatType = format; - wcslcpy(msg.Chat.message, message.str(), ARRAY_SIZE(msg.Chat.message)); - sendMessage(&msg); - - OnChat(m_name, m_localIP, message, format); -} - -void LANAPI::RequestGameStart( void ) -{ - if (m_inLobby || !m_currentGame || m_currentGame->getIP(0) != m_localIP) - return; - - LANMessage msg; - msg.messageType = LANMessage::MSG_GAME_START; - fillInLANMessage( &msg ); - sendMessage(&msg); - m_transport->update(); // force a send - - OnGameStart(); -} - -void LANAPI::ResetGameStartTimer( void ) -{ - m_gameStartTime = 0; - m_gameStartSeconds = 0; -} - -void LANAPI::RequestGameStartTimer( Int seconds ) -{ - if (m_inLobby || !m_currentGame || m_currentGame->getIP(0) != m_localIP) - return; - - UnsignedInt now = timeGetTime(); - m_gameStartTime = now + 1000; - m_gameStartSeconds = (seconds) ? seconds - 1 : 0; - - LANMessage msg; - msg.messageType = LANMessage::MSG_GAME_START_TIMER; - msg.StartTimer.seconds = seconds; - fillInLANMessage( &msg ); - sendMessage(&msg); - m_transport->update(); // force a send - - OnGameStartTimer(seconds); -} - -void LANAPI::RequestGameOptions( AsciiString gameOptions, Bool isPublic, UnsignedInt ip /* = 0 */ ) -{ - DEBUG_ASSERTCRASH(gameOptions.getLength() < m_lanMaxOptionsLength, ("Game options string is too long!")); - - if (!m_currentGame) - return; - - LANMessage msg; - fillInLANMessage( &msg ); - msg.messageType = LANMessage::MSG_GAME_OPTIONS; - strlcpy(msg.GameOptions.options, gameOptions.str(), ARRAY_SIZE(msg.GameOptions.options)); - sendMessage(&msg, ip); - - m_lastGameopt = gameOptions; - - int player; - for (player = 0; playergetIP(player) == m_localIP) - { - OnGameOptions(m_localIP, player, AsciiString(msg.GameOptions.options)); - break; - } - } - - // We can request game options (side, color, etc) while we don't have a slot yet. Of course, we don't need to - // call OnGameOptions for those, so it's okay to silently fail. - //DEBUG_ASSERTCRASH(player != MAX_SLOTS, ("Requested game options, but we're not in slot list!"); -} - -void LANAPI::RequestGameCreate( UnicodeString gameName, Bool isDirectConnect ) -{ - // No games of the same name should exist... Ignore that for now. - /// @todo: make sure LAN games with identical names don't crash things like in RA2. - - if ((!m_inLobby || m_currentGame) && !isDirectConnect) - { - DEBUG_ASSERTCRASH(m_inLobby && m_currentGame, ("Can't create a game while in one!")); - OnGameCreate(LANAPIInterface::RET_BUSY); - return; - } - - if (m_pendingAction != ACT_NONE) - { - OnGameCreate(LANAPIInterface::RET_BUSY); - return; - } - - // Create the local game object - m_inLobby = false; - LANGameInfo *myGame = NEW LANGameInfo; - - myGame->setSeed(GetTickCount()); - -// myGame->setInProgress(false); - myGame->enterGame(); - UnicodeString s; - s.format(L"%8.8X%8.8X", m_localIP, myGame->getSeed()); - if (gameName.isEmpty()) - s.concat(m_name); - else - s.concat(gameName); - - s.truncateTo(g_lanGameNameLength); - - DEBUG_LOG(("Setting local game name to '%ls'", s.str())); - - myGame->setName(s); - - LANGameSlot newSlot; - newSlot.setState(SLOT_PLAYER, m_name); - newSlot.setIP(m_localIP); - newSlot.setPort(NETWORK_BASE_PORT_NUMBER); // LAN game, everyone has a unique IP, so it's ok to use the same port. - newSlot.setLastHeard(0); - newSlot.setLogin(m_userName); - newSlot.setHost(m_hostName); - - myGame->setSlot(0,newSlot); - myGame->setNext(NULL); - LANPreferences pref; - - AsciiString mapName = pref.getPreferredMap(); - - myGame->setMap(mapName); - myGame->setIsDirectConnect(isDirectConnect); - - myGame->setLastHeard(timeGetTime()); - m_currentGame = myGame; - -/// @todo: Need to initialize the players elsewere. -/* for (int player = 1; player < MAX_SLOTS; ++player) - { - myGame->setPlayerName(player, UnicodeString(L"")); - myGame->setIP(player, 0); - myGame->setAccepted(player, false); - }*/ - - // Add the game to the local game list - addGame(myGame); - - // Send an announcement - //RequestSlotList(); -/* - LANMessage msg; - wcslcpy(msg.name, m_name.str(), ARRAY_SIZE(msg.name)); - wcscpy(msg.GameInfo.gameName, myGame->getName().str()); - for (player=0; playergetPlayerName(player).str()); - msg.GameInfo.ip[player] = myGame->getIP(player); - msg.GameInfo.playerAccepted[player] = myGame->getAccepted(player); - } - msg.messageType = LANMessage::MSG_GAME_ANNOUNCE; -*/ - OnGameCreate(LANAPIInterface::RET_OK); -} - - -/*static const char slotListID = 'S'; -static const char gameOptionsID = 'G'; -static const char acceptID = 'A'; -static const char wannaStartID = 'W'; - -AsciiString LANAPI::createSlotString( void ) -{ - AsciiString slotList; - slotList.concat(slotListID); - for (int i=0; igetLANSlot(i); - AsciiString str; - if (slot->isHuman()) - { - str = "H"; - LANPlayer *user = slot->getUser(); - DEBUG_ASSERTCRASH(user, ("Human player has no User*!")); - AsciiString name; - name.translate(user->getName()); - str.concat(name); - str.concat(','); - } - else if (slot->isAI()) - { - if (slot->getState() == SLOT_EASY_AI) - str = "CE,"; - if (slot->getState() == SLOT_MED_AI) - str = "CM,"; - else - str = "CB,"; - } - else if (slot->getState() == SLOT_OPEN) - { - str = "O,"; - } - else if (slot->getState() == SLOT_CLOSED) - { - str = "X,"; - } - else - { - DEBUG_ASSERTCRASH(false, ("Bad slot type")); - str = "X,"; - } - - slotList.concat(str); - } - return slotList; -} -*/ -/* -void LANAPI::RequestSlotList( void ) -{ - - LANMessage reply; - reply.messageType = LANMessage::MSG_GAME_ANNOUNCE; - wcslcpy(reply.name, m_name.str(), ARRAY_SIZE(reply.name)); - int player; - for (player = 0; player < MAX_SLOTS; ++player) - { - wcslcpy(reply.GameInfo.name[player], m_currentGame->getPlayerName(player).str(), ARRAY_SIZE(reply.GameInfo.name[player])); - reply.GameInfo.ip[player] = m_currentGame->getIP(player); - reply.GameInfo.playerAccepted[player] = m_currentGame->getSlot(player)->isAccepted(); - } - wcslcpy(reply.GameInfo.gameName, m_currentGame->getName().str(), ARRAY_SIZE(reply.GameInfo.gameName)); - reply.GameInfo.inProgress = m_currentGame->isGameInProgress(); - - sendMessage(&reply); - - OnSlotList(LANAPIInterface::RET_OK, m_currentGame); -} -*/ -void LANAPI::RequestSetName( UnicodeString newName ) -{ - newName.trim(); - if (m_pendingAction != ACT_NONE) - { - // Can't change name while joining games - OnNameChange(m_localIP, newName); - return; - } - - // Set up timer - m_lastResendTime = timeGetTime(); - - if (m_inLobby && m_pendingAction == ACT_NONE) - { - m_name = newName; - LANMessage msg; - fillInLANMessage( &msg ); - msg.messageType = LANMessage::MSG_LOBBY_ANNOUNCE; - sendMessage(&msg); - - // Update the interface - LANPlayer *player = LookupPlayer(m_localIP); - if (!player) - { - player = NEW LANPlayer; - player->setIP(m_localIP); - } - else - { - removePlayer(player); - } - player->setName(m_name); - player->setHost(m_hostName); - player->setLogin(m_userName); - player->setLastHeard(timeGetTime()); - - addPlayer(player); - - OnNameChange(player->getIP(), player->getName()); - } -} - -void LANAPI::fillInLANMessage( LANMessage *msg ) -{ - if (!msg) - return; - - wcslcpy(msg->name, m_name.str(), ARRAY_SIZE(msg->name)); - strlcpy(msg->userName, m_userName.str(), ARRAY_SIZE(msg->userName)); - strlcpy(msg->hostName, m_hostName.str(), ARRAY_SIZE(msg->hostName)); -} - -void LANAPI::RequestLobbyLeave( Bool forced ) -{ - LANMessage msg; - msg.messageType = LANMessage::MSG_REQUEST_LOBBY_LEAVE; - fillInLANMessage( &msg ); - sendMessage(&msg); - - if (forced) - m_transport->update(); -} - -// Misc utility functions -LANGameInfo * LANAPI::LookupGame( UnicodeString gameName ) -{ - LANGameInfo *theGame = m_games; - - while (theGame && theGame->getName() != gameName) - { - theGame = theGame->getNext(); - } - - return theGame; // NULL means we didn't find anything. -} - -LANGameInfo * LANAPI::LookupGameByListOffset( Int offset ) -{ - LANGameInfo *theGame = m_games; - - if (offset < 0) - return NULL; - - while (offset-- && theGame) - { - theGame = theGame->getNext(); - } - - return theGame; // NULL means we didn't find anything. -} - -void LANAPI::removeGame( LANGameInfo *game ) -{ - LANGameInfo *g = m_games; - if (!game) - { - return; - } - else if (m_games == game) - { - m_games = m_games->getNext(); - } - else - { - while (g->getNext() && g->getNext() != game) - { - g = g->getNext(); - } - if (g->getNext() == game) - { - g->setNext(game->getNext()); - } - else - { - // Odd. We went the whole way without finding it in the list. - DEBUG_ASSERTCRASH(false, ("LANGameInfo wasn't in the list")); - } - } -} - -LANPlayer * LANAPI::LookupPlayer( UnsignedInt playerIP ) -{ - LANPlayer *thePlayer = m_lobbyPlayers; - - while (thePlayer && thePlayer->getIP() != playerIP) - { - thePlayer = thePlayer->getNext(); - } - - return thePlayer; // NULL means we didn't find anything. -} - -void LANAPI::removePlayer( LANPlayer *player ) -{ - LANPlayer *p = m_lobbyPlayers; - if (!player) - { - return; - } - else if (m_lobbyPlayers == player) - { - m_lobbyPlayers = m_lobbyPlayers->getNext(); - } - else - { - while (p->getNext() && p->getNext() != player) - { - p = p->getNext(); - } - if (p->getNext() == player) - { - p->setNext(player->getNext()); - } - else - { - // Odd. We went the whole way without finding it in the list. - DEBUG_ASSERTCRASH(false, ("LANPlayer wasn't in the list")); - } - } -} - -void LANAPI::addGame( LANGameInfo *game ) -{ - if (!m_games) - { - m_games = game; - game->setNext(NULL); - return; - } - else - { - if (game->getName().compareNoCase(m_games->getName()) < 0) - { - game->setNext(m_games); - m_games = game; - return; - } - else - { - LANGameInfo *g = m_games; - while (g->getNext() && g->getNext()->getName().compareNoCase(game->getName()) > 0) - { - g = g->getNext(); - } - game->setNext(g->getNext()); - g->setNext(game); - return; - } - } -} - -void LANAPI::addPlayer( LANPlayer *player ) -{ - if (!m_lobbyPlayers) - { - m_lobbyPlayers = player; - player->setNext(NULL); - return; - } - else - { - if (player->getName().compareNoCase(m_lobbyPlayers->getName()) < 0) - { - player->setNext(m_lobbyPlayers); - m_lobbyPlayers = player; - return; - } - else - { - LANPlayer *p = m_lobbyPlayers; - while (p->getNext() && p->getNext()->getName().compareNoCase(player->getName()) > 0) - { - p = p->getNext(); - } - player->setNext(p->getNext()); - p->setNext(player); - return; - } - } -} - -Bool LANAPI::SetLocalIP( UnsignedInt localIP ) -{ - Bool retval = TRUE; - m_localIP = localIP; - - m_transport->reset(); - retval = m_transport->init(m_localIP, lobbyPort); - m_transport->allowBroadcasts(true); - - return retval; -} - -void LANAPI::SetLocalIP( AsciiString localIP ) -{ - UnsignedInt resolvedIP = ResolveIP(localIP); - SetLocalIP(resolvedIP); -} - -Bool LANAPI::AmIHost( void ) -{ - return m_currentGame && m_currentGame->getIP(0) == m_localIP; -} - -void LANAPI::setIsActive(Bool isActive) { - DEBUG_LOG(("LANAPI::setIsActive - entering")); - if (isActive != m_isActive) { - DEBUG_LOG(("LANAPI::setIsActive - m_isActive changed to %s", isActive ? "TRUE" : "FALSE")); - if (isActive == FALSE) { - if ((m_inLobby == FALSE) && (m_currentGame != NULL)) { - LANMessage msg; - fillInLANMessage( &msg ); - msg.messageType = LANMessage::MSG_INACTIVE; - sendMessage(&msg); - DEBUG_LOG(("LANAPI::setIsActive - sent an IsActive message")); - } - } - } - m_isActive = isActive; -} diff --git a/Generals/Code/GameEngine/Source/GameNetwork/LANAPICallbacks.cpp b/Generals/Code/GameEngine/Source/GameNetwork/LANAPICallbacks.cpp deleted file mode 100644 index 1c61c6c144..0000000000 --- a/Generals/Code/GameEngine/Source/GameNetwork/LANAPICallbacks.cpp +++ /dev/null @@ -1,737 +0,0 @@ -/* -** 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. // -// // -//////////////////////////////////////////////////////////////////////////////// - -/////////////////////////////////////////////////////////////////////////////////////// -// FILE: LANAPICallbacks.cpp -// Author: Chris Huybregts, October 2001 -// Description: LAN API Callbacks -/////////////////////////////////////////////////////////////////////////////////////// -#include "PreRTS.h" // This must go first in EVERY cpp file in the GameEngine - -#include "strtok_r.h" -#include "Common/GameEngine.h" -#include "Common/GlobalData.h" -#include "Common/MessageStream.h" -#include "Common/MultiplayerSettings.h" -#include "Common/PlayerTemplate.h" -#include "Common/QuotedPrintable.h" -#include "Common/RandomValue.h" -#include "Common/UserPreferences.h" -#include "GameClient/GameText.h" -#include "GameClient/LanguageFilter.h" -#include "GameClient/MapUtil.h" -#include "GameClient/MessageBox.h" -#include "GameLogic/GameLogic.h" -#include "GameNetwork/FileTransfer.h" -#include "GameNetwork/LANAPICallbacks.h" -#include "GameNetwork/networkutil.h" - -LANAPI *TheLAN = NULL; -extern Bool LANbuttonPushed; - - -//Colors used for the chat dialogs -const Color playerColor = GameMakeColor(255,255,255,255); -const Color gameColor = GameMakeColor(255,255,255,255); -const Color gameInProgressColor = GameMakeColor(128,128,128,255); -const Color chatNormalColor = GameMakeColor(50,215,230,255); -const Color chatActionColor = GameMakeColor(255,0,255,255); -const Color chatLocalNormalColor = GameMakeColor(255,128,0,255); -const Color chatLocalActionColor = GameMakeColor(128,255,255,255); -const Color chatSystemColor = GameMakeColor(255,255,255,255); -const Color acceptTrueColor = GameMakeColor(0,255,0,255); -const Color acceptFalseColor = GameMakeColor(255,0,0,255); - - -UnicodeString LANAPIInterface::getErrorStringFromReturnType( ReturnType ret ) -{ - switch (ret) - { - case RET_OK: - return TheGameText->fetch("LAN:OK"); - case RET_TIMEOUT: - return TheGameText->fetch("LAN:ErrorTimeout"); - case RET_GAME_FULL: - return TheGameText->fetch("LAN:ErrorGameFull"); - case RET_DUPLICATE_NAME: - return TheGameText->fetch("LAN:ErrorDuplicateName"); - case RET_CRC_MISMATCH: - return TheGameText->fetch("LAN:ErrorCRCMismatch"); - case RET_GAME_STARTED: - return TheGameText->fetch("LAN:ErrorGameStarted"); - case RET_GAME_EXISTS: - return TheGameText->fetch("LAN:ErrorGameExists"); - case RET_GAME_GONE: - return TheGameText->fetch("LAN:ErrorGameGone"); - case RET_BUSY: - return TheGameText->fetch("LAN:ErrorBusy"); - case RET_SERIAL_DUPE: - return TheGameText->fetch("WOL:ChatErrorSerialDup"); - default: - return TheGameText->fetch("LAN:ErrorUnknown"); - } -} - -// On functions are (generally) the result of network traffic - -void LANAPI::OnAccept( UnsignedInt playerIP, Bool status ) -{ - if( AmIHost() ) - { - Int i = 0; - for (; i < MAX_SLOTS; i++) - { - if (m_currentGame->getIP(i) == playerIP) - { - if(status) - m_currentGame->getLANSlot(i)->setAccept(); - else - m_currentGame->getLANSlot(i)->unAccept(); - break; - } - } - if (i != MAX_SLOTS ) - { - RequestGameOptions( GenerateGameOptionsString(), false ); - lanUpdateSlotList(); - } - } - else - { - //i'm not the host but if the accept came from the host... - if( m_currentGame->getIP(0) == playerIP ) - { - UnicodeString text; - text = TheGameText->fetch("GUI:HostWantsToStart"); - OnChat(UnicodeString(L"SYSTEM"), m_localIP, text, LANCHAT_SYSTEM); - } - } -} - -void LANAPI::OnHasMap( UnsignedInt playerIP, Bool status ) -{ - if( AmIHost() ) - { - Int i = 0; - for (; i < MAX_SLOTS; i++) - { - if (m_currentGame->getIP(i) == playerIP) - { - m_currentGame->getLANSlot(i)->setMapAvailability( status ); - break; - } - } - if (i != MAX_SLOTS ) - { - UnicodeString mapDisplayName; - const MapMetaData *mapData = TheMapCache->findMap( m_currentGame->getMap() ); - Bool willTransfer = TRUE; - if (mapData) - { - mapDisplayName.format(L"%ls", mapData->m_displayName.str()); - if (mapData->m_isOfficial) - willTransfer = FALSE; - } - else - { - mapDisplayName.format(L"%hs", m_currentGame->getMap().str()); - willTransfer = WouldMapTransfer(m_currentGame->getMap()); - } - if (!status) - { - UnicodeString text; - if (willTransfer) - text.format(TheGameText->fetch("GUI:PlayerNoMapWillTransfer"), m_currentGame->getLANSlot(i)->getName().str(), mapDisplayName.str()); - else - text.format(TheGameText->fetch("GUI:PlayerNoMap"), m_currentGame->getLANSlot(i)->getName().str(), mapDisplayName.str()); - OnChat(UnicodeString(L"SYSTEM"), m_localIP, text, LANCHAT_SYSTEM); - } - lanUpdateSlotList(); - } - } -} - -void LANAPI::OnGameStartTimer( Int seconds ) -{ - UnicodeString text; - if (seconds == 1) - text.format(TheGameText->fetch("LAN:GameStartTimerSingular"), seconds); - else - text.format(TheGameText->fetch("LAN:GameStartTimerPlural"), seconds); - OnChat(UnicodeString(L"SYSTEM"), m_localIP, text, LANCHAT_SYSTEM); -} - -void LANAPI::OnGameStart( void ) -{ - //DEBUG_LOG(("Map is '%s', preview is '%s'", m_currentGame->getMap().str(), GetPreviewFromMap(m_currentGame->getMap()).str())); - //DEBUG_LOG(("Map is '%s', INI is '%s'", m_currentGame->getMap().str(), GetINIFromMap(m_currentGame->getMap()).str())); - - if (m_currentGame) - { - LANPreferences pref; - AsciiString option; - option.format("%d", m_currentGame->getLANSlot( m_currentGame->getLocalSlotNum() )->getPlayerTemplate()); - pref["PlayerTemplate"] = option; - option.format("%d", m_currentGame->getLANSlot( m_currentGame->getLocalSlotNum() )->getColor()); - pref["Color"] = option; - if (m_currentGame->amIHost()) - { - pref["Map"] = AsciiStringToQuotedPrintable(m_currentGame->getMap()); - pref.setSuperweaponRestricted( m_currentGame->getSuperweaponRestriction() > 0 ); - pref.setStartingCash( m_currentGame->getStartingCash() ); - } - pref.write(); - - m_isInLANMenu = FALSE; - - //m_currentGame->startGame(0); - - // Set up the game network - DEBUG_ASSERTCRASH(TheNetwork == NULL, ("For some reason TheNetwork isn't NULL at the start of this game. Better look into that.")); - - delete TheNetwork; - TheNetwork = NULL; - - // Time to initialize TheNetwork for this game. - TheNetwork = NetworkInterface::createNetwork(); - TheNetwork->init(); - TheNetwork->setLocalAddress(m_localIP, 8088); - TheNetwork->initTransport(); - - TheNetwork->parseUserList(m_currentGame); - - if (TheGameLogic->isInGame()) - TheGameLogic->clearGameData(); - - Bool filesOk = DoAnyMapTransfers(m_currentGame); - - // see if we really have the map. if not, back out. - TheMapCache->updateCache(); - if (!filesOk || TheMapCache->findMap(m_currentGame->getMap()) == NULL) - { - DEBUG_LOG(("After transfer, we didn't really have the map. Bailing...")); - OnPlayerLeave(m_name); - removeGame(m_currentGame); - m_currentGame = NULL; - m_inLobby = TRUE; - - delete TheNetwork; - TheNetwork = NULL; - - OnChat(UnicodeString::TheEmptyString, 0, TheGameText->fetch("GUI:CouldNotTransferMap"), LANCHAT_SYSTEM); - return; - } - - m_currentGame->startGame(0); - - // shutdown the top, but do not pop it off the stack - //TheShell->hideShell(); - // setup the Global Data with the Map and Seed - TheWritableGlobalData->m_pendingFile = m_currentGame->getMap(); - - // send a message to the logic for a new game - GameMessage *msg = TheMessageStream->appendMessage( GameMessage::MSG_NEW_GAME ); - msg->appendIntegerArgument(GAME_LAN); - - TheWritableGlobalData->m_useFpsLimit = false; - - // Set the random seed - InitGameLogicRandom( m_currentGame->getSeed() ); - DEBUG_LOG(("InitGameLogicRandom( %d )", m_currentGame->getSeed())); - } -} - -void LANAPI::OnGameOptions( UnsignedInt playerIP, Int playerSlot, AsciiString options ) -{ - if (!m_currentGame) - return; - - if (m_currentGame->getIP(playerSlot) != playerIP) - return; // He's not in our game?!? - - - if (m_currentGame->isGameInProgress()) - return; // we don't want to process any game options while in game. - - if (playerSlot == 0 && !m_currentGame->amIHost()) - { - m_currentGame->setLastHeard(timeGetTime()); - AsciiString oldOptions = GameInfoToAsciiString(m_currentGame); // save these off for if we get booted - if(ParseGameOptionsString(m_currentGame,options)) - { - lanUpdateSlotList(); - updateGameOptions(); - } - Bool booted = true; - for(Int player = 1; player< MAX_SLOTS; player++) - { - if(m_currentGame->getIP(player) == m_localIP) - { - booted = false; - break; - } - } - if(booted) - { - // restore the options with us in so we can save prefs - ParseGameOptionsString(m_currentGame, oldOptions); - OnPlayerLeave(m_name); - } - - } - else - { - // Check for user/host updates - { - AsciiString key; - AsciiString munkee = options; - munkee.nextToken(&key, "="); - //DEBUG_LOG(("GameOpt request: key=%s, val=%s from player %d", key.str(), munkee.str(), playerSlot)); - - LANGameSlot *slot = m_currentGame->getLANSlot(playerSlot); - if (!slot) - return; - - if (key == "User") - { - slot->setLogin(munkee.str()+1); - return; - } - else if (key == "Host") - { - slot->setHost(munkee.str()+1); - return; - } - } - - // Parse player requests (side, color, etc) - if( AmIHost() && m_localIP != playerIP) - { - if (options.compare("HELLO") == 0) - { - m_currentGame->setPlayerLastHeard(playerSlot, timeGetTime()); - } - else - { - m_currentGame->setPlayerLastHeard(playerSlot, timeGetTime()); - Bool change = false; - Bool shouldUnaccept = false; - AsciiString key; - options.nextToken(&key, "="); - Int val = atoi(options.str()+1); - DEBUG_LOG(("GameOpt request: key=%s, val=%s from player %d", key.str(), options.str(), playerSlot)); - - LANGameSlot *slot = m_currentGame->getLANSlot(playerSlot); - if (!slot) - return; - - if (key == "Color") - { - if (val >= -1 && val < TheMultiplayerSettings->getNumColors() && val != slot->getColor() && slot->getPlayerTemplate() != PLAYERTEMPLATE_OBSERVER) - { - Bool colorAvailable = TRUE; - if(val != -1 ) - { - for(Int i=0; i getLANSlot(i); - if(val == checkSlot->getColor() && slot != checkSlot) - { - colorAvailable = FALSE; - break; - } - } - } - if(colorAvailable) - slot->setColor(val); - change = true; - } - else - { - DEBUG_LOG(("Rejecting invalid color %d", val)); - } - } - else if (key == "PlayerTemplate") - { - if (val >= PLAYERTEMPLATE_MIN && val < ThePlayerTemplateStore->getPlayerTemplateCount() && val != slot->getPlayerTemplate()) - { - slot->setPlayerTemplate(val); - if (val == PLAYERTEMPLATE_OBSERVER) - { - slot->setColor(-1); - slot->setStartPos(-1); - slot->setTeamNumber(-1); - } - change = true; - shouldUnaccept = true; - } - else - { - DEBUG_LOG(("Rejecting invalid PlayerTemplate %d", val)); - } - } - else if (key == "StartPos" && slot->getPlayerTemplate() != PLAYERTEMPLATE_OBSERVER) - { - - if (val >= -1 && val < MAX_SLOTS && val != slot->getStartPos()) - { - Bool startPosAvailable = TRUE; - if(val != -1) - for(Int i=0; i getLANSlot(i); - if(val == checkSlot->getStartPos() && slot != checkSlot) - { - startPosAvailable = FALSE; - break; - } - } - if(startPosAvailable) - slot->setStartPos(val); - change = true; - shouldUnaccept = true; - } - else - { - DEBUG_LOG(("Rejecting invalid startPos %d", val)); - } - } - else if (key == "Team") - { - if (val >= -1 && val < MAX_SLOTS/2 && val != slot->getTeamNumber() && slot->getPlayerTemplate() != PLAYERTEMPLATE_OBSERVER) - { - slot->setTeamNumber(val); - change = true; - shouldUnaccept = true; - } - else - { - DEBUG_LOG(("Rejecting invalid team %d", val)); - } - } - else if (key == "NAT") - { - if ((val >= FirewallHelperClass::FIREWALL_TYPE_SIMPLE) && - (val <= FirewallHelperClass::FIREWALL_TYPE_DESTINATION_PORT_DELTA)) - { - slot->setNATBehavior((FirewallHelperClass::FirewallBehaviorType)val); - DEBUG_LOG(("NAT behavior set to %d for player %d", val, playerSlot)); - change = true; - } - else - { - DEBUG_LOG(("Rejecting invalid NAT behavior %d", (Int)val)); - } - } - - if (change) - { - if (shouldUnaccept) - m_currentGame->resetAccepted(); - RequestGameOptions(GenerateGameOptionsString(), true); - lanUpdateSlotList(); - DEBUG_LOG(("Slot value is color=%d, PlayerTemplate=%d, startPos=%d, team=%d", - slot->getColor(), slot->getPlayerTemplate(), slot->getStartPos(), slot->getTeamNumber())); - DEBUG_LOG(("Slot list updated to %s", GenerateGameOptionsString().str())); - } - } - } - } -} - - -/* -void LANAPI::OnSlotList( ReturnType ret, LANGameInfo *theGame ) -{ - if (!theGame || theGame != m_currentGame) - return; - - Bool foundMe = false; - for (int player = 0; player < MAX_SLOTS; ++player) - { - if (m_currentGame->getIP(player) == m_localIP) - { - foundMe = true; - break; - } - } - if (!foundMe) - { - // I've been kicked - back to the lobby for me! - // We're counting on the fact that OnPlayerLeave winds up calling reset on TheLAN. - OnPlayerLeave(m_name); - return; - } - - lanUpdateSlotList(); -} -*/ -void LANAPI::OnPlayerJoin( Int slot, UnicodeString playerName ) -{ - if (m_currentGame && m_currentGame->getIP(0) == m_localIP) - { - // Someone New Joined.. lets reset the accepts - m_currentGame->resetAccepted(); - - // Send out the game options - RequestGameOptions(GenerateGameOptionsString(), true); - } - - lanUpdateSlotList(); -} - -void LANAPI::OnGameJoin( ReturnType ret, LANGameInfo *theGame ) -{ - if (ret == RET_OK) - { - LANbuttonPushed = true; - TheShell->push( AsciiString("Menus/LanGameOptionsMenu.wnd") ); - //lanUpdateSlotList(); - - LANPreferences pref; - AsciiString options; - options.format("PlayerTemplate=%d", pref.getPreferredFaction()); - RequestGameOptions(options, true); - options.format("Color=%d", pref.getPreferredColor()); - RequestGameOptions(options, true); - options.format("User=%s", m_userName.str()); - RequestGameOptions( options, true ); - options.format("Host=%s", m_hostName.str()); - RequestGameOptions( options, true ); - options.format("NAT=%d", FirewallHelperClass::FIREWALL_TYPE_SIMPLE); // BGC: This is a LAN game, so there is no firewall. - RequestGameOptions( options, true ); - } - else if (ret != RET_BUSY) - { - /// @todo: re-enable lobby controls? Error msgs? - UnicodeString title, body; - title = TheGameText->fetch("LAN:JoinFailed"); - body = getErrorStringFromReturnType(ret); - MessageBoxOk(title, body, NULL); - } -} - -void LANAPI::OnHostLeave( void ) -{ - DEBUG_ASSERTCRASH(!m_inLobby && m_currentGame, ("Game info is gone!")); - if (m_inLobby || !m_currentGame) - return; - LANbuttonPushed = true; - DEBUG_LOG(("Host left - popping to lobby")); - TheShell->pop(); -} - -void LANAPI::OnPlayerLeave( UnicodeString player ) -{ - DEBUG_ASSERTCRASH(!m_inLobby && m_currentGame, ("Game info is gone!")); - if (m_inLobby || !m_currentGame || m_currentGame->isGameInProgress()) - return; - - if (m_name.compare(player) == 0) - { - // We're leaving. Save options and Pop the shell up a screen. - //DEBUG_ASSERTCRASH(false, ("Slot is %d", m_currentGame->getLocalSlotNum())); - if (m_currentGame && m_currentGame->isInGame() && m_currentGame->getLocalSlotNum() >= 0) - { - LANPreferences pref; - AsciiString option; - option.format("%d", m_currentGame->getLANSlot( m_currentGame->getLocalSlotNum() )->getPlayerTemplate()); - pref["PlayerTemplate"] = option; - option.format("%d", m_currentGame->getLANSlot( m_currentGame->getLocalSlotNum() )->getColor()); - pref["Color"] = option; - if (m_currentGame->amIHost()) - pref["Map"] = AsciiStringToQuotedPrintable(m_currentGame->getMap()); - pref.write(); - } - LANbuttonPushed = true; - DEBUG_LOG(("OnPlayerLeave says we're leaving! pop away!")); - TheShell->pop(); - } - else - { - if (m_currentGame && m_currentGame->getIP(0) == m_localIP) - { - // Force a new slotlist send - m_lastResendTime = 0; - - lanUpdateSlotList(); - RequestGameOptions( GenerateGameOptionsString(), true ); - - } - } -} - -void LANAPI::OnGameList( LANGameInfo *gameList ) -{ - - if (m_inLobby) - { - LANDisplayGameList(listboxGames, gameList); - } -} - -void LANAPI::OnGameCreate( ReturnType ret ) -{ - if (ret == RET_OK) - { - - LANbuttonPushed = true; - TheShell->push( AsciiString("Menus/LanGameOptionsMenu.wnd") ); - - RequestLobbyLeave( false ); - //RequestGameAnnounce( ); // can't do this here, since we don't have a map set - } - else - { - if(m_inLobby) - { - switch( ret ) - { - case RET_GAME_EXISTS: - GadgetListBoxAddEntryText(listboxChatWindow, TheGameText->fetch("LAN:ErrorGameExists"), chatSystemColor, -1, -1); - break; - case RET_BUSY: - GadgetListBoxAddEntryText(listboxChatWindow, TheGameText->fetch("LAN:ErrorBusy"), chatSystemColor, -1, -1); - break; - default: - GadgetListBoxAddEntryText(listboxChatWindow, TheGameText->fetch("LAN:ErrorUnknown"), chatSystemColor, -1, -1); - } - } - } - -} - -void LANAPI::OnPlayerList( LANPlayer *playerList ) -{ - if (m_inLobby) - { - - UnsignedInt selectedIP = 0; - Int selectedIndex = -1; - Int indexToSelect = -1; - GadgetListBoxGetSelected(listboxPlayers, &selectedIndex); - - if (selectedIndex != -1 ) - selectedIP = (UnsignedInt) GadgetListBoxGetItemData(listboxPlayers, selectedIndex, 0); - - GadgetListBoxReset(listboxPlayers); - - LANPlayer *player = m_lobbyPlayers; - while (player) - { - Int addedIndex = GadgetListBoxAddEntryText(listboxPlayers, player->getName(), playerColor, -1, -1); - GadgetListBoxSetItemData(listboxPlayers, (void *)player->getIP(),addedIndex, 0 ); - - if (selectedIP == player->getIP()) - indexToSelect = addedIndex; - - player = player->getNext(); - } - - if (indexToSelect >= 0) - GadgetListBoxSetSelected(listboxPlayers, indexToSelect); - } -} - -void LANAPI::OnNameChange( UnsignedInt IP, UnicodeString newName ) -{ - OnPlayerList(m_lobbyPlayers); -} - -void LANAPI::OnInActive(UnsignedInt IP) { - -} - -void LANAPI::OnChat( UnicodeString player, UnsignedInt ip, UnicodeString message, ChatType format ) -{ - GameWindow *chatWindow = NULL; - - if (m_inLobby) - { - chatWindow = listboxChatWindow; - } - else if( m_currentGame && m_currentGame->isGameInProgress() && TheShell->isShellActive()) - { - chatWindow = listboxChatWindowScoreScreen; - } - else if( m_currentGame && !m_currentGame->isGameInProgress()) - { - chatWindow = listboxChatWindowLanGame; - } - if (chatWindow == NULL) - return; - Int index = -1; - UnicodeString unicodeChat; - switch (format) - { - case LANAPIInterface::LANCHAT_SYSTEM: - unicodeChat = L""; - unicodeChat.concat(message); - unicodeChat.concat(L""); - index =GadgetListBoxAddEntryText(chatWindow, unicodeChat, chatSystemColor, -1, -1); - break; - case LANAPIInterface::LANCHAT_EMOTE: - unicodeChat = player; - unicodeChat.concat(L' '); - unicodeChat.concat(message); - if (ip == m_localIP) - index =GadgetListBoxAddEntryText(chatWindow, unicodeChat, chatLocalActionColor, -1, -1); - else - index =GadgetListBoxAddEntryText(chatWindow, unicodeChat, chatActionColor, -1, -1); - break; - case LANAPIInterface::LANCHAT_NORMAL: - default: - { - // Do the language filtering. - TheLanguageFilter->filterLine(message); - - Color chatColor = GameMakeColor(255, 255, 255, 255); - if (m_currentGame) - { - Int slotNum = m_currentGame->getSlotNum(player); - // it'll be -1 if its invalid. - if (slotNum >= 0) { - GameSlot *gs = m_currentGame->getSlot(slotNum); - if (gs) { - Int colorIndex = gs->getColor(); - MultiplayerColorDefinition *def = TheMultiplayerSettings->getColor(colorIndex); - if (def) - chatColor = def->getColor(); - } - } - } - - unicodeChat = L"["; - unicodeChat.concat(player); - unicodeChat.concat(L"] "); - unicodeChat.concat(message); - if (ip == m_localIP) - index =GadgetListBoxAddEntryText(chatWindow, unicodeChat, chatColor, -1, -1); - else - index =GadgetListBoxAddEntryText(chatWindow, unicodeChat, chatColor, -1, -1); - break; - } - } - GadgetListBoxSetItemData(chatWindow, (void *)-1, index); -} diff --git a/Generals/Code/GameEngine/Source/GameNetwork/LANAPIhandlers.cpp b/Generals/Code/GameEngine/Source/GameNetwork/LANAPIhandlers.cpp deleted file mode 100644 index fd505c4129..0000000000 --- a/Generals/Code/GameEngine/Source/GameNetwork/LANAPIhandlers.cpp +++ /dev/null @@ -1,661 +0,0 @@ -/* -** 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. // -// // -//////////////////////////////////////////////////////////////////////////////// - -/////////////////////////////////////////////////////////////////////////////////////// -// FILE: LANAPIHandlers.cpp -// Author: Matthew D. Campbell, October 2001 -// Description: LAN callback handlers -/////////////////////////////////////////////////////////////////////////////////////// - -#include "PreRTS.h" // This must go first in EVERY cpp file in the GameEngine - -#include "Common/crc.h" -#include "Common/GameState.h" -#include "Common/Registry.h" -#include "Common/GlobalData.h" -#include "Common/QuotedPrintable.h" -#include "Common/UserPreferences.h" -#include "GameNetwork/LANAPI.h" -#include "GameNetwork/LANAPICallbacks.h" -#include "GameClient/MapUtil.h" - -void LANAPI::handleRequestLocations( LANMessage *msg, UnsignedInt senderIP ) -{ - if (m_inLobby) - { - LANMessage reply; - fillInLANMessage( &reply ); - reply.messageType = LANMessage::MSG_LOBBY_ANNOUNCE; - - sendMessage(&reply); - m_lastResendTime = timeGetTime(); - } - else - { - // In game - are we a game host? - if (m_currentGame) - { - if (m_currentGame->getIP(0) == m_localIP) - { - LANMessage reply; - fillInLANMessage( &reply ); - reply.messageType = LANMessage::MSG_GAME_ANNOUNCE; - AsciiString gameOpts = GenerateGameOptionsString(); - strlcpy(reply.GameInfo.options, gameOpts.str(), ARRAY_SIZE(reply.GameInfo.options)); - wcslcpy(reply.GameInfo.gameName, m_currentGame->getName().str(), ARRAY_SIZE(reply.GameInfo.gameName)); - reply.GameInfo.inProgress = m_currentGame->isGameInProgress(); - - sendMessage(&reply); - } - else - { - // We're a joiner - } - } - } - // Add the player to the lobby player list - LANPlayer *player = LookupPlayer(senderIP); - if (!player) - { - player = NEW LANPlayer; - player->setIP(senderIP); - } - else - { - removePlayer(player); - } - player->setName(UnicodeString(msg->name)); - player->setHost(msg->hostName); - player->setLogin(msg->userName); - player->setLastHeard(timeGetTime()); - - addPlayer(player); - - OnNameChange(player->getIP(), player->getName()); -} - -void LANAPI::handleGameAnnounce( LANMessage *msg, UnsignedInt senderIP ) -{ - if (senderIP == m_localIP) - { - return; // Don't try to update own info - } - else if (m_currentGame && m_currentGame->isGameInProgress()) - { - return; // Don't care about games if we're playing - } - else if (senderIP == m_directConnectRemoteIP) - { - - if (m_currentGame == NULL) - { - LANGameInfo *game = LookupGame(UnicodeString(msg->GameInfo.gameName)); - if (!game) - { - game = NEW LANGameInfo; - game->setName(UnicodeString(msg->GameInfo.gameName)); - addGame(game); - } - Bool success = ParseGameOptionsString(game,AsciiString(msg->GameInfo.options)); - game->setGameInProgress(msg->GameInfo.inProgress); - game->setIsDirectConnect(msg->GameInfo.isDirectConnect); - game->setLastHeard(timeGetTime()); - if (!success) - { - // remove from list - removeGame(game); - delete game; - return; - } - RequestGameJoin(game, m_directConnectRemoteIP); - } - } - else - { - LANGameInfo *game = LookupGame(UnicodeString(msg->GameInfo.gameName)); - if (!game) - { - game = NEW LANGameInfo; - game->setName(UnicodeString(msg->GameInfo.gameName)); - addGame(game); - } - Bool success = ParseGameOptionsString(game,AsciiString(msg->GameInfo.options)); - game->setGameInProgress(msg->GameInfo.inProgress); - game->setIsDirectConnect(msg->GameInfo.isDirectConnect); - game->setLastHeard(timeGetTime()); - if (!success) - { - // remove from list - removeGame(game); - delete game; - game = NULL; - } - - OnGameList( m_games ); - // if (game == m_currentGame && !m_inLobby) - // OnSlotList(RET_OK, game); - } -} - -void LANAPI::handleLobbyAnnounce( LANMessage *msg, UnsignedInt senderIP ) -{ - LANPlayer *player = LookupPlayer(senderIP); - if (!player) - { - player = NEW LANPlayer; - player->setIP(senderIP); - } - else - { - removePlayer(player); - } - player->setName(UnicodeString(msg->name)); - player->setHost(msg->hostName); - player->setLogin(msg->userName); - player->setLastHeard(timeGetTime()); - - addPlayer(player); - - OnNameChange(player->getIP(), player->getName()); -} - -void LANAPI::handleRequestGameInfo( LANMessage *msg, UnsignedInt senderIP ) -{ - // In game - are we a game host? - if (m_currentGame) - { - if (m_currentGame->getIP(0) == m_localIP || (m_currentGame->isGameInProgress() && TheNetwork && TheNetwork->isPacketRouter())) // if we're in game we should reply if we're the packet router - { - LANMessage reply; - fillInLANMessage( &reply ); - reply.messageType = LANMessage::MSG_GAME_ANNOUNCE; - - AsciiString gameOpts = GameInfoToAsciiString(m_currentGame); - strlcpy(reply.GameInfo.options,gameOpts.str(), ARRAY_SIZE(reply.GameInfo.options)); - wcslcpy(reply.GameInfo.gameName, m_currentGame->getName().str(), ARRAY_SIZE(reply.GameInfo.gameName)); - reply.GameInfo.inProgress = m_currentGame->isGameInProgress(); - reply.GameInfo.isDirectConnect = m_currentGame->getIsDirectConnect(); - - sendMessage(&reply, senderIP); - } - } -} - -void LANAPI::handleRequestJoin( LANMessage *msg, UnsignedInt senderIP ) -{ - UnsignedInt responseIP = senderIP; // need this cause the player may or may not be - // in the player list at the sendMessage. - - if (msg->GameToJoin.gameIP != m_localIP) - { - return; // Not us. Ignore it. - } - LANMessage reply; - fillInLANMessage( &reply ); - if (!m_inLobby && m_currentGame && m_currentGame->getIP(0) == m_localIP) - { - if (m_currentGame->isGameInProgress()) - { - reply.messageType = LANMessage::MSG_JOIN_DENY; - reply.GameNotJoined.reason = LANAPIInterface::RET_GAME_STARTED; - reply.GameNotJoined.gameIP = m_localIP; - reply.GameNotJoined.playerIP = senderIP; - DEBUG_LOG(("LANAPI::handleRequestJoin - join denied because game already started.")); - } - else - { - int player; - Bool canJoin = true; - - // see if the CRCs match -#if defined(RTS_DEBUG) - if (TheGlobalData->m_netMinPlayers > 0) { -#endif -// TheSuperHackers @todo Enable CRC checks! -#if !RTS_ZEROHOUR - if (msg->GameToJoin.iniCRC != TheGlobalData->m_iniCRC || - msg->GameToJoin.exeCRC != TheGlobalData->m_exeCRC) - { - DEBUG_LOG(("LANAPI::handleRequestJoin - join denied because of CRC mismatch. CRCs are them/us INI:%X/%X exe:%X/%X", - msg->GameToJoin.iniCRC, TheGlobalData->m_iniCRC, - msg->GameToJoin.exeCRC, TheGlobalData->m_exeCRC)); - reply.messageType = LANMessage::MSG_JOIN_DENY; - reply.GameNotJoined.reason = LANAPIInterface::RET_CRC_MISMATCH; - reply.GameNotJoined.gameIP = m_localIP; - reply.GameNotJoined.playerIP = senderIP; - canJoin = false; - } -#endif -#if defined(RTS_DEBUG) - } -#endif - -// TheSuperHackers @tweak Disables the duplicate serial check -#if 0 - // check for a duplicate serial - AsciiString s; - for (player = 0; canJoin && playergetLANSlot(player); - s.clear(); - if (player == 0) - { - GetStringFromRegistry("\\ergc", "", s); - } - else if (slot->isHuman()) - { - s = slot->getSerial(); - if (s.isEmpty()) - s = ""; - } - - if (s.isNotEmpty()) - { - DEBUG_LOG(("Checking serial '%s' in slot %d", s.str(), player)); - - if (!strncmp(s.str(), msg->GameToJoin.serial, g_maxSerialLength)) - { - // serials match! kick the punk! - reply.messageType = LANMessage::MSG_JOIN_DENY; - reply.GameNotJoined.reason = LANAPIInterface::RET_SERIAL_DUPE; - reply.GameNotJoined.gameIP = m_localIP; - reply.GameNotJoined.playerIP = senderIP; - canJoin = false; - - DEBUG_LOG(("LANAPI::handleRequestJoin - join denied because of duplicate serial # (%s).", s.str())); - break; - } - } - } -#endif - - // We're the host, so see if he has a duplicate name - for (player = 0; canJoin && playergetLANSlot(player); - if (slot->isHuman() && slot->getName().compare(msg->name) == 0) - { - // just deny duplicates - reply.messageType = LANMessage::MSG_JOIN_DENY; - reply.GameNotJoined.reason = LANAPIInterface::RET_DUPLICATE_NAME; - reply.GameNotJoined.gameIP = m_localIP; - reply.GameNotJoined.playerIP = senderIP; - canJoin = false; - - DEBUG_LOG(("LANAPI::handleRequestJoin - join denied because of duplicate names.")); - break; - } - } - - // TheSuperHackers @bugfix Stubbjax 26/09/2025 Players can now join open slots regardless of starting spots on the map. - for (player = 0; canJoin && playergetLANSlot(player)->isOpen()) - { - // OK, add him in. - reply.messageType = LANMessage::MSG_JOIN_ACCEPT; - wcslcpy(reply.GameJoined.gameName, m_currentGame->getName().str(), ARRAY_SIZE(reply.GameJoined.gameName)); - reply.GameJoined.slotPosition = player; - reply.GameJoined.gameIP = m_localIP; - reply.GameJoined.playerIP = senderIP; - - LANGameSlot newSlot; - newSlot.setState(SLOT_PLAYER, UnicodeString(msg->name)); - newSlot.setIP(senderIP); - newSlot.setPort(NETWORK_BASE_PORT_NUMBER); - newSlot.setLastHeard(timeGetTime()); - newSlot.setSerial(msg->GameToJoin.serial); - m_currentGame->setSlot(player,newSlot); - DEBUG_LOG(("LANAPI::handleRequestJoin - added player %ls at ip 0x%08x to the game", msg->name, senderIP)); - - OnPlayerJoin(player, UnicodeString(msg->name)); - responseIP = 0; - - break; - } - } - - if (canJoin && player == MAX_SLOTS) - { - reply.messageType = LANMessage::MSG_JOIN_DENY; - wcslcpy(reply.GameNotJoined.gameName, m_currentGame->getName().str(), ARRAY_SIZE(reply.GameNotJoined.gameName)); - reply.GameNotJoined.reason = LANAPIInterface::RET_GAME_FULL; - reply.GameNotJoined.gameIP = m_localIP; - reply.GameNotJoined.playerIP = senderIP; - DEBUG_LOG(("LANAPI::handleRequestJoin - join denied because game is full.")); - } - } - } - else - { - reply.messageType = LANMessage::MSG_JOIN_DENY; - reply.GameNotJoined.reason = LANAPIInterface::RET_GAME_GONE; - reply.GameNotJoined.gameIP = m_localIP; - reply.GameNotJoined.playerIP = senderIP; - } - sendMessage(&reply, responseIP); - RequestGameOptions(GenerateGameOptionsString(), true); -} - -void LANAPI::handleJoinAccept( LANMessage *msg, UnsignedInt senderIP ) -{ - if (msg->GameJoined.playerIP == m_localIP) // Is it for us? - { - if (m_pendingAction == ACT_JOIN) // Are we trying to join? - { - m_currentGame = LookupGame(UnicodeString(msg->GameJoined.gameName)); - - if (!m_currentGame) - { - DEBUG_ASSERTCRASH(false, ("Could not find game to join!")); - OnGameJoin(RET_UNKNOWN, NULL); - } - else - { - m_inLobby = false; - AsciiString options = GameInfoToAsciiString(m_currentGame); - m_currentGame->enterGame(); - ParseAsciiStringToGameInfo(m_currentGame, options); - - Int pos = msg->GameJoined.slotPosition; - - LANGameSlot slot; - slot.setState(SLOT_PLAYER, m_name); - slot.setIP(m_localIP); - slot.setPort(NETWORK_BASE_PORT_NUMBER); - slot.setLastHeard(0); - slot.setLogin(m_userName); - slot.setHost(m_hostName); - m_currentGame->setSlot(pos, slot); - - m_currentGame->getLANSlot(0)->setHost(msg->hostName); - m_currentGame->getLANSlot(0)->setLogin(msg->userName); - - LANPreferences prefs; - AsciiString entry; - entry.format("%d.%d.%d.%d:%s", PRINTF_IP_AS_4_INTS(senderIP), UnicodeStringToQuotedPrintable(m_currentGame->getSlot(0)->getName()).str()); - prefs["RemoteIP0"] = entry; - prefs.write(); - - OnGameJoin(RET_OK, m_currentGame); - //DEBUG_ASSERTCRASH(false, ("setting host to %ls@%ls", m_currentGame->getLANSlot(0)->getUser()->getLogin().str(), - // m_currentGame->getLANSlot(0)->getUser()->getHost().str())); - } - m_pendingAction = ACT_NONE; - m_expiration = 0; - } - } -} - -void LANAPI::handleJoinDeny( LANMessage *msg, UnsignedInt senderIP ) -{ - if (msg->GameJoined.playerIP == m_localIP) // Is it for us? - { - if (m_pendingAction == ACT_JOIN) // Are we trying to join? - { - OnGameJoin(msg->GameNotJoined.reason, LookupGame(UnicodeString(msg->GameNotJoined.gameName))); - m_pendingAction = ACT_NONE; - m_expiration = 0; - } - } -} - -void LANAPI::handleRequestGameLeave( LANMessage *msg, UnsignedInt senderIP ) -{ - if (!m_inLobby && m_currentGame && !m_currentGame->isGameInProgress()) - { - int player; - for (player = 0; player < MAX_SLOTS; ++player) - { - if (m_currentGame->getIP(player) == senderIP) - { - if (player == 0) - { - OnHostLeave(); - removeGame(m_currentGame); - delete m_currentGame; - m_currentGame = NULL; - - /// @todo re-add myself to lobby? Or just keep me there all the time? If we send a LOBBY_ANNOUNCE things'll work out... - LANPlayer *lanPlayer = LookupPlayer(m_localIP); - if (!lanPlayer) - { - lanPlayer = NEW LANPlayer; - lanPlayer->setIP(m_localIP); - } - else - { - removePlayer(lanPlayer); - } - lanPlayer->setName(UnicodeString(m_name)); - lanPlayer->setHost(m_hostName); - lanPlayer->setLogin(m_userName); - lanPlayer->setLastHeard(timeGetTime()); - addPlayer(lanPlayer); - - } - else - { - if (AmIHost()) - { - // remove the deadbeat - LANGameSlot slot; - slot.setState(SLOT_OPEN); - m_currentGame->setSlot( player, slot ); - } - OnPlayerLeave(UnicodeString(msg->name)); - m_currentGame->getLANSlot(player)->setState(SLOT_OPEN); - m_currentGame->resetAccepted(); - RequestGameOptions(GenerateGameOptionsString(), false, senderIP); - //m_currentGame->endGame(); - } - break; - } - DEBUG_ASSERTCRASH(player < MAX_SLOTS, ("Didn't find player!")); - } - } - else if (m_inLobby) - { - // Look for dissappearing games - LANGameInfo *game = m_games; - while (game) - { - if (game->getName().compare(msg->GameToLeave.gameName) == 0) - { - removeGame(game); - delete game; - OnGameList(m_games); - break; - } - game = game->getNext(); - } - } -} - -void LANAPI::handleRequestLobbyLeave( LANMessage *msg, UnsignedInt senderIP ) -{ - if (m_inLobby) - { - LANPlayer *player = m_lobbyPlayers; - while (player) - { - if (player->getIP() == senderIP) - { - removePlayer(player); - OnPlayerList(m_lobbyPlayers); - break; - } - player = player->getNext(); - } - } -} - -void LANAPI::handleSetAccept( LANMessage *msg, UnsignedInt senderIP ) -{ - if (!m_inLobby && m_currentGame && !m_currentGame->isGameInProgress()) - { - int player; - for (player = 0; player < MAX_SLOTS; ++player) - { - if (m_currentGame->getIP(player) == senderIP) - { - OnAccept(senderIP, msg->Accept.isAccepted); - break; - } - } - } -} - -void LANAPI::handleHasMap( LANMessage *msg, UnsignedInt senderIP ) -{ - if (!m_inLobby && m_currentGame) - { - CRC mapNameCRC; -// mapNameCRC.computeCRC(m_currentGame->getMap().str(), m_currentGame->getMap().getLength()); - AsciiString portableMapName = TheGameState->realMapPathToPortableMapPath(m_currentGame->getMap()); - mapNameCRC.computeCRC(portableMapName.str(), portableMapName.getLength()); - if (mapNameCRC.get() != msg->MapStatus.mapCRC) - { - return; - } - - int player; - for (player = 0; player < MAX_SLOTS; ++player) - { - if (m_currentGame->getIP(player) == senderIP) - { - OnHasMap(senderIP, msg->MapStatus.hasMap); - break; - } - } - } -} - -void LANAPI::handleChat( LANMessage *msg, UnsignedInt senderIP ) -{ - if (m_inLobby) - { - LANPlayer *player; - if((player=LookupPlayer(senderIP)) != 0) - { - OnChat(UnicodeString(player->getName()), player->getIP(), UnicodeString(msg->Chat.message), msg->Chat.chatType); - player->setLastHeard(timeGetTime()); - } - } - else - { - if (LookupGame(UnicodeString(msg->Chat.gameName)) != m_currentGame) - { - DEBUG_LOG(("Game '%ls' is not my game", msg->Chat.gameName)); - if (m_currentGame) - { - DEBUG_LOG(("Current game is '%ls'", m_currentGame->getName().str())); - } - return; - } - - int player; - for (player = 0; player < MAX_SLOTS; ++player) - { - if (m_currentGame && m_currentGame->getIP(player) == senderIP) - { - OnChat(UnicodeString(msg->name), m_currentGame->getIP(player), UnicodeString(msg->Chat.message), msg->Chat.chatType); - break; - } - } - } -} - -void LANAPI::handleGameStart( LANMessage *msg, UnsignedInt senderIP ) -{ - if (!m_inLobby && m_currentGame && m_currentGame->getIP(0) == senderIP && !m_currentGame->isGameInProgress()) - { - OnGameStart(); - } -} - -void LANAPI::handleGameStartTimer( LANMessage *msg, UnsignedInt senderIP ) -{ - if (!m_inLobby && m_currentGame && m_currentGame->getIP(0) == senderIP && !m_currentGame->isGameInProgress()) - { - OnGameStartTimer(msg->StartTimer.seconds); - } -} - -void LANAPI::handleGameOptions( LANMessage *msg, UnsignedInt senderIP ) -{ - if (!m_inLobby && m_currentGame && !m_currentGame->isGameInProgress()) - { - int player; - for (player = 0; player < MAX_SLOTS; ++player) - { - if (m_currentGame->getIP(player) == senderIP) - { - OnGameOptions(senderIP, player, AsciiString(msg->GameOptions.options)); - break; - } - } - } -} - -void LANAPI::handleInActive(LANMessage *msg, UnsignedInt senderIP) { - if (m_inLobby || (m_currentGame == NULL) || (m_currentGame->isGameInProgress())) { - return; - } - - // check to see if we are the host of this game. - if (m_currentGame->amIHost() == FALSE) { - return; - } - - UnicodeString playerName; - playerName = msg->name; - - Int slotNum = m_currentGame->getSlotNum(playerName); - if (slotNum < 0) - return; - GameSlot *slot = m_currentGame->getSlot(slotNum); - if (slot == NULL) { - return; - } - - if (senderIP != slot->getIP()) { - return; - } - - // don't want to unaccept the host, that's silly. They can't hit start alt-tabbed anyways. - if (senderIP == TheLAN->GetLocalIP()) { - return; - } - - // only unaccept if the timer hasn't started yet. - if (m_gameStartTime != 0) { - return; - } - - slot->unAccept(); - AsciiString options = GenerateGameOptionsString(); - RequestGameOptions(options, FALSE); - lanUpdateSlotList(); -} diff --git a/Generals/Code/GameEngine/Source/GameNetwork/LANGameInfo.cpp b/Generals/Code/GameEngine/Source/GameNetwork/LANGameInfo.cpp deleted file mode 100644 index 19ac4d52b0..0000000000 --- a/Generals/Code/GameEngine/Source/GameNetwork/LANGameInfo.cpp +++ /dev/null @@ -1,320 +0,0 @@ -/* -** 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. // -// // -//////////////////////////////////////////////////////////////////////////////// - -// FILE: LANGameInfo.cpp ////////////////////////////////////////////////////// -// LAN game setup state info -// Author: Matthew D. Campbell, December 2001 - -#include "PreRTS.h" // This must go first in EVERY cpp file in the GameEngine - -#include "GameClient/GameInfoWindow.h" -#include "GameClient/GameText.h" -#include "GameClient/GadgetListBox.h" -#include "GameNetwork/LANGameInfo.h" -#include "GameNetwork/LANAPICallbacks.h" -#include "Common/MultiplayerSettings.h" -#include "strtok_r.h" -/* -#include "GameNetwork/LAN.h" -#include "GameNetwork/LANGame.h" -#include "GameNetwork/LANPing.h" -#include "GameNetwork/LANusers.h" -#include "GameNetwork/LANmenus.h" -*/ - -// Singleton ------------------------------------------ - -LANGameInfo *TheLANGameInfo = NULL; - -// LANGameSlot ---------------------------------------- - -LANGameSlot::LANGameSlot() -{ - m_lastHeard = 0; -} - - -LANPlayer * LANGameSlot::getUser( void ) -{ - if (isHuman()) - { - m_user.setIP(getIP()); - m_user.setLastHeard(getLastHeard()); - m_user.setName(getName()); - m_user.setNext(NULL); - return &m_user; - } - return NULL; -} - -// Various tests -Bool LANGameSlot::isUser( LANPlayer *user ) -{ - return (user && m_state == SLOT_PLAYER && user->getIP() == getIP()); -} - -Bool LANGameSlot::isUser( UnicodeString userName ) -{ - return (m_state == SLOT_PLAYER && !userName.compareNoCase(getName())); -} - -Bool LANGameSlot::isLocalPlayer( void ) const -{ - return isHuman() && TheLAN && TheLAN->GetLocalIP() == getIP(); -} - -// LANGameInfo ---------------------------------------- - -LANGameInfo::LANGameInfo() -{ - //Added By Sadullah Nader - //Initializtions missing and needed - m_lastHeard = 0; - m_next = NULL; - // - for (Int i = 0; i< MAX_SLOTS; ++i) - setSlotPointer(i, &m_LANSlot[i]); - - setLocalIP(TheLAN->GetLocalIP()); -} - -void LANGameInfo::setSlot( Int slotNum, LANGameSlot slotInfo ) -{ - DEBUG_ASSERTCRASH( slotNum >= 0 && slotNum < MAX_SLOTS, ("LANGameInfo::setSlot - Invalid slot number")); - if (slotNum < 0 || slotNum >= MAX_SLOTS) - return; - - m_LANSlot[slotNum] = slotInfo; - - if (slotNum == 0) - { - m_LANSlot[slotNum].setAccept(); - m_LANSlot[slotNum].setMapAvailability(true); - } -} - -LANGameSlot* LANGameInfo::getLANSlot( Int slotNum ) -{ - DEBUG_ASSERTCRASH( slotNum >= 0 && slotNum < MAX_SLOTS, ("LANGameInfo::getLANSlot - Invalid slot number")); - if (slotNum < 0 || slotNum >= MAX_SLOTS) - return NULL; - - return &m_LANSlot[slotNum]; -} - -const LANGameSlot* LANGameInfo::getConstLANSlot( Int slotNum ) const -{ - DEBUG_ASSERTCRASH( slotNum >= 0 && slotNum < MAX_SLOTS, ("LANGameInfo::getConstLANSlot - Invalid slot number")); - if (slotNum < 0 || slotNum >= MAX_SLOTS) - return NULL; - - return &m_LANSlot[slotNum]; -} - -Int LANGameInfo::getLocalSlotNum( void ) const -{ - DEBUG_ASSERTCRASH(m_inGame, ("Looking for local game slot while not in game")); - if (!m_inGame) - return -1; - - for (Int i=0; iisLocalPlayer()) - return i; - } - return -1; -} - -Int LANGameInfo::getSlotNum( UnicodeString userName ) -{ - DEBUG_ASSERTCRASH(m_inGame, ("Looking for game slot while not in game")); - if (!m_inGame) - return -1; - - for (Int i=0; iisUser( userName )) - return i; - } - return -1; -} - -Bool LANGameInfo::amIHost( void ) -{ - DEBUG_ASSERTCRASH(m_inGame, ("Looking for game slot while not in game")); - if (!m_inGame) - return false; - - return getLANSlot(0)->isLocalPlayer(); -} - -void LANGameInfo::setMap( AsciiString mapName ) -{ - GameInfo::setMap(mapName); -} - -void LANGameInfo::setSeed( Int seed ) -{ - GameInfo::setSeed(seed); -} - -void LANGameInfo::resetAccepted( void ) -{ - if (TheLAN) - { - TheLAN->ResetGameStartTimer(); - if (TheLAN->GetMyGame() == this && TheLAN->AmIHost()) - LANEnableStartButton(true); - } - for(int i = 0; i< MAX_SLOTS; i++) - { - m_LANSlot[i].unAccept(); - } -} -// Misc game-related functionality -------------------- - - -void LANDisplayGameList( GameWindow *gameListbox, LANGameInfo *gameList ) -{ - LANGameInfo *selectedPtr = NULL; - Int selectedIndex = -1; - Int indexToSelect = -1; - if (gameListbox) - { - GadgetListBoxGetSelected(gameListbox, &selectedIndex); - - if (selectedIndex != -1 ) - { - selectedPtr = (LANGameInfo *)GadgetListBoxGetItemData(gameListbox, selectedIndex, 0); - } - - GadgetListBoxReset(gameListbox); - - while (gameList) - { - UnicodeString txtGName; - txtGName = L""; - if( gameList->isGameInProgress() ) - { - txtGName.concat(L"["); - } - txtGName.concat(gameList->getPlayerName(0)); - if( gameList->isGameInProgress() ) - { - txtGName.concat(L"]"); - } - Int addedIndex = GadgetListBoxAddEntryText(gameListbox, txtGName, (gameList->isGameInProgress())?gameInProgressColor:gameColor, -1, -1); - GadgetListBoxSetItemData(gameListbox, (void *)gameList, addedIndex, 0 ); - - if (selectedPtr == gameList) - indexToSelect = addedIndex; - - gameList = gameList->getNext(); - } - - if (indexToSelect >= 0) - GadgetListBoxSetSelected(gameListbox, indexToSelect); - else - HideGameInfoWindow(TRUE); - } -} - -AsciiString GenerateGameOptionsString( void ) -{ - if(!TheLAN->GetMyGame() || !TheLAN->GetMyGame()->amIHost()) - return AsciiString::TheEmptyString; - - return GameInfoToAsciiString(TheLAN->GetMyGame()); -} - -Bool ParseGameOptionsString(LANGameInfo *game, AsciiString options) -{ - if (!TheLAN || !game) - return false; - - Int oldLocalSlotNum = (game->isInGame()) ? game->getLocalSlotNum() : -1; - Bool wasInGame = oldLocalSlotNum >= 0; -// Int hadMap = wasInGame && game->getSlot(oldLocalSlotNum)->hasMap(); - AsciiString oldMap = game->getMap(); - UnsignedInt oldMapCRC, newMapCRC; - oldMapCRC = game->getMapCRC(); - - std::map oldLogins, oldMachines; - std::map::iterator mapIt; - Int i; - for (i=0; igetLANSlot(i); - if (slot && slot->isHuman()) - { - //DEBUG_LOG(("Saving off %ls@%ls for %ls", slot->getUser()->getLogin().str(), slot->getUser()->getHost().str(), slot->getName().str())); - oldLogins[slot->getName()] = slot->getUser()->getLogin(); - oldMachines[slot->getName()] = slot->getUser()->getHost(); - } - } - - if (ParseAsciiStringToGameInfo(game, options)) - { - Int newLocalSlotNum = (game->isInGame()) ? game->getLocalSlotNum() : -1; - Bool isInGame = newLocalSlotNum >= 0; - if (!TheLAN->AmIHost() && isInGame) - { -// Int hasMap = game->getSlot(newLocalSlotNum)->hasMap(); - newMapCRC = game->getMapCRC(); - //DEBUG_LOG(("wasInGame:%d isInGame:%d hadMap:%d hasMap:%d oldMap:%s newMap:%s", wasInGame, isInGame, hadMap, hasMap, oldMap.str(), game->getMap().str())); - if ( (oldMapCRC ^ newMapCRC)/*(hasMap ^ hadMap)*/ || (!wasInGame && isInGame) ) - { - // it changed. send it - TheLAN->RequestHasMap(); - lanUpdateSlotList(); - updateGameOptions(); - } - } - // clean up LAN users, etc. - UnsignedInt now = timeGetTime(); - for (i=0; igetLANSlot(i); - - if (slot->isHuman()) - { - slot->setLastHeard(now); - mapIt = oldLogins.find(slot->getName()); - if (mapIt != oldLogins.end()) - slot->setLogin(mapIt->second); - mapIt = oldMachines.find(slot->getName()); - if (mapIt != oldMachines.end()) - slot->setHost(mapIt->second); - //DEBUG_LOG(("Restored %ls@%ls for %ls", slot->getUser()->getLogin().str(), slot->getUser()->getHost().str(), slot->getName().str())); - } - } - - return true; - } - - return false; -} - diff --git a/Generals/Code/GameEngine/Source/GameNetwork/NAT.cpp b/Generals/Code/GameEngine/Source/GameNetwork/NAT.cpp deleted file mode 100644 index 7b9c63429d..0000000000 --- a/Generals/Code/GameEngine/Source/GameNetwork/NAT.cpp +++ /dev/null @@ -1,1294 +0,0 @@ -/* -** 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. // -// // -//////////////////////////////////////////////////////////////////////////////// - -// FILE: NAT.cpp ///////////////////////////////////////////////////////////////////////////////// -// Author: Bryan Cleveland April 2002 -// Props to Steve Tall for figuring all the NAT and Firewall behavior patterns out, making my job -// a LOT easier. -// Desc: Resolves NAT'd IPs and port numbers for the other players in a game. -/////////////////////////////////////////////////////////////////////////////////////////////////// - -#include "PreRTS.h" // This must go first in EVERY cpp file in the GameEngine - -#include "GameNetwork/NAT.h" -#include "GameNetwork/Transport.h" -#include "GameNetwork/NetworkDefs.h" -#include "GameClient/EstablishConnectionsMenu.h" -#include "GameNetwork/NetworkInterface.h" -#include "GameNetwork/GameInfo.h" -#include "GameNetwork/GameSpy/PeerThread.h" -#include "GameNetwork/GameSpy/PeerDefs.h" -#include "GameNetwork/GameSpy/PersistentStorageThread.h" -#include "GameNetwork/GameSpy/GSConfig.h" - - -/* - * In case you're wondering, we do this weird connection pairing scheme - * to speed up the negotiation process, especially in cases where there - * are 4 or more players (nodes). Take for example an 8 player game... - * In an 8 player game there are 28 connections that need to be negotiated, - * doing this pairing scheme thing, we can make those 28 connections in the - * time it would normally take to make 7 connections. Since each connection - * could potentially take several seconds, this can be a HUGE time savings. - - * Right now you're probably wondering who this Bryan Cleveland guy is. - * He's the network coder that got fired when this didn't work. - - * In case you're wondering, this did end up working and Bryan left by - * his own choice. - */ -// m_connectionPairs[num nodes] [round] [node index] -/* static */ Int NAT::m_connectionPairs[MAX_SLOTS-1][MAX_SLOTS-1][MAX_SLOTS] = -{ - { // 2 nodes - // node 0 node 1 node 2 node 3 node 4 node 5 node 6 node 7 - { 1, 0, -1, -1, -1, -1, -1, -1}, // round 0 - { -1, -1, -1, -1, -1, -1, -1, -1}, // round 1 - { -1, -1, -1, -1, -1, -1, -1, -1}, // round 2 - { -1, -1, -1, -1, -1, -1, -1, -1}, // round 3 - { -1, -1, -1, -1, -1, -1, -1, -1}, // round 4 - { -1, -1, -1, -1, -1, -1, -1, -1}, // round 5 - { -1, -1, -1, -1, -1, -1, -1, -1} // round 6 - }, - { // 3 nodes - // node 0 node 1 node 2 node 3 node 4 node 5 node 6 node 7 - { 1, 0, -1, -1, -1, -1, -1, -1}, // round 0 - { 2, -1, 0, -1, -1, -1, -1, -1}, // round 1 - { -1, 2, 1, -1, -1, -1, -1, -1}, // round 2 - { -1, -1, -1, -1, -1, -1, -1, -1}, // round 3 - { -1, -1, -1, -1, -1, -1, -1, -1}, // round 4 - { -1, -1, -1, -1, -1, -1, -1, -1}, // round 5 - { -1, -1, -1, -1, -1, -1, -1, -1} // round 6 - }, - { // 4 nodes - // node 0 node 1 node 2 node 3 node 4 node 5 node 6 node 7 - { 1, 0, 3, 2, -1, -1, -1, -1}, // round 0 - { 2, 3, 0, 1, -1, -1, -1, -1}, // round 1 - { 3, 2, 1, 0, -1, -1, -1, -1}, // round 2 - { -1, -1, -1, -1, -1, -1, -1, -1}, // round 3 - { -1, -1, -1, -1, -1, -1, -1, -1}, // round 4 - { -1, -1, -1, -1, -1, -1, -1, -1}, // round 5 - { -1, -1, -1, -1, -1, -1, -1, -1} // round 6 - }, - { // 5 nodes - // node 0 node 1 node 2 node 3 node 4 node 5 node 6 node 7 - { 2, 4, 0, -1, 1, -1, -1, -1}, // round 0 - { -1, 3, 4, 1, 2, -1, -1, -1}, // round 1 - { 3, 2, 1, 0, -1, -1, -1, -1}, // round 2 - { 4, -1, 3, 2, 0, -1, -1, -1}, // round 3 - { 1, 0, -1, 4, 3, -1, -1, -1}, // round 4 - { -1, -1, -1, -1, -1, -1, -1, -1}, // round 5 - { -1, -1, -1, -1, -1, -1, -1, -1} // round 6 - }, - { // 6 nodes - // node 0 node 1 node 2 node 3 node 4 node 5 node 6 node 7 - { 3, 5, 4, 0, 2, 1, -1, -1}, // round 0 - { 2, 4, 0, 5, 1, 3, -1, -1}, // round 1 - { 4, 3, 5, 1, 0, 2, -1, -1}, // round 2 - { 1, 0, 3, 2, 5, 4, -1, -1}, // round 3 - { 5, 2, 1, 4, 3, 0, -1, -1}, // round 4 - { -1, -1, -1, -1, -1, -1, -1, -1}, // round 5 - { -1, -1, -1, -1, -1, -1, -1, -1} // round 6 - }, - { // 7 nodes - // node 0 node 1 node 2 node 3 node 4 node 5 node 6 node 7 - { -1, 6, 5, 4, 3, 2, 1, -1}, // round 0 - { 2, -1, 0, 6, 5, 4, 3, -1}, // round 1 - { 4, 3, -1, 1, 0, 6, 5, -1}, // round 2 - { 6, 5, 4, -1, 2, 1, 0, -1}, // round 3 - { 1, 0, 6, 5, -1, 3, 2, -1}, // round 4 - { 3, 2, 1, 0, 6, -1, 4, -1}, // round 5 - { 5, 4, 3, 2, 1, 0, -1, -1} // round 6 - }, - { // 8 nodes - // node 0 node 1 node 2 node 3 node 4 node 5 node 6 node 7 - { 4, 5, 6, 7, 0, 1, 2, 3}, // round 0 - { 5, 4, 7, 6, 1, 0, 3, 2}, // round 1 - { 3, 6, 5, 0, 7, 2, 1, 4}, // round 2 - { 2, 7, 0, 5, 6, 3, 4, 1}, // round 3 - { 6, 3, 4, 1, 2, 7, 0, 5}, // round 4 - { 1, 0, 3, 2, 5, 4, 7, 6}, // round 5 - { 7, 2, 1, 4, 3, 6, 5, 0} // round 6 - } -}; - -/* static */ Int NAT::m_timeBetweenRetries = 500; // .5 seconds between retries sounds good to me. -/* static */ time_t NAT::m_manglerRetryTimeInterval = 300; // sounds good to me. -/* static */ Int NAT::m_maxAllowedManglerRetries = 25; // works for me. -/* static */ time_t NAT::m_keepaliveInterval = 15000; // 15 seconds between keepalive packets seems good. -/* static */ time_t NAT::m_timeToWaitForPort = 15000; // wait for 15 seconds for the other player's port number. -/* static */ time_t NAT::m_timeForRoundTimeout = 15000; // wait for at most 15 seconds for each connection round to finish. - -NAT *TheNAT = NULL; - -NAT::NAT() -{ - //Added By Sadullah Nader - //Initializations inserted - m_beenProbed = FALSE; - m_connectionPairIndex = 0; - m_connectionRound = 0; - m_localIP = 0; - m_localNodeNumber = 0; - m_manglerAddress = 0; - m_manglerRetries = 0; - m_numNodes = 0; - m_numRetries = 0; - m_previousSourcePort = 0; - for(Int i = 0; i < MAX_SLOTS; i++) - m_sourcePorts[i] = 0; - m_spareSocketPort = 0; - m_startingPortNumber = 0; - m_targetNodeNumber = 0; - // - m_transport = NULL; - m_slotList = NULL; - m_roundTimeout = 0; - - m_maxNumRetriesAllowed = 10; - m_packetID = 0x7f00; -} - -NAT::~NAT() { -} - -// if we're already finished, change to being idle -// if we are negotiating now, check to see if this round is done -// if it is, check to see if we're completely done with all rounds. -// if we are, set state to be done. -// if not go on to the next connection round. -// if we are negotiating still, call the connection update -// check to see if this connection is done for us, or if it has failed. -enum { MS_TO_WAIT_FOR_STATS = 5000 }; -NATStateType NAT::update() { - static UnsignedInt s_startStatWaitTime = 0; - if (m_NATState == NATSTATE_DONE) { - m_NATState = NATSTATE_IDLE; - } else if (m_NATState == NATSTATE_WAITFORSTATS) { - // check for all stats - Bool gotAllStats = TRUE; - Bool timedOut = FALSE; - for (Int i=0; igetGameSpySlot(i); - if (slot && slot->isHuman()) - { - PSPlayerStats stats = TheGameSpyPSMessageQueue->findPlayerStatsByID(slot->getProfileID()); - if (stats.id == 0) - { - gotAllStats = FALSE; - //DEBUG_LOG(("Failed to find stats for %ls(%d)", slot->getName().str(), slot->getProfileID())); - } - } - } - // check for timeout. Timing out is not a fatal error - it just means we didn't get the other - // player's stats. We'll see 0/0 as his record, but we can still play him just fine. - UnsignedInt now = timeGetTime(); - if (now > s_startStatWaitTime + MS_TO_WAIT_FOR_STATS) - { - DEBUG_LOG(("Timed out waiting for stats. Let's just start the dang game.")); - timedOut = TRUE; - } - if (gotAllStats || timedOut) - { - m_NATState = NATSTATE_DONE; - TheEstablishConnectionsMenu->endMenu(); - - delete TheFirewallHelper; - TheFirewallHelper = NULL; - } - } else if (m_NATState == NATSTATE_DOCONNECTIONPATHS) { - if (allConnectionsDoneThisRound() == TRUE) { - // we finished this round, move on to the next one. - ++m_connectionRound; -// m_roundTimeout = timeGetTime() + TheGameSpyConfig->getRoundTimeout(); - m_roundTimeout = timeGetTime() + m_timeForRoundTimeout; - DEBUG_LOG(("NAT::update - done with connection round, moving on to round %d", m_connectionRound)); - - // we finished that round, now check to see if we're done, or if there are more rounds to go. - if (allConnectionsDone() == TRUE) { - // we're all done, time to go back home. - m_NATState = NATSTATE_WAITFORSTATS; - - // 2/19/03 BGC - we have successfully negotaited a NAT thingy, so our behavior must be correct - // so therefore we don't need to refresh our NAT even if we previously thought we had to. - TheFirewallHelper->flagNeedToRefresh(FALSE); - - s_startStatWaitTime = timeGetTime(); - DEBUG_LOG(("NAT::update - done with all connections, woohoo!!")); - /* - m_NATState = NATSTATE_DONE; - TheEstablishConnectionsMenu->endMenu(); - - delete TheFirewallHelper; - TheFirewallHelper = NULL; - */ - } else { - doThisConnectionRound(); - } - } - NATConnectionState state = connectionUpdate(); - - if (timeGetTime() > m_roundTimeout) { - DEBUG_LOG(("NAT::update - round timeout expired")); - setConnectionState(m_localNodeNumber, NATCONNECTIONSTATE_FAILED); - notifyUsersOfConnectionFailed(m_localNodeNumber); - } - - if (state == NATCONNECTIONSTATE_FAILED) { - // if we fail - m_NATState = NATSTATE_FAILED; - TheEstablishConnectionsMenu->endMenu(); - if (TheFirewallHelper != NULL) { - // we failed NAT negotiation, perhaps we need to redetect our firewall settings. - // We don't trust the user to do it for themselves so we force them to do it next time - // the log in. - // 2/19/03 - ok, we don't want to do this right away, if the user tries to play in another game - // before they log out and log back in the game won't have a chance at working. - // so we need to simply flag it so that when they log out the firewall behavior gets blown away. - TheFirewallHelper->flagNeedToRefresh(TRUE); -// TheWritableGlobalData->m_firewallBehavior = FirewallHelperClass::FIREWALL_TYPE_UNKNOWN; -// TheFirewallHelper->writeFirewallBehavior(); - - delete TheFirewallHelper; - TheFirewallHelper = NULL; - } - // we failed to connect, so we don't have to pass on the transport to the network. - delete m_transport; - m_transport = NULL; - } - } - return m_NATState; -} - - -// update transport, check for PROBE packets from our target. -// check to see if its time to PROBE our target -// MANGLER: -// if we are talking to the mangler, check to see if we got a response -// if we didn't get a response, check to see if its time to send another packet to it -NATConnectionState NAT::connectionUpdate() { - - GameSlot *targetSlot = NULL; - if (m_targetNodeNumber >= 0) { - targetSlot = m_slotList[m_connectionNodes[m_targetNodeNumber].m_slotIndex]; - } else { - return m_connectionStates[m_localNodeNumber]; - } - - if (m_beenProbed == FALSE) { - if (timeGetTime() >= m_nextPortSendTime) { -// sendMangledPortNumberToTarget(m_previousSourcePort, targetSlot); - sendMangledPortNumberToTarget(m_sourcePorts[m_targetNodeNumber], targetSlot); -// m_nextPortSendTime = timeGetTime() + TheGameSpyConfig->getRetryInterval(); - m_nextPortSendTime = timeGetTime() + m_timeBetweenRetries; - } - } - - // check to see if its time to send out our keepalives. - if (timeGetTime() >= m_nextKeepaliveTime) { - for (UnsignedInt node = 0; node < m_numNodes; ++node) { - if (m_myConnections[node] == TRUE) { - // we've made this connection, send a keepalive. - Int slotIndex = m_connectionNodes[node].m_slotIndex; - GameSlot *slot = m_slotList[slotIndex]; - DEBUG_ASSERTCRASH(slot != NULL, ("Trying to send keepalive to a NULL slot")); - if (slot != NULL) { - UnsignedInt ip = slot->getIP(); - DEBUG_LOG(("NAT::connectionUpdate - sending keep alive to node %d at %d.%d.%d.%d:%d", node, - PRINTF_IP_AS_4_INTS(ip), slot->getPort())); - m_transport->queueSend(ip, slot->getPort(), (const unsigned char *)"KEEPALIVE", strlen("KEEPALIVE") + 1); - } - } - } -// m_nextKeepaliveTime = timeGetTime() + TheGameSpyConfig->getKeepaliveInterval(); - m_nextKeepaliveTime = timeGetTime() + m_keepaliveInterval; - } - - m_transport->update(); - - // check to see if we've been probed. - for (Int i = 0; i < MAX_MESSAGES; ++i) { - if (m_transport->m_inBuffer[i].length > 0) { -#ifdef DEBUG_LOGGING - UnsignedInt ip = m_transport->m_inBuffer[i].addr; -#endif - DEBUG_LOG(("NAT::connectionUpdate - got a packet from %d.%d.%d.%d:%d, length = %d", - PRINTF_IP_AS_4_INTS(ip), m_transport->m_inBuffer[i].port, m_transport->m_inBuffer[i].length)); - UnsignedByte *data = m_transport->m_inBuffer[i].data; - if (memcmp(data, "PROBE", strlen("PROBE")) == 0) { - Int fromNode = atoi((char *)data + strlen("PROBE")); - DEBUG_LOG(("NAT::connectionUpdate - we've been probed by node %d.", fromNode)); - - if (fromNode == m_targetNodeNumber) { - DEBUG_LOG(("NAT::connectionUpdate - probe was sent by our target, setting connection state %d to done.", m_targetNodeNumber)); - setConnectionState(m_targetNodeNumber, NATCONNECTIONSTATE_DONE); - - if (m_transport->m_inBuffer[i].addr != targetSlot->getIP()) { - UnsignedInt fromIP = m_transport->m_inBuffer[i].addr; -#ifdef DEBUG_LOGGING - UnsignedInt slotIP = targetSlot->getIP(); -#endif - DEBUG_LOG(("NAT::connectionUpdate - incomming packet has different from address than we expected, incoming: %d.%d.%d.%d expected: %d.%d.%d.%d", - PRINTF_IP_AS_4_INTS(fromIP), - PRINTF_IP_AS_4_INTS(slotIP))); - targetSlot->setIP(fromIP); - } - if (m_transport->m_inBuffer[i].port != targetSlot->getPort()) { - DEBUG_LOG(("NAT::connectionUpdate - incoming packet came from a different port than we expected, incoming: %d expected: %d", - m_transport->m_inBuffer[i].port, targetSlot->getPort())); - targetSlot->setPort(m_transport->m_inBuffer[i].port); - m_sourcePorts[m_targetNodeNumber] = m_transport->m_inBuffer[i].port; - } - notifyUsersOfConnectionDone(m_targetNodeNumber); - } - - m_transport->m_inBuffer[i].length = 0; - } - if (memcmp(data, "KEEPALIVE", strlen("KEEPALIVE")) == 0) { - // keep alive packet, just toss it. - DEBUG_LOG(("NAT::connectionUpdate - got keepalive from %d.%d.%d.%d:%d", - PRINTF_IP_AS_4_INTS(ip), m_transport->m_inBuffer[i].port)); - m_transport->m_inBuffer[i].length = 0; - } - } - } - - // we are waiting for our target to tell us that they have received our probe. - if (m_connectionStates[m_localNodeNumber] == NATCONNECTIONSTATE_WAITINGFORRESPONSE) { - // check to see if it's time to probe our target. - if ((m_timeTillNextSend != -1) && (m_timeTillNextSend <= timeGetTime())) { - if (m_numRetries > m_maxNumRetriesAllowed) { - DEBUG_LOG(("NAT::connectionUpdate - too many retries, connection failed.")); - setConnectionState(m_localNodeNumber, NATCONNECTIONSTATE_FAILED); - - notifyUsersOfConnectionFailed(m_localNodeNumber); - } else { - DEBUG_LOG(("NAT::connectionUpdate - trying to send another probe (#%d) to our target", m_numRetries+1)); - // Send a probe. - sendAProbe(targetSlot->getIP(), targetSlot->getPort(), m_localNodeNumber); -// m_timeTillNextSend = timeGetTime() + TheGameSpyConfig->getRetryInterval(); - m_timeTillNextSend = timeGetTime() + m_timeBetweenRetries; - - // tell the target they've been probed. In other words, our port is open. - notifyTargetOfProbe(targetSlot); - - ++m_numRetries; - } - } - } - - // we are waiting for a response from the mangler to tell us what port we're using. - if (m_connectionStates[m_localNodeNumber] == NATCONNECTIONSTATE_WAITINGFORMANGLERRESPONSE) { - UnsignedShort mangledPort = 0; - if (TheFirewallHelper != NULL) { - mangledPort = TheFirewallHelper->getManglerResponse(m_packetID); - } - if (mangledPort != 0) { - // we got a response. now we need to start probing (unless of course we have a netgear) - processManglerResponse(mangledPort); - - // we know there is a firewall helper if we got here. - TheFirewallHelper->closeSpareSocket(m_spareSocketPort); - m_spareSocketPort = 0; - } else { - if (timeGetTime() >= m_manglerRetryTime) { - ++m_manglerRetries; -// if (m_manglerRetries > TheGameSpyConfig->getMaxManglerRetries()) { - if (m_manglerRetries > m_maxAllowedManglerRetries) { - // we couldn't communicate with the mangler, just use our non-mangled - // port number and hope that works. - DEBUG_LOG(("NAT::connectionUpdate - couldn't talk with the mangler using default port number")); - sendMangledPortNumberToTarget(getSlotPort(m_connectionNodes[m_localNodeNumber].m_slotIndex), targetSlot); - m_sourcePorts[m_targetNodeNumber] = getSlotPort(m_connectionNodes[m_localNodeNumber].m_slotIndex); - setConnectionState(m_localNodeNumber, NATCONNECTIONSTATE_WAITINGFORRESPONSE); - } else { - if (TheFirewallHelper != NULL) { - DEBUG_LOG(("NAT::connectionUpdate - trying to send to the mangler again. mangler address: %d.%d.%d.%d, from port: %d, packet ID:%d", - PRINTF_IP_AS_4_INTS(m_manglerAddress), m_spareSocketPort, m_packetID)); - TheFirewallHelper->sendToManglerFromPort(m_manglerAddress, m_spareSocketPort, m_packetID); - } -// m_manglerRetryTime = TheGameSpyConfig->getRetryInterval() + timeGetTime(); - m_manglerRetryTime = m_manglerRetryTimeInterval + timeGetTime(); - } - } - } - } - - if (m_connectionStates[m_localNodeNumber] == NATCONNECTIONSTATE_WAITINGFORMANGLEDPORT) { - if (timeGetTime() > m_timeoutTime) { - DEBUG_LOG(("NAT::connectionUpdate - waiting too long to get the other player's port number, failed.")); - setConnectionState(m_localNodeNumber, NATCONNECTIONSTATE_FAILED); - - notifyUsersOfConnectionFailed(m_localNodeNumber); - } - } - - return m_connectionStates[m_localNodeNumber]; -} - -// this is the function that starts the NAT/firewall negotiation process. -// after calling this, you should call the update function untill it returns -// NATSTATE_DONE. -void NAT::establishConnectionPaths() { - DEBUG_LOG(("NAT::establishConnectionPaths - entering")); - m_NATState = NATSTATE_DOCONNECTIONPATHS; - DEBUG_LOG(("NAT::establishConnectionPaths - using %d as our starting port number", m_startingPortNumber)); - if (TheEstablishConnectionsMenu == NULL) { - TheEstablishConnectionsMenu = NEW EstablishConnectionsMenu; - } - TheEstablishConnectionsMenu->initMenu(); - - if (TheFirewallHelper == NULL) { - TheFirewallHelper = createFirewallHelper(); - } - - DEBUG_ASSERTCRASH(m_slotList != NULL, ("NAT::establishConnectionPaths - don't have a slot list")); - if (m_slotList == NULL) { - return; - } - - // determine how many nodes we have. - m_numNodes = 0; - Int i = 0; - for (; i < MAX_SLOTS; ++i) { - if (m_slotList[i] != NULL) { - if (m_slotList[i]->isHuman()) { - DEBUG_LOG(("NAT::establishConnectionPaths - slot %d is %ls", i, m_slotList[i]->getName().str())); - ++m_numNodes; - } - } - } - DEBUG_LOG(("NAT::establishConnectionPaths - number of nodes: %d", m_numNodes)); - - if (m_numNodes < 2) - { - // just start the game - there isn't anybody to which to connect. :P - m_NATState = NATSTATE_DONE; - return; - } - - m_connectionRound = 0; - m_connectionPairIndex = m_numNodes - 2; - Bool connectionAssigned[MAX_SLOTS]; - - for (i = 0; i < MAX_SLOTS; ++i) { - m_connectionNodes[i].m_slotIndex = -1; - connectionAssigned[i] = FALSE; - m_sourcePorts[i] = 0; - } - - m_previousSourcePort = 0; - -// check for netgear bug behavior. -// as an aside, if there are more than 2 netgear bug firewall's in the game, -// it probably isn't going to work so well. stupid netgear. - -// nodes with a netgear bug behavior need to be matched up first. This prevents -// the NAT table from being reset for connections to other nodes. This also happens -// to be the reason why I call them "nodes" rather than "slots" or "players" as the -// ordering has to be messed with to get the netgears to make love, not war. - DEBUG_LOG(("NAT::establishConnectionPaths - about to set up the node list")); - DEBUG_LOG(("NAT::establishConnectionPaths - doing the netgear stuff")); - UnsignedInt otherNetgearNum = -1; - for (i = 0; i < MAX_SLOTS; ++i) { - if ((m_slotList != NULL) && (m_slotList[i] != NULL)) { - if ((m_slotList[i]->getNATBehavior() & FirewallHelperClass::FIREWALL_TYPE_NETGEAR_BUG) != 0) { - if (otherNetgearNum == -1) { - // this is the start of a new pair, put it in as the first non -1 node connection pair thing. - Int nodeindex = 0; - while ((m_connectionPairs[m_connectionPairIndex][0][nodeindex] == -1) || (m_connectionNodes[nodeindex].m_slotIndex != -1)) { - ++nodeindex; - } - m_connectionNodes[nodeindex].m_slotIndex = i; - m_connectionNodes[nodeindex].m_behavior = m_slotList[i]->getNATBehavior(); - connectionAssigned[i] = TRUE; - otherNetgearNum = nodeindex; - DEBUG_LOG(("NAT::establishConnectionPaths - first netgear in pair. assigning node %d to slot %d (%ls)", nodeindex, i, m_slotList[i]->getName().str())); - } else { - // this is the second in the pair of netgears, pair this up with the other one - // for the first round. - Int nodeindex = 0; - while (m_connectionPairs[m_connectionPairIndex][0][nodeindex] != otherNetgearNum) { - ++nodeindex; - } - m_connectionNodes[nodeindex].m_slotIndex = i; - m_connectionNodes[nodeindex].m_behavior = m_slotList[i]->getNATBehavior(); - connectionAssigned[i] = TRUE; - otherNetgearNum = -1; - DEBUG_LOG(("NAT::establishConnectionPaths - second netgear in pair. assigning node %d to slot %d (%ls)", nodeindex, i, m_slotList[i]->getName().str())); - } - } - } - } - - // fill in the rest of the nodes with the remaining slots. - DEBUG_LOG(("NAT::establishConnectionPaths - doing the non-Netgear nodes")); - for (i = 0; i < MAX_SLOTS; ++i) { - if (connectionAssigned[i] == TRUE) { - continue; - } - if (m_slotList[i] == NULL) { - continue; - } - if (!(m_slotList[i]->isHuman())) { - continue; - } - // find the first available connection node for this slot. - Int nodeindex = 0; - while (m_connectionNodes[nodeindex].m_slotIndex != -1) { - ++nodeindex; - } - DEBUG_LOG(("NAT::establishConnectionPaths - assigning node %d to slot %d (%ls)", nodeindex, i, m_slotList[i]->getName().str())); - m_connectionNodes[nodeindex].m_slotIndex = i; - m_connectionNodes[nodeindex].m_behavior = m_slotList[i]->getNATBehavior(); - connectionAssigned[i] = TRUE; - } - -// sanity check -#if defined(RTS_DEBUG) - for (i = 0; i < m_numNodes; ++i) { - DEBUG_ASSERTCRASH(connectionAssigned[i] == TRUE, ("connection number %d not assigned", i)); - } -#endif - - // find the local node number. - for (i = 0; i < m_numNodes; ++i) { - if (m_connectionNodes[i].m_slotIndex == TheGameSpyGame->getLocalSlotNum()) { - m_localNodeNumber = i; - DEBUG_LOG(("NAT::establishConnectionPaths - local node is %d", m_localNodeNumber)); - break; - } - } - - // set up the names in the connection window. - Int playerNum = 0; - for (i = 0; i < MAX_SLOTS; ++i) { - while ((i < MAX_SLOTS) && (m_slotList[i] != NULL) && !(m_slotList[i]->isHuman())) { - ++i; - } - if (i >= MAX_SLOTS) { - break; - } - if (i != TheGameSpyGame->getLocalSlotNum()) { - TheEstablishConnectionsMenu->setPlayerName(playerNum, m_slotList[i]->getName()); - TheEstablishConnectionsMenu->setPlayerStatus(playerNum, NATCONNECTIONSTATE_WAITINGTOBEGIN); - ++playerNum; - } - } - -// m_roundTimeout = timeGetTime() + TheGameSpyConfig->getRoundTimeout(); - m_roundTimeout = timeGetTime() + m_timeForRoundTimeout; - - // make the connections for this round. - // this song is cool. - doThisConnectionRound(); -} - -void NAT::attachSlotList(GameSlot *slotList[], Int localSlot, UnsignedInt localIP) { - m_slotList = slotList; - m_localIP = localIP; - m_transport = new Transport; - DEBUG_LOG(("NAT::attachSlotList - initting the transport socket with address %d.%d.%d.%d:%d", - PRINTF_IP_AS_4_INTS(m_localIP), getSlotPort(localSlot))); - - m_startingPortNumber = NETWORK_BASE_PORT_NUMBER + ((timeGetTime() / 1000) % 20000); - DEBUG_LOG(("NAT::attachSlotList - using %d as the starting port number", m_startingPortNumber)); - generatePortNumbers(slotList, localSlot); - m_transport->init(m_localIP, getSlotPort(localSlot)); -} - -Int NAT::getSlotPort(Int slot) { -// return (slot + m_startingPortNumber); - if (m_slotList[slot] != NULL) { - return m_slotList[slot]->getPort(); - } - return 0; -} - -void NAT::generatePortNumbers(GameSlot *slotList[], Int localSlot) { - for (UnsignedInt i = 0; i < (UnsignedInt)MAX_SLOTS; ++i) { - if (slotList[i] != NULL) { - if ((i == localSlot) && (TheWritableGlobalData->m_firewallPortOverride != 0)) { - slotList[i]->setPort(TheWritableGlobalData->m_firewallPortOverride); - } else { - slotList[i]->setPort(i + m_startingPortNumber); - } - } - } -} - -Transport * NAT::getTransport() { - return m_transport; -} - -// figure out which port I'll be using. -// send the port number to our target for this round. -// init the m_connectionStates for all players. -void NAT::doThisConnectionRound() { - DEBUG_LOG(("NAT::doThisConnectionRound - starting process for connection round %d", m_connectionRound)); - // clear out the states from the last round. - m_targetNodeNumber = -1; - - Int i = 0; - for (; i < MAX_SLOTS; ++i) { - setConnectionState(i, NATCONNECTIONSTATE_NOSTATE); - } - - m_beenProbed = FALSE; - m_numRetries = 0; - - for (i = 0; i < m_numNodes; ++i) { - Int targetNodeNumber = m_connectionPairs[m_connectionPairIndex][m_connectionRound][i]; - DEBUG_LOG(("NAT::doThisConnectionRound - node %d needs to connect to node %d", i, targetNodeNumber)); - if (targetNodeNumber != -1) { - if (i == m_localNodeNumber) { - m_targetNodeNumber = targetNodeNumber; - DEBUG_LOG(("NAT::doThisConnectionRound - Local node is connecting to node %d", m_targetNodeNumber)); - UnsignedInt targetSlotIndex = m_connectionNodes[(m_connectionPairs[m_connectionPairIndex][m_connectionRound][i])].m_slotIndex; - GameSlot *targetSlot = m_slotList[targetSlotIndex]; - GameSlot *localSlot = m_slotList[m_connectionNodes[m_localNodeNumber].m_slotIndex]; - - DEBUG_ASSERTCRASH(localSlot != NULL, ("local slot is NULL")); - DEBUG_ASSERTCRASH(targetSlot != NULL, ("trying to negotiate with a NULL target slot, slot is %d", m_connectionPairs[m_connectionPairIndex][m_connectionRound][i])); - DEBUG_LOG(("NAT::doThisConnectionRound - Target slot index = %d (%ls)", targetSlotIndex, m_slotList[targetSlotIndex]->getName().str())); - DEBUG_LOG(("NAT::doThisConnectionRound - Target slot has NAT behavior 0x%8X, local slot has NAT behavior 0x%8X", targetSlot->getNATBehavior(), localSlot->getNATBehavior())); - -#if defined(DEBUG_LOGGING) - UnsignedInt targetIP = targetSlot->getIP(); - UnsignedInt localIP = localSlot->getIP(); -#endif - - DEBUG_LOG(("NAT::doThisConnectionRound - Target slot has IP %d.%d.%d.%d Local slot has IP %d.%d.%d.%d", - PRINTF_IP_AS_4_INTS(targetIP), - PRINTF_IP_AS_4_INTS(localIP))); - - if (((targetSlot->getNATBehavior() & FirewallHelperClass::FIREWALL_TYPE_NETGEAR_BUG) == 0) && - ((localSlot->getNATBehavior() & FirewallHelperClass::FIREWALL_TYPE_NETGEAR_BUG) != 0)) { - - // we have a netgear bug type behavior and the target does not, so we need them to send to us - // first to avoid having our NAT table reset. - - DEBUG_LOG(("NAT::doThisConnectionRound - Local node has a netgear and the target node does not, need to delay our probe.")); - m_timeTillNextSend = -1; - } - - // figure out which port number I'm using for this connection - // this merely starts to talk to the mangler server, we have to keep calling - // the update function till we get a response. - DEBUG_LOG(("NAT::doThisConnectionRound - About to attempt to get the next mangled source port")); - sendMangledSourcePort(); -// m_nextPortSendTime = timeGetTime() + TheGameSpyConfig->getRetryInterval(); - m_nextPortSendTime = timeGetTime() + m_timeBetweenRetries; -// m_timeoutTime = timeGetTime() + TheGameSpyConfig->getPortTimeout(); - m_timeoutTime = timeGetTime() + m_timeToWaitForPort; - } else { - // this is someone else that needs to connect to someone, so wait till they tell us - // that they're done. - setConnectionState(i, NATCONNECTIONSTATE_WAITINGFORRESPONSE); - } - } else { - // no one to connect to, so this one is done. - DEBUG_LOG(("NAT::doThisConnectionRound - node %d has no one to connect to, so they're done", i)); - setConnectionState(i, NATCONNECTIONSTATE_DONE); - } - } -} - -void NAT::sendAProbe(UnsignedInt ip, UnsignedShort port, Int fromNode) { - DEBUG_LOG(("NAT::sendAProbe - sending a probe from port %d to %d.%d.%d.%d:%d", getSlotPort(m_connectionNodes[m_localNodeNumber].m_slotIndex), - PRINTF_IP_AS_4_INTS(ip), port)); - AsciiString str; - str.format("PROBE%d", fromNode); - m_transport->queueSend(ip, port, (unsigned char *)str.str(), str.getLength() + 1); - m_transport->doSend(); -} - -// find the next mangled source port, and then send it to the other player. -// if this requires talking to the mangler, we'll have to wait till a later update -// to send our port out. -void NAT::sendMangledSourcePort() { - UnsignedShort sourcePort = getSlotPort(m_connectionNodes[m_localNodeNumber].m_slotIndex); - - FirewallHelperClass::tFirewallBehaviorType fwType = m_slotList[m_connectionNodes[m_localNodeNumber].m_slotIndex]->getNATBehavior(); - GameSlot *targetSlot = m_slotList[m_connectionNodes[m_targetNodeNumber].m_slotIndex]; - DEBUG_ASSERTCRASH(targetSlot != NULL, ("NAT::sendMangledSourcePort - targetSlot is NULL")); - if (targetSlot == NULL) { - DEBUG_LOG(("NAT::sendMangledSourcePort - targetSlot is NULL, failed this connection")); - setConnectionState(m_localNodeNumber, NATCONNECTIONSTATE_FAILED); - return; - } - - GameSlot *localSlot = m_slotList[m_connectionNodes[m_localNodeNumber].m_slotIndex]; - DEBUG_ASSERTCRASH(localSlot != NULL, ("NAT::sendMangledSourcePort - localSlot is NULL, WTF?")); - if (localSlot == NULL) { - DEBUG_LOG(("NAT::sendMangledSourcePort - localSlot is NULL, failed this connection")); - setConnectionState(m_localNodeNumber, NATCONNECTIONSTATE_FAILED); - return; - } - - // check to see if the target and I are behind the same NAT - if (targetSlot->getIP() == localSlot->getIP()) { -#if defined(DEBUG_LOGGING) - UnsignedInt localip = localSlot->getIP(); - UnsignedInt targetip = targetSlot->getIP(); -#endif - DEBUG_LOG(("NAT::sendMangledSourcePort - target and I are behind the same NAT, no mangling")); - DEBUG_LOG(("NAT::sendMangledSourcePort - I am %ls, target is %ls, my IP is %d.%d.%d.%d, target IP is %d.%d.%d.%d", localSlot->getName().str(), targetSlot->getName().str(), - PRINTF_IP_AS_4_INTS(localip), - PRINTF_IP_AS_4_INTS(targetip))); - - sendMangledPortNumberToTarget(sourcePort, targetSlot); - m_sourcePorts[m_targetNodeNumber] = sourcePort; - setConnectionState(m_localNodeNumber, NATCONNECTIONSTATE_WAITINGFORMANGLEDPORT); - // In case you're wondering, we don't set the m_previousSourcePort here because this will be a different source - // address than what other nodes will likely see (unless of course there are more than - // two of us behind the same NAT, but we won't worry about that cause theres no mangling - // in that case anyways) - return; - } - - // check to see if we are NAT'd at all. - if ((fwType == 0) || (fwType == FirewallHelperClass::FIREWALL_TYPE_SIMPLE)) { - // no mangling, just return the source port - DEBUG_LOG(("NAT::sendMangledSourcePort - no mangling, just using the source port")); - sendMangledPortNumberToTarget(sourcePort, targetSlot); - m_previousSourcePort = sourcePort; - m_sourcePorts[m_targetNodeNumber] = sourcePort; - setConnectionState(m_localNodeNumber, NATCONNECTIONSTATE_WAITINGFORMANGLEDPORT); - return; - } - - // check to see if our NAT keeps the same source port for different destinations. - // if this is the case, and we've already worked out what our mangled port number is - // then we don't have to figure it out again. - if (((fwType & FirewallHelperClass::FIREWALL_TYPE_DESTINATION_PORT_DELTA) == 0) && - ((fwType & FirewallHelperClass::FIREWALL_TYPE_SMART_MANGLING) == 0)) { - DEBUG_LOG(("NAT::sendMangledSourcePort - our firewall doesn't NAT based on destination address, checking for old connections from this address")); - if (m_previousSourcePort != 0) { - DEBUG_LOG(("NAT::sendMangledSourcePort - Previous source port was %d, using that one", m_previousSourcePort)); - sendMangledPortNumberToTarget(m_previousSourcePort, targetSlot); - m_sourcePorts[m_targetNodeNumber] = m_previousSourcePort; - setConnectionState(m_localNodeNumber, NATCONNECTIONSTATE_WAITINGFORMANGLEDPORT); - return; - } else { - DEBUG_LOG(("NAT::sendMangledSourcePort - Previous source port not found")); - } - } - - // At this point we know that our NAT uses some kind of relative port mapping scheme, so we - // need to talk to the mangler to find out where we are now so we can find out where we'll be on the - // next port allocation. - - // get the address of the mangler we need to talk to. - Char manglerName[256]; - FirewallHelperClass::getManglerName(1, manglerName); - DEBUG_LOG(("NAT::sendMangledSourcePort - about to call gethostbyname for mangler at %s", manglerName)); - struct hostent *hostInfo = gethostbyname(manglerName); - - if (hostInfo == NULL) { - DEBUG_LOG(("NAT::sendMangledSourcePort - gethostbyname failed for mangler address %s", manglerName)); - // can't find the mangler, we're screwed so just send the source port. - sendMangledPortNumberToTarget(sourcePort, targetSlot); - m_sourcePorts[m_targetNodeNumber] = sourcePort; - setConnectionState(m_localNodeNumber, NATCONNECTIONSTATE_WAITINGFORMANGLEDPORT); - return; - } - - memcpy(&m_manglerAddress, &(hostInfo->h_addr_list[0][0]), 4); - m_manglerAddress = ntohl(m_manglerAddress); - DEBUG_LOG(("NAT::sendMangledSourcePort - mangler %s address is %d.%d.%d.%d", manglerName, - PRINTF_IP_AS_4_INTS(m_manglerAddress))); - - DEBUG_LOG(("NAT::sendMangledSourcePort - NAT behavior = 0x%08x", fwType)); - -// m_manglerRetryTime = TheGameSpyConfig->getRetryInterval() + timeGetTime(); - m_manglerRetryTime = m_manglerRetryTimeInterval + timeGetTime(); - m_manglerRetries = 0; - - if (TheFirewallHelper != NULL) { - m_spareSocketPort = TheFirewallHelper->getNextTemporarySourcePort(0); - TheFirewallHelper->openSpareSocket(m_spareSocketPort); - TheFirewallHelper->sendToManglerFromPort(m_manglerAddress, m_spareSocketPort, m_packetID); -// m_manglerRetryTime = TheGameSpyConfig->getRetryInterval() + timeGetTime(); - m_manglerRetryTime = m_manglerRetryTimeInterval + timeGetTime(); - } - - setConnectionState(m_localNodeNumber, NATCONNECTIONSTATE_WAITINGFORMANGLERRESPONSE); -} - -void NAT::processManglerResponse(UnsignedShort mangledPort) { - DEBUG_LOG(("NAT::processManglerResponse - Work out what my NAT'd port will be")); - - GameSlot *targetSlot = m_slotList[m_connectionNodes[m_targetNodeNumber].m_slotIndex]; - DEBUG_ASSERTCRASH(targetSlot != NULL, ("NAT::processManglerResponse - targetSlot is NULL")); - if (targetSlot == NULL) { - DEBUG_LOG(("NAT::processManglerResponse - targetSlot is NULL, failed this connection")); - setConnectionState(m_localNodeNumber, NATCONNECTIONSTATE_FAILED); - return; - } - - Short delta = TheGlobalData->m_firewallPortAllocationDelta; - UnsignedShort sourcePort = getSlotPort(m_connectionNodes[m_localNodeNumber].m_slotIndex); - UnsignedShort returnPort = 0; - - FirewallHelperClass::tFirewallBehaviorType fwType = m_slotList[m_connectionNodes[m_localNodeNumber].m_slotIndex]->getNATBehavior(); - - if ((fwType & FirewallHelperClass::FIREWALL_TYPE_SIMPLE_PORT_ALLOCATION) != 0) { - returnPort = mangledPort + delta; - } else { - // to steal a line from Steve Tall... - // Rats. It's a relative mangler. This is much harder. Damn NAT32 guy. - if (delta == 100) { - // Special NAT32 section. - // NAT32 mangles source UDP port by ading 1700 + 100*NAT table index. - returnPort = mangledPort - m_spareSocketPort; - returnPort -= 1700; - - returnPort += delta; - returnPort += sourcePort; - returnPort += 1700; - - } else if (delta == 0) { - returnPort = sourcePort; - } else { - returnPort = mangledPort / delta; - returnPort = returnPort * delta; - - returnPort += (sourcePort % delta); - returnPort += delta; - } - } - - // This bit is probably doomed. - if (returnPort > 65535) { - returnPort -= 65535; - } - if (returnPort < 1024) { - returnPort += 1024; - } - - DEBUG_LOG(("NAT::processManglerResponse - mangled port is %d", returnPort)); - m_previousSourcePort = returnPort; - - sendMangledPortNumberToTarget(returnPort, targetSlot); - m_sourcePorts[m_targetNodeNumber] = returnPort; - if (targetSlot->getPort() == 0) { - // we haven't got the target's mangled port number yet, wait for it. - setConnectionState(m_localNodeNumber, NATCONNECTIONSTATE_WAITINGFORMANGLEDPORT); - } else { - // in this case we should have already sent a PROBE, so we'll just change the state - // and leave it at that. - setConnectionState(m_localNodeNumber, NATCONNECTIONSTATE_WAITINGFORRESPONSE); - } -} - -// check to see if we've completed all the rounds -// this is kind of a cheesy way to check, but it works. -Bool NAT::allConnectionsDone() { - if (m_numNodes < 2) { - return FALSE; - } - const Int requiredRounds = (m_numNodes & 1) ? m_numNodes : m_numNodes - 1; - return m_connectionRound >= requiredRounds; -} - -Bool NAT::allConnectionsDoneThisRound() { - Bool retval = TRUE; - for (UnsignedInt i = 0; (i < m_numNodes) && (retval == TRUE); ++i) { - if ((m_connectionStates[i] != NATCONNECTIONSTATE_DONE) && (m_connectionStates[i] != NATCONNECTIONSTATE_FAILED)) { - retval = FALSE; - } - } - return retval; -} - -// this node's connection for this round has been completed. -void NAT::connectionComplete(Int slotIndex) { -} - -// this node's connection for this round has failed. -void NAT::connectionFailed(Int slotIndex) { -} - -// I have been probed by the target. -void NAT::probed(Int nodeNumber) { - GameSlot *localSlot = m_slotList[m_connectionNodes[m_localNodeNumber].m_slotIndex]; - DEBUG_ASSERTCRASH(localSlot != NULL, ("NAT::probed - localSlot is NULL, WTF?")); - if (localSlot == NULL) { - DEBUG_LOG(("NAT::probed - localSlot is NULL, failed this connection")); - setConnectionState(m_localNodeNumber, NATCONNECTIONSTATE_FAILED); - return; - } - - if (m_beenProbed == FALSE) { - m_beenProbed = TRUE; - DEBUG_LOG(("NAT::probed - just got probed for the first time.")); - if ((localSlot->getNATBehavior() & FirewallHelperClass::FIREWALL_TYPE_NETGEAR_BUG) != 0) { - DEBUG_LOG(("NAT::probed - we have a NETGEAR and we were just probed for the first time")); - GameSlot *targetSlot = m_slotList[m_connectionNodes[m_targetNodeNumber].m_slotIndex]; - DEBUG_ASSERTCRASH(targetSlot != NULL, ("NAT::probed - targetSlot is NULL")); - if (targetSlot == NULL) { - DEBUG_LOG(("NAT::probed - targetSlot is NULL, failed this connection")); - setConnectionState(m_localNodeNumber, NATCONNECTIONSTATE_FAILED); - return; - } - - if (targetSlot->getPort() == 0) { - setConnectionState(m_localNodeNumber, NATCONNECTIONSTATE_WAITINGFORMANGLEDPORT); - DEBUG_LOG(("NAT::probed - still waiting for mangled port")); - } else { - DEBUG_LOG(("NAT::probed - sending a probe to %ls", targetSlot->getName().str())); - sendAProbe(targetSlot->getIP(), targetSlot->getPort(), m_localNodeNumber); - notifyTargetOfProbe(targetSlot); - setConnectionState(m_localNodeNumber, NATCONNECTIONSTATE_WAITINGFORRESPONSE); - } - } - } -} - -// got the mangled port for our target for this round. -void NAT::gotMangledPort(Int nodeNumber, UnsignedShort mangledPort) { - - // if we've already finished the connection, then we don't need to process this. - if (m_connectionStates[m_localNodeNumber] == NATCONNECTIONSTATE_DONE) { - DEBUG_LOG(("NAT::gotMangledPort - got a mangled port, but we've already finished this connection, ignoring.")); - return; - } - - GameSlot *targetSlot = m_slotList[m_connectionNodes[m_targetNodeNumber].m_slotIndex]; - DEBUG_ASSERTCRASH(targetSlot != NULL, ("NAT::gotMangledPort - targetSlot is NULL")); - if (targetSlot == NULL) { - DEBUG_LOG(("NAT::gotMangledPort - targetSlot is NULL, failed this connection")); - setConnectionState(m_localNodeNumber, NATCONNECTIONSTATE_FAILED); - return; - } - - GameSlot *localSlot = m_slotList[m_connectionNodes[m_localNodeNumber].m_slotIndex]; - DEBUG_ASSERTCRASH(localSlot != NULL, ("NAT::gotMangledPort - localSlot is NULL, WTF?")); - if (localSlot == NULL) { - DEBUG_LOG(("NAT::gotMangledPort - localSlot is NULL, failed this connection")); - setConnectionState(m_localNodeNumber, NATCONNECTIONSTATE_FAILED); - return; - } - - if (nodeNumber != m_targetNodeNumber) { - DEBUG_LOG(("NAT::gotMangledPort - got a mangled port number for someone that isn't my target. node = %d, target node = %d", nodeNumber, m_targetNodeNumber)); - return; - } - - targetSlot->setPort(mangledPort); - DEBUG_LOG(("NAT::gotMangledPort - got mangled port number %d from our target node (%ls)", mangledPort, targetSlot->getName().str())); - if (((localSlot->getNATBehavior() & FirewallHelperClass::FIREWALL_TYPE_NETGEAR_BUG) == 0) || (m_beenProbed == TRUE) || - (((localSlot->getNATBehavior() & FirewallHelperClass::FIREWALL_TYPE_NETGEAR_BUG) != 0) && ((targetSlot->getNATBehavior() & FirewallHelperClass::FIREWALL_TYPE_NETGEAR_BUG) != 0))) { -#ifdef DEBUG_LOGGING - UnsignedInt ip = targetSlot->getIP(); -#endif - DEBUG_LOG(("NAT::gotMangledPort - don't have a netgear or we have already been probed, or both my target and I have a netgear, send a PROBE. Sending to %d.%d.%d.%d:%d", - PRINTF_IP_AS_4_INTS(ip), targetSlot->getPort())); - - sendAProbe(targetSlot->getIP(), targetSlot->getPort(), m_localNodeNumber); - notifyTargetOfProbe(targetSlot); - setConnectionState(m_localNodeNumber, NATCONNECTIONSTATE_WAITINGFORRESPONSE); - } else { - DEBUG_LOG(("NAT::gotMangledPort - we are a netgear, not sending a PROBE yet.")); - } -} - -void NAT::gotInternalAddress(Int nodeNumber, UnsignedInt address) { - GameSlot *targetSlot = m_slotList[m_connectionNodes[nodeNumber].m_slotIndex]; - DEBUG_ASSERTCRASH(targetSlot != NULL, ("NAT::gotInternalAddress - targetSlot is NULL")); - if (targetSlot == NULL) { - return; - } - - GameSlot *localSlot = m_slotList[m_connectionNodes[m_localNodeNumber].m_slotIndex]; - DEBUG_ASSERTCRASH(localSlot != NULL, ("NAT::gotInternalAddress - localSlot is NULL, WTF?")); - if (localSlot == NULL) { - return; - } - - if (nodeNumber != m_targetNodeNumber) { - DEBUG_LOG(("NAT::gotInternalAddress - got a internal address for someone that isn't my target. node = %d, target node = %d", nodeNumber, m_targetNodeNumber)); - return; - } - - if (localSlot->getIP() == targetSlot->getIP()) { - // we have the same IP address, i.e. we are behind the same NAT. - // I need to talk directly to his internal address. - DEBUG_LOG(("NAT::gotInternalAddress - target and local players have same external address, using internal address.")); - targetSlot->setIP(address); // use the slot's internal address from now on - } -} - -void NAT::notifyTargetOfProbe(GameSlot *targetSlot) { - PeerRequest req; - AsciiString options; - options.format("PROBED%d", m_localNodeNumber); - req.peerRequestType = PeerRequest::PEERREQUEST_UTMPLAYER; - req.UTM.isStagingRoom = TRUE; - req.id = "NAT/"; - AsciiString hostName; - hostName.translate(targetSlot->getName()); - req.nick = hostName.str(); - req.options = options.str(); - TheGameSpyPeerMessageQueue->addRequest(req); - DEBUG_LOG(("NAT::notifyTargetOfProbe - notifying %ls that we have probed them.", targetSlot->getName().str())); -} - -void NAT::notifyUsersOfConnectionDone(Int nodeIndex) { - GameSlot *localSlot = m_slotList[m_connectionNodes[m_localNodeNumber].m_slotIndex]; - DEBUG_ASSERTCRASH(localSlot != NULL, ("NAT::notifyUsersOfConnectionDone - localSlot is NULL, WTF?")); - if (localSlot == NULL) { - DEBUG_LOG(("NAT::notifyUsersOfConnectionDone - localSlot is NULL, failed this connection")); - setConnectionState(m_localNodeNumber, NATCONNECTIONSTATE_FAILED); - return; - } - - PeerRequest req; - AsciiString options; - options.format("CONNDONE%d %d", nodeIndex, m_localNodeNumber); - - req.peerRequestType = PeerRequest::PEERREQUEST_UTMPLAYER; - req.UTM.isStagingRoom = TRUE; - req.id = "NAT"; - AsciiString names; - for (Int i=0; iisHuman() == FALSE)) { - continue; - } - - AsciiString name; - name.translate(m_slotList[i]->getName()); - if (names.isNotEmpty()) - { - names.concat(','); - } - names.concat(name); - } - req.nick = names.str(); - req.options = options.str(); - - DEBUG_LOG(("NAT::notifyUsersOfConnectionDone - sending %s to %s", options.str(), names.str())); - TheGameSpyPeerMessageQueue->addRequest(req); -} - -void NAT::notifyUsersOfConnectionFailed(Int nodeIndex) { - GameSlot *localSlot = m_slotList[m_connectionNodes[m_localNodeNumber].m_slotIndex]; - DEBUG_ASSERTCRASH(localSlot != NULL, ("NAT::notifyUsersOfConnectionFailed - localSlot is NULL, WTF?")); - if (localSlot == NULL) { - DEBUG_LOG(("NAT::notifyUsersOfConnectionFailed - localSlot is NULL, failed this connection")); - setConnectionState(m_localNodeNumber, NATCONNECTIONSTATE_FAILED); - return; - } - - PeerRequest req; - AsciiString options; - options.format("CONNFAILED%d", nodeIndex); -/* - req.peerRequestType = PeerRequest::PEERREQUEST_UTMROOM; - req.UTM.isStagingRoom = TRUE; - req.id = "NAT/"; - req.options = options.str(); - - DEBUG_LOG(("NAT::notifyUsersOfConnectionFailed - sending %s to room", options.str())); -*/ - - req.peerRequestType = PeerRequest::PEERREQUEST_UTMPLAYER; - req.UTM.isStagingRoom = TRUE; - req.id = "NAT"; - AsciiString names; - for (Int i=0; iisHuman() == FALSE)) { - continue; - } - - AsciiString name; - name.translate(m_slotList[i]->getName()); - if (names.isNotEmpty()) - { - names.concat(','); - } - names.concat(name); - } - req.nick = names.str(); - req.options = options.str(); - - DEBUG_LOG(("NAT::notifyUsersOfConnectionFailed - sending %s to %s", options.str(), names.str())); - - TheGameSpyPeerMessageQueue->addRequest(req); -} - -void NAT::sendMangledPortNumberToTarget(UnsignedShort mangledPort, GameSlot *targetSlot) { - PeerRequest req; - AsciiString options; - options.format("PORT%d %d %08X", m_localNodeNumber, mangledPort, m_localIP); - - req.peerRequestType = PeerRequest::PEERREQUEST_UTMPLAYER; - req.UTM.isStagingRoom = TRUE; - req.id = "NAT/"; - AsciiString hostName; - hostName.translate(targetSlot->getName()); - req.nick = hostName.str(); - req.options = options.str(); - DEBUG_LOG(("NAT::sendMangledPortNumberToTarget - sending \"%s\" to %s", options.str(), hostName.str())); - TheGameSpyPeerMessageQueue->addRequest(req); -} - -void NAT::processGlobalMessage(Int slotNum, const char *options) { - const char *ptr = options; - // skip preceding whitespace. - while (isspace(*ptr)) { - ++ptr; - } - DEBUG_LOG(("NAT::processGlobalMessage - got message from slot %d, message is \"%s\"", slotNum, ptr)); - if (!strncmp(ptr, "PROBED", strlen("PROBED"))) { - // format: PROBED - // a probe has been sent at us, if we are waiting because of a netgear or something, we - // should start sending our own probes. - Int node = atoi(ptr + strlen("PROBED")); - if (node == m_targetNodeNumber) { - // make sure we're being probed by who we're supposed to be probed by. - probed(node); - } else { - DEBUG_LOG(("NAT::processGlobalMessage - probed by node %d, not our target", node)); - } - } else if (!strncmp(ptr, "CONNDONE", strlen("CONNDONE"))) { - // format: CONNDONE - // we should get the node number of the player who's connection is done from the options - // and mark that down as part of the connectionStates. - const char *c = ptr + strlen("CONNDONE"); -/* while (*c != ' ') { - ++c; - } - while (*c == ' ') { - ++c; - } -*/ Int node; - Int sendingNode; - sscanf(c, "%d %d\n", &node, &sendingNode); - - if (m_connectionPairs[m_connectionPairIndex][m_connectionRound][node] == sendingNode) { -// Int node = atoi(ptr + strlen("CONNDONE")); - DEBUG_LOG(("NAT::processGlobalMessage - got a CONNDONE message for node %d", node)); - if ((node >= 0) && (node <= m_numNodes)) { - DEBUG_LOG(("NAT::processGlobalMessage - node %d's connection is complete, setting connection state to done", node)); - setConnectionState(node, NATCONNECTIONSTATE_DONE); - } - } else { - DEBUG_LOG(("NAT::processGlobalMessage - got a connection done message that isn't from this round. node: %d sending node: %d", node, sendingNode)); - } - } else if (!strncmp(ptr, "CONNFAILED", strlen("CONNFAILED"))) { - // format: CONNFAILED - // we should get the node number of the player who's connection failed from the options - // and mark that down as part of the connectionStates. - Int node = atoi(ptr + strlen("CONNFAILED")); - if ((node >= 0) && (node < m_numNodes)) { - DEBUG_LOG(("NAT::processGlobalMessage - node %d's connection failed, setting connection state to failed", node)); - setConnectionState(node, NATCONNECTIONSTATE_FAILED); - } - } else if (!strncmp(ptr, "PORT", strlen("PORT"))) { - // format: PORT - // we should get the node number and the mangled port number of the client we - // are supposed to be communicating with and start probing them. No, that was not - // meant to be a phallic reference, you sicko. - const char *c = ptr + strlen("PORT"); - Int node = atoi(c); - while (*c != ' ') { - ++c; - } - while (*c == ' ') { - ++c; - } - UnsignedInt intport = 0; - UnsignedInt addr = 0; - sscanf(c, "%d %X", &intport, &addr); - UnsignedShort port = (UnsignedShort)intport; - - DEBUG_LOG(("NAT::processGlobalMessage - got port message from node %d, port: %d, internal address: %d.%d.%d.%d", node, port, - PRINTF_IP_AS_4_INTS(addr))); - - if ((node >= 0) && (node < m_numNodes)) { - if (port < 1024) { - // it has to be less than 65535 cause its a short duh. - DEBUG_ASSERTCRASH(port >= 1024, ("Was passed an invalid port number")); - port += 1024; - } - gotInternalAddress(node, addr); - gotMangledPort(node, port); - } - } -} - -void NAT::setConnectionState(Int nodeNumber, NATConnectionState state) { - m_connectionStates[nodeNumber] = state; - - if (nodeNumber != m_localNodeNumber) { - return; - } - - // if this is the case we are starting a new round and we don't know - // who we're connecting to yet. - if (m_localNodeNumber == m_targetNodeNumber) { - return; - } - - // if this is the start of a new connection round we don't have a - // target yet. - if (m_targetNodeNumber == -1) { - return; - } - - // find the menu slot of the target node. - Int slotIndex = m_connectionNodes[m_targetNodeNumber].m_slotIndex; - Int slot = 0; - Int i = 0; - for (; i < MAX_SLOTS; ++i) { - if (m_slotList[i] != NULL) { - if (m_slotList[i]->isHuman()) { - if (i != m_connectionNodes[m_localNodeNumber].m_slotIndex) { - if (i == slotIndex) { - break; - } - ++slot; - } - } - } - } - if (i == MAX_SLOTS) { - DEBUG_ASSERTCRASH(i < MAX_SLOTS, ("Didn't find the node number in the slot list")); - return; - } - TheEstablishConnectionsMenu->setPlayerStatus(slot, state); -} diff --git a/Generals/Code/GameEngine/Source/GameNetwork/NetCommandList.cpp b/Generals/Code/GameEngine/Source/GameNetwork/NetCommandList.cpp deleted file mode 100644 index a7b005fcb9..0000000000 --- a/Generals/Code/GameEngine/Source/GameNetwork/NetCommandList.cpp +++ /dev/null @@ -1,455 +0,0 @@ -/* -** 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 in the GameEngine - -#include "GameNetwork/NetCommandList.h" -#include "GameNetwork/networkutil.h" - -/** - * Constructor. - */ -NetCommandList::NetCommandList() { - m_first = NULL; - m_last = NULL; - m_lastMessageInserted = NULL; -} - -/** - * Destructor. - */ -NetCommandList::~NetCommandList() { - reset(); -} - -/** - * Append the given list of commands to this list. - */ -void NetCommandList::appendList(NetCommandList *list) { - if (list == NULL) { - return; - } - - // Need to do it this way because of the reference counting that needs to happen in appendMessage. - NetCommandRef *msg = list->getFirstMessage(); - NetCommandRef *next = NULL; - while (msg != NULL) { - next = msg->getNext(); - NetCommandRef *temp = addMessage(msg->getCommand()); - if (temp != NULL) { - temp->setRelay(msg->getRelay()); - } - - msg = next; - } -} - -/** - * Return the first message in this list. - */ -NetCommandRef *NetCommandList::getFirstMessage() { - return m_first; -} - -/** - * Remove the given message from this list. - */ -void NetCommandList::removeMessage(NetCommandRef *msg) { - if (m_lastMessageInserted == msg) { - m_lastMessageInserted = msg->getNext(); - } - - if (msg->getPrev() != NULL) { - msg->getPrev()->setNext(msg->getNext()); - } - if (msg->getNext() != NULL) { - msg->getNext()->setPrev(msg->getPrev()); - } - - if (msg == m_first) { - m_first = msg->getNext(); - } - if (msg == m_last) { - m_last = msg->getPrev(); - } - - msg->setNext(NULL); - msg->setPrev(NULL); -} - -/** - * Initialize the list. - */ -void NetCommandList::init() { - reset(); -} - -/** - * Reset the contents of this list. - */ -void NetCommandList::reset() { - NetCommandRef *temp = m_first; - while (m_first != NULL) { - temp = m_first->getNext(); - m_first->setNext(NULL); - m_first->setPrev(NULL); - deleteInstance(m_first); - m_first = temp; - } - m_last = NULL; - m_lastMessageInserted = NULL; -} - -/** - * Insert sorts msg. Assumes that all the previous message inserts were done using this function. - * The message is sorted in based first on command type, then player id, and then command id. - */ -NetCommandRef * NetCommandList::addMessage(NetCommandMsg *cmdMsg) { - if (cmdMsg == NULL) { - DEBUG_ASSERTCRASH(cmdMsg != NULL, ("NetCommandList::addMessage - command message was NULL")); - return NULL; - } - -// UnsignedInt id = cmdMsg->getID(); - - NetCommandRef *msg = NEW_NETCOMMANDREF(cmdMsg); - - if (m_first == NULL) { - // this is the first node, so we don't have to worry about ordering it. - m_first = msg; - m_last = msg; - m_lastMessageInserted = msg; - return msg; - } - - if (m_lastMessageInserted != NULL) { - // Messages that are inserted in order should just be put in one right after the other. - // So saving the placement of the last message inserted can give us a huge boost in - // efficiency. - NetCommandRef *theNext = m_lastMessageInserted->getNext(); - if ((m_lastMessageInserted->getCommand()->getNetCommandType() == msg->getCommand()->getNetCommandType()) && - (m_lastMessageInserted->getCommand()->getPlayerID() == msg->getCommand()->getPlayerID()) && - (m_lastMessageInserted->getCommand()->getID() < msg->getCommand()->getID()) && - ((theNext == NULL) || ((theNext->getCommand()->getNetCommandType() > msg->getCommand()->getNetCommandType()) || - (theNext->getCommand()->getPlayerID() > msg->getCommand()->getPlayerID()) || - (theNext->getCommand()->getID() > msg->getCommand()->getID())))) { - - // Make sure this command isn't already in the list. - if (isEqualCommandMsg(m_lastMessageInserted->getCommand(), msg->getCommand())) { - - // This command is already in the list, don't duplicate it. - deleteInstance(msg); - msg = NULL; - return NULL; - } - - if (theNext == NULL) { - // this means that m_lastMessageInserted == m_last, so m_last should point to the msg that is being inserted. - msg->setNext(m_lastMessageInserted->getNext()); - msg->setPrev(m_lastMessageInserted); - m_lastMessageInserted->setNext(msg); - m_lastMessageInserted = msg; - m_last = msg; - } else { - msg->setNext(m_lastMessageInserted->getNext()); - msg->setPrev(m_lastMessageInserted); - m_lastMessageInserted->setNext(msg); - msg->getNext()->setPrev(msg); - m_lastMessageInserted = msg; - } - return msg; - } - } - - if (msg->getCommand()->getNetCommandType() > m_last->getCommand()->getNetCommandType()) { - // easy optimization for a command that goes at the end of the list - // since they are likely to be added in order. - - // Make sure this command isn't already in the list. - if (isEqualCommandMsg(m_last->getCommand(), msg->getCommand())) { - - // This command is already in the list, don't duplicate it. - deleteInstance(msg); - msg = NULL; - return NULL; - } - - msg->setPrev(m_last); - msg->setNext(NULL); - m_last->setNext(msg); - m_last = msg; - m_lastMessageInserted = msg; - return msg; - } - - if (msg->getCommand()->getNetCommandType() < m_first->getCommand()->getNetCommandType()) { - // Make sure this command isn't already in the list. - if (isEqualCommandMsg(m_first->getCommand(), msg->getCommand())) { - - // This command is already in the list, don't duplicate it. - deleteInstance(msg); - msg = NULL; - return NULL; - } - - // The command goes at the head of the list. - msg->setNext(m_first); - msg->setPrev(NULL); - m_first->setPrev(msg); - m_first = msg; - m_lastMessageInserted = msg; - return msg; - } - - - // Find the start of the command type we're looking for. - NetCommandRef *tempmsg = m_first; - while ((tempmsg != NULL) && (msg->getCommand()->getNetCommandType() > tempmsg->getCommand()->getNetCommandType())) { - tempmsg = tempmsg->getNext(); - } - - if (tempmsg == NULL) { - // Make sure this command isn't already in the list. - if (isEqualCommandMsg(m_last->getCommand(), msg->getCommand())) { - - // This command is already in the list, don't duplicate it. - deleteInstance(msg); - msg = NULL; - return NULL; - } - - // message goes at the end of the list. - msg->setPrev(m_last); - msg->setNext(NULL); - m_last->setNext(msg); - m_last = msg; - m_lastMessageInserted = msg; - return msg; - } - - // Now find the player position. munkee. - while ((tempmsg != NULL) && (msg->getCommand()->getNetCommandType() == tempmsg->getCommand()->getNetCommandType()) && (msg->getCommand()->getPlayerID() > tempmsg->getCommand()->getPlayerID())) { - tempmsg = tempmsg->getNext(); - } - - if (tempmsg == NULL) { - // Make sure this command isn't already in the list. - if (isEqualCommandMsg(m_last->getCommand(), msg->getCommand())) { - - // This command is already in the list, don't duplicate it. - deleteInstance(msg); - msg = NULL; - return NULL; - } - - // message goes at the end of the list. - msg->setPrev(m_last); - msg->setNext(NULL); - m_last->setNext(msg); - m_last = msg; - m_lastMessageInserted = msg; - return msg; - } - - // Find the position within the player's section based on the command ID. - // If the command type doesn't require a command ID, sort by whatever it should be sorted by. - while ((tempmsg != NULL) && (msg->getCommand()->getNetCommandType() == tempmsg->getCommand()->getNetCommandType()) && (msg->getCommand()->getPlayerID() == tempmsg->getCommand()->getPlayerID()) && (msg->getCommand()->getSortNumber() > tempmsg->getCommand()->getSortNumber())) { - tempmsg = tempmsg->getNext(); - } - - if (tempmsg == NULL) { - // Make sure this command isn't already in the list. - if (isEqualCommandMsg(m_last->getCommand(), msg->getCommand())) { - - // This command is already in the list, don't duplicate it. - deleteInstance(msg); - msg = NULL; - return NULL; - } - - // This message goes at the end of the list. - msg->setPrev(m_last); - msg->setNext(NULL); - m_last->setNext(msg); - m_last = msg; - m_lastMessageInserted = msg; - return msg; - } - - if (tempmsg == m_first) { - // Make sure this command isn't already in the list. - if (isEqualCommandMsg(m_first->getCommand(), msg->getCommand())) { - - // This command is already in the list, don't duplicate it. - deleteInstance(msg); - return NULL; - } - - // This message goes at the head of the list. - msg->setNext(m_first); - msg->setPrev(NULL); - m_first->setPrev(msg); - m_first = msg; - m_lastMessageInserted = msg; - return msg; - } - - // Make sure this command isn't already in the list. - if (isEqualCommandMsg(tempmsg->getCommand(), msg->getCommand())) { - - // This command is already in the list, don't duplicate it. - deleteInstance(msg); - msg = NULL; - return NULL; - } - - // Insert message before tempmsg. - msg->setNext(tempmsg); - msg->setPrev(tempmsg->getPrev()); - msg->getPrev()->setNext(msg); - tempmsg->setPrev(msg); - m_lastMessageInserted = msg; - - return msg; -} - -Int NetCommandList::length() { - Int retval = 0; - NetCommandRef *temp = m_first; - while (temp != NULL) { - ++retval; - temp = temp->getNext(); - } - return retval; -} - -/** - * This is really inefficient, but we can probably get away with it because - * there shouldn't be too many messages for any given frame. - */ -NetCommandRef * NetCommandList::findMessage(NetCommandMsg *msg) { - NetCommandRef *retval = m_first; - while ((retval != NULL) && (isEqualCommandMsg(retval->getCommand(), msg) == FALSE)) { - retval = retval->getNext(); - } - return retval; -} - -NetCommandRef * NetCommandList::findMessage(UnsignedShort commandID, UnsignedByte playerID) { - NetCommandRef *retval = m_first; - while (retval != NULL) { - if (DoesCommandRequireACommandID(retval->getCommand()->getNetCommandType())) { - if ((retval->getCommand()->getID() == commandID) && (retval->getCommand()->getPlayerID() == playerID)) { - return retval; - } - } - retval = retval->getNext(); - } - return retval; -} - -Bool NetCommandList::isEqualCommandMsg(NetCommandMsg *msg1, NetCommandMsg *msg2) { - if (DoesCommandRequireACommandID(msg1->getNetCommandType()) != DoesCommandRequireACommandID(msg2->getNetCommandType())) { - return FALSE; - } - - // At this point we know that the commands both do or do not require a command id. - // Do or do not, there is no try. - if (DoesCommandRequireACommandID(msg1->getNetCommandType())) { - // Are the commands from the same player? - if (msg1->getPlayerID() != msg2->getPlayerID()) { - return FALSE; - } - - // Do they have the same command ID? - if (msg1->getID() != msg2->getID()) { - return FALSE; - } - return TRUE; - } - - // If we've gotten this far, we know that the commands do not require a command id. - // So now our equality checking becomes type-specific. - - // Are they the same type? - if (msg1->getNetCommandType() != msg2->getNetCommandType()) { - return FALSE; - } - - // Are they from the same player? - if (msg1->getPlayerID() != msg2->getPlayerID()) { - return FALSE; - } - - // They are the same type and from the same player. - // Time for the type specific stuff. - if (msg1->getNetCommandType() == NETCOMMANDTYPE_ACKSTAGE1) { - NetAckStage1CommandMsg *ack1 = (NetAckStage1CommandMsg *)msg1; - NetAckStage1CommandMsg *ack2 = (NetAckStage1CommandMsg *)msg2; - - if (ack1->getOriginalPlayerID() != ack2->getOriginalPlayerID()) { - return FALSE; - } - - if (ack1->getCommandID() != ack2->getCommandID()) { - return FALSE; - } - return TRUE; - } - - // They are the same type and from the same player. - // Time for the type specific stuff. - if (msg1->getNetCommandType() == NETCOMMANDTYPE_ACKSTAGE2) { - NetAckStage2CommandMsg *ack1 = (NetAckStage2CommandMsg *)msg1; - NetAckStage2CommandMsg *ack2 = (NetAckStage2CommandMsg *)msg2; - - if (ack1->getOriginalPlayerID() != ack2->getOriginalPlayerID()) { - return FALSE; - } - - if (ack1->getCommandID() != ack2->getCommandID()) { - return FALSE; - } - return TRUE; - } - - // They are the same type and from the same player. - // Time for the type specific stuff. - if (msg1->getNetCommandType() == NETCOMMANDTYPE_ACKBOTH) { - NetAckBothCommandMsg *ack1 = (NetAckBothCommandMsg *)msg1; - NetAckBothCommandMsg *ack2 = (NetAckBothCommandMsg *)msg2; - - if (ack1->getOriginalPlayerID() != ack2->getOriginalPlayerID()) { - return FALSE; - } - - if (ack1->getCommandID() != ack2->getCommandID()) { - return FALSE; - } - return TRUE; - } - - return FALSE; -} diff --git a/Generals/Code/GameEngine/Source/GameNetwork/NetCommandMsg.cpp b/Generals/Code/GameEngine/Source/GameNetwork/NetCommandMsg.cpp deleted file mode 100644 index e2fd54682d..0000000000 --- a/Generals/Code/GameEngine/Source/GameNetwork/NetCommandMsg.cpp +++ /dev/null @@ -1,1066 +0,0 @@ -/* -** 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 in the GameEngine - -#include "GameNetwork/NetCommandMsg.h" -#include "Common/GameState.h" -#include "Common/PlayerList.h" -#include "Common/Player.h" - -/** - * Base constructor - */ -NetCommandMsg::NetCommandMsg() -{ - //Added By Sadullah Nader - //Initializations inserted - m_executionFrame = 0; - m_id = 0; - m_playerID = 0; - - // - m_timestamp = 0; - m_referenceCount = 1; // start this off as 1. This means that an "attach" is implied by creating a NetCommandMsg object. - m_commandType = NETCOMMANDTYPE_UNKNOWN; -} - -/** - * Destructor - */ -NetCommandMsg::~NetCommandMsg() { -} - -/** - * Adds one to the reference count. - */ -void NetCommandMsg::attach() { - ++m_referenceCount; -} - -/** - * Subtracts one from the reference count. If the reference count is 0, the this object is destroyed. - */ -void NetCommandMsg::detach() { - --m_referenceCount; - if (m_referenceCount == 0) { - deleteInstance(this); - return; - } - DEBUG_ASSERTCRASH(m_referenceCount > 0, ("Invalid reference count for NetCommandMsg")); // Just to make sure... - if (m_referenceCount < 0) { - deleteInstance(this); - } -} - -/** - * Returns the value by which this type of message should be sorted. - */ -Int NetCommandMsg::getSortNumber() { - return m_id; -} - -//------------------------------- -// NetGameCommandMsg -//------------------------------- - -/** - * Constructor with no argument, sets everything to default values. - */ -NetGameCommandMsg::NetGameCommandMsg() : NetCommandMsg() { - //Added By Sadullah Nader - //Initializations inserted - m_argSize = 0; - m_numArgs = 0; - // - - m_type = (GameMessage::Type)0; - m_commandType = NETCOMMANDTYPE_GAMECOMMAND; - m_argList = NULL; - m_argTail = NULL; -} - -/** - * Constructor with a GameMessage argument. Sets member variables appropriately for this GameMessage. - * Also copies all the arguments. - */ -NetGameCommandMsg::NetGameCommandMsg(GameMessage *msg) : NetCommandMsg() { - m_commandType = NETCOMMANDTYPE_GAMECOMMAND; - - m_type = msg->getType(); - Int count = msg->getArgumentCount(); - for (Int i = 0; i < count; ++i) { - addArgument(msg->getArgumentDataType(i), *(msg->getArgument(i))); - } -} - -/** - * Destructor - */ -NetGameCommandMsg::~NetGameCommandMsg() { - GameMessageArgument *arg = m_argList; - while (arg != NULL) { - m_argList = m_argList->m_next; - deleteInstance(arg); - arg = m_argList; - } -} - -/** - * Add an argument to this command. - */ -void NetGameCommandMsg::addArgument(const GameMessageArgumentDataType type, GameMessageArgumentType arg) -{ - if (m_argTail == NULL) { - m_argList = newInstance(GameMessageArgument); - m_argTail = m_argList; - m_argList->m_data = arg; - m_argList->m_type = type; - m_argList->m_next = NULL; - return; - } - - GameMessageArgument *newArg = newInstance(GameMessageArgument); - newArg->m_data = arg; - newArg->m_type = type; - newArg->m_next = NULL; - m_argTail->m_next = newArg; - m_argTail = newArg; -} - -// here's where we figure out which slot corresponds to which player -static Int indexFromMask(UnsignedInt mask) -{ - Player *player = NULL; - Int i; - - for( i = 0; i < MAX_PLAYER_COUNT; i++ ) - { - player = ThePlayerList->getNthPlayer( i ); - if( player && player->getPlayerMask() == mask ) - return i; - } - - return -1; -} - -/** - * Construct a new GameMessage object from the data in this object. - */ -GameMessage *NetGameCommandMsg::constructGameMessage() -{ - GameMessage *retval = newInstance(GameMessage)(m_type); - - AsciiString name; - name.format("player%d", getPlayerID()); - retval->friend_setPlayerIndex( ThePlayerList->findPlayerWithNameKey(TheNameKeyGenerator->nameToKey(name))->getPlayerIndex()); - - GameMessageArgument *arg = m_argList; - while (arg != NULL) { - - switch (arg->m_type) { - - case ARGUMENTDATATYPE_INTEGER: - retval->appendIntegerArgument(arg->m_data.integer); - break; - case ARGUMENTDATATYPE_REAL: - retval->appendRealArgument(arg->m_data.real); - break; - case ARGUMENTDATATYPE_BOOLEAN: - retval->appendBooleanArgument(arg->m_data.boolean); - break; - case ARGUMENTDATATYPE_OBJECTID: - retval->appendObjectIDArgument(arg->m_data.objectID); - break; - case ARGUMENTDATATYPE_DRAWABLEID: - retval->appendDrawableIDArgument(arg->m_data.drawableID); - break; - case ARGUMENTDATATYPE_TEAMID: - retval->appendTeamIDArgument(arg->m_data.teamID); - break; - case ARGUMENTDATATYPE_LOCATION: - retval->appendLocationArgument(arg->m_data.location); - break; - case ARGUMENTDATATYPE_PIXEL: - retval->appendPixelArgument(arg->m_data.pixel); - break; - case ARGUMENTDATATYPE_PIXELREGION: - retval->appendPixelRegionArgument(arg->m_data.pixelRegion); - break; - case ARGUMENTDATATYPE_TIMESTAMP: - retval->appendTimestampArgument(arg->m_data.timestamp); - break; - case ARGUMENTDATATYPE_WIDECHAR: - retval->appendWideCharArgument(arg->m_data.wChar); - break; - - } - - arg = arg->m_next; - } - return retval; -} - -/** - * Sets the type of game message - */ -void NetGameCommandMsg::setGameMessageType(GameMessage::Type type) { - m_type = type; -} - -//------------------------- -// NetAckBothCommandMsg -//------------------------- -/** - * Constructor. Sets the member variables according to the given message. - */ -NetAckBothCommandMsg::NetAckBothCommandMsg(NetCommandMsg *msg) : NetCommandMsg() { - m_commandID = msg->getID(); - m_commandType = NETCOMMANDTYPE_ACKBOTH; - m_originalPlayerID = msg->getPlayerID(); -} - -/** - * Constructor. Sets the member variables to default values. - */ -NetAckBothCommandMsg::NetAckBothCommandMsg() : NetCommandMsg() { - m_commandType = NETCOMMANDTYPE_ACKBOTH; -} - -/** - * Destructor. - */ -NetAckBothCommandMsg::~NetAckBothCommandMsg() { -} - -/** - * Returns the command ID of the command being ack'd. - */ -UnsignedShort NetAckBothCommandMsg::getCommandID() { - return m_commandID; -} - -/** - * Set the command ID of the command being ack'd. - */ -void NetAckBothCommandMsg::setCommandID(UnsignedShort commandID) { - m_commandID = commandID; -} - -/** - * Get the player id of the player who originally sent the command. - */ -UnsignedByte NetAckBothCommandMsg::getOriginalPlayerID() { - return m_originalPlayerID; -} - -/** - * Set the player id of the player who originally sent the command. - */ -void NetAckBothCommandMsg::setOriginalPlayerID(UnsignedByte originalPlayerID) { - m_originalPlayerID = originalPlayerID; -} - -Int NetAckBothCommandMsg::getSortNumber() { - return m_commandID; -} - -//------------------------- -// NetAckStage1CommandMsg -//------------------------- -/** - * Constructor. Sets the member variables according to the given message. - */ -NetAckStage1CommandMsg::NetAckStage1CommandMsg(NetCommandMsg *msg) : NetCommandMsg() { - m_commandID = msg->getID(); - m_commandType = NETCOMMANDTYPE_ACKSTAGE1; - m_originalPlayerID = msg->getPlayerID(); -} - -/** - * Constructor. Sets the member variables to default values. - */ -NetAckStage1CommandMsg::NetAckStage1CommandMsg() : NetCommandMsg() { - m_commandType = NETCOMMANDTYPE_ACKSTAGE1; -} - -/** - * Destructor. - */ -NetAckStage1CommandMsg::~NetAckStage1CommandMsg() { -} - -/** - * Returns the command ID of the command being ack'd. - */ -UnsignedShort NetAckStage1CommandMsg::getCommandID() { - return m_commandID; -} - -/** - * Set the command ID of the command being ack'd. - */ -void NetAckStage1CommandMsg::setCommandID(UnsignedShort commandID) { - m_commandID = commandID; -} - -/** - * Get the player id of the player who originally sent the command. - */ -UnsignedByte NetAckStage1CommandMsg::getOriginalPlayerID() { - return m_originalPlayerID; -} - -/** - * Set the player id of the player who originally sent the command. - */ -void NetAckStage1CommandMsg::setOriginalPlayerID(UnsignedByte originalPlayerID) { - m_originalPlayerID = originalPlayerID; -} - -Int NetAckStage1CommandMsg::getSortNumber() { - return m_commandID; -} - -//------------------------- -// NetAckStage2CommandMsg -//------------------------- -/** - * Constructor. Sets the member variables according to the given message. - */ -NetAckStage2CommandMsg::NetAckStage2CommandMsg(NetCommandMsg *msg) : NetCommandMsg() { - m_commandID = msg->getID(); - m_commandType = NETCOMMANDTYPE_ACKSTAGE2; - m_originalPlayerID = msg->getPlayerID(); -} - -/** - * Constructor. Sets the member variables to default values. - */ -NetAckStage2CommandMsg::NetAckStage2CommandMsg() : NetCommandMsg() { - m_commandType = NETCOMMANDTYPE_ACKSTAGE2; -} - -/** - * Destructor. - */ -NetAckStage2CommandMsg::~NetAckStage2CommandMsg() { -} - -/** - * Returns the command ID of the command being ack'd. - */ -UnsignedShort NetAckStage2CommandMsg::getCommandID() { - return m_commandID; -} - -/** - * Set the command ID of the command being ack'd. - */ -void NetAckStage2CommandMsg::setCommandID(UnsignedShort commandID) { - m_commandID = commandID; -} - -/** - * Get the player id of the player who originally sent the command. - */ -UnsignedByte NetAckStage2CommandMsg::getOriginalPlayerID() { - return m_originalPlayerID; -} - -/** - * Set the player id of the player who originally sent the command. - */ -void NetAckStage2CommandMsg::setOriginalPlayerID(UnsignedByte originalPlayerID) { - m_originalPlayerID = originalPlayerID; -} - -Int NetAckStage2CommandMsg::getSortNumber() { - return m_commandID; -} - -//------------------------- -// NetFrameCommandMsg -//------------------------- -/** - * Constructor. - */ -NetFrameCommandMsg::NetFrameCommandMsg() : NetCommandMsg() { - m_commandCount = 0; - m_commandType = NETCOMMANDTYPE_FRAMEINFO; -} - -/** - * Destructor - */ -NetFrameCommandMsg::~NetFrameCommandMsg() { -} - -/** - * Set the command count of this frame. - */ -void NetFrameCommandMsg::setCommandCount(UnsignedShort commandCount) { - m_commandCount = commandCount; -} - -/** - * Return the command count of this frame. - */ -UnsignedShort NetFrameCommandMsg::getCommandCount() { - return m_commandCount; -} - -//------------------------- -// NetPlayerLeaveCommandMsg -//------------------------- -/** - * Constructor - */ -NetPlayerLeaveCommandMsg::NetPlayerLeaveCommandMsg() : NetCommandMsg() { - m_leavingPlayerID = 0; - m_commandType = NETCOMMANDTYPE_PLAYERLEAVE; -} - -/** - * Destructor - */ -NetPlayerLeaveCommandMsg::~NetPlayerLeaveCommandMsg() { -} - -/** - * Get the id of the player leaving the game. - */ -UnsignedByte NetPlayerLeaveCommandMsg::getLeavingPlayerID() { - return m_leavingPlayerID; -} - -/** - * Set the id of the player leaving the game. - */ -void NetPlayerLeaveCommandMsg::setLeavingPlayerID(UnsignedByte id) { - m_leavingPlayerID = id; -} - -//------------------------- -// NetRunAheadMetricsCommandMsg -//------------------------- -/** - * Constructor - */ -NetRunAheadMetricsCommandMsg::NetRunAheadMetricsCommandMsg() : NetCommandMsg() { - m_averageLatency = 0.0; - m_averageFps = 0; - m_commandType = NETCOMMANDTYPE_RUNAHEADMETRICS; -} - -/** - * Destructor - */ -NetRunAheadMetricsCommandMsg::~NetRunAheadMetricsCommandMsg() { -} - -/** - * set the average latency - */ -void NetRunAheadMetricsCommandMsg::setAverageLatency(Real avgLat) { - m_averageLatency = avgLat; -} - -/** - * get the average latency - */ -Real NetRunAheadMetricsCommandMsg::getAverageLatency() { - return m_averageLatency; -} - -/** - * set the average fps - */ -void NetRunAheadMetricsCommandMsg::setAverageFps(Int fps) { - m_averageFps = fps; -} - -/** - * get the average fps - */ -Int NetRunAheadMetricsCommandMsg::getAverageFps() { - return m_averageFps; -} - -//------------------------- -// NetRunAheadCommandMsg -//------------------------- -NetRunAheadCommandMsg::NetRunAheadCommandMsg() : NetCommandMsg() { - m_runAhead = min(max(20, MIN_RUNAHEAD), MAX_FRAMES_AHEAD/2); - m_frameRate = 30; - m_commandType = NETCOMMANDTYPE_RUNAHEAD; -} - -NetRunAheadCommandMsg::~NetRunAheadCommandMsg() { -} - -UnsignedShort NetRunAheadCommandMsg::getRunAhead() { - return m_runAhead; -} - -void NetRunAheadCommandMsg::setRunAhead(UnsignedShort runAhead) { - m_runAhead = runAhead; -} - -UnsignedByte NetRunAheadCommandMsg::getFrameRate() { - return m_frameRate; -} - -void NetRunAheadCommandMsg::setFrameRate(UnsignedByte frameRate) { - m_frameRate = frameRate; -} - -//------------------------- -// NetDestroyPlayerCommandMsg -//------------------------- -/** - * Constructor - */ -NetDestroyPlayerCommandMsg::NetDestroyPlayerCommandMsg() : NetCommandMsg() -{ - m_playerIndex = 0; - m_commandType = NETCOMMANDTYPE_DESTROYPLAYER; -} - -/** - * Destructor - */ -NetDestroyPlayerCommandMsg::~NetDestroyPlayerCommandMsg() -{ -} - -/** - * set the CRC - */ -void NetDestroyPlayerCommandMsg::setPlayerIndex( UnsignedInt playerIndex ) -{ - m_playerIndex = playerIndex; -} - -/** - * get the average CRC - */ -UnsignedInt NetDestroyPlayerCommandMsg::getPlayerIndex( void ) -{ - return m_playerIndex; -} - -//------------------------- -// NetKeepAliveCommandMsg -//------------------------- -/** - * Constructor - */ -NetKeepAliveCommandMsg::NetKeepAliveCommandMsg() : NetCommandMsg() { - m_commandType = NETCOMMANDTYPE_KEEPALIVE; -} - -NetKeepAliveCommandMsg::~NetKeepAliveCommandMsg() { -} - -//------------------------- -// NetDisconnectKeepAliveCommandMsg -//------------------------- -/** - * Constructor - */ -NetDisconnectKeepAliveCommandMsg::NetDisconnectKeepAliveCommandMsg() : NetCommandMsg() { - m_commandType = NETCOMMANDTYPE_DISCONNECTKEEPALIVE; -} - -NetDisconnectKeepAliveCommandMsg::~NetDisconnectKeepAliveCommandMsg() { -} - -//------------------------- -// NetDisconnectPlayerCommandMsg -//------------------------- -/** - * Constructor - */ -NetDisconnectPlayerCommandMsg::NetDisconnectPlayerCommandMsg() : NetCommandMsg() { - m_commandType = NETCOMMANDTYPE_DISCONNECTPLAYER; - m_disconnectSlot = 0; -} - -/** - * Destructor - */ -NetDisconnectPlayerCommandMsg::~NetDisconnectPlayerCommandMsg() { -} - -/** - * Returns the disconnecting slot number - */ -UnsignedByte NetDisconnectPlayerCommandMsg::getDisconnectSlot() { - return m_disconnectSlot; -} - -/** - * Sets the disconnecting slot number - */ -void NetDisconnectPlayerCommandMsg::setDisconnectSlot(UnsignedByte slot) { - m_disconnectSlot = slot; -} - -/** - * Sets the disconnect frame - */ -void NetDisconnectPlayerCommandMsg::setDisconnectFrame(UnsignedInt frame) { - m_disconnectFrame = frame; -} - -/** - * returns the disconnect frame - */ -UnsignedInt NetDisconnectPlayerCommandMsg::getDisconnectFrame() { - return m_disconnectFrame; -} - -//------------------------- -// NetPacketRouterQueryCommandMsg -//------------------------- -/** - * Constructor - */ -NetPacketRouterQueryCommandMsg::NetPacketRouterQueryCommandMsg() : NetCommandMsg() { - m_commandType = NETCOMMANDTYPE_PACKETROUTERQUERY; -} - -/** - * Destructor - */ -NetPacketRouterQueryCommandMsg::~NetPacketRouterQueryCommandMsg() { -} - -//------------------------- -// NetPacketRouterAckCommandMsg -//------------------------- -/** - * Constructor - */ -NetPacketRouterAckCommandMsg::NetPacketRouterAckCommandMsg() : NetCommandMsg() { - m_commandType = NETCOMMANDTYPE_PACKETROUTERACK; -} - -/** - * Destructor - */ -NetPacketRouterAckCommandMsg::~NetPacketRouterAckCommandMsg() { -} - -//------------------------- -// NetDisconnectChatCommandMsg -//------------------------- -/** - * Constructor - */ -NetDisconnectChatCommandMsg::NetDisconnectChatCommandMsg() : NetCommandMsg() { - m_commandType = NETCOMMANDTYPE_DISCONNECTCHAT; -} - -/** - * Destructor - */ -NetDisconnectChatCommandMsg::~NetDisconnectChatCommandMsg() { -} - -/** - * Set the chat text for this message. - */ -void NetDisconnectChatCommandMsg::setText(UnicodeString text) { - m_text = text; -} - -/** - * Get the chat text for this message. - */ -UnicodeString NetDisconnectChatCommandMsg::getText() { - return m_text; -} - -//------------------------- -// NetChatCommandMsg -//------------------------- -/** - * Constructor - */ -NetChatCommandMsg::NetChatCommandMsg() : NetCommandMsg() -{ - m_commandType = NETCOMMANDTYPE_CHAT; - //added by Sadullah Nader - //Initializations inserted - m_playerMask = 0; - // -} - -/** - * Destructor - */ -NetChatCommandMsg::~NetChatCommandMsg() -{ -} - -/** - * Set the chat text for this message. - */ -void NetChatCommandMsg::setText(UnicodeString text) -{ - m_text = text; -} - -/** - * Get the chat text for this message. - */ -UnicodeString NetChatCommandMsg::getText() -{ - return m_text; -} - -/** - * Get the bitmask of chat recipients from this message. - */ -Int NetChatCommandMsg::getPlayerMask() -{ - return m_playerMask; -} - -/** - * Set a bitmask of chat recipients in this message. - */ -void NetChatCommandMsg::setPlayerMask( Int playerMask ) -{ - m_playerMask = playerMask; -} - -//------------------------- -// NetDisconnectVoteCommandMsg -//------------------------- -/** - * Constructor - */ -NetDisconnectVoteCommandMsg::NetDisconnectVoteCommandMsg() : NetCommandMsg() { - m_commandType = NETCOMMANDTYPE_DISCONNECTVOTE; - m_slot = 0; -} - -/** - * Destructor - */ -NetDisconnectVoteCommandMsg::~NetDisconnectVoteCommandMsg() { -} - -/** - * Set the slot that is being voted for. - */ -void NetDisconnectVoteCommandMsg::setSlot(UnsignedByte slot) { - m_slot = slot; -} - -/** - * Get the slot that is being voted for. - */ -UnsignedByte NetDisconnectVoteCommandMsg::getSlot() { - return m_slot; -} - -/** - * Get the vote frame. - */ -UnsignedInt NetDisconnectVoteCommandMsg::getVoteFrame() { - return m_voteFrame; -} - -/** - * Set the vote frame. - */ -void NetDisconnectVoteCommandMsg::setVoteFrame(UnsignedInt voteFrame) { - m_voteFrame = voteFrame; -} - -//------------------------- -// NetProgressCommandMsg -//------------------------- -NetProgressCommandMsg::NetProgressCommandMsg( void ) : NetCommandMsg() -{ - m_commandType = NETCOMMANDTYPE_PROGRESS; - m_percent = 0; -} - -NetProgressCommandMsg::~NetProgressCommandMsg( void ) {} - -UnsignedByte NetProgressCommandMsg::getPercentage() -{ - return m_percent; -} - -void NetProgressCommandMsg::setPercentage( UnsignedByte percent ) -{ - m_percent = percent; -} - -//------------------------- -// NetWrapperCommandMsg -//------------------------- -NetWrapperCommandMsg::NetWrapperCommandMsg() : NetCommandMsg() { - m_commandType = NETCOMMANDTYPE_WRAPPER; - m_numChunks = 0; - m_data = NULL; - m_totalDataLength = 0; - m_chunkNumber = 0; - m_dataLength = 0; - m_dataOffset = 0; - m_wrappedCommandID = 0; -} - -NetWrapperCommandMsg::~NetWrapperCommandMsg() { - delete m_data; - m_data = NULL; -} - -UnsignedByte * NetWrapperCommandMsg::getData() { - return m_data; -} - -void NetWrapperCommandMsg::setData(UnsignedByte *data, UnsignedInt dataLength) -{ - delete m_data; - m_data = NEW UnsignedByte[dataLength]; // pool[]ify - memcpy(m_data, data, dataLength); - m_dataLength = dataLength; -} - -UnsignedInt NetWrapperCommandMsg::getDataLength() { - return m_dataLength; -} - -UnsignedInt NetWrapperCommandMsg::getDataOffset() { - return m_dataOffset; -} - -void NetWrapperCommandMsg::setDataOffset(UnsignedInt offset) { - m_dataOffset = offset; -} - -UnsignedInt NetWrapperCommandMsg::getChunkNumber() { - return m_chunkNumber; -} - -void NetWrapperCommandMsg::setChunkNumber(UnsignedInt chunkNumber) { - m_chunkNumber = chunkNumber; -} - -UnsignedInt NetWrapperCommandMsg::getNumChunks() { - return m_numChunks; -} - -void NetWrapperCommandMsg::setNumChunks(UnsignedInt numChunks) { - m_numChunks = numChunks; -} - -UnsignedInt NetWrapperCommandMsg::getTotalDataLength() { - return m_totalDataLength; -} - -void NetWrapperCommandMsg::setTotalDataLength(UnsignedInt totalDataLength) { - m_totalDataLength = totalDataLength; -} - -UnsignedShort NetWrapperCommandMsg::getWrappedCommandID() { - return m_wrappedCommandID; -} - -void NetWrapperCommandMsg::setWrappedCommandID(UnsignedShort wrappedCommandID) { - m_wrappedCommandID = wrappedCommandID; -} - -//------------------------- -// NetFileCommandMsg -//------------------------- -NetFileCommandMsg::NetFileCommandMsg() : NetCommandMsg() { - m_commandType = NETCOMMANDTYPE_FILE; - m_data = NULL; - m_portableFilename.clear(); - m_dataLength = 0; -} - -NetFileCommandMsg::~NetFileCommandMsg() { - delete[] m_data; - m_data = NULL; -} - -AsciiString NetFileCommandMsg::getRealFilename() -{ - return TheGameState->portableMapPathToRealMapPath(m_portableFilename); -} - -void NetFileCommandMsg::setRealFilename(AsciiString filename) -{ - m_portableFilename = TheGameState->realMapPathToPortableMapPath(filename); -} - -UnsignedInt NetFileCommandMsg::getFileLength() { - return m_dataLength; -} - -UnsignedByte * NetFileCommandMsg::getFileData() { - return m_data; -} - -void NetFileCommandMsg::setFileData(UnsignedByte *data, UnsignedInt dataLength) -{ - m_dataLength = dataLength; - m_data = NEW UnsignedByte[dataLength]; // pool[]ify - memcpy(m_data, data, dataLength); -} - -//------------------------- -// NetFileAnnounceCommandMsg -//------------------------- -NetFileAnnounceCommandMsg::NetFileAnnounceCommandMsg() : NetCommandMsg() { - m_commandType = NETCOMMANDTYPE_FILEANNOUNCE; - m_portableFilename.clear(); - m_fileID = 0; - m_playerMask = 0; -} - -NetFileAnnounceCommandMsg::~NetFileAnnounceCommandMsg() { -} - -AsciiString NetFileAnnounceCommandMsg::getRealFilename() -{ - return TheGameState->portableMapPathToRealMapPath(m_portableFilename); -} - -void NetFileAnnounceCommandMsg::setRealFilename(AsciiString filename) -{ - m_portableFilename = TheGameState->realMapPathToPortableMapPath(filename); -} - -UnsignedShort NetFileAnnounceCommandMsg::getFileID() { - return m_fileID; -} - -void NetFileAnnounceCommandMsg::setFileID(UnsignedShort fileID) { - m_fileID = fileID; -} - -UnsignedByte NetFileAnnounceCommandMsg::getPlayerMask(void) { - return m_playerMask; -} - -void NetFileAnnounceCommandMsg::setPlayerMask(UnsignedByte playerMask) { - m_playerMask = playerMask; -} - - -//------------------------- -// NetFileProgressCommandMsg -//------------------------- -NetFileProgressCommandMsg::NetFileProgressCommandMsg() : NetCommandMsg() { - m_commandType = NETCOMMANDTYPE_FILEPROGRESS; - m_fileID = 0; - m_progress = 0; -} - -NetFileProgressCommandMsg::~NetFileProgressCommandMsg() { -} - -UnsignedShort NetFileProgressCommandMsg::getFileID() { - return m_fileID; -} - -void NetFileProgressCommandMsg::setFileID(UnsignedShort val) { - m_fileID = val; -} - -Int NetFileProgressCommandMsg::getProgress() { - return m_progress; -} - -void NetFileProgressCommandMsg::setProgress(Int val) { - m_progress = val; -} - -//------------------------- -// NetDisconnectFrameCommandMsg -//------------------------- -NetDisconnectFrameCommandMsg::NetDisconnectFrameCommandMsg() : NetCommandMsg() { - m_commandType = NETCOMMANDTYPE_DISCONNECTFRAME; - m_disconnectFrame = 0; -} - -NetDisconnectFrameCommandMsg::~NetDisconnectFrameCommandMsg() { -} - -UnsignedInt NetDisconnectFrameCommandMsg::getDisconnectFrame() { - return m_disconnectFrame; -} - -void NetDisconnectFrameCommandMsg::setDisconnectFrame(UnsignedInt disconnectFrame) { - m_disconnectFrame = disconnectFrame; -} - -//------------------------- -// NetDisconnectScreenOffCommandMsg -//------------------------- -NetDisconnectScreenOffCommandMsg::NetDisconnectScreenOffCommandMsg() : NetCommandMsg() { - m_commandType = NETCOMMANDTYPE_DISCONNECTSCREENOFF; - m_newFrame = 0; -} - -NetDisconnectScreenOffCommandMsg::~NetDisconnectScreenOffCommandMsg() { -} - -UnsignedInt NetDisconnectScreenOffCommandMsg::getNewFrame() { - return m_newFrame; -} - -void NetDisconnectScreenOffCommandMsg::setNewFrame(UnsignedInt newFrame) { - m_newFrame = newFrame; -} - -//------------------------- -// NetFrameResendRequestCommandMsg -//------------------------- -NetFrameResendRequestCommandMsg::NetFrameResendRequestCommandMsg() : NetCommandMsg() { - m_commandType = NETCOMMANDTYPE_FRAMERESENDREQUEST; - m_frameToResend = 0; -} - -NetFrameResendRequestCommandMsg::~NetFrameResendRequestCommandMsg() { -} - -UnsignedInt NetFrameResendRequestCommandMsg::getFrameToResend() { - return m_frameToResend; -} - -void NetFrameResendRequestCommandMsg::setFrameToResend(UnsignedInt frame) { - m_frameToResend = frame; -} diff --git a/Generals/Code/GameEngine/Source/GameNetwork/NetCommandRef.cpp b/Generals/Code/GameEngine/Source/GameNetwork/NetCommandRef.cpp deleted file mode 100644 index 66b004c09f..0000000000 --- a/Generals/Code/GameEngine/Source/GameNetwork/NetCommandRef.cpp +++ /dev/null @@ -1,71 +0,0 @@ -/* -** 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 in the GameEngine - -#include "GameNetwork/NetCommandRef.h" - -#ifdef DEBUG_NETCOMMANDREF -static UnsignedInt refNum = 0; -#endif - -/** - * Constructor. Attach to the given network command. - */ -#ifdef DEBUG_NETCOMMANDREF -NetCommandRef::NetCommandRef(NetCommandMsg *msg, char *filename, int line) -#else -NetCommandRef::NetCommandRef(NetCommandMsg *msg) -#endif -{ - m_msg = msg; - m_next = NULL; - m_prev = NULL; - m_msg->attach(); - m_timeLastSent = -1; - -#ifdef DEBUG_NETCOMMANDREF - m_id = ++refNum; - DEBUG_LOG(("NetCommandRef %d allocated in file %s line %d", m_id, filename, line)); -#endif -} - -/** - * Destructor. Detach from the network command. - */ -NetCommandRef::~NetCommandRef() -{ - if (m_msg != NULL) - { - m_msg->detach(); - } - DEBUG_ASSERTCRASH(m_next == NULL, ("NetCommandRef::~NetCommandRef - m_next != NULL")); - DEBUG_ASSERTCRASH(m_prev == NULL, ("NetCommandRef::~NetCommandRef - m_prev != NULL")); - -#ifdef DEBUG_NETCOMMANDREF - DEBUG_LOG(("NetCommandRef %d deleted", m_id)); -#endif -} - diff --git a/Generals/Code/GameEngine/Source/GameNetwork/NetCommandWrapperList.cpp b/Generals/Code/GameEngine/Source/GameNetwork/NetCommandWrapperList.cpp deleted file mode 100644 index 99c297c616..0000000000 --- a/Generals/Code/GameEngine/Source/GameNetwork/NetCommandWrapperList.cpp +++ /dev/null @@ -1,229 +0,0 @@ -/* -** 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. // -// // -//////////////////////////////////////////////////////////////////////////////// - -////// NetCommandWrapperList.cpp //////////////////////////////// -// Bryan Cleveland - -#include "PreRTS.h" // This must go first in EVERY cpp file in the GameEngine - -#include "GameNetwork/NetCommandWrapperList.h" -#include "GameNetwork/NetPacket.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -////// NetCommandWrapperListNode /////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////////////////////////// - -NetCommandWrapperListNode::NetCommandWrapperListNode(NetWrapperCommandMsg *msg) -{ - //Added By Sadullah Nader - //Initializations inserted - m_next = NULL; - - // - - m_numChunks = msg->getNumChunks(); - m_chunksPresent = NEW Bool[m_numChunks]; // pool[]ify - m_numChunksPresent = 0; - - for (UnsignedInt i = 0; i < m_numChunks; ++i) { - m_chunksPresent[i] = FALSE; - } - - m_dataLength = msg->getTotalDataLength(); - m_data = NEW UnsignedByte[m_dataLength]; // pool[]ify - - m_commandID = msg->getWrappedCommandID(); -} - -NetCommandWrapperListNode::~NetCommandWrapperListNode() { - delete[] m_chunksPresent; - m_chunksPresent = NULL; - - delete[] m_data; - m_data = NULL; -} - -Bool NetCommandWrapperListNode::isComplete() { - return m_numChunksPresent == m_numChunks; -} - -Int NetCommandWrapperListNode::getPercentComplete(void) { - if (isComplete()) - return 100; - else - return min(99, REAL_TO_INT( ((Real)m_numChunksPresent)/((Real)m_numChunks)*100.0f )); -} - -UnsignedShort NetCommandWrapperListNode::getCommandID() { - return m_commandID; -} - -UnsignedInt NetCommandWrapperListNode::getRawDataLength() { - return m_dataLength; -} - -void NetCommandWrapperListNode::copyChunkData(NetWrapperCommandMsg *msg) { - if (msg == NULL) { - DEBUG_CRASH(("Trying to copy data from a non-existent wrapper command message")); - return; - } - - DEBUG_ASSERTCRASH(msg->getChunkNumber() < m_numChunks, ("MunkeeChunk %d of %d", - msg->getChunkNumber(), m_numChunks)); - if (msg->getChunkNumber() >= m_numChunks) - return; - - DEBUG_LOG(("NetCommandWrapperListNode::copyChunkData() - copying chunk %d", - msg->getChunkNumber())); - - if (m_chunksPresent[msg->getChunkNumber()] == TRUE) { - // we already received this chunk, no need to recopy it. - return; - } - - m_chunksPresent[msg->getChunkNumber()] = TRUE; - UnsignedInt offset = msg->getDataOffset(); - memcpy(m_data + offset, msg->getData(), msg->getDataLength()); - ++m_numChunksPresent; -} - -UnsignedByte * NetCommandWrapperListNode::getRawData() { - return m_data; -} - -//////////////////////////////////////////////////////////////////////////////////////////////////// -////// NetCommandWrapperList /////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////////////////////////// - -NetCommandWrapperList::NetCommandWrapperList() { - m_list = NULL; -} - -NetCommandWrapperList::~NetCommandWrapperList() { - NetCommandWrapperListNode *temp; - while (m_list != NULL) { - temp = m_list->m_next; - deleteInstance(m_list); - m_list = temp; - } -} - -void NetCommandWrapperList::init() { - m_list = NULL; -} - -void NetCommandWrapperList::reset() { - NetCommandWrapperListNode *temp; - while (m_list != NULL) { - temp = m_list->m_next; - deleteInstance(m_list); - m_list = temp; - } -} - -Int NetCommandWrapperList::getPercentComplete(UnsignedShort wrappedCommandID) -{ - NetCommandWrapperListNode *temp = m_list; - - while ((temp != NULL) && (temp->getCommandID() != wrappedCommandID)) { - temp = temp->m_next; - } - - if (!temp) - return 0; - - return temp->getPercentComplete(); -} - -void NetCommandWrapperList::processWrapper(NetCommandRef *ref) { - NetCommandWrapperListNode *temp = m_list; - NetWrapperCommandMsg *msg = (NetWrapperCommandMsg *)(ref->getCommand()); - - while ((temp != NULL) && (temp->getCommandID() != msg->getWrappedCommandID())) { - temp = temp->m_next; - } - - if (temp == NULL) { - temp = newInstance(NetCommandWrapperListNode)(msg); - temp->m_next = m_list; - m_list = temp; - } - - temp->copyChunkData(msg); -} - -NetCommandList * NetCommandWrapperList::getReadyCommands() -{ - NetCommandList *retlist = newInstance(NetCommandList); - retlist->init(); - - NetCommandWrapperListNode *temp = m_list; - NetCommandWrapperListNode *next = NULL; - - while (temp != NULL) { - next = temp->m_next; - if (temp->isComplete()) { - NetCommandRef *msg = NetPacket::ConstructNetCommandMsgFromRawData(temp->getRawData(), temp->getRawDataLength()); - NetCommandRef *ret = retlist->addMessage(msg->getCommand()); - ret->setRelay(msg->getRelay()); - - deleteInstance(msg); - msg = NULL; - - removeFromList(temp); - temp = NULL; - } - temp = next; - } - - return retlist; -} - -void NetCommandWrapperList::removeFromList(NetCommandWrapperListNode *node) { - if (node == NULL) { - return; - } - - NetCommandWrapperListNode *temp = m_list; - NetCommandWrapperListNode *prev = NULL; - - while ((temp != NULL) && (temp->getCommandID() != node->getCommandID())) { - prev = temp; - temp = temp->m_next; - } - - if (temp == NULL) { - return; - } - - if (prev == NULL) { - m_list = temp->m_next; - deleteInstance(temp); - temp = NULL; - } else { - prev->m_next = temp->m_next; - deleteInstance(temp); - temp = NULL; - } -} diff --git a/Generals/Code/GameEngine/Source/GameNetwork/NetMessageStream.cpp b/Generals/Code/GameEngine/Source/GameNetwork/NetMessageStream.cpp deleted file mode 100644 index 8aa55eafe3..0000000000 --- a/Generals/Code/GameEngine/Source/GameNetwork/NetMessageStream.cpp +++ /dev/null @@ -1,227 +0,0 @@ -/* -** 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 in the GameEngine - - -// NetMessageStream.cpp -// Holds misc functions to encapsulate GameMessages into Command Packets to send -// over the network. -// Author: Matthew D. Campbell, July 2001 -/* -#include "stdlib.h" // VC++ wants this here, or gives compile error... - -#include "Common/GameType.h" -#include "Common/MessageStream.h" -#include "Common/GameEngine.h" -#include "GameLogic/GameLogic.h" -#include "GameNetwork/NetworkInterface.h" -#include "GameNetwork/NetworkDefs.h" - - - -// The per-player pointers for the list of commands -static CommandMsg *CommandHead[MAX_SLOTS] = { /// @todo: remove static initialization - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL -}; -static CommandMsg *CommandTail[MAX_SLOTS] = { - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL -}; - -/** - * AddToNetCommandList adds a CommandMsg to a list of commands. - * -static Bool AddToNetCommandList(GameMessage *msg, UnsignedInt timestamp, CommandMsg *& CommandHead, CommandMsg *& CommandTail) -{ - CommandMsg *cmdMsg = NEW CommandMsg(timestamp, msg); - if (!cmdMsg) - { - DEBUG_LOG(("Alloc failed!")); - return false; - } - - if (CommandTail == NULL) - { - CommandHead = cmdMsg; - CommandTail = cmdMsg; - } - else - { - cmdMsg->SetPrevCommandMsg(CommandTail); - CommandTail->SetNextCommandMsg(cmdMsg); - CommandTail = cmdMsg; - } - - return true; -} - -/** - * AddToRemoteNetCommandList is used by TheNetwork to queue up commands recieved from other players. - * -Bool AddToNetCommandList(Int playerNum, GameMessage *msg, UnsignedInt timestamp) -{ - if (playerNum < 0 || playerNum >= MAX_SLOTS) - return false; - - DEBUG_LOG(("Adding msg to NetCommandList %d", playerNum)); - return AddToNetCommandList(msg, timestamp, CommandHead[playerNum], CommandTail[playerNum]); -} - -/** - * GetCommandMsg returns a GameMessage (deleting its CommandMsg wrapper) that is valid - * for the current frame, or NULL. - * -static GameMessage * GetCommandMsg(UnsignedInt timestamp, CommandMsg *& CommandHead, CommandMsg *& CommandTail) -{ - if (!CommandHead) - return NULL; - - if (CommandHead->GetTimestamp() < timestamp) - { - DEBUG_LOG(("Time is %d, yet message timestamp is %d!", timestamp, CommandHead->GetTimestamp())); - return NULL; - } - - if (CommandHead->GetTimestamp() != timestamp) - return NULL; - - CommandMsg *theMsg = CommandHead; - - if (CommandHead->GetNextCommandMsg()) - { - CommandHead->GetNextCommandMsg()->SetPrevCommandMsg(NULL); - CommandHead = CommandHead->GetNextCommandMsg(); - } - else - { - CommandHead = CommandTail = NULL; - } - - GameMessage *msg = theMsg->GetGameMessage(); - delete theMsg; - return msg; -} - -/** - * GetCommandMsg returns a message from the command list. - * -GameMessage * GetCommandMsg(UnsignedInt timestamp, Int playerNum) -{ - if (playerNum < 0 || playerNum >= MAX_SLOTS) - return NULL; - - //DEBUG_LOG(("Adding msg to NetCommandList %d", playerNum)); - return GetCommandMsg(timestamp, CommandHead[playerNum], CommandTail[playerNum]); -} - - - - -//==================================================================================== - -// The commandBuf & commandPacket hold the commands we're building up for the frame. -static unsigned char commandBuf[sizeof(CommandPacket)+1]; -static CommandPacket *commandPacket = (CommandPacket *)(commandBuf+1); - -/** - * ClearCommandPacket clears the command packet at the start of the frame. - * -void ClearCommandPacket(UnsignedInt frame) -{ - commandPacket->m_frame = frame; - commandPacket->m_numCommands = 0; -} - -/** - * AddCommandToPacket creates a packet containing all move/attack/etc commands - * for the current frame. - * -Bool AddCommandToPacket(const GameMessage *msg) -{ - int messageSize = sizeofMessageHeader + sizeofMessageArg * msg->getArgumentCount(); - - // If we have too much, send what we have - if (bytesUsed && (bytesUsed + sizeof(CommandPacketHeader) + messageSize >= MAX_MESSAGE_LEN)) - { - commandBuf[0] = MSGTYPE_PARTIALCOMMAND; - if (!TheNetwork->queueSend(BROADCAST_CON, commandBuf, bytesUsed + sizeof(CommandPacketHeader) + 1, MSG_NEEDACK | MSG_SEQUENCED)) - { - //DEBUG_ASSERTCRASH(false, ("Too many commands in one frame! Some will be dropped.")); - DEBUG_LOG(("Too many commands in one frame! Some will be dropped.")); - return false; - } - commandBuf[0] = MSGTYPE_COMMANDCOUNT; - commandPacket->header.m_numCommands = 0; - bytesUsed = 0; - } - - if (bytesUsed + sizeof(CommandPacketHeader) + messageSize >= MAX_MESSAGE_LEN) - { - //DEBUG_ASSERTCRASH(false, ("Too many commands in one frame! Some will be dropped.")); - DEBUG_LOG(("Too many commands in one frame! Some will be dropped.")); - return false; - } - - // We have room, so add the message - commandPacket->header.m_numCommands++; - commandPacket->m_commands[bytesUsed++] = (unsigned char)msg->getType(); - commandPacket->m_commands[bytesUsed++] = msg->getArgumentCount(); - - for (int i=0; igetArgumentCount(); ++i) - { - memcpy((unsigned char *)(commandPacket->m_commands + bytesUsed), (unsigned char *)msg->getArgument(i), sizeofMessageArg); - bytesUsed += sizeofMessageArg; - } - - //DEBUG_ASSERTCRASH(bytesUsed + sizeof(CommandPacketHeader) < MAX_MESSAGE_LEN, ("Memory overwrite constructing command packet!")); - //DEBUG_LOG(("Memory overwrite constructing command packet!")); - return true; -} - -/** - * TheNetwork calls GetCommandPacket to get commands to send. - * -CommandPacket *GetCommandPacket(void) -{ - commandBuf[0] = MSGTYPE_COMMANDCOUNT; - return commandPacket; -} - -//==================================================================================== - -*/ diff --git a/Generals/Code/GameEngine/Source/GameNetwork/NetPacket.cpp b/Generals/Code/GameEngine/Source/GameNetwork/NetPacket.cpp deleted file mode 100644 index 56f4bed686..0000000000 --- a/Generals/Code/GameEngine/Source/GameNetwork/NetPacket.cpp +++ /dev/null @@ -1,5964 +0,0 @@ -/* -** 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. // -// // -//////////////////////////////////////////////////////////////////////////////// - -////////// NetPacket.cpp /////////////////////////// - -#include "PreRTS.h" // This must go first in EVERY cpp file in the GameEngine - -#include "GameNetwork/NetPacket.h" -#include "GameNetwork/NetCommandMsg.h" -#include "GameNetwork/NetworkDefs.h" -#include "GameNetwork/networkutil.h" -#include "GameNetwork/GameMessageParser.h" - -// TheSuperHackers @refactor BobTista 10/06/2025 Extract magic character literals into named constants for improved readability -typedef UnsignedByte NetPacketFieldType; - -namespace NetPacketFieldTypes { - constexpr const NetPacketFieldType CommandType = 'T'; // NetCommandType field - constexpr const NetPacketFieldType Relay = 'R'; // Relay field - constexpr const NetPacketFieldType PlayerId = 'P'; // Player ID field - constexpr const NetPacketFieldType CommandId = 'C'; // Command ID field - constexpr const NetPacketFieldType Frame = 'F'; // Frame field - constexpr const NetPacketFieldType Data = 'D'; // Data payload field -} - -// This function assumes that all of the fields are either of default value or are -// present in the raw data. -NetCommandRef * NetPacket::ConstructNetCommandMsgFromRawData(UnsignedByte *data, UnsignedShort dataLength) { - NetCommandType commandType = NETCOMMANDTYPE_GAMECOMMAND; - UnsignedShort commandID = 0; - UnsignedInt frame = 0; - UnsignedByte playerID = 0; - UnsignedByte relay = 0; - - Int offset = 0; - NetCommandRef *ref = NULL; - NetCommandMsg *msg = NULL; - - while (offset < (Int)dataLength) { - - switch (data[offset]) { - - case NetPacketFieldTypes::CommandType: - ++offset; - memcpy(&commandType, data + offset, sizeof(UnsignedByte)); - offset += sizeof(UnsignedByte); - break; - - case NetPacketFieldTypes::Relay: - ++offset; - memcpy(&relay, data + offset, sizeof(UnsignedByte)); - offset += sizeof(UnsignedByte); - break; - - case NetPacketFieldTypes::PlayerId: - ++offset; - memcpy(&playerID, data + offset, sizeof(UnsignedByte)); - offset += sizeof(UnsignedByte); - break; - - case NetPacketFieldTypes::CommandId: - ++offset; - memcpy(&commandID, data + offset, sizeof(UnsignedShort)); - offset += sizeof(UnsignedShort); - break; - - case NetPacketFieldTypes::Frame: - ++offset; - memcpy(&frame, data + offset, sizeof(UnsignedInt)); - offset += sizeof(UnsignedInt); - break; - - case NetPacketFieldTypes::Data: - ++offset; - - switch (commandType) { - - case NETCOMMANDTYPE_GAMECOMMAND: - msg = readGameMessage(data, offset); - break; - case NETCOMMANDTYPE_ACKBOTH: - msg = readAckBothMessage(data, offset); - break; - case NETCOMMANDTYPE_ACKSTAGE1: - msg = readAckStage1Message(data, offset); - break; - case NETCOMMANDTYPE_ACKSTAGE2: - msg = readAckStage2Message(data, offset); - break; - case NETCOMMANDTYPE_FRAMEINFO: - msg = readFrameMessage(data, offset); - break; - case NETCOMMANDTYPE_PLAYERLEAVE: - msg = readPlayerLeaveMessage(data, offset); - break; - case NETCOMMANDTYPE_RUNAHEADMETRICS: - msg = readRunAheadMetricsMessage(data, offset); - break; - case NETCOMMANDTYPE_RUNAHEAD: - msg = readRunAheadMessage(data, offset); - break; - case NETCOMMANDTYPE_DESTROYPLAYER: - msg = readDestroyPlayerMessage(data, offset); - break; - case NETCOMMANDTYPE_KEEPALIVE: - msg = readKeepAliveMessage(data, offset); - break; - case NETCOMMANDTYPE_DISCONNECTKEEPALIVE: - msg = readDisconnectKeepAliveMessage(data, offset); - break; - case NETCOMMANDTYPE_DISCONNECTPLAYER: - msg = readDisconnectPlayerMessage(data, offset); - break; - case NETCOMMANDTYPE_PACKETROUTERQUERY: - msg = readPacketRouterQueryMessage(data, offset); - break; - case NETCOMMANDTYPE_PACKETROUTERACK: - msg = readPacketRouterAckMessage(data, offset); - break; - case NETCOMMANDTYPE_DISCONNECTCHAT: - msg = readDisconnectChatMessage(data, offset); - break; - case NETCOMMANDTYPE_DISCONNECTVOTE: - msg = readDisconnectVoteMessage(data, offset); - break; - case NETCOMMANDTYPE_CHAT: - msg = readChatMessage(data, offset); - break; - case NETCOMMANDTYPE_PROGRESS: - msg = readProgressMessage(data, offset); - break; - case NETCOMMANDTYPE_LOADCOMPLETE: - msg = readLoadCompleteMessage(data, offset); - break; - case NETCOMMANDTYPE_TIMEOUTSTART: - msg = readTimeOutGameStartMessage(data, offset); - break; - case NETCOMMANDTYPE_WRAPPER: - msg = readWrapperMessage(data, offset); - break; - case NETCOMMANDTYPE_FILE: - msg = readFileMessage(data, offset); - break; - case NETCOMMANDTYPE_FILEANNOUNCE: - msg = readFileAnnounceMessage(data, offset); - break; - case NETCOMMANDTYPE_FILEPROGRESS: - msg = readFileProgressMessage(data, offset); - break; - case NETCOMMANDTYPE_DISCONNECTFRAME: - msg = readDisconnectFrameMessage(data, offset); - break; - case NETCOMMANDTYPE_DISCONNECTSCREENOFF: - msg = readDisconnectScreenOffMessage(data, offset); - break; - case NETCOMMANDTYPE_FRAMERESENDREQUEST: - msg = readFrameResendRequestMessage(data, offset); - break; - - } - - msg->setExecutionFrame(frame); - msg->setID(commandID); - msg->setPlayerID(playerID); - msg->setNetCommandType(commandType); - - ref = NEW_NETCOMMANDREF(msg); - - ref->setRelay(relay); - - msg->detach(); - msg = NULL; - - return ref; - - } - - } - - return ref; -} - -NetPacketList NetPacket::ConstructBigCommandPacketList(NetCommandRef *ref) { - // if we don't have a unique command ID, then the wrapped command cannot - // be identified. Therefore don't allow commands without a unique ID to - // be wrapped. - NetCommandMsg *msg = ref->getCommand(); - - if (!DoesCommandRequireACommandID(msg->getNetCommandType())) { - DEBUG_CRASH(("Trying to wrap a command that doesn't have a unique command ID")); - return NetPacketList(); - } - - UnsignedInt bufferSize = GetBufferSizeNeededForCommand(msg); // need to implement. I have a drinking problem. - UnsignedByte *bigPacketData = NULL; - - NetPacketList packetList; - - // create the buffer for the huge message and fill the buffer with that message. - UnsignedInt bigPacketCurrentOffset = 0; - bigPacketData = NEW UnsignedByte[bufferSize]; - FillBufferWithCommand(bigPacketData, ref); - - // create the wrapper command message we'll be using. - NetWrapperCommandMsg *wrapperMsg = newInstance(NetWrapperCommandMsg); - // get the amount of space needed for the wrapper message, not including the wrapped command data. - UnsignedInt wrapperSize = GetBufferSizeNeededForCommand(wrapperMsg); - UnsignedInt commandSizePerPacket = MAX_PACKET_SIZE - wrapperSize; - - UnsignedInt numChunks = bufferSize / commandSizePerPacket; - if ((bufferSize % commandSizePerPacket) > 0) { - ++numChunks; - } - UnsignedInt currentChunk = 0; - - // create the packets and the wrapper messages. - while (currentChunk < numChunks) { - NetPacket *packet = newInstance(NetPacket); - - UnsignedShort dataSizeThisPacket = commandSizePerPacket; - if ((bufferSize - bigPacketCurrentOffset) < dataSizeThisPacket) { - dataSizeThisPacket = bufferSize - bigPacketCurrentOffset; - } - - if (DoesCommandRequireACommandID(wrapperMsg->getNetCommandType())) { - wrapperMsg->setID(GenerateNextCommandID()); - } - wrapperMsg->setPlayerID(msg->getPlayerID()); - wrapperMsg->setExecutionFrame(msg->getExecutionFrame()); - - wrapperMsg->setChunkNumber(currentChunk); - wrapperMsg->setNumChunks(numChunks); - wrapperMsg->setDataOffset(bigPacketCurrentOffset); - wrapperMsg->setData(bigPacketData + bigPacketCurrentOffset, dataSizeThisPacket); - wrapperMsg->setTotalDataLength(bufferSize); - wrapperMsg->setWrappedCommandID(msg->getID()); - - bigPacketCurrentOffset += dataSizeThisPacket; - - NetCommandRef * ref = NEW_NETCOMMANDREF(wrapperMsg); - ref->setRelay(ref->getRelay()); - - if (packet->addCommand(ref) == FALSE) { - DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("NetPacket::BeginBigCommandPacketList - failed to add a wrapper command to the packet")); // I still have a drinking problem. - } - - packetList.push_back(packet); - - deleteInstance(ref); - ref = NULL; - - ++currentChunk; - } - wrapperMsg->detach(); - wrapperMsg = NULL; - - delete[] bigPacketData; - bigPacketData = NULL; - - return packetList; -} - -UnsignedInt NetPacket::GetBufferSizeNeededForCommand(NetCommandMsg *msg) { - // This is where the fun begins... - - if (msg == NULL) { - return TRUE; // There was nothing to add, so it was successful. - } - - switch(msg->getNetCommandType()) - { - case NETCOMMANDTYPE_GAMECOMMAND: - return GetGameCommandSize(msg); - case NETCOMMANDTYPE_ACKSTAGE1: - case NETCOMMANDTYPE_ACKSTAGE2: - case NETCOMMANDTYPE_ACKBOTH: - return GetAckCommandSize(msg); - case NETCOMMANDTYPE_FRAMEINFO: - return GetFrameCommandSize(msg); - case NETCOMMANDTYPE_PLAYERLEAVE: - return GetPlayerLeaveCommandSize(msg); - case NETCOMMANDTYPE_RUNAHEADMETRICS: - return GetRunAheadMetricsCommandSize(msg); - case NETCOMMANDTYPE_RUNAHEAD: - return GetRunAheadCommandSize(msg); - case NETCOMMANDTYPE_DESTROYPLAYER: - return GetDestroyPlayerCommandSize(msg); - case NETCOMMANDTYPE_KEEPALIVE: - return GetKeepAliveCommandSize(msg); - case NETCOMMANDTYPE_DISCONNECTKEEPALIVE: - return GetDisconnectKeepAliveCommandSize(msg); - case NETCOMMANDTYPE_DISCONNECTPLAYER: - return GetDisconnectPlayerCommandSize(msg); - case NETCOMMANDTYPE_PACKETROUTERQUERY: - return GetPacketRouterQueryCommandSize(msg); - case NETCOMMANDTYPE_PACKETROUTERACK: - return GetPacketRouterAckCommandSize(msg); - case NETCOMMANDTYPE_DISCONNECTCHAT: - return GetDisconnectChatCommandSize(msg); - case NETCOMMANDTYPE_DISCONNECTVOTE: - return GetDisconnectVoteCommandSize(msg); - case NETCOMMANDTYPE_CHAT: - return GetChatCommandSize(msg); - case NETCOMMANDTYPE_PROGRESS: - return GetProgressMessageSize(msg); - case NETCOMMANDTYPE_LOADCOMPLETE: - return GetLoadCompleteMessageSize(msg); - case NETCOMMANDTYPE_TIMEOUTSTART: - return GetTimeOutGameStartMessageSize(msg); - case NETCOMMANDTYPE_WRAPPER: - return GetWrapperCommandSize(msg); - case NETCOMMANDTYPE_FILE: - return GetFileCommandSize(msg); - case NETCOMMANDTYPE_FILEANNOUNCE: - return GetFileAnnounceCommandSize(msg); - case NETCOMMANDTYPE_FILEPROGRESS: - return GetFileProgressCommandSize(msg); - case NETCOMMANDTYPE_DISCONNECTFRAME: - return GetDisconnectFrameCommandSize(msg); - case NETCOMMANDTYPE_DISCONNECTSCREENOFF: - return GetDisconnectScreenOffCommandSize(msg); - case NETCOMMANDTYPE_FRAMERESENDREQUEST: - return GetFrameResendRequestCommandSize(msg); - default: - DEBUG_CRASH(("Unknown NETCOMMANDTYPE %d", msg->getNetCommandType())); - break; - } - - return 0; -} - -UnsignedInt NetPacket::GetGameCommandSize(NetCommandMsg *msg) { - NetGameCommandMsg *cmdMsg = (NetGameCommandMsg *)msg; - - UnsignedShort msglen = 0; - msglen += sizeof(UnsignedInt) + sizeof(UnsignedByte); // frame number - msglen += sizeof(UnsignedByte) + sizeof(UnsignedByte); // player ID - msglen += sizeof(UnsignedByte) + sizeof(UnsignedByte); // relay - msglen += sizeof(UnsignedByte) + sizeof(UnsignedByte); // command type - msglen += sizeof(UnsignedShort) + sizeof(UnsignedByte); // command ID - msglen += sizeof(UnsignedByte); // the NetPacketFieldTypes::Data for the data section. - - GameMessage *gmsg = cmdMsg->constructGameMessage(); - GameMessageParser *parser = newInstance(GameMessageParser)(gmsg); - - msglen += sizeof(GameMessage::Type); - msglen += sizeof(UnsignedByte); -// Int numTypes = parser->getNumTypes(); - GameMessageParserArgumentType *arg = parser->getFirstArgumentType(); - while (arg != NULL) { - msglen += 2 * sizeof(UnsignedByte); // for the type and number of args of that type declaration. - GameMessageArgumentDataType type = arg->getType(); - - switch (type) { - - case ARGUMENTDATATYPE_INTEGER: - msglen += arg->getArgCount() * sizeof(Int); - break; - case ARGUMENTDATATYPE_REAL: - msglen += arg->getArgCount() * sizeof(Real); - break; - case ARGUMENTDATATYPE_BOOLEAN: - msglen += arg->getArgCount() * sizeof(Bool); - break; - case ARGUMENTDATATYPE_OBJECTID: - msglen += arg->getArgCount() * sizeof(ObjectID); - break; - case ARGUMENTDATATYPE_DRAWABLEID: - msglen += arg->getArgCount() * sizeof(DrawableID); - break; - case ARGUMENTDATATYPE_TEAMID: - msglen += arg->getArgCount() * sizeof(UnsignedInt); - break; - case ARGUMENTDATATYPE_LOCATION: - msglen += arg->getArgCount() * sizeof(Coord3D); - break; - case ARGUMENTDATATYPE_PIXEL: - msglen += arg->getArgCount() * sizeof(ICoord2D); - break; - case ARGUMENTDATATYPE_PIXELREGION: - msglen += arg->getArgCount() * sizeof(IRegion2D); - break; - case ARGUMENTDATATYPE_TIMESTAMP: - msglen += arg->getArgCount() * sizeof(UnsignedInt); - break; - case ARGUMENTDATATYPE_WIDECHAR: - msglen += arg->getArgCount() * sizeof(WideChar); - break; - - } - - arg = arg->getNext(); - } - - deleteInstance(parser); - parser = NULL; - - deleteInstance(gmsg); - gmsg = NULL; - - return msglen; -} - -UnsignedInt NetPacket::GetAckCommandSize(NetCommandMsg *msg) { - Int msglen = 0; - ++msglen; - msglen += sizeof(UnsignedByte); - ++msglen; - msglen += sizeof(UnsignedByte); - - ++msglen; - msglen += sizeof(UnsignedShort); - msglen += sizeof(UnsignedByte); - - return msglen; -} - -UnsignedInt NetPacket::GetFrameCommandSize(NetCommandMsg *msg) { - Int msglen = 0; - ++msglen; - msglen += sizeof(UnsignedByte); - msglen += sizeof(UnsignedInt) + sizeof(UnsignedByte); - msglen += sizeof(UnsignedByte) + sizeof(UnsignedByte); - ++msglen; - msglen += sizeof(UnsignedByte); - msglen += sizeof(UnsignedShort) + sizeof(UnsignedByte); - - ++msglen; - msglen += sizeof(UnsignedShort); - - return msglen; -} - -UnsignedInt NetPacket::GetPlayerLeaveCommandSize(NetCommandMsg *msg) { - Int msglen = 0; - - ++msglen; - msglen += sizeof(UnsignedByte); - msglen += sizeof(UnsignedByte) + sizeof(UnsignedByte); - msglen += sizeof(UnsignedInt) + sizeof(UnsignedByte); - ++msglen; - msglen += sizeof(UnsignedByte); - msglen += sizeof(UnsignedShort) + sizeof(UnsignedByte); - - ++msglen; - msglen += sizeof(UnsignedByte); - - return msglen; -} - -UnsignedInt NetPacket::GetRunAheadMetricsCommandSize(NetCommandMsg *msg) { - Int msglen = 0; - - ++msglen; - msglen += sizeof(UnsignedByte); - msglen += sizeof(UnsignedByte) + sizeof(UnsignedByte); - ++msglen; - msglen += sizeof(UnsignedByte); - msglen += sizeof(UnsignedShort) + sizeof(UnsignedByte); - - ++msglen; - msglen += sizeof(UnsignedByte); - msglen += sizeof(Real); - - return msglen; -} - -UnsignedInt NetPacket::GetRunAheadCommandSize(NetCommandMsg *msg) { - Int msglen = 0; - - ++msglen; - msglen += sizeof(UnsignedByte); - msglen += sizeof(UnsignedByte) + sizeof(UnsignedByte); - msglen += sizeof(UnsignedInt) + sizeof(UnsignedByte); - ++msglen; - msglen += sizeof(UnsignedByte); - msglen += sizeof(UnsignedShort) + sizeof(UnsignedByte); - - ++msglen; - msglen += sizeof(UnsignedShort); - msglen += sizeof(UnsignedByte); - - return msglen; -} - -UnsignedInt NetPacket::GetDestroyPlayerCommandSize(NetCommandMsg *msg) { - Int msglen = 0; - - ++msglen; - msglen += sizeof(UnsignedByte); - msglen += sizeof(UnsignedByte) + sizeof(UnsignedByte); - msglen += sizeof(UnsignedInt) + sizeof(UnsignedByte); - ++msglen; - msglen += sizeof(UnsignedByte); - msglen += sizeof(UnsignedShort) + sizeof(UnsignedByte); - - ++msglen; - msglen += sizeof(UnsignedInt); - - return msglen; -} - -UnsignedInt NetPacket::GetKeepAliveCommandSize(NetCommandMsg *msg) { - Int msglen = 0; - - ++msglen; - msglen += sizeof(UnsignedByte); - msglen += sizeof(UnsignedByte) + sizeof(UnsignedByte); - ++msglen; - msglen += sizeof(UnsignedByte); - - ++msglen; // For the NetPacketFieldTypes::Data - - return msglen; -} - -UnsignedInt NetPacket::GetDisconnectKeepAliveCommandSize(NetCommandMsg *msg) { - Int msglen = 0; - - ++msglen; - msglen += sizeof(UnsignedByte); - msglen += sizeof(UnsignedByte) + sizeof(UnsignedByte); - ++msglen; - msglen += sizeof(UnsignedByte); - - ++msglen; // For the NetPacketFieldTypes::Data - - return msglen; -} - -UnsignedInt NetPacket::GetDisconnectPlayerCommandSize(NetCommandMsg *msg) { - Int msglen = 0; - - ++msglen; - msglen += sizeof(UnsignedByte); - msglen += sizeof(UnsignedByte) + sizeof(UnsignedByte); - ++msglen; - msglen += sizeof(UnsignedByte); - msglen += sizeof(UnsignedShort) + sizeof(UnsignedByte); - - ++msglen; // the NetPacketFieldTypes::Data - msglen += sizeof(UnsignedByte); // slot number - msglen += sizeof(UnsignedInt); // disconnect frame - - return msglen; -} - -UnsignedInt NetPacket::GetPacketRouterQueryCommandSize(NetCommandMsg *msg) { - Int msglen = 0; - - ++msglen; - msglen += sizeof(UnsignedByte); - msglen += sizeof(UnsignedByte) + sizeof(UnsignedByte); - ++msglen; - msglen += sizeof(UnsignedByte); - - ++msglen; // the NetPacketFieldTypes::Data - - return msglen; -} - -UnsignedInt NetPacket::GetPacketRouterAckCommandSize(NetCommandMsg *msg) { - Int msglen = 0; - - ++msglen; - msglen += sizeof(UnsignedByte); - msglen += sizeof(UnsignedByte) + sizeof(UnsignedByte); - ++msglen; - msglen += sizeof(UnsignedByte); - - ++msglen; // the NetPacketFieldTypes::Data - - return msglen; -} - -UnsignedInt NetPacket::GetDisconnectChatCommandSize(NetCommandMsg *msg) { - Int msglen = 0; - NetDisconnectChatCommandMsg *cmdMsg = (NetDisconnectChatCommandMsg *)(msg); - - ++msglen; - msglen += sizeof(UnsignedByte); - msglen += sizeof(UnsignedByte) + sizeof(UnsignedByte); - ++msglen; - msglen += sizeof(UnsignedByte); - - ++msglen; // the NetPacketFieldTypes::Data - msglen += sizeof(UnsignedByte); // string msglength - UnsignedByte textmsglen = cmdMsg->getText().getLength(); - msglen += textmsglen * sizeof(UnsignedShort); - - return msglen; -} - -UnsignedInt NetPacket::GetDisconnectVoteCommandSize(NetCommandMsg *msg) { - Int msglen = 0; - - ++msglen; - msglen += sizeof(UnsignedByte); - msglen += sizeof(UnsignedByte) + sizeof(UnsignedByte); - ++msglen; - msglen += sizeof(UnsignedByte); - msglen += sizeof(UnsignedShort) + sizeof(UnsignedByte); - - ++msglen; // the NetPacketFieldTypes::Data - msglen += sizeof(UnsignedByte); // slot number - msglen += sizeof(UnsignedInt); // vote frame. - - return msglen; -} - -UnsignedInt NetPacket::GetChatCommandSize(NetCommandMsg *msg) { - Int msglen = 0; - NetChatCommandMsg *cmdMsg = (NetChatCommandMsg *)(msg); - - ++msglen; - msglen += sizeof(UnsignedByte); - msglen += sizeof(UnsignedInt) + sizeof(UnsignedByte); - msglen += sizeof(UnsignedByte) + sizeof(UnsignedByte); - ++msglen; - msglen += sizeof(UnsignedByte); - msglen += sizeof(UnsignedShort) + sizeof(UnsignedByte); - - ++msglen; // the NetPacketFieldTypes::Data - msglen += sizeof(UnsignedByte); // string msglength - UnsignedByte textmsglen = cmdMsg->getText().getLength(); - msglen += textmsglen * sizeof(UnsignedShort); - msglen += sizeof(Int); // playerMask - - return msglen; -} - -UnsignedInt NetPacket::GetProgressMessageSize(NetCommandMsg *msg) { - Int msglen = 0; - - ++msglen; - msglen += sizeof(UnsignedByte); - msglen += sizeof(UnsignedByte) + sizeof(UnsignedByte); - ++msglen; - msglen += sizeof(UnsignedByte); - - ++msglen; // For the NetPacketFieldTypes::Data - ++msglen; // percentage - - return msglen; -} - -UnsignedInt NetPacket::GetLoadCompleteMessageSize(NetCommandMsg *msg) { - Int msglen = 0; - - ++msglen; - msglen += sizeof(UnsignedByte); - msglen += sizeof(UnsignedByte) + sizeof(UnsignedByte); - ++msglen; - msglen += sizeof(UnsignedByte); - - ++msglen; // For the NetPacketFieldTypes::Data - - return msglen; -} - -UnsignedInt NetPacket::GetTimeOutGameStartMessageSize(NetCommandMsg *msg) { - Int msglen = 0; - - ++msglen; - msglen += sizeof(UnsignedByte); - msglen += sizeof(UnsignedByte) + sizeof(UnsignedByte); - ++msglen; - msglen += sizeof(UnsignedByte); - - ++msglen; // For the NetPacketFieldTypes::Data - - return msglen; -} - -// type, player, ID, relay, Data -UnsignedInt NetPacket::GetWrapperCommandSize(NetCommandMsg *msg) { - UnsignedInt msglen = 0; - - ++msglen; // NetPacketFieldTypes::CommandType - msglen += sizeof(UnsignedByte); // command type - msglen += sizeof(UnsignedByte) + sizeof(UnsignedByte); // NetPacketFieldTypes::PlayerId and player ID - msglen += sizeof(UnsignedByte) + sizeof(UnsignedShort); // NetPacketFieldTypes::CommandId and command ID - msglen += sizeof(UnsignedByte) + sizeof(UnsignedByte); // NetPacketFieldTypes::Relay and relay - ++msglen; // NetPacketFieldTypes::Data - - msglen += sizeof(UnsignedShort); // m_wrappedCommandID - msglen += sizeof(UnsignedInt); // m_chunkNumber - msglen += sizeof(UnsignedInt); // m_numChunks - msglen += sizeof(UnsignedInt); // m_totalDataLength - msglen += sizeof(UnsignedInt); // m_dataLength - msglen += sizeof(UnsignedInt); // m_dataOffset - - return msglen; -} - -UnsignedInt NetPacket::GetFileCommandSize(NetCommandMsg *msg) { - NetFileCommandMsg *filemsg = (NetFileCommandMsg *)msg; - UnsignedInt msglen = 0; - msglen += sizeof(UnsignedByte) + sizeof(UnsignedByte); // NetPacketFieldTypes::CommandType and command type - msglen += sizeof(UnsignedByte) + sizeof(UnsignedByte); // NetPacketFieldTypes::PlayerId and player ID - msglen += sizeof(UnsignedByte) + sizeof(UnsignedShort); // NetPacketFieldTypes::CommandId and command ID - msglen += sizeof(UnsignedByte) + sizeof(UnsignedByte); // NetPacketFieldTypes::Relay and relay - - ++msglen; // NetPacketFieldTypes::Data - - msglen += filemsg->getPortableFilename().getLength() + 1; // PORTABLE filename and the terminating 0 - msglen += sizeof(UnsignedInt); // file data length - msglen += filemsg->getFileLength(); // the file data - - return msglen; -} - -UnsignedInt NetPacket::GetFileAnnounceCommandSize(NetCommandMsg *msg) { - NetFileAnnounceCommandMsg *filemsg = (NetFileAnnounceCommandMsg *)msg; - UnsignedInt msglen = 0; - msglen += sizeof(UnsignedByte) + sizeof(UnsignedByte); // NetPacketFieldTypes::CommandType and command type - msglen += sizeof(UnsignedByte) + sizeof(UnsignedByte); // NetPacketFieldTypes::PlayerId and player ID - msglen += sizeof(UnsignedByte) + sizeof(UnsignedShort); // NetPacketFieldTypes::CommandId and command ID - msglen += sizeof(UnsignedByte) + sizeof(UnsignedByte); // NetPacketFieldTypes::Relay and relay - - ++msglen; // NetPacketFieldTypes::Data - - msglen += filemsg->getPortableFilename().getLength() + 1; // PORTABLE filename and the terminating 0 - msglen += sizeof(UnsignedShort); // m_fileID - msglen += sizeof(UnsignedByte); // m_playerMask - - return msglen; -} - -UnsignedInt NetPacket::GetFileProgressCommandSize(NetCommandMsg *msg) { - UnsignedInt msglen = 0; - msglen += sizeof(UnsignedByte) + sizeof(UnsignedByte); // NetPacketFieldTypes::CommandType and command type - msglen += sizeof(UnsignedByte) + sizeof(UnsignedByte); // NetPacketFieldTypes::PlayerId and player ID - msglen += sizeof(UnsignedByte) + sizeof(UnsignedShort); // NetPacketFieldTypes::CommandId and command ID - msglen += sizeof(UnsignedByte) + sizeof(UnsignedByte); // NetPacketFieldTypes::Relay and relay - - ++msglen; // NetPacketFieldTypes::Data - - msglen += sizeof(UnsignedShort); // m_fileID - msglen += sizeof(Int); // m_progress - - return msglen; -} - -UnsignedInt NetPacket::GetDisconnectFrameCommandSize(NetCommandMsg *msg) { - UnsignedInt msglen = 0; - msglen += sizeof(UnsignedByte) + sizeof(UnsignedByte); // NetPacketFieldTypes::CommandType and command type - msglen += sizeof(UnsignedByte) + sizeof(UnsignedByte); // NetPacketFieldTypes::PlayerId and player ID - msglen += sizeof(UnsignedByte) + sizeof(UnsignedShort); // NetPacketFieldTypes::CommandId and command ID - msglen += sizeof(UnsignedByte) + sizeof(UnsignedByte); // NetPacketFieldTypes::Relay and relay - - ++msglen; // NetPacketFieldTypes::Data - msglen += sizeof(UnsignedInt); // disconnect frame - - return msglen; -} - -UnsignedInt NetPacket::GetDisconnectScreenOffCommandSize(NetCommandMsg *msg) { - UnsignedInt msglen = 0; - msglen += sizeof(UnsignedByte) + sizeof(UnsignedByte); // NetPacketFieldTypes::CommandType and command type - msglen += sizeof(UnsignedByte) + sizeof(UnsignedByte); // NetPacketFieldTypes::PlayerId and player ID - msglen += sizeof(UnsignedByte) + sizeof(UnsignedShort); // NetPacketFieldTypes::CommandId and command ID - msglen += sizeof(UnsignedByte) + sizeof(UnsignedByte); // NetPacketFieldTypes::Relay and relay - - ++msglen; // NetPacketFieldTypes::Data - msglen += sizeof(UnsignedInt); // new frame - - return msglen; -} - -UnsignedInt NetPacket::GetFrameResendRequestCommandSize(NetCommandMsg *msg) { - UnsignedInt msglen = 0; - msglen += sizeof(UnsignedByte) + sizeof(UnsignedByte); // NetPacketFieldTypes::CommandType and command type - msglen += sizeof(UnsignedByte) + sizeof(UnsignedByte); // NetPacketFieldTypes::PlayerId and player ID - msglen += sizeof(UnsignedByte) + sizeof(UnsignedShort); // NetPacketFieldTypes::CommandId and command ID - msglen += sizeof(UnsignedByte) + sizeof(UnsignedByte); // NetPacketFieldTypes::Relay and relay - - ++msglen; // NetPacketFieldTypes::Data - msglen += sizeof(UnsignedInt); // frame to resend - - return msglen; -} - -// this function assumes that buffer is already the correct size. -void NetPacket::FillBufferWithCommand(UnsignedByte *buffer, NetCommandRef *ref) { - NetCommandMsg *msg = ref->getCommand(); - - switch(msg->getNetCommandType()) - { - case NETCOMMANDTYPE_GAMECOMMAND: - FillBufferWithGameCommand(buffer, ref); - break; - case NETCOMMANDTYPE_ACKSTAGE1: - case NETCOMMANDTYPE_ACKSTAGE2: - case NETCOMMANDTYPE_ACKBOTH: - FillBufferWithAckCommand(buffer, ref); - break; - case NETCOMMANDTYPE_FRAMEINFO: - FillBufferWithFrameCommand(buffer, ref); - break; - case NETCOMMANDTYPE_PLAYERLEAVE: - FillBufferWithPlayerLeaveCommand(buffer, ref); - break; - case NETCOMMANDTYPE_RUNAHEADMETRICS: - FillBufferWithRunAheadMetricsCommand(buffer, ref); - break; - case NETCOMMANDTYPE_RUNAHEAD: - FillBufferWithRunAheadCommand(buffer, ref); - break; - case NETCOMMANDTYPE_DESTROYPLAYER: - FillBufferWithDestroyPlayerCommand(buffer, ref); - break; - case NETCOMMANDTYPE_KEEPALIVE: - FillBufferWithKeepAliveCommand(buffer, ref); - break; - case NETCOMMANDTYPE_DISCONNECTKEEPALIVE: - FillBufferWithDisconnectKeepAliveCommand(buffer, ref); - break; - case NETCOMMANDTYPE_DISCONNECTPLAYER: - FillBufferWithDisconnectPlayerCommand(buffer, ref); - break; - case NETCOMMANDTYPE_PACKETROUTERQUERY: - FillBufferWithPacketRouterQueryCommand(buffer, ref); - break; - case NETCOMMANDTYPE_PACKETROUTERACK: - FillBufferWithPacketRouterAckCommand(buffer, ref); - break; - case NETCOMMANDTYPE_DISCONNECTCHAT: - FillBufferWithDisconnectChatCommand(buffer, ref); - break; - case NETCOMMANDTYPE_DISCONNECTVOTE: - FillBufferWithDisconnectVoteCommand(buffer, ref); - break; - case NETCOMMANDTYPE_CHAT: - FillBufferWithChatCommand(buffer, ref); - break; - case NETCOMMANDTYPE_PROGRESS: - FillBufferWithProgressMessage(buffer, ref); - break; - case NETCOMMANDTYPE_LOADCOMPLETE: - FillBufferWithLoadCompleteMessage(buffer, ref); - break; - case NETCOMMANDTYPE_TIMEOUTSTART: - FillBufferWithTimeOutGameStartMessage(buffer, ref); - break; - case NETCOMMANDTYPE_FILE: - FillBufferWithFileMessage(buffer, ref); - break; - case NETCOMMANDTYPE_FILEANNOUNCE: - FillBufferWithFileAnnounceMessage(buffer, ref); - break; - case NETCOMMANDTYPE_FILEPROGRESS: - FillBufferWithFileProgressMessage(buffer, ref); - break; - case NETCOMMANDTYPE_DISCONNECTFRAME: - FillBufferWithDisconnectFrameMessage(buffer, ref); - break; - case NETCOMMANDTYPE_DISCONNECTSCREENOFF: - FillBufferWithDisconnectScreenOffMessage(buffer, ref); - break; - case NETCOMMANDTYPE_FRAMERESENDREQUEST: - FillBufferWithFrameResendRequestMessage(buffer, ref); - break; - default: - DEBUG_CRASH(("Unknown NETCOMMANDTYPE %d", msg->getNetCommandType())); - break; - } -} - -void NetPacket::FillBufferWithGameCommand(UnsignedByte *buffer, NetCommandRef *msg) { - NetGameCommandMsg *cmdMsg = (NetGameCommandMsg *)(msg->getCommand()); - UnsignedShort offset = 0; - // get the game message from the NetCommandMsg - GameMessage *gmsg = cmdMsg->constructGameMessage(); - - //DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("NetPacket::FillBufferWithGameCommand for command ID %d", cmdMsg->getID())); - - // If necessary, put the NetCommandType into the packet. - buffer[offset] = NetPacketFieldTypes::CommandType; - ++offset; - buffer[offset] = cmdMsg->getNetCommandType(); - offset += sizeof(UnsignedByte); - - // If necessary, put the execution frame into the packet. - buffer[offset] = NetPacketFieldTypes::Frame; - ++offset; - UnsignedInt newframe = cmdMsg->getExecutionFrame(); - memcpy(buffer+offset, &newframe, sizeof(UnsignedInt)); - offset += sizeof(UnsignedInt); - - // If necessary, put the relay into the packet. - buffer[offset] = NetPacketFieldTypes::Relay; - ++offset; - UnsignedByte newRelay = msg->getRelay(); - memcpy(buffer+offset, &newRelay, sizeof(UnsignedByte)); - offset += sizeof(UnsignedByte); - - // If necessary, put the playerID into the packet. - buffer[offset] = NetPacketFieldTypes::PlayerId; - ++offset; - buffer[offset] = cmdMsg->getPlayerID(); - offset += sizeof(UnsignedByte); - - // If necessary, specify the command ID of this command. - buffer[offset] = NetPacketFieldTypes::CommandId; - ++offset; - UnsignedShort newID = cmdMsg->getID(); - memcpy(buffer + offset, &newID, sizeof(UnsignedShort)); - offset += sizeof(UnsignedShort); - - buffer[offset] = NetPacketFieldTypes::Data; - ++offset; - - // Now copy the GameMessage type into the packet. - GameMessage::Type newType = gmsg->getType(); - memcpy(buffer + offset, &newType, sizeof(GameMessage::Type)); - offset += sizeof(GameMessage::Type); - - - GameMessageParser *parser = newInstance(GameMessageParser)(gmsg); - UnsignedByte numTypes = parser->getNumTypes(); - memcpy(buffer + offset, &numTypes, sizeof(numTypes)); - offset += sizeof(numTypes); - - GameMessageParserArgumentType *argType = parser->getFirstArgumentType(); - while (argType != NULL) { - UnsignedByte type = (UnsignedByte)(argType->getType()); - memcpy(buffer + offset, &type, sizeof(type)); - offset += sizeof(type); - - UnsignedByte argTypeCount = argType->getArgCount(); - memcpy(buffer + offset, &argTypeCount, sizeof(argTypeCount)); - offset += sizeof(argTypeCount); - - argType = argType->getNext(); - } - - Int numArgs = gmsg->getArgumentCount(); - for (Int i = 0; i < numArgs; ++i) { - GameMessageArgumentDataType type = gmsg->getArgumentDataType(i); - GameMessageArgumentType arg = *(gmsg->getArgument(i)); - - switch (type) { - - case ARGUMENTDATATYPE_INTEGER: - memcpy(buffer + offset, &(arg.integer), sizeof(arg.integer)); - offset += sizeof(arg.integer); - break; - case ARGUMENTDATATYPE_REAL: - memcpy(buffer + offset, &(arg.real), sizeof(arg.real)); - offset += sizeof(arg.real); - break; - case ARGUMENTDATATYPE_BOOLEAN: - memcpy(buffer + offset, &(arg.boolean), sizeof(arg.boolean)); - offset += sizeof(arg.boolean); - break; - case ARGUMENTDATATYPE_OBJECTID: - memcpy(buffer + offset, &(arg.objectID), sizeof(arg.objectID)); - offset += sizeof(arg.objectID); - break; - case ARGUMENTDATATYPE_DRAWABLEID: - memcpy(buffer + offset, &(arg.drawableID), sizeof(arg.drawableID)); - offset += sizeof(arg.drawableID); - break; - case ARGUMENTDATATYPE_TEAMID: - memcpy(buffer + offset, &(arg.teamID), sizeof(arg.teamID)); - offset += sizeof(arg.teamID); - break; - case ARGUMENTDATATYPE_LOCATION: - memcpy(buffer + offset, &(arg.location), sizeof(arg.location)); - offset += sizeof(arg.location); - break; - case ARGUMENTDATATYPE_PIXEL: - memcpy(buffer + offset, &(arg.pixel), sizeof(arg.pixel)); - offset += sizeof(arg.pixel); - break; - case ARGUMENTDATATYPE_PIXELREGION: - memcpy(buffer + offset, &(arg.pixelRegion), sizeof(arg.pixelRegion)); - offset += sizeof(arg.pixelRegion); - break; - case ARGUMENTDATATYPE_TIMESTAMP: - memcpy(buffer + offset, &(arg.timestamp), sizeof(arg.timestamp)); - offset += sizeof(arg.timestamp); - break; - case ARGUMENTDATATYPE_WIDECHAR: - memcpy(buffer + offset, &(arg.wChar), sizeof(arg.wChar)); - offset += sizeof(arg.wChar); - break; - } - - } - - deleteInstance(parser); - parser = NULL; - -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("NetPacket::addGameMessage - added game message, frame %d, player %d, command ID %d", m_lastFrame, m_lastPlayerID, m_lastCommandID)); - - deleteInstance(gmsg); - gmsg = NULL; -} - -void NetPacket::FillBufferWithAckCommand(UnsignedByte *buffer, NetCommandRef *msg) { -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("NetPacket::FillBufferWithAckCommand - adding ack for command %d for player %d", cmdMsg->getCommandID(), msg->getCommand()->getPlayerID())); - - NetCommandMsg *cmdMsg = msg->getCommand(); - UnsignedShort offset = 0; - - UnsignedShort commandID = 0; - UnsignedByte originalPlayerID = 0; - - NetCommandType type = cmdMsg->getNetCommandType(); - - switch (type) { - - case NETCOMMANDTYPE_ACKBOTH: { - NetAckBothCommandMsg* ackbothmsg = (NetAckBothCommandMsg*)msg; - commandID = ackbothmsg->getCommandID(); - originalPlayerID = ackbothmsg->getOriginalPlayerID(); - break; - } - - case NETCOMMANDTYPE_ACKSTAGE1: { - NetAckStage1CommandMsg* ackstageonemsg = (NetAckStage1CommandMsg*)msg; - commandID = ackstageonemsg->getCommandID(); - originalPlayerID = ackstageonemsg->getOriginalPlayerID(); - break; - } - - case NETCOMMANDTYPE_ACKSTAGE2: { - NetAckStage2CommandMsg* ackstagetwomsg = (NetAckStage2CommandMsg*)msg; - commandID = ackstagetwomsg->getCommandID(); - originalPlayerID = ackstagetwomsg->getOriginalPlayerID(); - break; - } - - } - - buffer[offset] = NetPacketFieldTypes::CommandType; - ++offset; - buffer[offset] = type; - offset += sizeof(UnsignedByte); - - buffer[offset] = NetPacketFieldTypes::PlayerId; - ++offset; - buffer[offset] = cmdMsg->getPlayerID(); - offset += sizeof(UnsignedByte); - - // Put in the command id of the command we are acking. - buffer[offset] = NetPacketFieldTypes::Data; - ++offset; - memcpy(buffer + offset, &commandID, sizeof(UnsignedShort)); - offset += sizeof(UnsignedShort); - memcpy(buffer + offset, &originalPlayerID, sizeof(UnsignedByte)); - offset += sizeof(UnsignedByte); - - // DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("outgoing - added ACK, original player %d, command id %d", origPlayerID, cmdID)); -} - -void NetPacket::FillBufferWithFrameCommand(UnsignedByte *buffer, NetCommandRef *msg) { - NetFrameCommandMsg *cmdMsg = (NetFrameCommandMsg *)(msg->getCommand()); - UnsignedShort offset = 0; - // DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("NetPacket::addFrameCommand - adding frame command for frame %d, command count = %d, command id = %d", cmdMsg->getExecutionFrame(), cmdMsg->getCommandCount(), cmdMsg->getID())); - -// If necessary, put the NetCommandType into the packet. - buffer[offset] = NetPacketFieldTypes::CommandType; - ++offset; - buffer[offset] = cmdMsg->getNetCommandType(); - offset += sizeof(UnsignedByte); - -// If necessary, put the execution frame into the packet. - buffer[offset] = NetPacketFieldTypes::Frame; - ++offset; - UnsignedInt newframe = cmdMsg->getExecutionFrame(); - memcpy(buffer+offset, &newframe, sizeof(UnsignedInt)); - offset += sizeof(UnsignedInt); - -// If necessary, put the relay into the packet. - buffer[offset] = NetPacketFieldTypes::Relay; - ++offset; - UnsignedByte newRelay = msg->getRelay(); - memcpy(buffer+offset, &newRelay, sizeof(UnsignedByte)); - offset += sizeof(UnsignedByte); - -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("relay = %d, ", m_lastRelay)); - - buffer[offset] = NetPacketFieldTypes::PlayerId; - ++offset; - buffer[offset] = cmdMsg->getPlayerID(); - offset += sizeof(UnsignedByte); - -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("player = %d", m_lastPlayerID)); - -// If necessary, specify the command ID of this command. - buffer[offset] = NetPacketFieldTypes::CommandId; - ++offset; - UnsignedShort newID = cmdMsg->getID(); - memcpy(buffer + offset, &newID, sizeof(UnsignedShort)); - offset += sizeof(UnsignedShort); - -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("command id = %d", m_lastCommandID)); - - buffer[offset] = NetPacketFieldTypes::Data; - ++offset; - UnsignedShort cmdCount = cmdMsg->getCommandCount(); - memcpy(buffer + offset, &cmdCount, sizeof(UnsignedShort)); - offset += sizeof(UnsignedShort); - - // frameinfodebug -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("outgoing - added frame %d, player %d, command count = %d, command id = %d", cmdMsg->getExecutionFrame(), cmdMsg->getPlayerID(), cmdMsg->getCommandCount(), cmdMsg->getID())); -} - -void NetPacket::FillBufferWithPlayerLeaveCommand(UnsignedByte *buffer, NetCommandRef *msg) { - NetPlayerLeaveCommandMsg *cmdMsg = (NetPlayerLeaveCommandMsg *)(msg->getCommand()); - UnsignedShort offset = 0; -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("NetPacket::addPlayerLeaveCommand - adding player leave command for player %d", cmdMsg->getLeavingPlayerID())); - - // If necessary, put the NetCommandType into the packet. - buffer[offset] = NetPacketFieldTypes::CommandType; - ++offset; - buffer[offset] = cmdMsg->getNetCommandType(); - offset += sizeof(UnsignedByte); - -// If necessary, put the relay into the packet. - buffer[offset] = NetPacketFieldTypes::Relay; - ++offset; - UnsignedByte newRelay = msg->getRelay(); - memcpy(buffer+offset, &newRelay, sizeof(UnsignedByte)); - offset += sizeof(UnsignedByte); - -// If necessary, put the execution frame into the packet. - buffer[offset] = NetPacketFieldTypes::Frame; - ++offset; - UnsignedInt newframe = cmdMsg->getExecutionFrame(); - memcpy(buffer+offset, &newframe, sizeof(UnsignedInt)); - offset += sizeof(UnsignedInt); - -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("relay = %d, ", m_lastRelay)); - - buffer[offset] = NetPacketFieldTypes::PlayerId; - ++offset; - buffer[offset] = cmdMsg->getPlayerID(); - offset += sizeof(UnsignedByte); - -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("player = %d", m_lastPlayerID)); - -// If necessary, specify the command ID of this command. - buffer[offset] = NetPacketFieldTypes::CommandId; - ++offset; - UnsignedShort newID = cmdMsg->getID(); - memcpy(buffer + offset, &newID, sizeof(UnsignedShort)); - offset += sizeof(UnsignedShort); - -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("command id = %d", m_lastCommandID)); - - buffer[offset] = NetPacketFieldTypes::Data; - ++offset; - UnsignedByte leavingPlayerID = cmdMsg->getLeavingPlayerID(); - memcpy(buffer + offset, &leavingPlayerID, sizeof(UnsignedByte)); - offset += sizeof(UnsignedByte); -} - -void NetPacket::FillBufferWithRunAheadMetricsCommand(UnsignedByte *buffer, NetCommandRef *msg) { - NetRunAheadMetricsCommandMsg *cmdMsg = (NetRunAheadMetricsCommandMsg *)(msg->getCommand()); - UnsignedShort offset = 0; -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("NetPacket::addRunAheadMetricsCommand - adding run ahead metrics for player %d, fps = %d, latency = %f", cmdMsg->getPlayerID(), cmdMsg->getAverageFps(), cmdMsg->getAverageLatency())); - - // If necessary, put the NetCommandType into the packet. - buffer[offset] = NetPacketFieldTypes::CommandType; - ++offset; - buffer[offset] = cmdMsg->getNetCommandType(); - offset += sizeof(UnsignedByte); - -// If necessary, put the relay into the packet. - buffer[offset] = NetPacketFieldTypes::Relay; - ++offset; - UnsignedByte newRelay = msg->getRelay(); - memcpy(buffer+offset, &newRelay, sizeof(UnsignedByte)); - offset += sizeof(UnsignedByte); - -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("relay = %d, ", m_lastRelay)); - - buffer[offset] = NetPacketFieldTypes::PlayerId; - ++offset; - buffer[offset] = cmdMsg->getPlayerID(); - offset += sizeof(UnsignedByte); - -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("player = %d", m_lastPlayerID)); - -// If necessary, specify the command ID of this command. - buffer[offset] = NetPacketFieldTypes::CommandId; - ++offset; - UnsignedShort newID = cmdMsg->getID(); - memcpy(buffer + offset, &newID, sizeof(UnsignedShort)); - offset += sizeof(UnsignedShort); - -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("command id = %d", m_lastCommandID)); - - buffer[offset] = NetPacketFieldTypes::Data; - ++offset; - // write the average latency - Real averageLatency = cmdMsg->getAverageLatency(); - memcpy(buffer + offset, &averageLatency, sizeof(averageLatency)); - offset += sizeof(averageLatency); - // write the average fps - UnsignedShort averageFps = (UnsignedShort)(cmdMsg->getAverageFps()); - memcpy(buffer + offset, &averageFps, sizeof(averageFps)); - offset += sizeof(averageFps); -} - -void NetPacket::FillBufferWithRunAheadCommand(UnsignedByte *buffer, NetCommandRef *msg) { - NetRunAheadCommandMsg *cmdMsg = (NetRunAheadCommandMsg *)(msg->getCommand()); - UnsignedShort offset = 0; - //DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("NetPacket::FillBufferWithRunAheadCommand - adding run ahead command")); - - // If necessary, put the NetCommandType into the packet. - buffer[offset] = NetPacketFieldTypes::CommandType; - ++offset; - buffer[offset] = cmdMsg->getNetCommandType(); - offset += sizeof(UnsignedByte); - - // If necessary, put the relay into the packet. - buffer[offset] = NetPacketFieldTypes::Relay; - ++offset; - UnsignedByte newRelay = msg->getRelay(); - memcpy(buffer+offset, &newRelay, sizeof(UnsignedByte)); - offset += sizeof(UnsignedByte); - - // If necessary, put the execution frame into the packet. - buffer[offset] = NetPacketFieldTypes::Frame; - ++offset; - UnsignedInt newframe = cmdMsg->getExecutionFrame(); - memcpy(buffer+offset, &newframe, sizeof(UnsignedInt)); - offset += sizeof(UnsignedInt); - -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("relay = %d, ", m_lastRelay)); - - buffer[offset] = NetPacketFieldTypes::PlayerId; - ++offset; - buffer[offset] = cmdMsg->getPlayerID(); - offset += sizeof(UnsignedByte); - -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("player = %d", m_lastPlayerID)); - - // If necessary, specify the command ID of this command. - buffer[offset] = NetPacketFieldTypes::CommandId; - ++offset; - UnsignedShort newID = cmdMsg->getID(); - memcpy(buffer + offset, &newID, sizeof(UnsignedShort)); - offset += sizeof(UnsignedShort); - -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("command id = %d", m_lastCommandID)); - - buffer[offset] = NetPacketFieldTypes::Data; - ++offset; - UnsignedShort newRunAhead = cmdMsg->getRunAhead(); - memcpy(buffer + offset, &newRunAhead, sizeof(UnsignedShort)); - offset += sizeof(UnsignedShort); - - UnsignedByte newFrameRate = cmdMsg->getFrameRate(); - memcpy(buffer + offset, &newFrameRate, sizeof(UnsignedByte)); - offset += sizeof(UnsignedByte); - -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("NetPacket - added run ahead command, frame %d, player id %d command id %d", m_lastFrame, m_lastPlayerID, m_lastCommandID)); -} - -void NetPacket::FillBufferWithDestroyPlayerCommand(UnsignedByte *buffer, NetCommandRef *msg) { - NetDestroyPlayerCommandMsg *cmdMsg = (NetDestroyPlayerCommandMsg *)(msg->getCommand()); - UnsignedShort offset = 0; -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("NetPacket::addRunAheadCommand - adding run ahead command")); - -// If necessary, put the NetCommandType into the packet. - buffer[offset] = NetPacketFieldTypes::CommandType; - ++offset; - buffer[offset] = cmdMsg->getNetCommandType(); - offset += sizeof(UnsignedByte); - -// If necessary, put the relay into the packet. - buffer[offset] = NetPacketFieldTypes::Relay; - ++offset; - UnsignedByte newRelay = msg->getRelay(); - memcpy(buffer+offset, &newRelay, sizeof(UnsignedByte)); - offset += sizeof(UnsignedByte); - -// If necessary, put the execution frame into the packet. - buffer[offset] = NetPacketFieldTypes::Frame; - ++offset; - UnsignedInt newframe = cmdMsg->getExecutionFrame(); - memcpy(buffer+offset, &newframe, sizeof(UnsignedInt)); - offset += sizeof(UnsignedInt); - -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("relay = %d, ", m_lastRelay)); - - buffer[offset] = NetPacketFieldTypes::PlayerId; - ++offset; - buffer[offset] = cmdMsg->getPlayerID(); - offset += sizeof(UnsignedByte); - -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("player = %d", m_lastPlayerID)); - -// If necessary, specify the command ID of this command. - buffer[offset] = NetPacketFieldTypes::CommandId; - ++offset; - UnsignedShort newID = cmdMsg->getID(); - memcpy(buffer + offset, &newID, sizeof(UnsignedShort)); - offset += sizeof(UnsignedShort); - -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("command id = %d", m_lastCommandID)); - - buffer[offset] = NetPacketFieldTypes::Data; - ++offset; - UnsignedInt newVal = cmdMsg->getPlayerIndex(); - memcpy(buffer + offset, &newVal, sizeof(UnsignedInt)); - offset += sizeof(UnsignedInt); -} - -void NetPacket::FillBufferWithKeepAliveCommand(UnsignedByte *buffer, NetCommandRef *msg) { - NetKeepAliveCommandMsg *cmdMsg = (NetKeepAliveCommandMsg *)(msg->getCommand()); - UnsignedShort offset = 0; - - // If necessary, put the NetCommandType into the packet. - buffer[offset] = NetPacketFieldTypes::CommandType; - ++offset; - buffer[offset] = cmdMsg->getNetCommandType(); - offset += sizeof(UnsignedByte); - -// If necessary, put the relay into the packet. - buffer[offset] = NetPacketFieldTypes::Relay; - ++offset; - UnsignedByte newRelay = msg->getRelay(); - memcpy(buffer+offset, &newRelay, sizeof(UnsignedByte)); - offset += sizeof(UnsignedByte); - - buffer[offset] = NetPacketFieldTypes::PlayerId; - ++offset; - buffer[offset] = cmdMsg->getPlayerID(); - offset += sizeof(UnsignedByte); - - buffer[offset] = NetPacketFieldTypes::Data; - ++offset; -} - -void NetPacket::FillBufferWithDisconnectKeepAliveCommand(UnsignedByte *buffer, NetCommandRef *msg) { - NetDisconnectKeepAliveCommandMsg *cmdMsg = (NetDisconnectKeepAliveCommandMsg *)(msg->getCommand()); - UnsignedShort offset = 0; - - // Put the NetCommandType into the packet. - buffer[offset] = NetPacketFieldTypes::CommandType; - ++offset; - buffer[offset] = cmdMsg->getNetCommandType(); - offset += sizeof(UnsignedByte); - - // Put the relay into the packet. - buffer[offset] = NetPacketFieldTypes::Relay; - ++offset; - UnsignedByte newRelay = msg->getRelay(); - memcpy(buffer+offset, &newRelay, sizeof(UnsignedByte)); - offset += sizeof(UnsignedByte); - - // Put the player ID into the packet. - buffer[offset] = NetPacketFieldTypes::PlayerId; - ++offset; - buffer[offset] = cmdMsg->getPlayerID(); - offset += sizeof(UnsignedByte); - - buffer[offset] = NetPacketFieldTypes::Data; - ++offset; -} - -void NetPacket::FillBufferWithDisconnectPlayerCommand(UnsignedByte *buffer, NetCommandRef *msg) { - NetDisconnectPlayerCommandMsg *cmdMsg = (NetDisconnectPlayerCommandMsg *)(msg->getCommand()); - UnsignedShort offset = 0; -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("NetPacket::addDisconnectPlayerCommand - adding run ahead command")); - - // If necessary, put the NetCommandType into the packet. - buffer[offset] = NetPacketFieldTypes::CommandType; - ++offset; - buffer[offset] = cmdMsg->getNetCommandType(); - offset += sizeof(UnsignedByte); - -// If necessary, put the relay into the packet. - buffer[offset] = NetPacketFieldTypes::Relay; - ++offset; - UnsignedByte newRelay = msg->getRelay(); - memcpy(buffer+offset, &newRelay, sizeof(UnsignedByte)); - offset += sizeof(UnsignedByte); - -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("relay = %d, ", m_lastRelay)); - - buffer[offset] = NetPacketFieldTypes::PlayerId; - ++offset; - buffer[offset] = cmdMsg->getPlayerID(); - offset += sizeof(UnsignedByte); - -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("player = %d", m_lastPlayerID)); - -// If necessary, specify the command ID of this command. - buffer[offset] = NetPacketFieldTypes::CommandId; - ++offset; - UnsignedShort newID = cmdMsg->getID(); - memcpy(buffer + offset, &newID, sizeof(UnsignedShort)); - offset += sizeof(UnsignedShort); - - // DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("command id = %d", m_lastCommandID)); - - buffer[offset] = NetPacketFieldTypes::Data; - ++offset; - UnsignedByte slot = cmdMsg->getDisconnectSlot(); - memcpy(buffer + offset, &slot, sizeof(slot)); - offset += sizeof(slot); - - UnsignedInt disconnectFrame = cmdMsg->getDisconnectFrame(); - memcpy(buffer + offset, &disconnectFrame, sizeof(disconnectFrame)); - offset += sizeof(disconnectFrame); -} - -void NetPacket::FillBufferWithPacketRouterQueryCommand(UnsignedByte *buffer, NetCommandRef *msg) { - NetPacketRouterQueryCommandMsg *cmdMsg = (NetPacketRouterQueryCommandMsg *)(msg->getCommand()); - UnsignedShort offset = 0; -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("NetPacket::addPacketRouterQueryCommand - adding packet router query command")); - - // If necessary, put the NetCommandType into the packet. - buffer[offset] = NetPacketFieldTypes::CommandType; - ++offset; - buffer[offset] = cmdMsg->getNetCommandType(); - offset += sizeof(UnsignedByte); - - // If necessary, put the relay into the packet. - buffer[offset] = NetPacketFieldTypes::Relay; - ++offset; - UnsignedByte newRelay = msg->getRelay(); - memcpy(buffer+offset, &newRelay, sizeof(UnsignedByte)); - offset += sizeof(UnsignedByte); - -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("relay = %d, ", m_lastRelay)); - buffer[offset] = NetPacketFieldTypes::PlayerId; - ++offset; - buffer[offset] = cmdMsg->getPlayerID(); - offset += sizeof(UnsignedByte); - -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("player = %d", m_lastPlayerID)); - - buffer[offset] = NetPacketFieldTypes::Data; - ++offset; -} - -void NetPacket::FillBufferWithPacketRouterAckCommand(UnsignedByte *buffer, NetCommandRef *msg) { - NetPacketRouterAckCommandMsg *cmdMsg = (NetPacketRouterAckCommandMsg *)(msg->getCommand()); - UnsignedShort offset = 0; -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("NetPacket::addPacketRouterAckCommand - adding packet router query command")); - - // If necessary, put the NetCommandType into the packet. - buffer[offset] = NetPacketFieldTypes::CommandType; - ++offset; - buffer[offset] = cmdMsg->getNetCommandType(); - offset += sizeof(UnsignedByte); - - // If necessary, put the relay into the packet. - buffer[offset] = NetPacketFieldTypes::Relay; - ++offset; - UnsignedByte newRelay = msg->getRelay(); - memcpy(buffer+offset, &newRelay, sizeof(UnsignedByte)); - offset += sizeof(UnsignedByte); - -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("relay = %d, ", m_lastRelay)); - - buffer[offset] = NetPacketFieldTypes::PlayerId; - ++offset; - buffer[offset] = cmdMsg->getPlayerID(); - offset += sizeof(UnsignedByte); - -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("player = %d", m_lastPlayerID)); - - buffer[offset] = NetPacketFieldTypes::Data; - ++offset; -} - -void NetPacket::FillBufferWithDisconnectChatCommand(UnsignedByte *buffer, NetCommandRef *msg) { - NetDisconnectChatCommandMsg *cmdMsg = (NetDisconnectChatCommandMsg *)(msg->getCommand()); - UnsignedShort offset = 0; -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("NetPacket::addDisconnectChatCommand - adding run ahead command")); - -// If necessary, put the NetCommandType into the packet. - buffer[offset] = NetPacketFieldTypes::CommandType; - ++offset; - buffer[offset] = cmdMsg->getNetCommandType(); - offset += sizeof(UnsignedByte); - -// If necessary, put the relay into the packet. - buffer[offset] = NetPacketFieldTypes::Relay; - ++offset; - UnsignedByte newRelay = msg->getRelay(); - memcpy(buffer+offset, &newRelay, sizeof(UnsignedByte)); - offset += sizeof(UnsignedByte); - -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("relay = %d, ", m_lastRelay)); - - buffer[offset] = NetPacketFieldTypes::PlayerId; - ++offset; - buffer[offset] = cmdMsg->getPlayerID(); - offset += sizeof(UnsignedByte); - -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("player = %d", m_lastPlayerID)); - - buffer[offset] = NetPacketFieldTypes::Data; - ++offset; - UnicodeString unitext = cmdMsg->getText(); - UnsignedByte length = unitext.getLength(); - memcpy(buffer + offset, &length, sizeof(UnsignedByte)); - offset += sizeof(UnsignedByte); - - memcpy(buffer + offset, unitext.str(), length * sizeof(UnsignedShort)); - offset += length * sizeof(UnsignedShort); -} - -void NetPacket::FillBufferWithDisconnectVoteCommand(UnsignedByte *buffer, NetCommandRef *msg) { - NetDisconnectVoteCommandMsg *cmdMsg = (NetDisconnectVoteCommandMsg *)(msg->getCommand()); - UnsignedShort offset = 0; -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("NetPacket::addDisconnectVoteCommand - adding run ahead command")); - -// If necessary, put the NetCommandType into the packet. - buffer[offset] = NetPacketFieldTypes::CommandType; - ++offset; - buffer[offset] = cmdMsg->getNetCommandType(); - offset += sizeof(UnsignedByte); - -// If necessary, put the relay into the packet. - buffer[offset] = NetPacketFieldTypes::Relay; - ++offset; - UnsignedByte newRelay = msg->getRelay(); - memcpy(buffer+offset, &newRelay, sizeof(UnsignedByte)); - offset += sizeof(UnsignedByte); - -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("relay = %d, ", m_lastRelay)); - - buffer[offset] = NetPacketFieldTypes::PlayerId; - ++offset; - buffer[offset] = cmdMsg->getPlayerID(); - offset += sizeof(UnsignedByte); - -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("player = %d", m_lastPlayerID)); - -// If necessary, specify the command ID of this command. - buffer[offset] = NetPacketFieldTypes::CommandId; - ++offset; - UnsignedShort newID = cmdMsg->getID(); - memcpy(buffer + offset, &newID, sizeof(UnsignedShort)); - offset += sizeof(UnsignedShort); - -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("command id = %d", m_lastCommandID)); - - buffer[offset] = NetPacketFieldTypes::Data; - ++offset; - UnsignedByte slot = cmdMsg->getSlot(); - memcpy(buffer + offset, &slot, sizeof(slot)); - offset += sizeof(slot); - - UnsignedInt voteFrame = cmdMsg->getVoteFrame(); - memcpy(buffer + offset, &voteFrame, sizeof(voteFrame)); - offset += sizeof(voteFrame); -} - -void NetPacket::FillBufferWithChatCommand(UnsignedByte *buffer, NetCommandRef *msg) { - NetChatCommandMsg *cmdMsg = (NetChatCommandMsg *)(msg->getCommand()); - UnsignedShort offset = 0; -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("NetPacket::addDisconnectChatCommand - adding run ahead command")); - -// If necessary, put the NetCommandType into the packet. - buffer[offset] = NetPacketFieldTypes::CommandType; - ++offset; - buffer[offset] = cmdMsg->getNetCommandType(); - offset += sizeof(UnsignedByte); - -// If necessary, put the execution frame into the packet. - buffer[offset] = NetPacketFieldTypes::Frame; - ++offset; - UnsignedInt newframe = cmdMsg->getExecutionFrame(); - memcpy(buffer+offset, &newframe, sizeof(UnsignedInt)); - offset += sizeof(UnsignedInt); - -// If necessary, put the relay into the packet. - buffer[offset] = NetPacketFieldTypes::Relay; - ++offset; - UnsignedByte newRelay = msg->getRelay(); - memcpy(buffer+offset, &newRelay, sizeof(UnsignedByte)); - offset += sizeof(UnsignedByte); - -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("relay = %d, ", m_lastRelay)); - - buffer[offset] = NetPacketFieldTypes::PlayerId; - ++offset; - buffer[offset] = cmdMsg->getPlayerID(); - offset += sizeof(UnsignedByte); - -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("player = %d", m_lastPlayerID)); - -// If necessary, specify the command ID of this command. - buffer[offset] = NetPacketFieldTypes::CommandId; - ++offset; - UnsignedShort newID = cmdMsg->getID(); - memcpy(buffer + offset, &newID, sizeof(UnsignedShort)); - offset += sizeof(UnsignedShort); - -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("command id = %d", m_lastCommandID)); - - buffer[offset] = NetPacketFieldTypes::Data; - ++offset; - UnicodeString unitext = cmdMsg->getText(); - UnsignedByte length = unitext.getLength(); - Int playerMask = cmdMsg->getPlayerMask(); - memcpy(buffer + offset, &length, sizeof(UnsignedByte)); - offset += sizeof(UnsignedByte); - - memcpy(buffer + offset, unitext.str(), length * sizeof(UnsignedShort)); - offset += length * sizeof(UnsignedShort); - - memcpy(buffer + offset, &playerMask, sizeof(Int)); - offset += sizeof(Int); -} - -void NetPacket::FillBufferWithProgressMessage(UnsignedByte *buffer, NetCommandRef *msg) { - NetProgressCommandMsg *cmdMsg = (NetProgressCommandMsg *)(msg->getCommand()); - UnsignedShort offset = 0; - -// If necessary, put the NetCommandType into the packet. - buffer[offset] = NetPacketFieldTypes::CommandType; - ++offset; - buffer[offset] = cmdMsg->getNetCommandType(); - offset += sizeof(UnsignedByte); - -// If necessary, put the relay into the packet. - buffer[offset] = NetPacketFieldTypes::Relay; - ++offset; - UnsignedByte newRelay = msg->getRelay(); - memcpy(buffer+offset, &newRelay, sizeof(UnsignedByte)); - offset += sizeof(UnsignedByte); - -// Put the player ID into the packet. - buffer[offset] = NetPacketFieldTypes::PlayerId; - ++offset; - buffer[offset] = cmdMsg->getPlayerID(); - offset += sizeof(UnsignedByte); - - buffer[offset] = NetPacketFieldTypes::Data; - ++offset; - - buffer[offset] = cmdMsg->getPercentage(); - ++offset; -} - -void NetPacket::FillBufferWithLoadCompleteMessage(UnsignedByte *buffer, NetCommandRef *msg) { - NetCommandMsg *cmdMsg = (NetCommandMsg *)(msg->getCommand()); - UnsignedShort offset = 0; - -// If necessary, put the NetCommandType into the packet. - buffer[offset] = NetPacketFieldTypes::CommandType; - ++offset; - buffer[offset] = cmdMsg->getNetCommandType(); - offset += sizeof(UnsignedByte); - -// If necessary, put the relay into the packet. - buffer[offset] = NetPacketFieldTypes::Relay; - ++offset; - UnsignedByte newRelay = msg->getRelay(); - memcpy(buffer+offset, &newRelay, sizeof(UnsignedByte)); - offset += sizeof(UnsignedByte); - - buffer[offset] = NetPacketFieldTypes::PlayerId; - ++offset; - buffer[offset] = cmdMsg->getPlayerID(); - offset += sizeof(UnsignedByte); - -// If necessary, specify the command ID of this command. - buffer[offset] = NetPacketFieldTypes::CommandId; - ++offset; - UnsignedShort newID = cmdMsg->getID(); - memcpy(buffer + offset, &newID, sizeof(UnsignedShort)); - offset += sizeof(UnsignedShort); - - buffer[offset] = NetPacketFieldTypes::Data; - ++offset; -} - -void NetPacket::FillBufferWithTimeOutGameStartMessage(UnsignedByte *buffer, NetCommandRef *msg) { - NetCommandMsg *cmdMsg = (NetCommandMsg *)(msg->getCommand()); - UnsignedShort offset = 0; - -// If necessary, put the NetCommandType into the packet. - buffer[offset] = NetPacketFieldTypes::CommandType; - ++offset; - buffer[offset] = cmdMsg->getNetCommandType(); - offset += sizeof(UnsignedByte); - -// If necessary, put the relay into the packet. - buffer[offset] = NetPacketFieldTypes::Relay; - ++offset; - UnsignedByte newRelay = msg->getRelay(); - memcpy(buffer+offset, &newRelay, sizeof(UnsignedByte)); - offset += sizeof(UnsignedByte); - buffer[offset] = NetPacketFieldTypes::PlayerId; - ++offset; - buffer[offset] = cmdMsg->getPlayerID(); - offset += sizeof(UnsignedByte); - -// If necessary, specify the command ID of this command. - buffer[offset] = NetPacketFieldTypes::CommandId; - ++offset; - UnsignedShort newID = cmdMsg->getID(); - memcpy(buffer + offset, &newID, sizeof(UnsignedShort)); - offset += sizeof(UnsignedShort); - - buffer[offset] = NetPacketFieldTypes::Data; - ++offset; -} - -void NetPacket::FillBufferWithFileMessage(UnsignedByte *buffer, NetCommandRef *msg) { - NetFileCommandMsg *cmdMsg = (NetFileCommandMsg *)(msg->getCommand()); - UnsignedInt offset = 0; - - // command type - buffer[offset] = NetPacketFieldTypes::CommandType; - ++offset; - buffer[offset] = cmdMsg->getNetCommandType(); - offset += sizeof(UnsignedByte); - - // relay - buffer[offset] = NetPacketFieldTypes::Relay; - ++offset; - buffer[offset] = msg->getRelay(); - offset += sizeof(UnsignedByte); - - // player ID - buffer[offset] = NetPacketFieldTypes::PlayerId; - ++offset; - buffer[offset] = cmdMsg->getPlayerID(); - offset += sizeof(UnsignedByte); - - // command ID - buffer[offset] = NetPacketFieldTypes::CommandId; - ++offset; - UnsignedShort newID = cmdMsg->getID(); - memcpy(buffer + offset, &newID, sizeof(newID)); - offset += sizeof(newID); - - // data - buffer[offset] = NetPacketFieldTypes::Data; - ++offset; - - AsciiString filename = cmdMsg->getPortableFilename(); // PORTABLE - for (Int i = 0; i < filename.getLength(); ++i) { - buffer[offset] = filename.getCharAt(i); - ++offset; - } - buffer[offset] = 0; - ++offset; - - UnsignedInt newInt = cmdMsg->getFileLength(); - memcpy(buffer + offset, &newInt, sizeof(newInt)); - offset += sizeof(newInt); - - memcpy(buffer + offset, cmdMsg->getFileData(), cmdMsg->getFileLength()); - offset += cmdMsg->getFileLength(); -} - -void NetPacket::FillBufferWithFileAnnounceMessage(UnsignedByte *buffer, NetCommandRef *msg) { - NetFileAnnounceCommandMsg *cmdMsg = (NetFileAnnounceCommandMsg *)(msg->getCommand()); - UnsignedInt offset = 0; - - // command type - buffer[offset] = NetPacketFieldTypes::CommandType; - ++offset; - buffer[offset] = cmdMsg->getNetCommandType(); - offset += sizeof(UnsignedByte); - - // relay - buffer[offset] = NetPacketFieldTypes::Relay; - ++offset; - buffer[offset] = msg->getRelay(); - offset += sizeof(UnsignedByte); - - // player ID - buffer[offset] = NetPacketFieldTypes::PlayerId; - ++offset; - buffer[offset] = cmdMsg->getPlayerID(); - offset += sizeof(UnsignedByte); - - // command ID - buffer[offset] = NetPacketFieldTypes::CommandId; - ++offset; - UnsignedShort newID = cmdMsg->getID(); - memcpy(buffer + offset, &newID, sizeof(newID)); - offset += sizeof(newID); - - // data - buffer[offset] = NetPacketFieldTypes::Data; - ++offset; - - AsciiString filename = cmdMsg->getPortableFilename(); // PORTABLE - for (Int i = 0; i < filename.getLength(); ++i) { - buffer[offset] = filename.getCharAt(i); - ++offset; - } - buffer[offset] = 0; - ++offset; - - UnsignedShort fileID = cmdMsg->getFileID(); - memcpy(buffer + offset, &fileID, sizeof(fileID)); - offset += sizeof(fileID); - - UnsignedByte playerMask = cmdMsg->getPlayerMask(); - memcpy(buffer + offset, &playerMask, sizeof(playerMask)); - offset += sizeof(playerMask); -} - -void NetPacket::FillBufferWithFileProgressMessage(UnsignedByte *buffer, NetCommandRef *msg) { - NetFileProgressCommandMsg *cmdMsg = (NetFileProgressCommandMsg *)(msg->getCommand()); - UnsignedInt offset = 0; - - // command type - buffer[offset] = NetPacketFieldTypes::CommandType; - ++offset; - buffer[offset] = cmdMsg->getNetCommandType(); - offset += sizeof(UnsignedByte); - - // relay - buffer[offset] = NetPacketFieldTypes::Relay; - ++offset; - buffer[offset] = msg->getRelay(); - offset += sizeof(UnsignedByte); - - // player ID - buffer[offset] = NetPacketFieldTypes::PlayerId; - ++offset; - buffer[offset] = cmdMsg->getPlayerID(); - offset += sizeof(UnsignedByte); - - // command ID - buffer[offset] = NetPacketFieldTypes::CommandId; - ++offset; - UnsignedShort newID = cmdMsg->getID(); - memcpy(buffer + offset, &newID, sizeof(newID)); - offset += sizeof(newID); - - // data - buffer[offset] = NetPacketFieldTypes::Data; - ++offset; - - UnsignedShort fileID = cmdMsg->getFileID(); - memcpy(buffer + offset, &fileID, sizeof(fileID)); - offset += sizeof(fileID); - - Int progress = cmdMsg->getProgress(); - memcpy(buffer + offset, &progress, sizeof(progress)); - offset += sizeof(progress); -} - -void NetPacket::FillBufferWithDisconnectFrameMessage(UnsignedByte *buffer, NetCommandRef *msg) { - NetDisconnectFrameCommandMsg *cmdMsg = (NetDisconnectFrameCommandMsg *)(msg->getCommand()); - UnsignedInt offset = 0; - - // command type - buffer[offset] = NetPacketFieldTypes::CommandType; - ++offset; - buffer[offset] = cmdMsg->getNetCommandType(); - offset += sizeof(UnsignedByte); - - // relay - buffer[offset] = NetPacketFieldTypes::Relay; - ++offset; - buffer[offset] = msg->getRelay(); - offset += sizeof(UnsignedByte); - - // player ID - buffer[offset] = NetPacketFieldTypes::PlayerId; - ++offset; - buffer[offset] = cmdMsg->getPlayerID(); - offset += sizeof(UnsignedByte); - - // command ID - buffer[offset] = NetPacketFieldTypes::CommandId; - ++offset; - UnsignedShort newID = cmdMsg->getID(); - memcpy(buffer + offset, &newID, sizeof(newID)); - offset += sizeof(newID); - - // data - buffer[offset] = NetPacketFieldTypes::Data; - ++offset; - - UnsignedInt disconnectFrame = cmdMsg->getDisconnectFrame(); - memcpy(buffer + offset, &disconnectFrame, sizeof(disconnectFrame)); - offset += sizeof(disconnectFrame); -} - -void NetPacket::FillBufferWithDisconnectScreenOffMessage(UnsignedByte *buffer, NetCommandRef *msg) { - NetDisconnectScreenOffCommandMsg *cmdMsg = (NetDisconnectScreenOffCommandMsg *)(msg->getCommand()); - UnsignedInt offset = 0; - - // command type - buffer[offset] = NetPacketFieldTypes::CommandType; - ++offset; - buffer[offset] = cmdMsg->getNetCommandType(); - offset += sizeof(UnsignedByte); - - // relay - buffer[offset] = NetPacketFieldTypes::Relay; - ++offset; - buffer[offset] = msg->getRelay(); - offset += sizeof(UnsignedByte); - - // player ID - buffer[offset] = NetPacketFieldTypes::PlayerId; - ++offset; - buffer[offset] = cmdMsg->getPlayerID(); - offset += sizeof(UnsignedByte); - - // command ID - buffer[offset] = NetPacketFieldTypes::CommandId; - ++offset; - UnsignedShort newID = cmdMsg->getID(); - memcpy(buffer + offset, &newID, sizeof(newID)); - offset += sizeof(newID); - - // data - buffer[offset] = NetPacketFieldTypes::Data; - ++offset; - - UnsignedInt newFrame = cmdMsg->getNewFrame(); - memcpy(buffer + offset, &newFrame, sizeof(newFrame)); - offset += sizeof(newFrame); -} - -void NetPacket::FillBufferWithFrameResendRequestMessage(UnsignedByte *buffer, NetCommandRef *msg) { - NetFrameResendRequestCommandMsg *cmdMsg = (NetFrameResendRequestCommandMsg *)(msg->getCommand()); - UnsignedInt offset = 0; - - // command type - buffer[offset] = NetPacketFieldTypes::CommandType; - ++offset; - buffer[offset] = cmdMsg->getNetCommandType(); - offset += sizeof(UnsignedByte); - - // relay - buffer[offset] = NetPacketFieldTypes::Relay; - ++offset; - buffer[offset] = msg->getRelay(); - offset += sizeof(UnsignedByte); - - // player ID - buffer[offset] = NetPacketFieldTypes::PlayerId; - ++offset; - buffer[offset] = cmdMsg->getPlayerID(); - offset += sizeof(UnsignedByte); - - // command ID - buffer[offset] = NetPacketFieldTypes::CommandId; - ++offset; - UnsignedShort newID = cmdMsg->getID(); - memcpy(buffer + offset, &newID, sizeof(newID)); - offset += sizeof(newID); - - // data - buffer[offset] = NetPacketFieldTypes::Data; - ++offset; - - UnsignedInt frameToResend = cmdMsg->getFrameToResend(); - memcpy(buffer + offset, &frameToResend, sizeof(frameToResend)); - offset += sizeof(frameToResend); -} - - -/** - * Constructor - */ -NetPacket::NetPacket() { - init(); -} - -/** - * Constructor given raw transport data. - */ -NetPacket::NetPacket(TransportMessage *msg) { - init(); - m_packetLen = msg->length; - memcpy(m_packet, msg->data, MAX_PACKET_SIZE); - m_numCommands = -1; - m_addr = msg->addr; - m_port = msg->port; -} - -/** - * Destructor - */ -NetPacket::~NetPacket() { - deleteInstance(m_lastCommand); - m_lastCommand = NULL; -} - -/** - * Initialize all the member variable values. - */ -void NetPacket::init() { - m_addr = 0; - m_port = 0; - m_numCommands = 0; - m_packetLen = 0; - m_packet[0] = 0; - - m_lastPlayerID = 0; - m_lastFrame = 0; - m_lastCommandID = 0; - m_lastCommandType = 0; - m_lastRelay = 0; - - m_lastCommand = NULL; -} - -void NetPacket::reset() { - deleteInstance(m_lastCommand); - m_lastCommand = NULL; - - init(); -} - -/** - * Set the address to which this packet is to be sent. - */ -void NetPacket::setAddress(Int addr, Int port) { - m_addr = addr; - m_port = port; -} - -/** - * Adds this command to the packet. Returns false if there wasn't enough room - * in the packet for this message, true otherwise. - */ -Bool NetPacket::addCommand(NetCommandRef *msg) { - // This is where the fun begins... - - NetCommandMsg *cmdMsg = msg->getCommand(); - - if (msg == NULL) { - return TRUE; // There was nothing to add, so it was successful. - } - - switch(cmdMsg->getNetCommandType()) - { - case NETCOMMANDTYPE_GAMECOMMAND: - return addGameCommand(msg); - case NETCOMMANDTYPE_ACKSTAGE1: - return addAckStage1Command(msg); - case NETCOMMANDTYPE_ACKSTAGE2: - return addAckStage2Command(msg); - case NETCOMMANDTYPE_ACKBOTH: - return addAckBothCommand(msg); - case NETCOMMANDTYPE_FRAMEINFO: - return addFrameCommand(msg); - case NETCOMMANDTYPE_PLAYERLEAVE: - return addPlayerLeaveCommand(msg); - case NETCOMMANDTYPE_RUNAHEADMETRICS: - return addRunAheadMetricsCommand(msg); - case NETCOMMANDTYPE_RUNAHEAD: - return addRunAheadCommand(msg); - case NETCOMMANDTYPE_DESTROYPLAYER: - return addDestroyPlayerCommand(msg); - case NETCOMMANDTYPE_KEEPALIVE: - return addKeepAliveCommand(msg); - case NETCOMMANDTYPE_DISCONNECTKEEPALIVE: - return addDisconnectKeepAliveCommand(msg); - case NETCOMMANDTYPE_DISCONNECTPLAYER: - return addDisconnectPlayerCommand(msg); - case NETCOMMANDTYPE_PACKETROUTERQUERY: - return addPacketRouterQueryCommand(msg); - case NETCOMMANDTYPE_PACKETROUTERACK: - return addPacketRouterAckCommand(msg); - case NETCOMMANDTYPE_DISCONNECTCHAT: - return addDisconnectChatCommand(msg); - case NETCOMMANDTYPE_DISCONNECTVOTE: - return addDisconnectVoteCommand(msg); - case NETCOMMANDTYPE_CHAT: - return addChatCommand(msg); - case NETCOMMANDTYPE_PROGRESS: - return addProgressMessage(msg); - case NETCOMMANDTYPE_LOADCOMPLETE: - return addLoadCompleteMessage(msg); - case NETCOMMANDTYPE_TIMEOUTSTART: - return addTimeOutGameStartMessage(msg); - case NETCOMMANDTYPE_WRAPPER: - return addWrapperCommand(msg); - case NETCOMMANDTYPE_FILE: - return addFileCommand(msg); - case NETCOMMANDTYPE_FILEANNOUNCE: - return addFileAnnounceCommand(msg); - case NETCOMMANDTYPE_FILEPROGRESS: - return addFileProgressCommand(msg); - case NETCOMMANDTYPE_DISCONNECTFRAME: - return addDisconnectFrameCommand(msg); - case NETCOMMANDTYPE_DISCONNECTSCREENOFF: - return addDisconnectScreenOffCommand(msg); - case NETCOMMANDTYPE_FRAMERESENDREQUEST: - return addFrameResendRequestCommand(msg); - default: - DEBUG_CRASH(("Unknown NETCOMMANDTYPE %d", cmdMsg->getNetCommandType())); - break; - } - - return TRUE; -} - -/* -T = Net command type -F = Execution frame -P = Player ID -C = Command ID -R = Relay -D = Command Data -Z = Repeat last command -*/ -Bool NetPacket::addFrameResendRequestCommand(NetCommandRef *msg) { - Bool needNewCommandID = FALSE; - if (isRoomForFrameResendRequestMessage(msg)) { - NetFrameResendRequestCommandMsg *cmdMsg = (NetFrameResendRequestCommandMsg *)(msg->getCommand()); - - // If necessary, put the NetCommandType into the packet. - if (m_lastCommandType != cmdMsg->getNetCommandType()) { - m_packet[m_packetLen] = NetPacketFieldTypes::CommandType; - ++m_packetLen; - m_packet[m_packetLen] = cmdMsg->getNetCommandType(); - m_packetLen += sizeof(UnsignedByte); - - m_lastCommandType = cmdMsg->getNetCommandType(); - } - - // If necessary, put the execution frame into the packet. - if (m_lastFrame != cmdMsg->getExecutionFrame()) { - m_packet[m_packetLen] = NetPacketFieldTypes::Frame; - ++m_packetLen; - UnsignedInt newframe = cmdMsg->getExecutionFrame(); - memcpy(m_packet+m_packetLen, &newframe, sizeof(UnsignedInt)); - m_packetLen += sizeof(UnsignedInt); - - m_lastFrame = newframe; - } - - // If necessary, put the relay into the packet. - if (m_lastRelay != msg->getRelay()) { - m_packet[m_packetLen] = NetPacketFieldTypes::Relay; - ++m_packetLen; - UnsignedByte newRelay = msg->getRelay(); - memcpy(m_packet + m_packetLen, &newRelay, sizeof(UnsignedByte)); - m_packetLen += sizeof(UnsignedByte); - - m_lastRelay = newRelay; - } - - // If necessary put the player ID into the packet. - if (m_lastPlayerID != cmdMsg->getPlayerID()) { - m_packet[m_packetLen] = NetPacketFieldTypes::PlayerId; - ++m_packetLen; - m_packet[m_packetLen] = cmdMsg->getPlayerID(); - m_packetLen += sizeof(UnsignedByte); - - m_lastPlayerID = cmdMsg->getPlayerID(); - needNewCommandID = TRUE; - } - - // If necessary, specify the command ID of this command. - if (((m_lastCommandID + 1) != (UnsignedShort)(cmdMsg->getID())) || (needNewCommandID == TRUE)) { - m_packet[m_packetLen] = NetPacketFieldTypes::CommandId; - ++m_packetLen; - UnsignedShort newID = cmdMsg->getID(); - memcpy(m_packet + m_packetLen, &newID, sizeof(UnsignedShort)); - m_packetLen += sizeof(UnsignedShort); - } - m_lastCommandID = cmdMsg->getID(); - - m_packet[m_packetLen] = NetPacketFieldTypes::Data; - ++m_packetLen; - - UnsignedInt frameToResend = cmdMsg->getFrameToResend(); - memcpy(m_packet + m_packetLen, &frameToResend, sizeof(frameToResend)); - m_packetLen += sizeof(frameToResend); - - DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("NetPacket::addFrameResendRequest - added frame resend request command from player %d for frame %d, command id = %d", m_lastPlayerID, frameToResend, m_lastCommandID)); - - ++m_numCommands; - - deleteInstance(m_lastCommand); - m_lastCommand = NEW_NETCOMMANDREF(msg->getCommand()); - m_lastCommand->setRelay(msg->getRelay()); - - return TRUE; - } - return FALSE; -} - -Bool NetPacket::isRoomForFrameResendRequestMessage(NetCommandRef *msg) { - Int len = 0; - Bool needNewCommandID = FALSE; - NetFrameResendRequestCommandMsg *cmdMsg = (NetFrameResendRequestCommandMsg *)(msg->getCommand()); - if (m_lastCommandType != cmdMsg->getNetCommandType()) { - ++len; - len += sizeof(UnsignedByte); - } - if (m_lastRelay != msg->getRelay()) { - len += sizeof(UnsignedByte) + sizeof(UnsignedByte); - } - if (m_lastFrame != cmdMsg->getExecutionFrame()) { - len += sizeof(UnsignedInt) + sizeof(UnsignedByte); - } - if (m_lastPlayerID != cmdMsg->getPlayerID()) { - ++len; - len += sizeof(UnsignedByte); - needNewCommandID = TRUE; - } - if (((m_lastCommandID + 1) != (UnsignedShort)(cmdMsg->getID())) || (needNewCommandID == TRUE)) { - len += sizeof(UnsignedShort) + sizeof(UnsignedByte); - } - - ++len; // for NetPacketFieldTypes::Data - len += sizeof(UnsignedInt); // for the frame to be resent - if ((len + m_packetLen) > MAX_PACKET_SIZE) { - return FALSE; - } - return TRUE; -} - -Bool NetPacket::addDisconnectScreenOffCommand(NetCommandRef *msg) { - Bool needNewCommandID = FALSE; - if (isRoomForDisconnectScreenOffMessage(msg)) { - NetDisconnectScreenOffCommandMsg *cmdMsg = (NetDisconnectScreenOffCommandMsg *)(msg->getCommand()); - - // If necessary, put the NetCommandType into the packet. - if (m_lastCommandType != cmdMsg->getNetCommandType()) { - m_packet[m_packetLen] = NetPacketFieldTypes::CommandType; - ++m_packetLen; - m_packet[m_packetLen] = cmdMsg->getNetCommandType(); - m_packetLen += sizeof(UnsignedByte); - - m_lastCommandType = cmdMsg->getNetCommandType(); - } - - // If necessary, put the execution frame into the packet. - if (m_lastFrame != cmdMsg->getExecutionFrame()) { - m_packet[m_packetLen] = NetPacketFieldTypes::Frame; - ++m_packetLen; - UnsignedInt newframe = cmdMsg->getExecutionFrame(); - memcpy(m_packet+m_packetLen, &newframe, sizeof(UnsignedInt)); - m_packetLen += sizeof(UnsignedInt); - - m_lastFrame = newframe; - } - - // If necessary, put the relay into the packet. - if (m_lastRelay != msg->getRelay()) { - m_packet[m_packetLen] = NetPacketFieldTypes::Relay; - ++m_packetLen; - UnsignedByte newRelay = msg->getRelay(); - memcpy(m_packet + m_packetLen, &newRelay, sizeof(UnsignedByte)); - m_packetLen += sizeof(UnsignedByte); - - m_lastRelay = newRelay; - } - - // If necessary put the player ID into the packet. - if (m_lastPlayerID != cmdMsg->getPlayerID()) { - m_packet[m_packetLen] = NetPacketFieldTypes::PlayerId; - ++m_packetLen; - m_packet[m_packetLen] = cmdMsg->getPlayerID(); - m_packetLen += sizeof(UnsignedByte); - - m_lastPlayerID = cmdMsg->getPlayerID(); - needNewCommandID = TRUE; - } - - // If necessary, specify the command ID of this command. - if (((m_lastCommandID + 1) != (UnsignedShort)(cmdMsg->getID())) || (needNewCommandID == TRUE)) { - m_packet[m_packetLen] = NetPacketFieldTypes::CommandId; - ++m_packetLen; - UnsignedShort newID = cmdMsg->getID(); - memcpy(m_packet + m_packetLen, &newID, sizeof(UnsignedShort)); - m_packetLen += sizeof(UnsignedShort); - } - m_lastCommandID = cmdMsg->getID(); - - m_packet[m_packetLen] = NetPacketFieldTypes::Data; - ++m_packetLen; - - UnsignedInt newFrame = cmdMsg->getNewFrame(); - memcpy(m_packet + m_packetLen, &newFrame, sizeof(newFrame)); - m_packetLen += sizeof(newFrame); - - DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("NetPacket::addDisconnectScreenOff - added disconnect screen off command from player %d for frame %d, command id = %d", m_lastPlayerID, newFrame, m_lastCommandID)); - - ++m_numCommands; - - deleteInstance(m_lastCommand); - m_lastCommand = NEW_NETCOMMANDREF(msg->getCommand()); - m_lastCommand->setRelay(msg->getRelay()); - - return TRUE; - } - return FALSE; -} - -Bool NetPacket::isRoomForDisconnectScreenOffMessage(NetCommandRef *msg) { - Int len = 0; - Bool needNewCommandID = FALSE; - NetDisconnectScreenOffCommandMsg *cmdMsg = (NetDisconnectScreenOffCommandMsg *)(msg->getCommand()); - if (m_lastCommandType != cmdMsg->getNetCommandType()) { - ++len; - len += sizeof(UnsignedByte); - } - if (m_lastRelay != msg->getRelay()) { - len += sizeof(UnsignedByte) + sizeof(UnsignedByte); - } - if (m_lastFrame != cmdMsg->getExecutionFrame()) { - len += sizeof(UnsignedInt) + sizeof(UnsignedByte); - } - if (m_lastPlayerID != cmdMsg->getPlayerID()) { - ++len; - len += sizeof(UnsignedByte); - needNewCommandID = TRUE; - } - if (((m_lastCommandID + 1) != (UnsignedShort)(cmdMsg->getID())) || (needNewCommandID == TRUE)) { - len += sizeof(UnsignedShort) + sizeof(UnsignedByte); - } - - ++len; // for NetPacketFieldTypes::Data - len += sizeof(UnsignedInt); // for the disconnect frame - if ((len + m_packetLen) > MAX_PACKET_SIZE) { - return FALSE; - } - return TRUE; -} - -Bool NetPacket::addDisconnectFrameCommand(NetCommandRef *msg) { - Bool needNewCommandID = FALSE; - if (isRoomForDisconnectFrameMessage(msg)) { - NetDisconnectFrameCommandMsg *cmdMsg = (NetDisconnectFrameCommandMsg *)(msg->getCommand()); - - // If necessary, put the NetCommandType into the packet. - if (m_lastCommandType != cmdMsg->getNetCommandType()) { - m_packet[m_packetLen] = NetPacketFieldTypes::CommandType; - ++m_packetLen; - m_packet[m_packetLen] = cmdMsg->getNetCommandType(); - m_packetLen += sizeof(UnsignedByte); - - m_lastCommandType = cmdMsg->getNetCommandType(); - } - - // If necessary, put the execution frame into the packet. - if (m_lastFrame != cmdMsg->getExecutionFrame()) { - m_packet[m_packetLen] = NetPacketFieldTypes::Frame; - ++m_packetLen; - UnsignedInt newframe = cmdMsg->getExecutionFrame(); - memcpy(m_packet+m_packetLen, &newframe, sizeof(UnsignedInt)); - m_packetLen += sizeof(UnsignedInt); - - m_lastFrame = newframe; - } - - // If necessary, put the relay into the packet. - if (m_lastRelay != msg->getRelay()) { - m_packet[m_packetLen] = NetPacketFieldTypes::Relay; - ++m_packetLen; - UnsignedByte newRelay = msg->getRelay(); - memcpy(m_packet + m_packetLen, &newRelay, sizeof(UnsignedByte)); - m_packetLen += sizeof(UnsignedByte); - - m_lastRelay = newRelay; - } - - // If necessary put the player ID into the packet. - if (m_lastPlayerID != cmdMsg->getPlayerID()) { - m_packet[m_packetLen] = NetPacketFieldTypes::PlayerId; - ++m_packetLen; - m_packet[m_packetLen] = cmdMsg->getPlayerID(); - m_packetLen += sizeof(UnsignedByte); - - m_lastPlayerID = cmdMsg->getPlayerID(); - needNewCommandID = TRUE; - } - - // If necessary, specify the command ID of this command. - if (((m_lastCommandID + 1) != (UnsignedShort)(cmdMsg->getID())) || (needNewCommandID == TRUE)) { - m_packet[m_packetLen] = NetPacketFieldTypes::CommandId; - ++m_packetLen; - UnsignedShort newID = cmdMsg->getID(); - memcpy(m_packet + m_packetLen, &newID, sizeof(UnsignedShort)); - m_packetLen += sizeof(UnsignedShort); - } - m_lastCommandID = cmdMsg->getID(); - - m_packet[m_packetLen] = NetPacketFieldTypes::Data; - ++m_packetLen; - - UnsignedInt disconnectFrame = cmdMsg->getDisconnectFrame(); - memcpy(m_packet + m_packetLen, &disconnectFrame, sizeof(disconnectFrame)); - m_packetLen += sizeof(disconnectFrame); - - ++m_numCommands; - - deleteInstance(m_lastCommand); - m_lastCommand = NEW_NETCOMMANDREF(msg->getCommand()); - m_lastCommand->setRelay(msg->getRelay()); - - DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("NetPacket::addDisconnectFrame - added disconnect frame command from player %d for frame %d, command id = %d", m_lastPlayerID, disconnectFrame, m_lastCommandID)); - - return TRUE; - } - return FALSE; -} - -Bool NetPacket::isRoomForDisconnectFrameMessage(NetCommandRef *msg) { - Int len = 0; - Bool needNewCommandID = FALSE; - NetDisconnectFrameCommandMsg *cmdMsg = (NetDisconnectFrameCommandMsg *)(msg->getCommand()); - if (m_lastCommandType != cmdMsg->getNetCommandType()) { - ++len; - len += sizeof(UnsignedByte); - } - if (m_lastRelay != msg->getRelay()) { - len += sizeof(UnsignedByte) + sizeof(UnsignedByte); - } - if (m_lastFrame != cmdMsg->getExecutionFrame()) { - len += sizeof(UnsignedInt) + sizeof(UnsignedByte); - } - if (m_lastPlayerID != cmdMsg->getPlayerID()) { - ++len; - len += sizeof(UnsignedByte); - needNewCommandID = TRUE; - } - if (((m_lastCommandID + 1) != (UnsignedShort)(cmdMsg->getID())) || (needNewCommandID == TRUE)) { - len += sizeof(UnsignedShort) + sizeof(UnsignedByte); - } - - ++len; // for NetPacketFieldTypes::Data - len += sizeof(UnsignedInt); // for the disconnect frame - if ((len + m_packetLen) > MAX_PACKET_SIZE) { - return FALSE; - } - return TRUE; -} - -Bool NetPacket::addFileCommand(NetCommandRef *msg) { - Bool needNewCommandID = FALSE; - if (isRoomForFileMessage(msg)) { - NetFileCommandMsg *cmdMsg = (NetFileCommandMsg *)(msg->getCommand()); - - // If necessary, put the NetCommandType into the packet. - if (m_lastCommandType != cmdMsg->getNetCommandType()) { - m_packet[m_packetLen] = NetPacketFieldTypes::CommandType; - ++m_packetLen; - m_packet[m_packetLen] = cmdMsg->getNetCommandType(); - m_packetLen += sizeof(UnsignedByte); - - m_lastCommandType = cmdMsg->getNetCommandType(); - } - - // If necessary, put the relay into the packet. - if (m_lastRelay != msg->getRelay()) { - m_packet[m_packetLen] = NetPacketFieldTypes::Relay; - ++m_packetLen; - UnsignedByte newRelay = msg->getRelay(); - memcpy(m_packet + m_packetLen, &newRelay, sizeof(UnsignedByte)); - m_packetLen += sizeof(UnsignedByte); - - m_lastRelay = newRelay; - } - - // If necessary put the player ID into the packet. - if (m_lastPlayerID != cmdMsg->getPlayerID()) { - m_packet[m_packetLen] = NetPacketFieldTypes::PlayerId; - ++m_packetLen; - m_packet[m_packetLen] = cmdMsg->getPlayerID(); - m_packetLen += sizeof(UnsignedByte); - - m_lastPlayerID = cmdMsg->getPlayerID(); - needNewCommandID = TRUE; - } - - // If necessary, specify the command ID of this command. - if (((m_lastCommandID + 1) != (UnsignedShort)(cmdMsg->getID())) || (needNewCommandID == TRUE)) { - m_packet[m_packetLen] = NetPacketFieldTypes::CommandId; - ++m_packetLen; - UnsignedShort newID = cmdMsg->getID(); - memcpy(m_packet + m_packetLen, &newID, sizeof(UnsignedShort)); - m_packetLen += sizeof(UnsignedShort); - } - m_lastCommandID = cmdMsg->getID(); - - - m_packet[m_packetLen] = NetPacketFieldTypes::Data; - ++m_packetLen; - - AsciiString filename = cmdMsg->getPortableFilename(); // PORTABLE - strcpy((char *)(m_packet + m_packetLen), filename.str()); - m_packetLen += filename.getLength() + 1; - - UnsignedInt fileLength = cmdMsg->getFileLength(); - memcpy(m_packet + m_packetLen, &fileLength, sizeof(fileLength)); - m_packetLen += sizeof(fileLength); - - memcpy(m_packet + m_packetLen, cmdMsg->getFileData(), fileLength); - m_packetLen += fileLength; - - ++m_numCommands; - - deleteInstance(m_lastCommand); - m_lastCommand = NEW_NETCOMMANDREF(msg->getCommand()); - m_lastCommand->setRelay(msg->getRelay()); - return TRUE; - } - return FALSE; -} - -Bool NetPacket::isRoomForFileMessage(NetCommandRef *msg) { - Int len = 0; - Bool needNewCommandID = FALSE; - NetFileCommandMsg *cmdMsg = (NetFileCommandMsg *)(msg->getCommand()); - if (m_lastCommandType != cmdMsg->getNetCommandType()) { - len += sizeof(UnsignedByte) + sizeof(UnsignedByte); - } - if (m_lastRelay != msg->getRelay()) { - len += sizeof(UnsignedByte) + sizeof(UnsignedByte); - } - if (m_lastPlayerID != cmdMsg->getPlayerID()) { - len += sizeof(UnsignedByte) + sizeof(UnsignedByte); - needNewCommandID = TRUE; - } - if (((m_lastCommandID + 1) != (UnsignedShort)(cmdMsg->getID())) || (needNewCommandID == TRUE)) { - len += sizeof(UnsignedByte) + sizeof(UnsignedShort); - } - - ++len; // NetPacketFieldTypes::Data - len += cmdMsg->getPortableFilename().getLength() + 1; // PORTABLE filename + the terminating 0 - len += sizeof(UnsignedInt); // filedata length - len += cmdMsg->getFileLength(); - - if ((len + m_packetLen) > MAX_PACKET_SIZE) { - return FALSE; - } - - return TRUE; -} - -Bool NetPacket::addFileAnnounceCommand(NetCommandRef *msg) { - Bool needNewCommandID = FALSE; - if (isRoomForFileAnnounceMessage(msg)) { - NetFileAnnounceCommandMsg *cmdMsg = (NetFileAnnounceCommandMsg *)(msg->getCommand()); - - // If necessary, put the NetCommandType into the packet. - if (m_lastCommandType != cmdMsg->getNetCommandType()) { - m_packet[m_packetLen] = NetPacketFieldTypes::CommandType; - ++m_packetLen; - m_packet[m_packetLen] = cmdMsg->getNetCommandType(); - m_packetLen += sizeof(UnsignedByte); - - m_lastCommandType = cmdMsg->getNetCommandType(); - } - - // If necessary, put the relay into the packet. - if (m_lastRelay != msg->getRelay()) { - m_packet[m_packetLen] = NetPacketFieldTypes::Relay; - ++m_packetLen; - UnsignedByte newRelay = msg->getRelay(); - memcpy(m_packet + m_packetLen, &newRelay, sizeof(UnsignedByte)); - m_packetLen += sizeof(UnsignedByte); - - m_lastRelay = newRelay; - } - - // If necessary put the player ID into the packet. - if (m_lastPlayerID != cmdMsg->getPlayerID()) { - m_packet[m_packetLen] = NetPacketFieldTypes::PlayerId; - ++m_packetLen; - m_packet[m_packetLen] = cmdMsg->getPlayerID(); - m_packetLen += sizeof(UnsignedByte); - - m_lastPlayerID = cmdMsg->getPlayerID(); - needNewCommandID = TRUE; - } - - // If necessary, specify the command ID of this command. - if (((m_lastCommandID + 1) != (UnsignedShort)(cmdMsg->getID())) || (needNewCommandID == TRUE)) { - m_packet[m_packetLen] = NetPacketFieldTypes::CommandId; - ++m_packetLen; - UnsignedShort newID = cmdMsg->getID(); - memcpy(m_packet + m_packetLen, &newID, sizeof(UnsignedShort)); - m_packetLen += sizeof(UnsignedShort); - } - m_lastCommandID = cmdMsg->getID(); - - - m_packet[m_packetLen] = NetPacketFieldTypes::Data; - ++m_packetLen; - - AsciiString filename = cmdMsg->getPortableFilename(); // PORTABLE - strcpy((char *)(m_packet + m_packetLen), filename.str()); - m_packetLen += filename.getLength() + 1; - - UnsignedShort fileID = cmdMsg->getFileID(); - memcpy(m_packet + m_packetLen, &fileID, sizeof(fileID)); - m_packetLen += sizeof(fileID); - - UnsignedByte playerMask = cmdMsg->getPlayerMask(); - memcpy(m_packet + m_packetLen, &playerMask, sizeof(playerMask)); - m_packetLen += sizeof(playerMask); - - ++m_numCommands; - - deleteInstance(m_lastCommand); - m_lastCommand = NEW_NETCOMMANDREF(msg->getCommand()); - m_lastCommand->setRelay(msg->getRelay()); - - DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("Adding file announce message for fileID %d, ID %d to packet", - cmdMsg->getFileID(), cmdMsg->getID())); - return TRUE; - } - DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("No room to add file announce message to packet")); - return FALSE; -} - -Bool NetPacket::isRoomForFileAnnounceMessage(NetCommandRef *msg) { - Int len = 0; - Bool needNewCommandID = FALSE; - NetFileAnnounceCommandMsg *cmdMsg = (NetFileAnnounceCommandMsg *)(msg->getCommand()); - if (m_lastCommandType != cmdMsg->getNetCommandType()) { - len += sizeof(UnsignedByte) + sizeof(UnsignedByte); - } - if (m_lastRelay != msg->getRelay()) { - len += sizeof(UnsignedByte) + sizeof(UnsignedByte); - } - if (m_lastPlayerID != cmdMsg->getPlayerID()) { - len += sizeof(UnsignedByte) + sizeof(UnsignedByte); - needNewCommandID = TRUE; - } - if (((m_lastCommandID + 1) != (UnsignedShort)(cmdMsg->getID())) || (needNewCommandID == TRUE)) { - len += sizeof(UnsignedByte) + sizeof(UnsignedShort); - } - - ++len; // NetPacketFieldTypes::Data - len += cmdMsg->getPortableFilename().getLength() + 1; // PORTABLE filename + the terminating 0 - len += sizeof(UnsignedShort); // m_fileID - len += sizeof(UnsignedByte); // m_playerMask - - if ((len + m_packetLen) > MAX_PACKET_SIZE) { - return FALSE; - } - - return TRUE; -} - -Bool NetPacket::addFileProgressCommand(NetCommandRef *msg) { - Bool needNewCommandID = FALSE; - if (isRoomForFileProgressMessage(msg)) { - NetFileProgressCommandMsg *cmdMsg = (NetFileProgressCommandMsg *)(msg->getCommand()); - - // If necessary, put the NetCommandType into the packet. - if (m_lastCommandType != cmdMsg->getNetCommandType()) { - m_packet[m_packetLen] = NetPacketFieldTypes::CommandType; - ++m_packetLen; - m_packet[m_packetLen] = cmdMsg->getNetCommandType(); - m_packetLen += sizeof(UnsignedByte); - - m_lastCommandType = cmdMsg->getNetCommandType(); - } - - // If necessary, put the relay into the packet. - if (m_lastRelay != msg->getRelay()) { - m_packet[m_packetLen] = NetPacketFieldTypes::Relay; - ++m_packetLen; - UnsignedByte newRelay = msg->getRelay(); - memcpy(m_packet + m_packetLen, &newRelay, sizeof(UnsignedByte)); - m_packetLen += sizeof(UnsignedByte); - - m_lastRelay = newRelay; - } - - // If necessary put the player ID into the packet. - if (m_lastPlayerID != cmdMsg->getPlayerID()) { - m_packet[m_packetLen] = NetPacketFieldTypes::PlayerId; - ++m_packetLen; - m_packet[m_packetLen] = cmdMsg->getPlayerID(); - m_packetLen += sizeof(UnsignedByte); - - m_lastPlayerID = cmdMsg->getPlayerID(); - needNewCommandID = TRUE; - } - - // If necessary, specify the command ID of this command. - if (((m_lastCommandID + 1) != (UnsignedShort)(cmdMsg->getID())) || (needNewCommandID == TRUE)) { - m_packet[m_packetLen] = NetPacketFieldTypes::CommandId; - ++m_packetLen; - UnsignedShort newID = cmdMsg->getID(); - memcpy(m_packet + m_packetLen, &newID, sizeof(UnsignedShort)); - m_packetLen += sizeof(UnsignedShort); - } - m_lastCommandID = cmdMsg->getID(); - - - m_packet[m_packetLen] = NetPacketFieldTypes::Data; - ++m_packetLen; - - UnsignedShort fileID = cmdMsg->getFileID(); - memcpy(m_packet + m_packetLen, &fileID, sizeof(fileID)); - m_packetLen += sizeof(fileID); - - Int progress = cmdMsg->getProgress(); - memcpy(m_packet + m_packetLen, &progress, sizeof(progress)); - m_packetLen += sizeof(progress); - - ++m_numCommands; - - deleteInstance(m_lastCommand); - m_lastCommand = NEW_NETCOMMANDREF(msg->getCommand()); - m_lastCommand->setRelay(msg->getRelay()); - - return TRUE; - } - return FALSE; -} - -Bool NetPacket::isRoomForFileProgressMessage(NetCommandRef *msg) { - Int len = 0; - Bool needNewCommandID = FALSE; - NetFileProgressCommandMsg *cmdMsg = (NetFileProgressCommandMsg *)(msg->getCommand()); - if (m_lastCommandType != cmdMsg->getNetCommandType()) { - len += sizeof(UnsignedByte) + sizeof(UnsignedByte); - } - if (m_lastRelay != msg->getRelay()) { - len += sizeof(UnsignedByte) + sizeof(UnsignedByte); - } - if (m_lastPlayerID != cmdMsg->getPlayerID()) { - len += sizeof(UnsignedByte) + sizeof(UnsignedByte); - needNewCommandID = TRUE; - } - if (((m_lastCommandID + 1) != (UnsignedShort)(cmdMsg->getID())) || (needNewCommandID == TRUE)) { - len += sizeof(UnsignedByte) + sizeof(UnsignedShort); - } - - ++len; // NetPacketFieldTypes::Data - len += sizeof(UnsignedShort); // m_fileID - len += sizeof(Int); // m_progress - - if ((len + m_packetLen) > MAX_PACKET_SIZE) { - return FALSE; - } - - return TRUE; -} - -Bool NetPacket::addWrapperCommand(NetCommandRef *msg) { - Bool needNewCommandID = FALSE; - if (isRoomForWrapperMessage(msg)) { - NetWrapperCommandMsg *cmdMsg = (NetWrapperCommandMsg *)(msg->getCommand()); - - // If necessary, put the NetCommandType into the packet. - if (m_lastCommandType != cmdMsg->getNetCommandType()) { - m_packet[m_packetLen] = NetPacketFieldTypes::CommandType; - ++m_packetLen; - m_packet[m_packetLen] = cmdMsg->getNetCommandType(); - m_packetLen += sizeof(UnsignedByte); - - m_lastCommandType = cmdMsg->getNetCommandType(); - } - - // If necessary, put the relay into the packet. - if (m_lastRelay != msg->getRelay()) { - m_packet[m_packetLen] = NetPacketFieldTypes::Relay; - ++m_packetLen; - UnsignedByte newRelay = msg->getRelay(); - memcpy(m_packet + m_packetLen, &newRelay, sizeof(UnsignedByte)); - m_packetLen += sizeof(UnsignedByte); - - m_lastRelay = newRelay; - } - - // If necessary put the player ID into the packet. - if (m_lastPlayerID != cmdMsg->getPlayerID()) { - m_packet[m_packetLen] = NetPacketFieldTypes::PlayerId; - ++m_packetLen; - m_packet[m_packetLen] = cmdMsg->getPlayerID(); - m_packetLen += sizeof(UnsignedByte); - - m_lastPlayerID = cmdMsg->getPlayerID(); - needNewCommandID = TRUE; - } - - // If necessary, specify the command ID of this command. - if (((m_lastCommandID + 1) != (UnsignedShort)(cmdMsg->getID())) || (needNewCommandID == TRUE)) { - m_packet[m_packetLen] = NetPacketFieldTypes::CommandId; - ++m_packetLen; - UnsignedShort newID = cmdMsg->getID(); - memcpy(m_packet + m_packetLen, &newID, sizeof(UnsignedShort)); - m_packetLen += sizeof(UnsignedShort); - } - m_lastCommandID = cmdMsg->getID(); - - - m_packet[m_packetLen] = NetPacketFieldTypes::Data; - ++m_packetLen; - - // wrapped command ID - UnsignedShort wrappedCommandID = cmdMsg->getWrappedCommandID(); - memcpy(m_packet + m_packetLen, &wrappedCommandID, sizeof(wrappedCommandID)); - m_packetLen += sizeof(wrappedCommandID); - - // chunk number -// m_packet[m_packetLen] = cmdMsg->getChunkNumber(); -// ++m_packetLen; - UnsignedInt chunkNumber = cmdMsg->getChunkNumber(); - memcpy(m_packet + m_packetLen, &chunkNumber, sizeof(chunkNumber)); - m_packetLen += sizeof(chunkNumber); - - // number of chunks -// m_packet[m_packetLen] = cmdMsg->getNumChunks(); -// ++m_packetLen; - UnsignedInt numChunks = cmdMsg->getNumChunks(); - memcpy(m_packet + m_packetLen, &numChunks, sizeof(numChunks)); - m_packetLen += sizeof(numChunks); - - // total length of data for all chunks - UnsignedInt totalDataLength = cmdMsg->getTotalDataLength(); - memcpy(m_packet + m_packetLen, &totalDataLength, sizeof(totalDataLength)); - m_packetLen += sizeof(totalDataLength); - - // data length for this chunk - UnsignedInt dataLength = cmdMsg->getDataLength(); - memcpy(m_packet + m_packetLen, &dataLength, sizeof(dataLength)); - m_packetLen += sizeof(dataLength); - - // the offset into the data of this chunk - UnsignedInt dataOffset = cmdMsg->getDataOffset(); - memcpy(m_packet + m_packetLen, &dataOffset, sizeof(dataOffset)); - m_packetLen += sizeof(dataOffset); - - // the data for this chunk - UnsignedByte *data = cmdMsg->getData(); - memcpy(m_packet + m_packetLen, data, dataLength); - m_packetLen += dataLength; - - ++m_numCommands; - - deleteInstance(m_lastCommand); - m_lastCommand = NEW_NETCOMMANDREF(msg->getCommand()); - m_lastCommand->setRelay(msg->getRelay()); - - return TRUE; - } - return FALSE; -} - -Bool NetPacket::isRoomForWrapperMessage(NetCommandRef *msg) { - Int len = 0; - Bool needNewCommandID = FALSE; - NetWrapperCommandMsg *cmdMsg = (NetWrapperCommandMsg *)(msg->getCommand()); - if (m_lastCommandType != cmdMsg->getNetCommandType()) { - len += sizeof(UnsignedByte) + sizeof(UnsignedByte); - } - if (m_lastRelay != msg->getRelay()) { - len += sizeof(UnsignedByte) + sizeof(UnsignedByte); - } - if (m_lastPlayerID != cmdMsg->getPlayerID()) { - len += sizeof(UnsignedByte) + sizeof(UnsignedByte); - needNewCommandID = TRUE; - } - if (((m_lastCommandID + 1) != (UnsignedShort)(cmdMsg->getID())) || (needNewCommandID == TRUE)) { - len += sizeof(UnsignedByte) + sizeof(UnsignedShort); - } - - ++len; // NetPacketFieldTypes::Data - len += sizeof(UnsignedShort); // wrapped command ID - len += sizeof(UnsignedInt); // chunk number - len += sizeof(UnsignedInt); // number of chunks - len += sizeof(UnsignedInt); // total data length - len += sizeof(UnsignedInt); // data length of this chunk - len += sizeof(UnsignedInt); // offset of this chunk - len += cmdMsg->getDataLength(); // for the data of this chunk - - if ((len + m_packetLen) > MAX_PACKET_SIZE) { - return FALSE; - } - - return TRUE; -} - -/** - * Add a TimeOutGameStart to the packet. Returns true if successful. - */ -Bool NetPacket::addTimeOutGameStartMessage(NetCommandRef *msg) { - Bool needNewCommandID = FALSE; - if (isRoomForLoadCompleteMessage(msg)) { - NetCommandMsg *cmdMsg = (NetCommandMsg *)(msg->getCommand()); - - // If necessary, put the NetCommandType into the packet. - if (m_lastCommandType != cmdMsg->getNetCommandType()) { - m_packet[m_packetLen] = NetPacketFieldTypes::CommandType; - ++m_packetLen; - m_packet[m_packetLen] = cmdMsg->getNetCommandType(); - m_packetLen += sizeof(UnsignedByte); - - m_lastCommandType = cmdMsg->getNetCommandType(); - } - - // If necessary, put the relay into the packet. - if (m_lastRelay != msg->getRelay()) { - m_packet[m_packetLen] = NetPacketFieldTypes::Relay; - ++m_packetLen; - UnsignedByte newRelay = msg->getRelay(); - memcpy(m_packet+m_packetLen, &newRelay, sizeof(UnsignedByte)); - m_packetLen += sizeof(UnsignedByte); - - m_lastRelay = newRelay; - } - - if (m_lastPlayerID != cmdMsg->getPlayerID()) { - m_packet[m_packetLen] = NetPacketFieldTypes::PlayerId; - ++m_packetLen; - m_packet[m_packetLen] = cmdMsg->getPlayerID(); - m_packetLen += sizeof(UnsignedByte); - - m_lastPlayerID = cmdMsg->getPlayerID(); - needNewCommandID = TRUE; - } - - // If necessary, specify the command ID of this command. - if (((m_lastCommandID + 1) != (UnsignedShort)(cmdMsg->getID())) || (needNewCommandID == TRUE)) { - m_packet[m_packetLen] = NetPacketFieldTypes::CommandId; - ++m_packetLen; - UnsignedShort newID = cmdMsg->getID(); - memcpy(m_packet + m_packetLen, &newID, sizeof(UnsignedShort)); - m_packetLen += sizeof(UnsignedShort); - } - m_lastCommandID = cmdMsg->getID(); - - m_packet[m_packetLen] = NetPacketFieldTypes::Data; - ++m_packetLen; - - ++m_numCommands; - - deleteInstance(m_lastCommand); - m_lastCommand = NEW_NETCOMMANDREF(msg->getCommand()); - m_lastCommand->setRelay(msg->getRelay()); - -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("Added keep alive command to packet.")); - - return TRUE; - } - return FALSE; -} - -/** - * Returns true if there is room in the packet for this command. - */ -Bool NetPacket::isRoomForTimeOutGameStartMessage(NetCommandRef *msg) { - Int len = 0; - NetCommandMsg *cmdMsg = (NetCommandMsg *)(msg->getCommand()); - if (m_lastCommandType != cmdMsg->getNetCommandType()) { - ++len; - len += sizeof(UnsignedByte); - } - if (m_lastRelay != msg->getRelay()) { - len += sizeof(UnsignedByte) + sizeof(UnsignedByte); - } - if (m_lastPlayerID != cmdMsg->getPlayerID()) { - ++len; - len += sizeof(UnsignedByte); - } - - ++len; // For the NetPacketFieldTypes::Data - if ((len + m_packetLen) > MAX_PACKET_SIZE) { - return FALSE; - } - return TRUE; -} - - - -/** - * Add a Progress command to the packet. Returns true if successful. - */ -Bool NetPacket::addLoadCompleteMessage(NetCommandRef *msg) { - Bool needNewCommandID = FALSE; - if (isRoomForLoadCompleteMessage(msg)) { - NetCommandMsg *cmdMsg = (NetCommandMsg *)(msg->getCommand()); - - // If necessary, put the NetCommandType into the packet. - if (m_lastCommandType != cmdMsg->getNetCommandType()) { - m_packet[m_packetLen] = NetPacketFieldTypes::CommandType; - ++m_packetLen; - m_packet[m_packetLen] = cmdMsg->getNetCommandType(); - m_packetLen += sizeof(UnsignedByte); - - m_lastCommandType = cmdMsg->getNetCommandType(); - } - - // If necessary, put the relay into the packet. - if (m_lastRelay != msg->getRelay()) { - m_packet[m_packetLen] = NetPacketFieldTypes::Relay; - ++m_packetLen; - UnsignedByte newRelay = msg->getRelay(); - memcpy(m_packet+m_packetLen, &newRelay, sizeof(UnsignedByte)); - m_packetLen += sizeof(UnsignedByte); - - m_lastRelay = newRelay; - } - - if (m_lastPlayerID != cmdMsg->getPlayerID()) { - m_packet[m_packetLen] = NetPacketFieldTypes::PlayerId; - ++m_packetLen; - m_packet[m_packetLen] = cmdMsg->getPlayerID(); - m_packetLen += sizeof(UnsignedByte); - - m_lastPlayerID = cmdMsg->getPlayerID(); - needNewCommandID = TRUE; - } - - // If necessary, specify the command ID of this command. - if (((m_lastCommandID + 1) != (UnsignedShort)(cmdMsg->getID())) || (needNewCommandID == TRUE)) { - m_packet[m_packetLen] = NetPacketFieldTypes::CommandId; - ++m_packetLen; - UnsignedShort newID = cmdMsg->getID(); - memcpy(m_packet + m_packetLen, &newID, sizeof(UnsignedShort)); - m_packetLen += sizeof(UnsignedShort); - } - m_lastCommandID = cmdMsg->getID(); - - m_packet[m_packetLen] = NetPacketFieldTypes::Data; - ++m_packetLen; - - ++m_numCommands; - - deleteInstance(m_lastCommand); - m_lastCommand = NEW_NETCOMMANDREF(msg->getCommand()); - m_lastCommand->setRelay(msg->getRelay()); - -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("Added keep alive command to packet.")); - - return TRUE; - } - return FALSE; -} - -/** - * Returns true if there is room in the packet for this command. - */ -Bool NetPacket::isRoomForLoadCompleteMessage(NetCommandRef *msg) { - Int len = 0; - NetCommandMsg *cmdMsg = (NetCommandMsg *)(msg->getCommand()); - if (m_lastCommandType != cmdMsg->getNetCommandType()) { - ++len; - len += sizeof(UnsignedByte); - } - if (m_lastRelay != msg->getRelay()) { - len += sizeof(UnsignedByte) + sizeof(UnsignedByte); - } - if (m_lastPlayerID != cmdMsg->getPlayerID()) { - ++len; - len += sizeof(UnsignedByte); - } - - ++len; // For the NetPacketFieldTypes::Data - if ((len + m_packetLen) > MAX_PACKET_SIZE) { - return FALSE; - } - return TRUE; -} - - - - -/** - * Add a Progress command to the packet. Returns true if successful. - */ -Bool NetPacket::addProgressMessage(NetCommandRef *msg) { - if (isRoomForProgressMessage(msg)) { - NetProgressCommandMsg *cmdMsg = (NetProgressCommandMsg *)(msg->getCommand()); - - // If necessary, put the NetCommandType into the packet. - if (m_lastCommandType != cmdMsg->getNetCommandType()) { - m_packet[m_packetLen] = NetPacketFieldTypes::CommandType; - ++m_packetLen; - m_packet[m_packetLen] = cmdMsg->getNetCommandType(); - m_packetLen += sizeof(UnsignedByte); - - m_lastCommandType = cmdMsg->getNetCommandType(); - } - - // If necessary, put the relay into the packet. - if (m_lastRelay != msg->getRelay()) { - m_packet[m_packetLen] = NetPacketFieldTypes::Relay; - ++m_packetLen; - UnsignedByte newRelay = msg->getRelay(); - memcpy(m_packet+m_packetLen, &newRelay, sizeof(UnsignedByte)); - m_packetLen += sizeof(UnsignedByte); - - m_lastRelay = newRelay; - } - - if (m_lastPlayerID != cmdMsg->getPlayerID()) { - m_packet[m_packetLen] = NetPacketFieldTypes::PlayerId; - ++m_packetLen; - m_packet[m_packetLen] = cmdMsg->getPlayerID(); - m_packetLen += sizeof(UnsignedByte); - - m_lastPlayerID = cmdMsg->getPlayerID(); - } - - m_packet[m_packetLen] = NetPacketFieldTypes::Data; - ++m_packetLen; - - m_packet[m_packetLen] = cmdMsg->getPercentage(); - ++m_packetLen; - - ++m_numCommands; - - deleteInstance(m_lastCommand); - m_lastCommand = NEW_NETCOMMANDREF(msg->getCommand()); - m_lastCommand->setRelay(msg->getRelay()); - -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("Added keep alive command to packet.")); - - return TRUE; - } - return FALSE; -} - -/** - * Returns true if there is room in the packet for this command. - */ -Bool NetPacket::isRoomForProgressMessage(NetCommandRef *msg) { - Int len = 0; - NetProgressCommandMsg *cmdMsg = (NetProgressCommandMsg *)(msg->getCommand()); - if (m_lastCommandType != cmdMsg->getNetCommandType()) { - ++len; - len += sizeof(UnsignedByte); - } - if (m_lastRelay != msg->getRelay()) { - len += sizeof(UnsignedByte) + sizeof(UnsignedByte); - } - if (m_lastPlayerID != cmdMsg->getPlayerID()) { - ++len; - len += sizeof(UnsignedByte); - } - - ++len; // For the NetPacketFieldTypes::Data - ++len; // percentage - if ((len + m_packetLen) > MAX_PACKET_SIZE) { - return FALSE; - } - return TRUE; -} - - - -Bool NetPacket::addDisconnectVoteCommand(NetCommandRef *msg) { - Bool needNewCommandID = FALSE; - -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("NetPacket::addDisconnectVoteCommand - entering...")); - // need type, player id, relay, command id, slot number - if (isRoomForDisconnectVoteMessage(msg)) { - NetDisconnectVoteCommandMsg *cmdMsg = (NetDisconnectVoteCommandMsg *)(msg->getCommand()); -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("NetPacket::addDisconnectVoteCommand - adding run ahead command")); - - // If necessary, put the NetCommandType into the packet. - if (m_lastCommandType != cmdMsg->getNetCommandType()) { - m_packet[m_packetLen] = NetPacketFieldTypes::CommandType; - ++m_packetLen; - m_packet[m_packetLen] = cmdMsg->getNetCommandType(); - m_packetLen += sizeof(UnsignedByte); - - m_lastCommandType = cmdMsg->getNetCommandType(); - } - - // If necessary, put the relay into the packet. - if (m_lastRelay != msg->getRelay()) { - m_packet[m_packetLen] = NetPacketFieldTypes::Relay; - ++m_packetLen; - UnsignedByte newRelay = msg->getRelay(); - memcpy(m_packet+m_packetLen, &newRelay, sizeof(UnsignedByte)); - m_packetLen += sizeof(UnsignedByte); - - m_lastRelay = newRelay; - } - -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("relay = %d, ", m_lastRelay)); - - if (m_lastPlayerID != cmdMsg->getPlayerID()) { - m_packet[m_packetLen] = NetPacketFieldTypes::PlayerId; - ++m_packetLen; - m_packet[m_packetLen] = cmdMsg->getPlayerID(); - m_packetLen += sizeof(UnsignedByte); - - m_lastPlayerID = cmdMsg->getPlayerID(); - needNewCommandID = TRUE; - } - -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("player = %d", m_lastPlayerID)); - - // If necessary, specify the command ID of this command. - if (((m_lastCommandID + 1) != (UnsignedShort)(cmdMsg->getID())) || (needNewCommandID == TRUE)) { - m_packet[m_packetLen] = NetPacketFieldTypes::CommandId; - ++m_packetLen; - UnsignedShort newID = cmdMsg->getID(); - memcpy(m_packet + m_packetLen, &newID, sizeof(UnsignedShort)); - m_packetLen += sizeof(UnsignedShort); - } - m_lastCommandID = cmdMsg->getID(); - -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("command id = %d", m_lastCommandID)); - - m_packet[m_packetLen] = NetPacketFieldTypes::Data; - ++m_packetLen; - UnsignedByte slot = cmdMsg->getSlot(); - memcpy(m_packet + m_packetLen, &slot, sizeof(slot)); - m_packetLen += sizeof(slot); - - UnsignedInt voteFrame = cmdMsg->getVoteFrame(); - memcpy(m_packet + m_packetLen, &voteFrame, sizeof(voteFrame)); - m_packetLen += sizeof(voteFrame); - -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("NetPacket::addDisconnectVoteCommand - added disconnect vote command, player id %d command id %d, voted slot %d", m_lastPlayerID, m_lastCommandID, slot)); - - ++m_numCommands; - - deleteInstance(m_lastCommand); - m_lastCommand = NEW_NETCOMMANDREF(msg->getCommand()); - m_lastCommand->setRelay(msg->getRelay()); - return TRUE; - } - return FALSE; -} - -/** - * Returns true if there is room for this player disconnect command in this packet. - */ -Bool NetPacket::isRoomForDisconnectVoteMessage(NetCommandRef *msg) { - Int len = 0; - Bool needNewCommandID = FALSE; - NetDisconnectVoteCommandMsg *cmdMsg = (NetDisconnectVoteCommandMsg *)(msg->getCommand()); - if (m_lastCommandType != cmdMsg->getNetCommandType()) { - ++len; - len += sizeof(UnsignedByte); - } - if (m_lastRelay != msg->getRelay()) { - len += sizeof(UnsignedByte) + sizeof(UnsignedByte); - } - if (m_lastPlayerID != cmdMsg->getPlayerID()) { - ++len; - len += sizeof(UnsignedByte); - needNewCommandID = TRUE; - } - if (((m_lastCommandID + 1) != (UnsignedShort)(cmdMsg->getID())) || (needNewCommandID == TRUE)) { - len += sizeof(UnsignedShort) + sizeof(UnsignedByte); - } - - ++len; // the NetPacketFieldTypes::Data - len += sizeof(UnsignedByte); // slot number - len += sizeof(UnsignedInt); // vote frame - - if ((len + m_packetLen) > MAX_PACKET_SIZE) { - return FALSE; - } - return TRUE; -} - -Bool NetPacket::addDisconnectChatCommand(NetCommandRef *msg) { - // type, player, id, relay, data - // data format: 1 byte string length, string (two bytes per character) -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("NetPacket::addDisconnectChatCommand - Entering...")); - if (isRoomForDisconnectChatMessage(msg)) { - NetDisconnectChatCommandMsg *cmdMsg = (NetDisconnectChatCommandMsg *)(msg->getCommand()); -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("NetPacket::addDisconnectChatCommand - adding run ahead command")); - - // If necessary, put the NetCommandType into the packet. - if (m_lastCommandType != cmdMsg->getNetCommandType()) { - m_packet[m_packetLen] = NetPacketFieldTypes::CommandType; - ++m_packetLen; - m_packet[m_packetLen] = cmdMsg->getNetCommandType(); - m_packetLen += sizeof(UnsignedByte); - - m_lastCommandType = cmdMsg->getNetCommandType(); - } - - // If necessary, put the relay into the packet. - if (m_lastRelay != msg->getRelay()) { - m_packet[m_packetLen] = NetPacketFieldTypes::Relay; - ++m_packetLen; - UnsignedByte newRelay = msg->getRelay(); - memcpy(m_packet+m_packetLen, &newRelay, sizeof(UnsignedByte)); - m_packetLen += sizeof(UnsignedByte); - - m_lastRelay = newRelay; - } - -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("relay = %d, ", m_lastRelay)); - - if (m_lastPlayerID != cmdMsg->getPlayerID()) { - m_packet[m_packetLen] = NetPacketFieldTypes::PlayerId; - ++m_packetLen; - m_packet[m_packetLen] = cmdMsg->getPlayerID(); - m_packetLen += sizeof(UnsignedByte); - - m_lastPlayerID = cmdMsg->getPlayerID(); - } - -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("player = %d", m_lastPlayerID)); - - m_packet[m_packetLen] = NetPacketFieldTypes::Data; - ++m_packetLen; - UnicodeString unitext = cmdMsg->getText(); - UnsignedByte length = unitext.getLength(); - memcpy(m_packet + m_packetLen, &length, sizeof(UnsignedByte)); - m_packetLen += sizeof(UnsignedByte); - - memcpy(m_packet + m_packetLen, unitext.str(), length * sizeof(UnsignedShort)); - m_packetLen += length * sizeof(UnsignedShort); - -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("NetPacket - added disconnect chat command")); - - ++m_numCommands; - - deleteInstance(m_lastCommand); - m_lastCommand = NEW_NETCOMMANDREF(msg->getCommand()); - m_lastCommand->setRelay(msg->getRelay()); - return TRUE; - } - return FALSE; -} - -Bool NetPacket::isRoomForDisconnectChatMessage(NetCommandRef *msg) { - Int len = 0; - NetDisconnectChatCommandMsg *cmdMsg = (NetDisconnectChatCommandMsg *)(msg->getCommand()); - if (m_lastCommandType != cmdMsg->getNetCommandType()) { - ++len; - len += sizeof(UnsignedByte); - } - if (m_lastRelay != msg->getRelay()) { - len += sizeof(UnsignedByte) + sizeof(UnsignedByte); - } - if (m_lastPlayerID != cmdMsg->getPlayerID()) { - ++len; - len += sizeof(UnsignedByte); - } - - ++len; // the NetPacketFieldTypes::Data - len += sizeof(UnsignedByte); // string length - UnsignedByte textLen = cmdMsg->getText().getLength(); - len += textLen * sizeof(UnsignedShort); - if ((len + m_packetLen) > MAX_PACKET_SIZE) { - return FALSE; - } - return TRUE; -} - -Bool NetPacket::addChatCommand(NetCommandRef *msg) { - Bool needNewCommandID = FALSE; - if (isRoomForChatMessage(msg)) { - NetChatCommandMsg *cmdMsg = (NetChatCommandMsg *)(msg->getCommand()); -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("NetPacket::addDisconnectChatCommand - adding run ahead command")); - - // If necessary, put the NetCommandType into the packet. - if (m_lastCommandType != cmdMsg->getNetCommandType()) { - m_packet[m_packetLen] = NetPacketFieldTypes::CommandType; - ++m_packetLen; - m_packet[m_packetLen] = cmdMsg->getNetCommandType(); - m_packetLen += sizeof(UnsignedByte); - - m_lastCommandType = cmdMsg->getNetCommandType(); - } - - // If necessary, put the execution frame into the packet. - if (m_lastFrame != cmdMsg->getExecutionFrame()) { - m_packet[m_packetLen] = NetPacketFieldTypes::Frame; - ++m_packetLen; - UnsignedInt newframe = cmdMsg->getExecutionFrame(); - memcpy(m_packet+m_packetLen, &newframe, sizeof(UnsignedInt)); - m_packetLen += sizeof(UnsignedInt); - - m_lastFrame = newframe; - } - - // If necessary, put the relay into the packet. - if (m_lastRelay != msg->getRelay()) { - m_packet[m_packetLen] = NetPacketFieldTypes::Relay; - ++m_packetLen; - UnsignedByte newRelay = msg->getRelay(); - memcpy(m_packet+m_packetLen, &newRelay, sizeof(UnsignedByte)); - m_packetLen += sizeof(UnsignedByte); - - m_lastRelay = newRelay; - } - -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("relay = %d, ", m_lastRelay)); - - if (m_lastPlayerID != cmdMsg->getPlayerID()) { - m_packet[m_packetLen] = NetPacketFieldTypes::PlayerId; - ++m_packetLen; - m_packet[m_packetLen] = cmdMsg->getPlayerID(); - m_packetLen += sizeof(UnsignedByte); - - m_lastPlayerID = cmdMsg->getPlayerID(); - needNewCommandID = TRUE; - } - -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("player = %d", m_lastPlayerID)); - - // If necessary, specify the command ID of this command. - if (((m_lastCommandID + 1) != (UnsignedShort)(cmdMsg->getID())) || (needNewCommandID == TRUE)) { - m_packet[m_packetLen] = NetPacketFieldTypes::CommandId; - ++m_packetLen; - UnsignedShort newID = cmdMsg->getID(); - memcpy(m_packet + m_packetLen, &newID, sizeof(UnsignedShort)); - m_packetLen += sizeof(UnsignedShort); - } - m_lastCommandID = cmdMsg->getID(); - -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("command id = %d", m_lastCommandID)); - - m_packet[m_packetLen] = NetPacketFieldTypes::Data; - ++m_packetLen; - UnicodeString unitext = cmdMsg->getText(); - UnsignedByte length = unitext.getLength(); - Int playerMask = cmdMsg->getPlayerMask(); - memcpy(m_packet + m_packetLen, &length, sizeof(UnsignedByte)); - m_packetLen += sizeof(UnsignedByte); - - memcpy(m_packet + m_packetLen, unitext.str(), length * sizeof(UnsignedShort)); - m_packetLen += length * sizeof(UnsignedShort); - - memcpy(m_packet + m_packetLen, &playerMask, sizeof(Int)); - m_packetLen += sizeof(Int); - -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("NetPacket - added chat command")); - - ++m_numCommands; - - deleteInstance(m_lastCommand); - m_lastCommand = NEW_NETCOMMANDREF(msg->getCommand()); - m_lastCommand->setRelay(msg->getRelay()); - return TRUE; - } - return FALSE; -} - -Bool NetPacket::isRoomForChatMessage(NetCommandRef *msg) { - Bool needNewCommandID = FALSE; - Int len = 0; - NetChatCommandMsg *cmdMsg = (NetChatCommandMsg *)(msg->getCommand()); - if (m_lastCommandType != cmdMsg->getNetCommandType()) { - ++len; - len += sizeof(UnsignedByte); - } - if (m_lastFrame != cmdMsg->getExecutionFrame()) { - len += sizeof(UnsignedInt) + sizeof(UnsignedByte); - } - if (m_lastRelay != msg->getRelay()) { - len += sizeof(UnsignedByte) + sizeof(UnsignedByte); - } - if (m_lastPlayerID != cmdMsg->getPlayerID()) { - ++len; - len += sizeof(UnsignedByte); - needNewCommandID = TRUE; - } - if (((m_lastCommandID + 1) != (UnsignedShort)(cmdMsg->getID())) || (needNewCommandID == TRUE)) { - len += sizeof(UnsignedShort) + sizeof(UnsignedByte); - } - - ++len; // the NetPacketFieldTypes::Data - len += sizeof(UnsignedByte); // string length - UnsignedByte textLen = cmdMsg->getText().getLength(); - len += textLen * sizeof(UnsignedShort); - len += sizeof(Int); // playerMask - if ((len + m_packetLen) > MAX_PACKET_SIZE) { - return FALSE; - } - return TRUE; -} - -Bool NetPacket::addPacketRouterAckCommand(NetCommandRef *msg) { - // need type, player id, relay, command id, slot number - if (isRoomForPacketRouterAckMessage(msg)) { - NetPacketRouterAckCommandMsg *cmdMsg = (NetPacketRouterAckCommandMsg *)(msg->getCommand()); -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("NetPacket::addPacketRouterAckCommand - adding packet router query command")); - - // If necessary, put the NetCommandType into the packet. - if (m_lastCommandType != cmdMsg->getNetCommandType()) { - m_packet[m_packetLen] = NetPacketFieldTypes::CommandType; - ++m_packetLen; - m_packet[m_packetLen] = cmdMsg->getNetCommandType(); - m_packetLen += sizeof(UnsignedByte); - - m_lastCommandType = cmdMsg->getNetCommandType(); - } - - // If necessary, put the relay into the packet. - if (m_lastRelay != msg->getRelay()) { - m_packet[m_packetLen] = NetPacketFieldTypes::Relay; - ++m_packetLen; - UnsignedByte newRelay = msg->getRelay(); - memcpy(m_packet+m_packetLen, &newRelay, sizeof(UnsignedByte)); - m_packetLen += sizeof(UnsignedByte); - - m_lastRelay = newRelay; - } - -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("relay = %d, ", m_lastRelay)); - - if (m_lastPlayerID != cmdMsg->getPlayerID()) { - m_packet[m_packetLen] = NetPacketFieldTypes::PlayerId; - ++m_packetLen; - m_packet[m_packetLen] = cmdMsg->getPlayerID(); - m_packetLen += sizeof(UnsignedByte); - - m_lastPlayerID = cmdMsg->getPlayerID(); - } - -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("player = %d", m_lastPlayerID)); - - m_packet[m_packetLen] = NetPacketFieldTypes::Data; - ++m_packetLen; - -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("NetPacket - added packet router ack command, player id %d", m_lastPlayerID)); - - ++m_numCommands; - - deleteInstance(m_lastCommand); - m_lastCommand = NEW_NETCOMMANDREF(msg->getCommand()); - m_lastCommand->setRelay(msg->getRelay()); - return TRUE; - } - return FALSE; -} - -/** - * Returns true if there is room for this packet router ack command in this packet. - */ -Bool NetPacket::isRoomForPacketRouterAckMessage(NetCommandRef *msg) { - Int len = 0; - NetPacketRouterAckCommandMsg *cmdMsg = (NetPacketRouterAckCommandMsg *)(msg->getCommand()); - if (m_lastCommandType != cmdMsg->getNetCommandType()) { - ++len; - len += sizeof(UnsignedByte); - } - if (m_lastRelay != msg->getRelay()) { - len += sizeof(UnsignedByte) + sizeof(UnsignedByte); - } - if (m_lastPlayerID != cmdMsg->getPlayerID()) { - ++len; - len += sizeof(UnsignedByte); - } - - ++len; // the NetPacketFieldTypes::Data - if ((len + m_packetLen) > MAX_PACKET_SIZE) { - return FALSE; - } - return TRUE; -} - -Bool NetPacket::addPacketRouterQueryCommand(NetCommandRef *msg) { - // need type, player id, relay, command id, slot number - if (isRoomForPacketRouterQueryMessage(msg)) { - NetPacketRouterQueryCommandMsg *cmdMsg = (NetPacketRouterQueryCommandMsg *)(msg->getCommand()); -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("NetPacket::addPacketRouterQueryCommand - adding packet router query command")); - - // If necessary, put the NetCommandType into the packet. - if (m_lastCommandType != cmdMsg->getNetCommandType()) { - m_packet[m_packetLen] = NetPacketFieldTypes::CommandType; - ++m_packetLen; - m_packet[m_packetLen] = cmdMsg->getNetCommandType(); - m_packetLen += sizeof(UnsignedByte); - - m_lastCommandType = cmdMsg->getNetCommandType(); - } - - // If necessary, put the relay into the packet. - if (m_lastRelay != msg->getRelay()) { - m_packet[m_packetLen] = NetPacketFieldTypes::Relay; - ++m_packetLen; - UnsignedByte newRelay = msg->getRelay(); - memcpy(m_packet+m_packetLen, &newRelay, sizeof(UnsignedByte)); - m_packetLen += sizeof(UnsignedByte); - - m_lastRelay = newRelay; - } - -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("relay = %d, ", m_lastRelay)); - - if (m_lastPlayerID != cmdMsg->getPlayerID()) { - m_packet[m_packetLen] = NetPacketFieldTypes::PlayerId; - ++m_packetLen; - m_packet[m_packetLen] = cmdMsg->getPlayerID(); - m_packetLen += sizeof(UnsignedByte); - - m_lastPlayerID = cmdMsg->getPlayerID(); - } - -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("player = %d", m_lastPlayerID)); - - m_packet[m_packetLen] = NetPacketFieldTypes::Data; - ++m_packetLen; - -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("NetPacket - added packet router query command, player id %d", m_lastPlayerID)); - - ++m_numCommands; - - deleteInstance(m_lastCommand); - m_lastCommand = NEW_NETCOMMANDREF(msg->getCommand()); - m_lastCommand->setRelay(msg->getRelay()); - return TRUE; - } - return FALSE; -} - -/** - * Returns true if there is room for this packet router query command in this packet. - */ -Bool NetPacket::isRoomForPacketRouterQueryMessage(NetCommandRef *msg) { - Int len = 0; - NetPacketRouterQueryCommandMsg *cmdMsg = (NetPacketRouterQueryCommandMsg *)(msg->getCommand()); - if (m_lastCommandType != cmdMsg->getNetCommandType()) { - ++len; - len += sizeof(UnsignedByte); - } - if (m_lastRelay != msg->getRelay()) { - len += sizeof(UnsignedByte) + sizeof(UnsignedByte); - } - if (m_lastPlayerID != cmdMsg->getPlayerID()) { - ++len; - len += sizeof(UnsignedByte); - } - - ++len; // the NetPacketFieldTypes::Data - if ((len + m_packetLen) > MAX_PACKET_SIZE) { - return FALSE; - } - return TRUE; -} - -Bool NetPacket::addDisconnectPlayerCommand(NetCommandRef *msg) { - Bool needNewCommandID = FALSE; - -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("NetPacket::addDisconnectPlayerCommand - entering...")); - // need type, player id, relay, command id, slot number - if (isRoomForDisconnectPlayerMessage(msg)) { - NetDisconnectPlayerCommandMsg *cmdMsg = (NetDisconnectPlayerCommandMsg *)(msg->getCommand()); -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("NetPacket::addDisconnectPlayerCommand - adding run ahead command")); - - // If necessary, put the NetCommandType into the packet. - if (m_lastCommandType != cmdMsg->getNetCommandType()) { - m_packet[m_packetLen] = NetPacketFieldTypes::CommandType; - ++m_packetLen; - m_packet[m_packetLen] = cmdMsg->getNetCommandType(); - m_packetLen += sizeof(UnsignedByte); - - m_lastCommandType = cmdMsg->getNetCommandType(); - } - - // If necessary, put the relay into the packet. - if (m_lastRelay != msg->getRelay()) { - m_packet[m_packetLen] = NetPacketFieldTypes::Relay; - ++m_packetLen; - UnsignedByte newRelay = msg->getRelay(); - memcpy(m_packet+m_packetLen, &newRelay, sizeof(UnsignedByte)); - m_packetLen += sizeof(UnsignedByte); - - m_lastRelay = newRelay; - } - -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("relay = %d, ", m_lastRelay)); - - if (m_lastPlayerID != cmdMsg->getPlayerID()) { - m_packet[m_packetLen] = NetPacketFieldTypes::PlayerId; - ++m_packetLen; - m_packet[m_packetLen] = cmdMsg->getPlayerID(); - m_packetLen += sizeof(UnsignedByte); - - m_lastPlayerID = cmdMsg->getPlayerID(); - needNewCommandID = TRUE; - } - -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("player = %d", m_lastPlayerID)); - - // If necessary, specify the command ID of this command. - if (((m_lastCommandID + 1) != (UnsignedShort)(cmdMsg->getID())) || (needNewCommandID == TRUE)) { - m_packet[m_packetLen] = NetPacketFieldTypes::CommandId; - ++m_packetLen; - UnsignedShort newID = cmdMsg->getID(); - memcpy(m_packet + m_packetLen, &newID, sizeof(UnsignedShort)); - m_packetLen += sizeof(UnsignedShort); - } - m_lastCommandID = cmdMsg->getID(); - -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("command id = %d", m_lastCommandID)); - - m_packet[m_packetLen] = NetPacketFieldTypes::Data; - ++m_packetLen; - UnsignedByte slot = cmdMsg->getDisconnectSlot(); - memcpy(m_packet + m_packetLen, &slot, sizeof(slot)); - m_packetLen += sizeof(slot); - - UnsignedInt disconnectFrame = cmdMsg->getDisconnectFrame(); - memcpy(m_packet + m_packetLen, &disconnectFrame, sizeof(disconnectFrame)); - m_packetLen += sizeof(disconnectFrame); - -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("NetPacket::addDisconnectPlayerCommand - added disconnect player command, player id %d command id %d, disconnecting slot %d", m_lastPlayerID, m_lastCommandID, slot)); - - ++m_numCommands; - - deleteInstance(m_lastCommand); - m_lastCommand = NEW_NETCOMMANDREF(msg->getCommand()); - m_lastCommand->setRelay(msg->getRelay()); - return TRUE; - } - return FALSE; -} - -/** - * Returns true if there is room for this player disconnect command in this packet. - */ -Bool NetPacket::isRoomForDisconnectPlayerMessage(NetCommandRef *msg) { - Int len = 0; - Bool needNewCommandID = FALSE; - NetDisconnectPlayerCommandMsg *cmdMsg = (NetDisconnectPlayerCommandMsg *)(msg->getCommand()); - if (m_lastCommandType != cmdMsg->getNetCommandType()) { - ++len; - len += sizeof(UnsignedByte); - } - if (m_lastRelay != msg->getRelay()) { - len += sizeof(UnsignedByte) + sizeof(UnsignedByte); - } - if (m_lastPlayerID != cmdMsg->getPlayerID()) { - ++len; - len += sizeof(UnsignedByte); - needNewCommandID = TRUE; - } - if (((m_lastCommandID + 1) != (UnsignedShort)(cmdMsg->getID())) || (needNewCommandID == TRUE)) { - len += sizeof(UnsignedShort) + sizeof(UnsignedByte); - } - - ++len; // the NetPacketFieldTypes::Data - len += sizeof(UnsignedByte); // slot number - len += sizeof(UnsignedInt); // disconnectFrame - if ((len + m_packetLen) > MAX_PACKET_SIZE) { - return FALSE; - } - return TRUE; -} - - -/** - * Add a keep alive command to the packet. Returns true if successful. - */ -Bool NetPacket::addDisconnectKeepAliveCommand(NetCommandRef *msg) { - if (isRoomForDisconnectKeepAliveMessage(msg)) { - NetDisconnectKeepAliveCommandMsg *cmdMsg = (NetDisconnectKeepAliveCommandMsg *)(msg->getCommand()); - - // If necessary, put the NetCommandType into the packet. - if (m_lastCommandType != cmdMsg->getNetCommandType()) { - m_packet[m_packetLen] = NetPacketFieldTypes::CommandType; - ++m_packetLen; - m_packet[m_packetLen] = cmdMsg->getNetCommandType(); - m_packetLen += sizeof(UnsignedByte); - - m_lastCommandType = cmdMsg->getNetCommandType(); - } - - // If necessary, put the relay into the packet. - if (m_lastRelay != msg->getRelay()) { - m_packet[m_packetLen] = NetPacketFieldTypes::Relay; - ++m_packetLen; - UnsignedByte newRelay = msg->getRelay(); - memcpy(m_packet+m_packetLen, &newRelay, sizeof(UnsignedByte)); - m_packetLen += sizeof(UnsignedByte); - - m_lastRelay = newRelay; - } - - if (m_lastPlayerID != cmdMsg->getPlayerID()) { - m_packet[m_packetLen] = NetPacketFieldTypes::PlayerId; - ++m_packetLen; - m_packet[m_packetLen] = cmdMsg->getPlayerID(); - m_packetLen += sizeof(UnsignedByte); - - m_lastPlayerID = cmdMsg->getPlayerID(); - } - - m_packet[m_packetLen] = NetPacketFieldTypes::Data; - ++m_packetLen; - - ++m_numCommands; - - deleteInstance(m_lastCommand); - m_lastCommand = NEW_NETCOMMANDREF(msg->getCommand()); - m_lastCommand->setRelay(msg->getRelay()); - -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("Added keep alive command to packet.")); - - return TRUE; - } - return FALSE; -} - -/** - * Returns true if there is room in the packet for this command. - */ -Bool NetPacket::isRoomForDisconnectKeepAliveMessage(NetCommandRef *msg) { - Int len = 0; - NetDisconnectKeepAliveCommandMsg *cmdMsg = (NetDisconnectKeepAliveCommandMsg *)(msg->getCommand()); - if (m_lastCommandType != cmdMsg->getNetCommandType()) { - ++len; - len += sizeof(UnsignedByte); - } - if (m_lastRelay != msg->getRelay()) { - len += sizeof(UnsignedByte) + sizeof(UnsignedByte); - } - if (m_lastPlayerID != cmdMsg->getPlayerID()) { - ++len; - len += sizeof(UnsignedByte); - } - - ++len; // For the NetPacketFieldTypes::Data - if ((len + m_packetLen) > MAX_PACKET_SIZE) { - return FALSE; - } - return TRUE; -} - -/** - * Add a keep alive command to the packet. Returns true if successful. - */ -Bool NetPacket::addKeepAliveCommand(NetCommandRef *msg) { - if (isRoomForKeepAliveMessage(msg)) { - NetKeepAliveCommandMsg *cmdMsg = (NetKeepAliveCommandMsg *)(msg->getCommand()); - - // If necessary, put the NetCommandType into the packet. - if (m_lastCommandType != cmdMsg->getNetCommandType()) { - m_packet[m_packetLen] = NetPacketFieldTypes::CommandType; - ++m_packetLen; - m_packet[m_packetLen] = cmdMsg->getNetCommandType(); - m_packetLen += sizeof(UnsignedByte); - - m_lastCommandType = cmdMsg->getNetCommandType(); - } - - // If necessary, put the relay into the packet. - if (m_lastRelay != msg->getRelay()) { - m_packet[m_packetLen] = NetPacketFieldTypes::Relay; - ++m_packetLen; - UnsignedByte newRelay = msg->getRelay(); - memcpy(m_packet+m_packetLen, &newRelay, sizeof(UnsignedByte)); - m_packetLen += sizeof(UnsignedByte); - - m_lastRelay = newRelay; - } - - if (m_lastPlayerID != cmdMsg->getPlayerID()) { - m_packet[m_packetLen] = NetPacketFieldTypes::PlayerId; - ++m_packetLen; - m_packet[m_packetLen] = cmdMsg->getPlayerID(); - m_packetLen += sizeof(UnsignedByte); - - m_lastPlayerID = cmdMsg->getPlayerID(); - } - - m_packet[m_packetLen] = NetPacketFieldTypes::Data; - ++m_packetLen; - - ++m_numCommands; - - deleteInstance(m_lastCommand); - m_lastCommand = NEW_NETCOMMANDREF(msg->getCommand()); - m_lastCommand->setRelay(msg->getRelay()); - -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("Added keep alive command to packet.")); - - return TRUE; - } - return FALSE; -} - -/** - * Returns true if there is room in the packet for this command. - */ -Bool NetPacket::isRoomForKeepAliveMessage(NetCommandRef *msg) { - Int len = 0; - NetKeepAliveCommandMsg *cmdMsg = (NetKeepAliveCommandMsg *)(msg->getCommand()); - if (m_lastCommandType != cmdMsg->getNetCommandType()) { - ++len; - len += sizeof(UnsignedByte); - } - if (m_lastRelay != msg->getRelay()) { - len += sizeof(UnsignedByte) + sizeof(UnsignedByte); - } - if (m_lastPlayerID != cmdMsg->getPlayerID()) { - ++len; - len += sizeof(UnsignedByte); - } - - ++len; // For the NetPacketFieldTypes::Data - if ((len + m_packetLen) > MAX_PACKET_SIZE) { - return FALSE; - } - return TRUE; -} - -/** - * Add a run ahead command to the packet. Returns true if successful. - */ -Bool NetPacket::addRunAheadCommand(NetCommandRef *msg) { - Bool needNewCommandID = FALSE; - if (isRoomForRunAheadMessage(msg)) { - NetRunAheadCommandMsg *cmdMsg = (NetRunAheadCommandMsg *)(msg->getCommand()); - //DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("NetPacket::addRunAheadCommand - adding run ahead command")); - - // If necessary, put the NetCommandType into the packet. - if (m_lastCommandType != cmdMsg->getNetCommandType()) { - m_packet[m_packetLen] = NetPacketFieldTypes::CommandType; - ++m_packetLen; - m_packet[m_packetLen] = cmdMsg->getNetCommandType(); - m_packetLen += sizeof(UnsignedByte); - - m_lastCommandType = cmdMsg->getNetCommandType(); - } - - // If necessary, put the relay into the packet. - if (m_lastRelay != msg->getRelay()) { - m_packet[m_packetLen] = NetPacketFieldTypes::Relay; - ++m_packetLen; - UnsignedByte newRelay = msg->getRelay(); - memcpy(m_packet+m_packetLen, &newRelay, sizeof(UnsignedByte)); - m_packetLen += sizeof(UnsignedByte); - - m_lastRelay = newRelay; - } - - // If necessary, put the execution frame into the packet. - if (m_lastFrame != cmdMsg->getExecutionFrame()) { - m_packet[m_packetLen] = NetPacketFieldTypes::Frame; - ++m_packetLen; - UnsignedInt newframe = cmdMsg->getExecutionFrame(); - memcpy(m_packet+m_packetLen, &newframe, sizeof(UnsignedInt)); - m_packetLen += sizeof(UnsignedInt); - - m_lastFrame = newframe; - } - -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("relay = %d, ", m_lastRelay)); - - if (m_lastPlayerID != cmdMsg->getPlayerID()) { - m_packet[m_packetLen] = NetPacketFieldTypes::PlayerId; - ++m_packetLen; - m_packet[m_packetLen] = cmdMsg->getPlayerID(); - m_packetLen += sizeof(UnsignedByte); - - m_lastPlayerID = cmdMsg->getPlayerID(); - needNewCommandID = TRUE; - } - -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("player = %d", m_lastPlayerID)); - - // If necessary, specify the command ID of this command. - if (((m_lastCommandID + 1) != (UnsignedShort)(cmdMsg->getID())) || (needNewCommandID == TRUE)) { - m_packet[m_packetLen] = NetPacketFieldTypes::CommandId; - ++m_packetLen; - UnsignedShort newID = cmdMsg->getID(); - memcpy(m_packet + m_packetLen, &newID, sizeof(UnsignedShort)); - m_packetLen += sizeof(UnsignedShort); - } - m_lastCommandID = cmdMsg->getID(); - -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("command id = %d", m_lastCommandID)); - - m_packet[m_packetLen] = NetPacketFieldTypes::Data; - ++m_packetLen; - UnsignedShort newRunAhead = cmdMsg->getRunAhead(); - memcpy(m_packet + m_packetLen, &newRunAhead, sizeof(UnsignedShort)); - m_packetLen += sizeof(UnsignedShort); - - UnsignedByte newFrameRate = cmdMsg->getFrameRate(); - memcpy(m_packet + m_packetLen, &newFrameRate, sizeof(UnsignedByte)); - m_packetLen += sizeof(UnsignedByte); - -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("NetPacket - added run ahead command, frame %d, player id %d command id %d", m_lastFrame, m_lastPlayerID, m_lastCommandID)); - - ++m_numCommands; - - deleteInstance(m_lastCommand); - m_lastCommand = NEW_NETCOMMANDREF(msg->getCommand()); - m_lastCommand->setRelay(msg->getRelay()); - return TRUE; - } - return FALSE; -} - -/** - * Returns true if there is room for this run ahead command in this packet. - */ -Bool NetPacket::isRoomForRunAheadMessage(NetCommandRef *msg) { - Int len = 0; - Bool needNewCommandID = FALSE; - NetRunAheadCommandMsg *cmdMsg = (NetRunAheadCommandMsg *)(msg->getCommand()); - if (m_lastCommandType != cmdMsg->getNetCommandType()) { - ++len; - len += sizeof(UnsignedByte); - } - if (m_lastRelay != msg->getRelay()) { - len += sizeof(UnsignedByte) + sizeof(UnsignedByte); - } - if (m_lastFrame != cmdMsg->getExecutionFrame()) { - len += sizeof(UnsignedInt) + sizeof(UnsignedByte); - } - if (m_lastPlayerID != cmdMsg->getPlayerID()) { - ++len; - len += sizeof(UnsignedByte); - needNewCommandID = TRUE; - } - if (((m_lastCommandID + 1) != (UnsignedShort)(cmdMsg->getID())) || (needNewCommandID == TRUE)) { - len += sizeof(UnsignedShort) + sizeof(UnsignedByte); - } - - ++len; // for NetPacketFieldTypes::Data - len += sizeof(UnsignedShort); - len += sizeof(UnsignedByte); - if ((len + m_packetLen) > MAX_PACKET_SIZE) { - return FALSE; - } - return TRUE; -} - -/** - * Add a DestroyPlayer command to the packet. Returns true if successful. - */ -Bool NetPacket::addDestroyPlayerCommand(NetCommandRef *msg) { - Bool needNewCommandID = FALSE; - if (isRoomForDestroyPlayerMessage(msg)) { - NetDestroyPlayerCommandMsg *cmdMsg = (NetDestroyPlayerCommandMsg *)(msg->getCommand()); - - // If necessary, put the NetCommandType into the packet. - if (m_lastCommandType != cmdMsg->getNetCommandType()) { - m_packet[m_packetLen] = NetPacketFieldTypes::CommandType; - ++m_packetLen; - m_packet[m_packetLen] = cmdMsg->getNetCommandType(); - m_packetLen += sizeof(UnsignedByte); - - m_lastCommandType = cmdMsg->getNetCommandType(); - } - - // If necessary, put the relay into the packet. - if (m_lastRelay != msg->getRelay()) { - m_packet[m_packetLen] = NetPacketFieldTypes::Relay; - ++m_packetLen; - UnsignedByte newRelay = msg->getRelay(); - memcpy(m_packet+m_packetLen, &newRelay, sizeof(UnsignedByte)); - m_packetLen += sizeof(UnsignedByte); - - m_lastRelay = newRelay; - } - - // If necessary, put the execution frame into the packet. - if (m_lastFrame != cmdMsg->getExecutionFrame()) { - m_packet[m_packetLen] = NetPacketFieldTypes::Frame; - ++m_packetLen; - UnsignedInt newframe = cmdMsg->getExecutionFrame(); - memcpy(m_packet+m_packetLen, &newframe, sizeof(UnsignedInt)); - m_packetLen += sizeof(UnsignedInt); - - m_lastFrame = newframe; - } - -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("relay = %d, ", m_lastRelay)); - - if (m_lastPlayerID != cmdMsg->getPlayerID()) { - m_packet[m_packetLen] = NetPacketFieldTypes::PlayerId; - ++m_packetLen; - m_packet[m_packetLen] = cmdMsg->getPlayerID(); - m_packetLen += sizeof(UnsignedByte); - - m_lastPlayerID = cmdMsg->getPlayerID(); - needNewCommandID = TRUE; - } - -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("player = %d", m_lastPlayerID)); - - // If necessary, specify the command ID of this command. - if (((m_lastCommandID + 1) != (UnsignedShort)(cmdMsg->getID())) || (needNewCommandID == TRUE)) { - m_packet[m_packetLen] = NetPacketFieldTypes::CommandId; - ++m_packetLen; - UnsignedShort newID = cmdMsg->getID(); - memcpy(m_packet + m_packetLen, &newID, sizeof(UnsignedShort)); - m_packetLen += sizeof(UnsignedShort); - } - m_lastCommandID = cmdMsg->getID(); - -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("command id = %d", m_lastCommandID)); - - m_packet[m_packetLen] = NetPacketFieldTypes::Data; - ++m_packetLen; - UnsignedInt newVal = cmdMsg->getPlayerIndex(); - memcpy(m_packet + m_packetLen, &newVal, sizeof(UnsignedInt)); - m_packetLen += sizeof(UnsignedInt); - - //DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("NetPacket - added CRC:0x%8.8X info command, frame %d, player id %d command id %d", newCRC, m_lastFrame, m_lastPlayerID, m_lastCommandID)); - - ++m_numCommands; - - deleteInstance(m_lastCommand); - m_lastCommand = NEW_NETCOMMANDREF(msg->getCommand()); - m_lastCommand->setRelay(msg->getRelay()); - return TRUE; - } - return FALSE; -} - -/** - * Returns true if there is room for this DestroyPlayer command in this packet. - */ -Bool NetPacket::isRoomForDestroyPlayerMessage(NetCommandRef *msg) { - Int len = 0; - Bool needNewCommandID = FALSE; - NetDestroyPlayerCommandMsg *cmdMsg = (NetDestroyPlayerCommandMsg *)(msg->getCommand()); - if (m_lastCommandType != cmdMsg->getNetCommandType()) { - ++len; - len += sizeof(UnsignedByte); - } - if (m_lastRelay != msg->getRelay()) { - len += sizeof(UnsignedByte) + sizeof(UnsignedByte); - } - if (m_lastFrame != cmdMsg->getExecutionFrame()) { - len += sizeof(UnsignedInt) + sizeof(UnsignedByte); - } - if (m_lastPlayerID != cmdMsg->getPlayerID()) { - ++len; - len += sizeof(UnsignedByte); - needNewCommandID = TRUE; - } - if (((m_lastCommandID + 1) != (UnsignedShort)(cmdMsg->getID())) || (needNewCommandID == TRUE)) { - len += sizeof(UnsignedShort) + sizeof(UnsignedByte); - } - - ++len; // for NetPacketFieldTypes::Data - len += sizeof(UnsignedInt); - if ((len + m_packetLen) > MAX_PACKET_SIZE) { - return FALSE; - } - return TRUE; -} - -/** - * Add a run ahead metrics command to the packet. Returns true if successful. - */ -Bool NetPacket::addRunAheadMetricsCommand(NetCommandRef *msg) { - Bool needNewCommandID = FALSE; - if (isRoomForRunAheadMetricsMessage(msg)) { - NetRunAheadMetricsCommandMsg *cmdMsg = (NetRunAheadMetricsCommandMsg *)(msg->getCommand()); -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("NetPacket::addRunAheadMetricsCommand - adding run ahead metrics for player %d, fps = %d, latency = %f", cmdMsg->getPlayerID(), cmdMsg->getAverageFps(), cmdMsg->getAverageLatency())); - - // If necessary, put the NetCommandType into the packet. - if (m_lastCommandType != cmdMsg->getNetCommandType()) { - m_packet[m_packetLen] = NetPacketFieldTypes::CommandType; - ++m_packetLen; - m_packet[m_packetLen] = cmdMsg->getNetCommandType(); - m_packetLen += sizeof(UnsignedByte); - - m_lastCommandType = cmdMsg->getNetCommandType(); - } - - // If necessary, put the relay into the packet. - if (m_lastRelay != msg->getRelay()) { - m_packet[m_packetLen] = NetPacketFieldTypes::Relay; - ++m_packetLen; - UnsignedByte newRelay = msg->getRelay(); - memcpy(m_packet+m_packetLen, &newRelay, sizeof(UnsignedByte)); - m_packetLen += sizeof(UnsignedByte); - - m_lastRelay = newRelay; - } - -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("relay = %d, ", m_lastRelay)); - - if (m_lastPlayerID != cmdMsg->getPlayerID()) { - m_packet[m_packetLen] = NetPacketFieldTypes::PlayerId; - ++m_packetLen; - m_packet[m_packetLen] = cmdMsg->getPlayerID(); - m_packetLen += sizeof(UnsignedByte); - - m_lastPlayerID = cmdMsg->getPlayerID(); - needNewCommandID = TRUE; - } - -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("player = %d", m_lastPlayerID)); - - // If necessary, specify the command ID of this command. - if (((m_lastCommandID + 1) != (UnsignedShort)(cmdMsg->getID())) || (needNewCommandID == TRUE)) { - m_packet[m_packetLen] = NetPacketFieldTypes::CommandId; - ++m_packetLen; - UnsignedShort newID = cmdMsg->getID(); - memcpy(m_packet + m_packetLen, &newID, sizeof(UnsignedShort)); - m_packetLen += sizeof(UnsignedShort); - } - m_lastCommandID = cmdMsg->getID(); - -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("command id = %d", m_lastCommandID)); - - m_packet[m_packetLen] = NetPacketFieldTypes::Data; - ++m_packetLen; - // write the average latency - Real averageLatency = cmdMsg->getAverageLatency(); - memcpy(m_packet + m_packetLen, &averageLatency, sizeof(averageLatency)); - m_packetLen += sizeof(averageLatency); - // write the average fps - UnsignedShort averageFps = (UnsignedShort)(cmdMsg->getAverageFps()); - memcpy(m_packet + m_packetLen, &averageFps, sizeof(averageFps)); - m_packetLen += sizeof(averageFps); - - deleteInstance(m_lastCommand); - m_lastCommand = NEW_NETCOMMANDREF(msg->getCommand()); - m_lastCommand->setRelay(msg->getRelay()); - - ++m_numCommands; - return TRUE; - } - return FALSE; -} - -/** - * Returns true if there is enough room in the packet to fit this message. - */ -Bool NetPacket::isRoomForRunAheadMetricsMessage(NetCommandRef *msg) { - Int len = 0; - Bool needNewCommandID = FALSE; - NetRunAheadMetricsCommandMsg *cmdMsg = (NetRunAheadMetricsCommandMsg *)(msg->getCommand()); - if (m_lastCommandType != cmdMsg->getNetCommandType()) { - ++len; - len += sizeof(UnsignedByte); - } - if (m_lastRelay != msg->getRelay()) { - len += sizeof(UnsignedByte) + sizeof(UnsignedByte); - } - if (m_lastPlayerID != cmdMsg->getPlayerID()) { - ++len; - len += sizeof(UnsignedByte); - needNewCommandID = TRUE; - } - if (((m_lastCommandID + 1) != (UnsignedShort)(cmdMsg->getID())) || (needNewCommandID == TRUE)) { - len += sizeof(UnsignedShort) + sizeof(UnsignedByte); - } - - ++len; // NetPacketFieldTypes::Data - len += sizeof(UnsignedShort); - len += sizeof(Real); - if ((len + m_packetLen) > MAX_PACKET_SIZE) { - return FALSE; - } - return TRUE; -} - - -/** - * Add a player leave command to the packet. Returns true if successful. - */ -Bool NetPacket::addPlayerLeaveCommand(NetCommandRef *msg) { - Bool needNewCommandID = FALSE; - if (isRoomForPlayerLeaveMessage(msg)) { - NetPlayerLeaveCommandMsg *cmdMsg = (NetPlayerLeaveCommandMsg *)(msg->getCommand()); -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("NetPacket::addPlayerLeaveCommand - adding player leave command for player %d", cmdMsg->getLeavingPlayerID())); - - // If necessary, put the NetCommandType into the packet. - if (m_lastCommandType != cmdMsg->getNetCommandType()) { - m_packet[m_packetLen] = NetPacketFieldTypes::CommandType; - ++m_packetLen; - m_packet[m_packetLen] = cmdMsg->getNetCommandType(); - m_packetLen += sizeof(UnsignedByte); - - m_lastCommandType = cmdMsg->getNetCommandType(); - } - - // If necessary, put the relay into the packet. - if (m_lastRelay != msg->getRelay()) { - m_packet[m_packetLen] = NetPacketFieldTypes::Relay; - ++m_packetLen; - UnsignedByte newRelay = msg->getRelay(); - memcpy(m_packet+m_packetLen, &newRelay, sizeof(UnsignedByte)); - m_packetLen += sizeof(UnsignedByte); - - m_lastRelay = newRelay; - } - - // If necessary, put the execution frame into the packet. - if (m_lastFrame != cmdMsg->getExecutionFrame()) { - m_packet[m_packetLen] = NetPacketFieldTypes::Frame; - ++m_packetLen; - UnsignedInt newframe = cmdMsg->getExecutionFrame(); - memcpy(m_packet+m_packetLen, &newframe, sizeof(UnsignedInt)); - m_packetLen += sizeof(UnsignedInt); - - m_lastFrame = newframe; - } - -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("relay = %d, ", m_lastRelay)); - - if (m_lastPlayerID != cmdMsg->getPlayerID()) { - m_packet[m_packetLen] = NetPacketFieldTypes::PlayerId; - ++m_packetLen; - m_packet[m_packetLen] = cmdMsg->getPlayerID(); - m_packetLen += sizeof(UnsignedByte); - - m_lastPlayerID = cmdMsg->getPlayerID(); - needNewCommandID = TRUE; - } - -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("player = %d", m_lastPlayerID)); - - // If necessary, specify the command ID of this command. - if (((m_lastCommandID + 1) != (UnsignedShort)(cmdMsg->getID())) || (needNewCommandID == TRUE)) { - m_packet[m_packetLen] = NetPacketFieldTypes::CommandId; - ++m_packetLen; - UnsignedShort newID = cmdMsg->getID(); - memcpy(m_packet + m_packetLen, &newID, sizeof(UnsignedShort)); - m_packetLen += sizeof(UnsignedShort); - } - m_lastCommandID = cmdMsg->getID(); - -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("command id = %d", m_lastCommandID)); - - m_packet[m_packetLen] = NetPacketFieldTypes::Data; - ++m_packetLen; - UnsignedByte leavingPlayerID = cmdMsg->getLeavingPlayerID(); - memcpy(m_packet + m_packetLen, &leavingPlayerID, sizeof(UnsignedByte)); - m_packetLen += sizeof(UnsignedByte); - - deleteInstance(m_lastCommand); - m_lastCommand = NEW_NETCOMMANDREF(msg->getCommand()); - m_lastCommand->setRelay(msg->getRelay()); - - ++m_numCommands; - return TRUE; - } - return FALSE; -} - -/** - * Returns true if there is enough room in the packet to fit this message. - */ -Bool NetPacket::isRoomForPlayerLeaveMessage(NetCommandRef *msg) { - Int len = 0; - Bool needNewCommandID = FALSE; - NetPlayerLeaveCommandMsg *cmdMsg = (NetPlayerLeaveCommandMsg *)(msg->getCommand()); - if (m_lastCommandType != cmdMsg->getNetCommandType()) { - ++len; - len += sizeof(UnsignedByte); - } - if (m_lastRelay != msg->getRelay()) { - len += sizeof(UnsignedByte) + sizeof(UnsignedByte); - } - if (m_lastFrame != cmdMsg->getExecutionFrame()) { - len += sizeof(UnsignedInt) + sizeof(UnsignedByte); - } - if (m_lastPlayerID != cmdMsg->getPlayerID()) { - ++len; - len += sizeof(UnsignedByte); - needNewCommandID = TRUE; - } - if (((m_lastCommandID + 1) != (UnsignedShort)(cmdMsg->getID())) || (needNewCommandID == TRUE)) { - len += sizeof(UnsignedShort) + sizeof(UnsignedByte); - } - - ++len; // for NetPacketFieldTypes::Data - len += sizeof(UnsignedByte); - if ((len + m_packetLen) > MAX_PACKET_SIZE) { - return FALSE; - } - return TRUE; -} - -/** - * Add this frame command message. Returns true if successful. - */ -Bool NetPacket::addFrameCommand(NetCommandRef *msg) { - Bool needNewCommandID = FALSE; - if (isFrameRepeat(msg)) { - if (m_packetLen >= MAX_PACKET_SIZE) { - return FALSE; - } - m_packet[m_packetLen] = 'Z'; - ++m_packetLen; - m_lastCommandID = msg->getCommand()->getID(); - deleteInstance(m_lastCommand); - m_lastCommand = newInstance(NetCommandRef)(msg->getCommand()); - m_lastCommand->setRelay(msg->getRelay()); - ++m_lastFrame; // need this cause we're actually advancing to the next frame by adding this command. - ++m_numCommands; - // frameinfodebug -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("outgoing - added frame %d, player %d, command count = %d, command id = %d, repeat", m_lastFrame, m_lastPlayerID, 0, m_lastCommandID)); - return TRUE; - } - if (isRoomForFrameMessage(msg)) { - NetFrameCommandMsg *cmdMsg = (NetFrameCommandMsg *)(msg->getCommand()); -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("NetPacket::addFrameCommand - adding frame command for frame %d, command count = %d, command id = %d", cmdMsg->getExecutionFrame(), cmdMsg->getCommandCount(), cmdMsg->getID())); - - // If necessary, put the NetCommandType into the packet. - if (m_lastCommandType != cmdMsg->getNetCommandType()) { - m_packet[m_packetLen] = NetPacketFieldTypes::CommandType; - ++m_packetLen; - m_packet[m_packetLen] = cmdMsg->getNetCommandType(); - m_packetLen += sizeof(UnsignedByte); - - m_lastCommandType = cmdMsg->getNetCommandType(); - } - - // If necessary, put the execution frame into the packet. - if (m_lastFrame != cmdMsg->getExecutionFrame()) { - m_packet[m_packetLen] = NetPacketFieldTypes::Frame; - ++m_packetLen; - UnsignedInt newframe = cmdMsg->getExecutionFrame(); - memcpy(m_packet+m_packetLen, &newframe, sizeof(UnsignedInt)); - m_packetLen += sizeof(UnsignedInt); - - m_lastFrame = newframe; - } - - // If necessary, put the relay into the packet. - if (m_lastRelay != msg->getRelay()) { - m_packet[m_packetLen] = NetPacketFieldTypes::Relay; - ++m_packetLen; - UnsignedByte newRelay = msg->getRelay(); - memcpy(m_packet+m_packetLen, &newRelay, sizeof(UnsignedByte)); - m_packetLen += sizeof(UnsignedByte); - - m_lastRelay = newRelay; - } - -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("relay = %d, ", m_lastRelay)); - - if (m_lastPlayerID != cmdMsg->getPlayerID()) { - m_packet[m_packetLen] = NetPacketFieldTypes::PlayerId; - ++m_packetLen; - m_packet[m_packetLen] = cmdMsg->getPlayerID(); - m_packetLen += sizeof(UnsignedByte); - - m_lastPlayerID = cmdMsg->getPlayerID(); - needNewCommandID = TRUE; - } - -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("player = %d", m_lastPlayerID)); - - // If necessary, specify the command ID of this command. - if (((m_lastCommandID + 1) != (UnsignedShort)(cmdMsg->getID())) || (needNewCommandID == TRUE)) { - m_packet[m_packetLen] = NetPacketFieldTypes::CommandId; - ++m_packetLen; - UnsignedShort newID = cmdMsg->getID(); - memcpy(m_packet + m_packetLen, &newID, sizeof(UnsignedShort)); - m_packetLen += sizeof(UnsignedShort); - } - m_lastCommandID = cmdMsg->getID(); - -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("command id = %d", m_lastCommandID)); - - m_packet[m_packetLen] = NetPacketFieldTypes::Data; - ++m_packetLen; - UnsignedShort cmdCount = cmdMsg->getCommandCount(); - memcpy(m_packet + m_packetLen, &cmdCount, sizeof(UnsignedShort)); - m_packetLen += sizeof(UnsignedShort); - - // frameinfodebug -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("outgoing - added frame %d, player %d, command count = %d, command id = %d", cmdMsg->getExecutionFrame(), cmdMsg->getPlayerID(), cmdMsg->getCommandCount(), cmdMsg->getID())); - - deleteInstance(m_lastCommand); - m_lastCommand = NEW_NETCOMMANDREF(msg->getCommand()); - m_lastCommand->setRelay(msg->getRelay()); - - ++m_numCommands; - return TRUE; - } - return FALSE; -} - -/** - * Returns true if there is enough room in this packet for this frame message. - */ -Bool NetPacket::isRoomForFrameMessage(NetCommandRef *msg) { - Int len = 0; - Bool needNewCommandID = FALSE; - NetFrameCommandMsg *cmdMsg = (NetFrameCommandMsg *)(msg->getCommand()); - if (m_lastCommandType != cmdMsg->getNetCommandType()) { - ++len; - len += sizeof(UnsignedByte); - } - if (m_lastFrame != cmdMsg->getExecutionFrame()) { - len += sizeof(UnsignedInt) + sizeof(UnsignedByte); - } - if (m_lastRelay != msg->getRelay()) { - len += sizeof(UnsignedByte) + sizeof(UnsignedByte); - } - if (m_lastPlayerID != cmdMsg->getPlayerID()) { - ++len; - len += sizeof(UnsignedByte); - needNewCommandID = TRUE; - } - if (((m_lastCommandID + 1) != (UnsignedShort)(cmdMsg->getID())) || (needNewCommandID == TRUE)) { - len += sizeof(UnsignedShort) + sizeof(UnsignedByte); - } - - ++len; // for NetPacketFieldTypes::Data - len += sizeof(UnsignedShort); - if ((len + m_packetLen) > MAX_PACKET_SIZE) { - return FALSE; - } - return TRUE; -} - -Bool NetPacket::isFrameRepeat(NetCommandRef *msg) { - if (m_lastCommand == NULL) { - return FALSE; - } - if (m_lastCommand->getCommand()->getNetCommandType() != NETCOMMANDTYPE_FRAMEINFO) { - return FALSE; - } - NetFrameCommandMsg *framemsg = (NetFrameCommandMsg *)(msg->getCommand()); - NetFrameCommandMsg *lastmsg = (NetFrameCommandMsg *)(m_lastCommand->getCommand()); - if (framemsg->getCommandCount() != 0) { - return FALSE; - } - if (framemsg->getExecutionFrame() != (lastmsg->getExecutionFrame() + 1)) { - return FALSE; - } - if (msg->getRelay() != m_lastCommand->getRelay()) { - return FALSE; - } - if (framemsg->getID() != (lastmsg->getID() + 1)) { - return FALSE; - } - return TRUE; -} - -/** - * Add an ack "both" command. - */ -Bool NetPacket::addAckBothCommand(NetCommandRef *msg) { - NetAckBothCommandMsg *ackmsg = (NetAckBothCommandMsg *)(msg->getCommand()); - return addAckCommand(msg, ackmsg->getCommandID(), ackmsg->getOriginalPlayerID()); -} - -/** - * Add an ack stage 1 command. - */ -Bool NetPacket::addAckStage1Command(NetCommandRef *msg) { - NetAckStage1CommandMsg *ackmsg = (NetAckStage1CommandMsg *)(msg->getCommand()); - return addAckCommand(msg, ackmsg->getCommandID(), ackmsg->getOriginalPlayerID()); -} - -/** - * Add an ack stage 2 command. - */ -Bool NetPacket::addAckStage2Command(NetCommandRef *msg) { - NetAckStage2CommandMsg *ackmsg = (NetAckStage2CommandMsg *)(msg->getCommand()); - return addAckCommand(msg, ackmsg->getCommandID(), ackmsg->getOriginalPlayerID()); -} - -/** - * Add this ack command to the packet. Returns true if successful. - */ -Bool NetPacket::addAckCommand(NetCommandRef *msg, UnsignedShort commandID, UnsignedByte originalPlayerID) { - if (isAckRepeat(msg)) { - if (m_packetLen >= MAX_PACKET_SIZE) { - return FALSE; - } - m_packet[m_packetLen] = 'Z'; - ++m_packetLen; - ++m_numCommands; - - deleteInstance(m_lastCommand); - m_lastCommand = NEW_NETCOMMANDREF(msg->getCommand()); - m_lastCommand->setRelay(msg->getRelay()); - return TRUE; - } - if (isRoomForAckMessage(msg)) { - NetCommandMsg *cmdMsg = msg->getCommand(); -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("NetPacket::addAckCommand - adding ack for command %d for player %d", cmdMsg->getCommandID(), msg->getCommand()->getPlayerID())); - // If necessary, put the NetCommandType into the packet. - if (m_lastCommandType != cmdMsg->getNetCommandType()) { - m_packet[m_packetLen] = NetPacketFieldTypes::CommandType; - ++m_packetLen; - m_packet[m_packetLen] = cmdMsg->getNetCommandType(); - m_packetLen += sizeof(UnsignedByte); - - m_lastCommandType = cmdMsg->getNetCommandType(); - } - - if (m_lastPlayerID != cmdMsg->getPlayerID()) { - m_packet[m_packetLen] = NetPacketFieldTypes::PlayerId; - ++m_packetLen; - m_packet[m_packetLen] = cmdMsg->getPlayerID(); - m_packetLen += sizeof(UnsignedByte); - - m_lastPlayerID = cmdMsg->getPlayerID(); - } - - // Put in the command id of the command we are acking. - m_packet[m_packetLen] = NetPacketFieldTypes::Data; - ++m_packetLen; - memcpy(m_packet + m_packetLen, &commandID, sizeof(UnsignedShort)); - m_packetLen += sizeof(UnsignedShort); - memcpy(m_packet + m_packetLen, &originalPlayerID, sizeof(UnsignedByte)); - m_packetLen += sizeof(UnsignedByte); - - deleteInstance(m_lastCommand); - m_lastCommand = NEW_NETCOMMANDREF(msg->getCommand()); - m_lastCommand->setRelay(msg->getRelay()); - -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("outgoing - added ACK, original player %d, command id %d", origPlayerID, cmdID)); - ++m_numCommands; - return TRUE; - } - return FALSE; -} - -/** - * Returns true if there is enough room in the packet for this ack message. - */ -Bool NetPacket::isRoomForAckMessage(NetCommandRef *msg) { - Int len = 0; - NetCommandMsg *cmdMsg = msg->getCommand(); - if (m_lastCommandType != cmdMsg->getNetCommandType()) { - ++len; - len += sizeof(UnsignedByte); - } - if (m_lastPlayerID != cmdMsg->getPlayerID()) { - ++len; - len += sizeof(UnsignedByte); - } - - ++len; // for NetPacketFieldTypes::Data - len += sizeof(UnsignedShort); - len += sizeof(UnsignedByte); - if ((len + m_packetLen) > MAX_PACKET_SIZE) { - return FALSE; - } - return TRUE; -} - -Bool NetPacket::isAckRepeat(NetCommandRef *msg) { - if (m_lastCommand == NULL) { - return FALSE; - } - if (m_lastCommand->getCommand()->getNetCommandType() != msg->getCommand()->getNetCommandType()) { - return FALSE; - } - if (msg->getCommand()->getNetCommandType() == NETCOMMANDTYPE_ACKBOTH) { - return isAckBothRepeat(msg); - } - if (msg->getCommand()->getNetCommandType() == NETCOMMANDTYPE_ACKSTAGE1) { - return isAckStage1Repeat(msg); - } - if (msg->getCommand()->getNetCommandType() == NETCOMMANDTYPE_ACKSTAGE2) { - return isAckStage2Repeat(msg); - } - return FALSE; -} - -Bool NetPacket::isAckBothRepeat(NetCommandRef *msg) { - NetAckBothCommandMsg *ack = (NetAckBothCommandMsg *)(msg->getCommand()); - NetAckBothCommandMsg *lastAck = (NetAckBothCommandMsg *)(m_lastCommand->getCommand()); - if (lastAck->getCommandID() != (ack->getCommandID() - 1)) { - return FALSE; - } - if (lastAck->getOriginalPlayerID() != ack->getOriginalPlayerID()) { - return FALSE; - } - if (msg->getRelay() != m_lastCommand->getRelay()) { - return FALSE; - } - return TRUE; -} - -Bool NetPacket::isAckStage1Repeat(NetCommandRef *msg) { - NetAckStage2CommandMsg *ack = (NetAckStage2CommandMsg *)(msg->getCommand()); - NetAckStage2CommandMsg *lastAck = (NetAckStage2CommandMsg *)(m_lastCommand->getCommand()); - if (lastAck->getCommandID() != (ack->getCommandID() - 1)) { - return FALSE; - } - if (lastAck->getOriginalPlayerID() != ack->getOriginalPlayerID()) { - return FALSE; - } - if (msg->getRelay() != m_lastCommand->getRelay()) { - return FALSE; - } - return TRUE; -} - -Bool NetPacket::isAckStage2Repeat(NetCommandRef *msg) { - NetAckStage2CommandMsg *ack = (NetAckStage2CommandMsg *)(msg->getCommand()); - NetAckStage2CommandMsg *lastAck = (NetAckStage2CommandMsg *)(m_lastCommand->getCommand()); - if (lastAck->getCommandID() != (ack->getCommandID() - 1)) { - return FALSE; - } - if (lastAck->getOriginalPlayerID() != ack->getOriginalPlayerID()) { - return FALSE; - } - if (msg->getRelay() != m_lastCommand->getRelay()) { - return FALSE; - } - return TRUE; -} - -/** - * Adds this game command to the packet. Returns true if successful. - */ -Bool NetPacket::addGameCommand(NetCommandRef *msg) { - Bool retval = FALSE; - NetGameCommandMsg *cmdMsg = (NetGameCommandMsg *)(msg->getCommand()); - // get the game message from the NetCommandMsg - GameMessage *gmsg = cmdMsg->constructGameMessage(); - -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("NetPacket::addGameCommand for command ID %d", cmdMsg->getID())); - - if (isRoomForGameMessage(msg, gmsg)) { - // Now we know there is enough room, put the new game message into the packet. - - Bool needNewCommandID = FALSE; // this is to allow us to force the starting command ID to be respecified with this command. - - // If necessary, put the NetCommandType into the packet. - if (m_lastCommandType != cmdMsg->getNetCommandType()) { - m_packet[m_packetLen] = NetPacketFieldTypes::CommandType; - ++m_packetLen; - m_packet[m_packetLen] = cmdMsg->getNetCommandType(); - m_packetLen += sizeof(UnsignedByte); - - m_lastCommandType = cmdMsg->getNetCommandType(); - } - - // If necessary, put the execution frame into the packet. - if (m_lastFrame != cmdMsg->getExecutionFrame()) { - m_packet[m_packetLen] = NetPacketFieldTypes::Frame; - ++m_packetLen; - UnsignedInt newframe = cmdMsg->getExecutionFrame(); - memcpy(m_packet+m_packetLen, &newframe, sizeof(UnsignedInt)); - m_packetLen += sizeof(UnsignedInt); - - m_lastFrame = newframe; - } - - // If necessary, put the relay into the packet. - if (m_lastRelay != msg->getRelay()) { - m_packet[m_packetLen] = NetPacketFieldTypes::Relay; - ++m_packetLen; - UnsignedByte newRelay = msg->getRelay(); - memcpy(m_packet+m_packetLen, &newRelay, sizeof(UnsignedByte)); - m_packetLen += sizeof(UnsignedByte); - - m_lastRelay = newRelay; - } - - // If necessary, put the playerID into the packet. - if (m_lastPlayerID != cmdMsg->getPlayerID()) { - m_packet[m_packetLen] = NetPacketFieldTypes::PlayerId; - ++m_packetLen; - m_packet[m_packetLen] = cmdMsg->getPlayerID(); - m_packetLen += sizeof(UnsignedByte); - //since if we have a new player we need to respecify the starting command ID, lets force the command id to be different. - needNewCommandID = TRUE; - - m_lastPlayerID = cmdMsg->getPlayerID(); - } - - // If necessary, specify the command ID of this command. - if (((m_lastCommandID + 1) != (UnsignedShort)(cmdMsg->getID())) || (needNewCommandID == TRUE)) { - m_packet[m_packetLen] = NetPacketFieldTypes::CommandId; - ++m_packetLen; - UnsignedShort newID = cmdMsg->getID(); - memcpy(m_packet + m_packetLen, &newID, sizeof(UnsignedShort)); - m_packetLen += sizeof(UnsignedShort); - } - m_lastCommandID = cmdMsg->getID(); - - m_packet[m_packetLen] = NetPacketFieldTypes::Data; - ++m_packetLen; - - // Now copy the GameMessage type into the packet. - GameMessage::Type newType = gmsg->getType(); - memcpy(m_packet + m_packetLen, &newType, sizeof(GameMessage::Type)); - m_packetLen += sizeof(GameMessage::Type); - - - GameMessageParser *parser = newInstance(GameMessageParser)(gmsg); - UnsignedByte numTypes = parser->getNumTypes(); - memcpy(m_packet + m_packetLen, &numTypes, sizeof(numTypes)); - m_packetLen += sizeof(numTypes); - - GameMessageParserArgumentType *argType = parser->getFirstArgumentType(); - while (argType != NULL) { - UnsignedByte type = (UnsignedByte)(argType->getType()); - memcpy(m_packet + m_packetLen, &type, sizeof(type)); - m_packetLen += sizeof(type); - - UnsignedByte argTypeCount = argType->getArgCount(); - memcpy(m_packet + m_packetLen, &argTypeCount, sizeof(argTypeCount)); - m_packetLen += sizeof(argTypeCount); - - argType = argType->getNext(); - } - - Int numArgs = gmsg->getArgumentCount(); - for (Int i = 0; i < numArgs; ++i) { - GameMessageArgumentDataType type = gmsg->getArgumentDataType(i); - GameMessageArgumentType arg = *(gmsg->getArgument(i)); - writeGameMessageArgumentToPacket(type, arg); - } - - deleteInstance(parser); - parser = NULL; - -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("NetPacket::addGameMessage - added game message, frame %d, player %d, command ID %d", m_lastFrame, m_lastPlayerID, m_lastCommandID)); - - ++m_numCommands; - - deleteInstance(m_lastCommand); - m_lastCommand = NEW_NETCOMMANDREF(msg->getCommand()); - m_lastCommand->setRelay(msg->getRelay()); - - retval = TRUE; - } - - deleteInstance(gmsg); - gmsg = NULL; - - return retval; -} - -void NetPacket::writeGameMessageArgumentToPacket(GameMessageArgumentDataType type, GameMessageArgumentType arg) { - - switch(type) { - - case ARGUMENTDATATYPE_INTEGER: - memcpy(m_packet + m_packetLen, &(arg.integer), sizeof(arg.integer)); - m_packetLen += sizeof(arg.integer); - break; - case ARGUMENTDATATYPE_REAL: - memcpy(m_packet + m_packetLen, &(arg.real), sizeof(arg.real)); - m_packetLen += sizeof(arg.real); - break; - case ARGUMENTDATATYPE_BOOLEAN: - memcpy(m_packet + m_packetLen, &(arg.boolean), sizeof(arg.boolean)); - m_packetLen += sizeof(arg.boolean); - break; - case ARGUMENTDATATYPE_OBJECTID: - memcpy(m_packet + m_packetLen, &(arg.objectID), sizeof(arg.objectID)); - m_packetLen += sizeof(arg.objectID); - break; - case ARGUMENTDATATYPE_DRAWABLEID: - memcpy(m_packet + m_packetLen, &(arg.drawableID), sizeof(arg.drawableID)); - m_packetLen += sizeof(arg.drawableID); - break; - case ARGUMENTDATATYPE_TEAMID: - memcpy(m_packet + m_packetLen, &(arg.teamID), sizeof(arg.teamID)); - m_packetLen += sizeof(arg.teamID); - break; - case ARGUMENTDATATYPE_LOCATION: - memcpy(m_packet + m_packetLen, &(arg.location), sizeof(arg.location)); - m_packetLen += sizeof(arg.location); - break; - case ARGUMENTDATATYPE_PIXEL: - memcpy(m_packet + m_packetLen, &(arg.pixel), sizeof(arg.pixel)); - m_packetLen += sizeof(arg.pixel); - break; - case ARGUMENTDATATYPE_PIXELREGION: - memcpy(m_packet + m_packetLen, &(arg.pixelRegion), sizeof(arg.pixelRegion)); - m_packetLen += sizeof(arg.pixelRegion); - break; - case ARGUMENTDATATYPE_TIMESTAMP: - memcpy(m_packet + m_packetLen, &(arg.timestamp), sizeof(arg.timestamp)); - m_packetLen += sizeof(arg.timestamp); - break; - case ARGUMENTDATATYPE_WIDECHAR: - memcpy(m_packet + m_packetLen, &(arg.wChar), sizeof(arg.wChar)); - m_packetLen += sizeof(arg.wChar); - break; - - } -} - -/** - * Returns true if there is enough room in this packet for this message. - */ -Bool NetPacket::isRoomForGameMessage(NetCommandRef *msg, GameMessage *gmsg) { - // Calculate how much space the NetCommandMsg will take in this packet. - Int msglen = 0; - - NetGameCommandMsg *cmdMsg = (NetGameCommandMsg *)(msg->getCommand()); - - Bool needNewCommandID = FALSE; - - if (m_lastFrame != cmdMsg->getExecutionFrame()) { - msglen += sizeof(UnsignedInt) + sizeof(UnsignedByte); - } - if (m_lastPlayerID != cmdMsg->getPlayerID()) { - msglen += sizeof(UnsignedByte) + sizeof(UnsignedByte); - needNewCommandID = TRUE; - } - if (m_lastRelay != msg->getRelay()) { - msglen += sizeof(UnsignedByte) + sizeof(UnsignedByte); - } - if (m_lastCommandType != cmdMsg->getNetCommandType()) { - msglen += sizeof(UnsignedByte) + sizeof(UnsignedByte); - } - if (((m_lastCommandID + 1) != (UnsignedShort)(cmdMsg->getID())) || (needNewCommandID == TRUE)) { - msglen += sizeof(UnsignedShort) + sizeof(UnsignedByte); - } - - GameMessageParser *parser = newInstance(GameMessageParser)(gmsg); - - ++msglen; // for NetPacketFieldTypes::Data - msglen += sizeof(GameMessage::Type); - msglen += sizeof(UnsignedByte); -// Int numTypes = parser->getNumTypes(); - GameMessageParserArgumentType *arg = parser->getFirstArgumentType(); - while (arg != NULL) { - msglen += 2 * sizeof(UnsignedByte); // for the type and number of args of that type declaration. - GameMessageArgumentDataType type = arg->getType(); - - switch (type) { - - case ARGUMENTDATATYPE_INTEGER: - msglen += arg->getArgCount() * sizeof(Int); - break; - case ARGUMENTDATATYPE_REAL: - msglen += arg->getArgCount() * sizeof(Real); - break; - case ARGUMENTDATATYPE_BOOLEAN: - msglen += arg->getArgCount() * sizeof(Bool); - break; - case ARGUMENTDATATYPE_OBJECTID: - msglen += arg->getArgCount() * sizeof(ObjectID); - break; - case ARGUMENTDATATYPE_DRAWABLEID: - msglen += arg->getArgCount() * sizeof(DrawableID); - break; - case ARGUMENTDATATYPE_TEAMID: - msglen += arg->getArgCount() * sizeof(UnsignedInt); - break; - case ARGUMENTDATATYPE_LOCATION: - msglen += arg->getArgCount() * sizeof(Coord3D); - break; - case ARGUMENTDATATYPE_PIXEL: - msglen += arg->getArgCount() * sizeof(ICoord2D); - break; - case ARGUMENTDATATYPE_PIXELREGION: - msglen += arg->getArgCount() * sizeof(IRegion2D); - break; - case ARGUMENTDATATYPE_TIMESTAMP: - msglen += arg->getArgCount() * sizeof(UnsignedInt); - break; - case ARGUMENTDATATYPE_WIDECHAR: - msglen += arg->getArgCount() * sizeof(WideChar); - break; - - } - - arg = arg->getNext(); - - } - - deleteInstance(parser); - parser = NULL; - - // Is there enough room in the packet for this message? - if (msglen > (MAX_PACKET_SIZE - m_packetLen)) { - return FALSE; // there isn't enough room in this packet for this new message. - } - return TRUE; -} - -/** - * Returns the list of commands that are in this packet. - */ -NetCommandList * NetPacket::getCommandList() { - NetCommandList *retval = newInstance(NetCommandList); -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("NetPacket::getCommandList, packet length = %d", m_packetLen)); - retval->init(); - - // These need to be the same as the default values for m_lastPlayerID, m_lastFrame, etc. - UnsignedByte playerID = 0; - UnsignedInt frame = 0; - UnsignedShort commandID = 1; // The first command is going to be - UnsignedByte commandType = 0; - UnsignedByte relay = 0; - NetCommandRef *lastCommand = NULL; - - Int i = 0; - while (i < m_packetLen) { - - switch(m_packet[i]) { - - case NetPacketFieldTypes::CommandType: - ++i; - memcpy(&commandType, m_packet + i, sizeof(UnsignedByte)); - i += sizeof(UnsignedByte); - break; - case NetPacketFieldTypes::Frame: - ++i; - memcpy(&frame, m_packet + i, sizeof(UnsignedInt)); - i += sizeof(UnsignedInt); - break; - case NetPacketFieldTypes::PlayerId: - ++i; - memcpy(&playerID, m_packet + i, sizeof(UnsignedByte)); - i += sizeof(UnsignedByte); - break; - case NetPacketFieldTypes::Relay: - ++i; - memcpy(&relay, m_packet + i, sizeof(UnsignedByte)); - i += sizeof(UnsignedByte); - break; - case NetPacketFieldTypes::CommandId: - ++i; - memcpy(&commandID, m_packet + i, sizeof(UnsignedShort)); - i += sizeof(UnsignedShort); - break; - case NetPacketFieldTypes::Data: { - ++i; - - NetCommandMsg *msg = NULL; - - //DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("NetPacket::getCommandList() - command of type %d(%s)", commandType, GetNetCommandTypeAsString((NetCommandType)commandType))); - - switch((NetCommandType)commandType) - { - case NETCOMMANDTYPE_GAMECOMMAND: - msg = readGameMessage(m_packet, i); - //DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("read game command from player %d for frame %d", playerID, frame)); - break; - case NETCOMMANDTYPE_ACKBOTH: - msg = readAckBothMessage(m_packet, i); - break; - case NETCOMMANDTYPE_ACKSTAGE1: - msg = readAckStage1Message(m_packet, i); - break; - case NETCOMMANDTYPE_ACKSTAGE2: - msg = readAckStage2Message(m_packet, i); - break; - case NETCOMMANDTYPE_FRAMEINFO: - msg = readFrameMessage(m_packet, i); - // frameinfodebug - DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("read frame %d from player %d, command count = %d, relay = 0x%X", frame, playerID, ((NetFrameCommandMsg *)msg)->getCommandCount(), relay)); - break; - case NETCOMMANDTYPE_PLAYERLEAVE: - msg = readPlayerLeaveMessage(m_packet, i); -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("read player leave message from player %d for execution on frame %d", playerID, frame)); - break; - case NETCOMMANDTYPE_RUNAHEADMETRICS: - msg = readRunAheadMetricsMessage(m_packet, i); - break; - case NETCOMMANDTYPE_RUNAHEAD: - msg = readRunAheadMessage(m_packet, i); -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("read run ahead message from player %d for execution on frame %d", playerID, frame)); - break; - case NETCOMMANDTYPE_DESTROYPLAYER: - msg = readDestroyPlayerMessage(m_packet, i); -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("read CRC info message from player %d for execution on frame %d", playerID, frame)); - break; - case NETCOMMANDTYPE_KEEPALIVE: - msg = readKeepAliveMessage(m_packet, i); -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("read keep alive message from player %d", playerID)); - break; - case NETCOMMANDTYPE_DISCONNECTKEEPALIVE: - msg = readDisconnectKeepAliveMessage(m_packet, i); -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("read keep alive message from player %d", playerID)); - break; - case NETCOMMANDTYPE_DISCONNECTPLAYER: - msg = readDisconnectPlayerMessage(m_packet, i); -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("read disconnect player message from player %d", playerID)); - break; - case NETCOMMANDTYPE_PACKETROUTERQUERY: - msg = readPacketRouterQueryMessage(m_packet, i); -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("read packet router query message from player %d", playerID)); - break; - case NETCOMMANDTYPE_PACKETROUTERACK: - msg = readPacketRouterAckMessage(m_packet, i); -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("read packet router ack message from player %d", playerID)); - break; - case NETCOMMANDTYPE_DISCONNECTCHAT: - msg = readDisconnectChatMessage(m_packet, i); -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("read disconnect chat message from player %d", playerID)); - break; - case NETCOMMANDTYPE_DISCONNECTVOTE: - msg = readDisconnectVoteMessage(m_packet, i); -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("read disconnect vote message from player %d", playerID)); - break; - case NETCOMMANDTYPE_CHAT: - msg = readChatMessage(m_packet, i); -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("read chat message from player %d", playerID)); - break; - case NETCOMMANDTYPE_PROGRESS: - msg = readProgressMessage(m_packet, i); -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("read Progress message from player %d", playerID)); - break; - case NETCOMMANDTYPE_LOADCOMPLETE: - msg = readLoadCompleteMessage(m_packet, i); -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("read LoadComplete message from player %d", playerID)); - break; - case NETCOMMANDTYPE_TIMEOUTSTART: - msg = readTimeOutGameStartMessage(m_packet, i); -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("read TimeOutGameStart message from player %d", playerID)); - break; - case NETCOMMANDTYPE_WRAPPER: - DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("read Wrapper message from player %d", playerID)); - msg = readWrapperMessage(m_packet, i); - DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("Done reading Wrapper message from player %d - wrapped command was %d", playerID, - ((NetWrapperCommandMsg *)msg)->getWrappedCommandID())); - break; - case NETCOMMANDTYPE_FILE: - DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("read file message from player %d", playerID)); - msg = readFileMessage(m_packet, i); - break; - case NETCOMMANDTYPE_FILEANNOUNCE: - DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("read file announce message from player %d", playerID)); - msg = readFileAnnounceMessage(m_packet, i); - break; - case NETCOMMANDTYPE_FILEPROGRESS: - DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("read file progress message from player %d", playerID)); - msg = readFileProgressMessage(m_packet, i); - break; - case NETCOMMANDTYPE_DISCONNECTFRAME: - DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("read disconnect frame message from player %d", playerID)); - msg = readDisconnectFrameMessage(m_packet, i); - break; - case NETCOMMANDTYPE_DISCONNECTSCREENOFF: - DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("read disconnect screen off message from player %d", playerID)); - msg = readDisconnectScreenOffMessage(m_packet, i); - break; - case NETCOMMANDTYPE_FRAMERESENDREQUEST: - DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("read frame resend request message from player %d", playerID)); - msg = readFrameResendRequestMessage(m_packet, i); - break; - } - - if (msg == NULL) { - DEBUG_CRASH(("Didn't read a message from the packet. Things are about to go wrong.")); - continue; - } - - // set the info - msg->setExecutionFrame(frame); - msg->setPlayerID(playerID); - msg->setNetCommandType((NetCommandType)commandType); - msg->setID(commandID); - -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("frame = %d, player = %d, command type = %d, id = %d", frame, playerID, commandType, commandID)); - - // increment to the next command ID. - if (DoesCommandRequireACommandID((NetCommandType)commandType)) { - ++commandID; - } - - // add the message to the list. - NetCommandRef *ref = retval->addMessage(msg); - if (ref != NULL) { - ref->setRelay(relay); - } else { - DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("NetPacket::getCommandList - failed to set relay for message %d", msg->getID())); - } - - deleteInstance(lastCommand); - lastCommand = newInstance(NetCommandRef)(msg); - - msg->detach(); // Need to detach from new NetCommandMsg created by the "readXMessage" above. - - // since the message is part of the list now, we don't have to keep track of it. So we'll just set it to NULL. - msg = NULL; - break; - } - - case 'Z': { - - ++i; - // Repeat the last command, doing some funky cool byte-saving stuff - if (lastCommand == NULL) { - DEBUG_CRASH(("Got a repeat command with no command to repeat.")); - } - - NetCommandMsg *msg = NULL; - - switch(commandType) { - - case NETCOMMANDTYPE_ACKSTAGE1: { - msg = newInstance(NetAckStage1CommandMsg)(); - NetAckStage1CommandMsg* laststageone = (NetAckStage1CommandMsg*)(lastCommand->getCommand()); - ((NetAckStage1CommandMsg*)msg)->setCommandID(laststageone->getCommandID() + 1); - ((NetAckStage1CommandMsg*)msg)->setOriginalPlayerID(laststageone->getOriginalPlayerID()); - break; - } - case NETCOMMANDTYPE_ACKSTAGE2: { - msg = newInstance(NetAckStage2CommandMsg)(); - NetAckStage2CommandMsg* laststagetwo = (NetAckStage2CommandMsg*)(lastCommand->getCommand()); - ((NetAckStage2CommandMsg*)msg)->setCommandID(laststagetwo->getCommandID() + 1); - ((NetAckStage2CommandMsg*)msg)->setOriginalPlayerID(laststagetwo->getOriginalPlayerID()); - break; - } - case NETCOMMANDTYPE_ACKBOTH: { - msg = newInstance(NetAckBothCommandMsg)(); - NetAckBothCommandMsg* lastboth = (NetAckBothCommandMsg*)(lastCommand->getCommand()); - ((NetAckBothCommandMsg*)msg)->setCommandID(lastboth->getCommandID() + 1); - ((NetAckBothCommandMsg*)msg)->setOriginalPlayerID(lastboth->getOriginalPlayerID()); - break; - } - case NETCOMMANDTYPE_FRAMEINFO: { - msg = newInstance(NetFrameCommandMsg)(); - ++frame; // this is set below. - ((NetFrameCommandMsg*)msg)->setCommandCount(0); - DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("Read a repeated frame command, frame = %d, player = %d, commandID = %d", frame, playerID, commandID)); - break; - } - default: - DEBUG_CRASH(("Trying to repeat a command that shouldn't be repeated.")); - continue; - - } - - msg->setExecutionFrame(frame); - msg->setPlayerID(playerID); - msg->setNetCommandType((NetCommandType)commandType); - msg->setID(commandID); - -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("frame = %d, player = %d, command type = %d, id = %d", frame, playerID, commandType, commandID)); - - // increment to the next command ID. - if (DoesCommandRequireACommandID((NetCommandType)commandType)) { - ++commandID; - } - - // add the message to the list. - NetCommandRef *ref = retval->addMessage(msg); - if (ref != NULL) { - ref->setRelay(relay); - } - - deleteInstance(lastCommand); -// lastCommand = newInstance(NetCommandRef)(msg); - lastCommand = NEW_NETCOMMANDREF(msg); - - msg->detach(); // Need to detach from new NetCommandMsg created by the "readXMessage" above. - - // since the message is part of the list now, we don't have to keep track of it. So we'll just set it to NULL. - msg = NULL; - break; - } - - default: - // we don't recognize this command, but we have to increment i so we don't fall into an infinite loop. - DEBUG_CRASH(("Unrecognized packet entry, ignoring.")); - DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("NetPacket::getCommandList - Unrecognized packet entry at index %d", i)); - dumpPacketToLog(); - ++i; - break; - - } - - } - - deleteInstance(lastCommand); - lastCommand = NULL; - - return retval; -} - -/** - * Reads the data portion of a game message from the given position in the packet. - */ -NetCommandMsg * NetPacket::readGameMessage(UnsignedByte *data, Int &i) -{ - NetGameCommandMsg *msg = newInstance(NetGameCommandMsg); - -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("NetPacket::readGameMessage")); - - // Get the GameMessage command type. - GameMessage::Type newType; - memcpy(&newType, data + i, sizeof(GameMessage::Type)); - i += sizeof(GameMessage::Type); - msg->setGameMessageType(newType); - - // Get the number of argument types - UnsignedByte numArgTypes = 0; - memcpy(&numArgTypes, data + i, sizeof(numArgTypes)); - i += sizeof(numArgTypes); - - // Get the types and the number of arguments of those types. - Int totalArgCount = 0; - GameMessageParser *parser = newInstance(GameMessageParser)(); - Int j = 0; - for (; j < numArgTypes; ++j) { - UnsignedByte type = (UnsignedByte)ARGUMENTDATATYPE_UNKNOWN; - memcpy(&type, data + i, sizeof(type)); - i += sizeof(type); - - UnsignedByte argCount = 0; - memcpy(&argCount, data + i, sizeof(argCount)); - i += sizeof(argCount); - - parser->addArgType((GameMessageArgumentDataType)type, argCount); - totalArgCount += argCount; - } - - GameMessageParserArgumentType *parserArgType = parser->getFirstArgumentType(); - GameMessageArgumentDataType lasttype = ARGUMENTDATATYPE_UNKNOWN; - Int argsLeftForType = 0; - if (parserArgType != NULL) { - lasttype = parserArgType->getType(); - argsLeftForType = parserArgType->getArgCount(); - } - for (j = 0; j < totalArgCount; ++j) { - readGameMessageArgumentFromPacket(lasttype, msg, data, i); - - --argsLeftForType; - if (argsLeftForType == 0) { - DEBUG_ASSERTCRASH(parserArgType != NULL, ("parserArgType was NULL when it shouldn't have been.")); - if (parserArgType == NULL) { - return NULL; - } - - parserArgType = parserArgType->getNext(); - // parserArgType is allowed to be NULL here - if (parserArgType != NULL) { - argsLeftForType = parserArgType->getArgCount(); - lasttype = parserArgType->getType(); - } - } - } - - deleteInstance(parser); - parser = NULL; - - return (NetCommandMsg *)msg; -} - -void NetPacket::readGameMessageArgumentFromPacket(GameMessageArgumentDataType type, NetGameCommandMsg *msg, UnsignedByte *data, Int &i) { - - GameMessageArgumentType arg; - - switch (type) { - - case ARGUMENTDATATYPE_INTEGER: - Int theint; - memcpy(&theint, data + i, sizeof(theint)); - i += sizeof(theint); - arg.integer = theint; - msg->addArgument(type, arg); - break; - - case ARGUMENTDATATYPE_REAL: - Real thereal; - memcpy(&thereal, data + i, sizeof(thereal)); - i += sizeof(thereal); - arg.real = thereal; - msg->addArgument(type, arg); - break; - - case ARGUMENTDATATYPE_BOOLEAN: - Bool thebool; - memcpy(&thebool, data + i, sizeof(thebool)); - i += sizeof(thebool); - arg.boolean = thebool; - msg->addArgument(type, arg); - break; - - case ARGUMENTDATATYPE_OBJECTID: - ObjectID theobjectid; - memcpy(&theobjectid, data + i, sizeof(theobjectid)); - i += sizeof(theobjectid); - arg.objectID = theobjectid; - msg->addArgument(type, arg); - break; - - case ARGUMENTDATATYPE_DRAWABLEID: - DrawableID thedrawableid; - memcpy(&thedrawableid, data + i, sizeof(thedrawableid)); - i += sizeof(thedrawableid); - arg.drawableID = thedrawableid; - msg->addArgument(type, arg); - break; - - case ARGUMENTDATATYPE_TEAMID: - UnsignedInt theunsignedint; - memcpy(&theunsignedint, data + i, sizeof(theunsignedint)); - i += sizeof(theunsignedint); - arg.teamID = theunsignedint; - msg->addArgument(type, arg); - break; - - case ARGUMENTDATATYPE_LOCATION: - Coord3D coord; - memcpy(&coord, data + i, sizeof(coord)); - i += sizeof(coord); - arg.location = coord; - msg->addArgument(type, arg); - break; - - case ARGUMENTDATATYPE_PIXEL: - ICoord2D pixel; - memcpy(&pixel, data + i, sizeof(pixel)); - i += sizeof(pixel); - arg.pixel = pixel; - msg->addArgument(type, arg); - break; - - case ARGUMENTDATATYPE_PIXELREGION: - IRegion2D reg; - memcpy(®, data + i, sizeof(reg)); - i += sizeof(reg); - arg.pixelRegion = reg; - msg->addArgument(type, arg); - break; - - case ARGUMENTDATATYPE_TIMESTAMP: - UnsignedInt stamp; - memcpy(&stamp, data + i, sizeof(stamp)); - i += sizeof(stamp); - arg.timestamp = stamp; - msg->addArgument(type, arg); - break; - - case ARGUMENTDATATYPE_WIDECHAR: - WideChar c; - memcpy(&c, data + i, sizeof(c)); - i += sizeof(c); - arg.wChar = c; - msg->addArgument(type, arg); - break; - - } - -} - -/** - * Reads the data portion of the ack message at this position in the packet. - */ -NetCommandMsg * NetPacket::readAckBothMessage(UnsignedByte *data, Int &i) { - NetAckBothCommandMsg *msg = newInstance(NetAckBothCommandMsg); - - //DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("NetPacket::readAckMessage, ")); - UnsignedShort cmdID = 0; - - memcpy(&cmdID, data + i, sizeof(UnsignedShort)); - i += sizeof(UnsignedShort); - msg->setCommandID(cmdID); - //DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("commandID = %d, ", cmdID)); - - UnsignedByte origPlayerID = 0; - memcpy(&origPlayerID, data + i, sizeof(UnsignedByte)); - i += sizeof(UnsignedByte); - msg->setOriginalPlayerID(origPlayerID); - //DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("original player id = %d", origPlayerID)); - - return msg; -} - -/** - * Reads the data portion of the ack message at this position in the packet. - */ -NetCommandMsg * NetPacket::readAckStage1Message(UnsignedByte *data, Int &i) { - NetAckStage1CommandMsg *msg = newInstance(NetAckStage1CommandMsg); - -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("NetPacket::readAckMessage, ")); - UnsignedShort cmdID = 0; - - memcpy(&cmdID, data + i, sizeof(UnsignedShort)); - i += sizeof(UnsignedShort); - msg->setCommandID(cmdID); -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("commandID = %d, ", cmdID)); - - UnsignedByte origPlayerID = 0; - memcpy(&origPlayerID, data + i, sizeof(UnsignedByte)); - i += sizeof(UnsignedByte); - msg->setOriginalPlayerID(origPlayerID); -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("original player id = %d", origPlayerID)); - - return msg; -} - -/** - * Reads the data portion of the ack message at this position in the packet. - */ -NetCommandMsg * NetPacket::readAckStage2Message(UnsignedByte *data, Int &i) { - NetAckStage2CommandMsg *msg = newInstance(NetAckStage2CommandMsg); - -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("NetPacket::readAckMessage, ")); - UnsignedShort cmdID = 0; - - memcpy(&cmdID, data + i, sizeof(UnsignedShort)); - i += sizeof(UnsignedShort); - msg->setCommandID(cmdID); -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("commandID = %d, ", cmdID)); - - UnsignedByte origPlayerID = 0; - memcpy(&origPlayerID, data + i, sizeof(UnsignedByte)); - i += sizeof(UnsignedByte); - msg->setOriginalPlayerID(origPlayerID); -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("original player id = %d", origPlayerID)); - - return msg; -} - -/** - * Reads the data portion of the frame message at this position in the packet. - */ -NetCommandMsg * NetPacket::readFrameMessage(UnsignedByte *data, Int &i) { - NetFrameCommandMsg *msg = newInstance(NetFrameCommandMsg); - -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("NetPacket::readFrameMessage, ")); - UnsignedShort cmdCount = 0; - - memcpy(&cmdCount, data + i, sizeof(UnsignedShort)); - i += sizeof(UnsignedShort); - msg->setCommandCount(cmdCount); -// DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("command count = %d, ", cmdCount)); - - return msg; -} - -/** - * Reads the player leave message at this position in the packet. - */ -NetCommandMsg * NetPacket::readPlayerLeaveMessage(UnsignedByte *data, Int &i) { - NetPlayerLeaveCommandMsg *msg = newInstance(NetPlayerLeaveCommandMsg); - - UnsignedByte leavingPlayerID = 0; - - memcpy(&leavingPlayerID, data + i, sizeof(UnsignedByte)); - i += sizeof(UnsignedByte); - msg->setLeavingPlayerID(leavingPlayerID); - - return msg; -} - -/** - * Reads the run ahead metrics message at this position in the packet. - */ -NetCommandMsg * NetPacket::readRunAheadMetricsMessage(UnsignedByte *data, Int &i) { - NetRunAheadMetricsCommandMsg *msg = newInstance(NetRunAheadMetricsCommandMsg); - - Real averageLatency = (Real)0.2; - UnsignedShort averageFps = 30; - - memcpy(&averageLatency, data + i, sizeof(Real)); - i += sizeof(Real); - msg->setAverageLatency(averageLatency); - - memcpy(&averageFps, data + i, sizeof(UnsignedShort)); - i += sizeof(UnsignedShort); - msg->setAverageFps((Int)averageFps); - return msg; -} - -/** - * Reads the run ahead message at this position in the packet. - */ -NetCommandMsg * NetPacket::readRunAheadMessage(UnsignedByte *data, Int &i) { - NetRunAheadCommandMsg *msg = newInstance(NetRunAheadCommandMsg); - - UnsignedShort newRunAhead = 20; - memcpy(&newRunAhead, data + i, sizeof(UnsignedShort)); - i += sizeof(UnsignedShort); - msg->setRunAhead(newRunAhead); - - UnsignedByte newFrameRate = 30; - memcpy(&newFrameRate, data + i, sizeof(UnsignedByte)); - i += sizeof(UnsignedByte); - msg->setFrameRate(newFrameRate); - - return msg; -} - -/** - * Reads the CRC info message at this position in the packet. - */ -NetCommandMsg * NetPacket::readDestroyPlayerMessage(UnsignedByte *data, Int &i) { - NetDestroyPlayerCommandMsg *msg = newInstance(NetDestroyPlayerCommandMsg); - - UnsignedInt newVal = 0; - memcpy(&newVal, data + i, sizeof(UnsignedInt)); - i += sizeof(UnsignedInt); - msg->setPlayerIndex(newVal); - //DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("Saw CRC of 0x%8.8X", newCRC)); - - return msg; -} - -/** - * Reads the keep alive data, of which there is none. - */ -NetCommandMsg * NetPacket::readKeepAliveMessage(UnsignedByte *data, Int &i) { - NetKeepAliveCommandMsg *msg = newInstance(NetKeepAliveCommandMsg); - - return msg; -} - -/** - * Reads the disconnect keep alive data, of which there is none. - */ -NetCommandMsg * NetPacket::readDisconnectKeepAliveMessage(UnsignedByte *data, Int &i) { - NetDisconnectKeepAliveCommandMsg *msg = newInstance(NetDisconnectKeepAliveCommandMsg); - - return msg; -} - -/** - * Reads the disconnect player data. Which is the slot number of the player being disconnected. - */ -NetCommandMsg * NetPacket::readDisconnectPlayerMessage(UnsignedByte *data, Int &i) { - NetDisconnectPlayerCommandMsg *msg = newInstance(NetDisconnectPlayerCommandMsg); - - UnsignedByte slot = 0; - memcpy(&slot, data + i, sizeof(slot)); - i += sizeof(slot); - msg->setDisconnectSlot(slot); - - UnsignedInt disconnectFrame = 0; - memcpy(&disconnectFrame, data + i, sizeof(disconnectFrame)); - i += sizeof(disconnectFrame); - msg->setDisconnectFrame(disconnectFrame); - - return msg; -} - -/** - * Reads the packet router query data, of which there is none. - */ -NetCommandMsg * NetPacket::readPacketRouterQueryMessage(UnsignedByte *data, Int &i) { - NetPacketRouterQueryCommandMsg *msg = newInstance(NetPacketRouterQueryCommandMsg); - - return msg; -} - -/** - * Reads the packet router ack data, of which there is none. - */ -NetCommandMsg * NetPacket::readPacketRouterAckMessage(UnsignedByte *data, Int &i) { - NetPacketRouterAckCommandMsg *msg = newInstance(NetPacketRouterAckCommandMsg); - - return msg; -} - -/** - * Reads the disconnect chat data, which is just the string. - */ -NetCommandMsg * NetPacket::readDisconnectChatMessage(UnsignedByte *data, Int &i) { - NetDisconnectChatCommandMsg *msg = newInstance(NetDisconnectChatCommandMsg); - - WideChar text[256]; - UnsignedByte length; - memcpy(&length, data + i, sizeof(UnsignedByte)); - ++i; - memcpy(text, data + i, length * sizeof(WideChar)); - i += length * sizeof(WideChar); - text[length] = 0; - - UnicodeString unitext; - unitext.set(text); - - //DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("NetPacket::readDisconnectChatMessage - read message, message is %ls", unitext.str())); - - msg->setText(unitext); - return msg; -} - -/** - * Reads the chat data, which is just the string. - */ -NetCommandMsg * NetPacket::readChatMessage(UnsignedByte *data, Int &i) { - NetChatCommandMsg *msg = newInstance(NetChatCommandMsg); - - WideChar text[256]; - UnsignedByte length; - Int playerMask; - memcpy(&length, data + i, sizeof(UnsignedByte)); - ++i; - memcpy(text, data + i, length * sizeof(WideChar)); - i += length * sizeof(WideChar); - text[length] = 0; - memcpy(&playerMask, data + i, sizeof(Int)); - i += sizeof(Int); - - - UnicodeString unitext; - unitext.set(text); - - //DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("NetPacket::readChatMessage - read message, message is %ls", unitext.str())); - - msg->setText(unitext); - msg->setPlayerMask(playerMask); - return msg; -} - -/** - * Reads the disconnect vote data. Which is the slot number of the player being disconnected. - */ -NetCommandMsg * NetPacket::readDisconnectVoteMessage(UnsignedByte *data, Int &i) { - NetDisconnectVoteCommandMsg *msg = newInstance(NetDisconnectVoteCommandMsg); - - UnsignedByte slot = 0; - memcpy(&slot, data + i, sizeof(slot)); - i += sizeof(slot); - msg->setSlot(slot); - - UnsignedInt voteFrame = 0; - memcpy(&voteFrame, data + i, sizeof(voteFrame)); - i += sizeof(voteFrame); - msg->setVoteFrame(voteFrame); - - return msg; -} - -/** - * Reads the Progress data. Which is the slot number of the player being disconnected. - */ -NetCommandMsg * NetPacket::readProgressMessage(UnsignedByte *data, Int &i) { - NetProgressCommandMsg *msg = newInstance(NetProgressCommandMsg); - - UnsignedByte percentage = 0; - memcpy(&percentage, data + i, sizeof(UnsignedByte)); - i += sizeof(UnsignedByte); - msg->setPercentage(percentage); - - return msg; -} - -NetCommandMsg * NetPacket::readLoadCompleteMessage(UnsignedByte *data, Int &i) { - NetCommandMsg *msg = newInstance(NetCommandMsg); - return msg; -} - -NetCommandMsg * NetPacket::readTimeOutGameStartMessage(UnsignedByte *data, Int &i) { - NetCommandMsg *msg = newInstance(NetCommandMsg); - return msg; -} - -NetCommandMsg * NetPacket::readWrapperMessage(UnsignedByte *data, Int &i) { - NetWrapperCommandMsg *msg = newInstance(NetWrapperCommandMsg); - - // get the wrapped command ID - UnsignedShort wrappedCommandID = 0; - memcpy(&wrappedCommandID, data + i, sizeof(wrappedCommandID)); - msg->setWrappedCommandID(wrappedCommandID); - i += sizeof(wrappedCommandID); - DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("NetPacket::readWrapperMessage - wrapped command ID == %d", wrappedCommandID)); - - // get the chunk number. - UnsignedInt chunkNumber = 0; - memcpy(&chunkNumber, data + i, sizeof(chunkNumber)); - msg->setChunkNumber(chunkNumber); - i += sizeof(chunkNumber); - DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("NetPacket::readWrapperMessage - chunk number = %d", chunkNumber)); - - // get the number of chunks - UnsignedInt numChunks = 0; - memcpy(&numChunks, data + i, sizeof(numChunks)); - msg->setNumChunks(numChunks); - i += sizeof(numChunks); - DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("NetPacket::readWrapperMessage - number of chunks = %d", numChunks)); - - // get the total data length - UnsignedInt totalDataLength = 0; - memcpy(&totalDataLength, data + i, sizeof(totalDataLength)); - msg->setTotalDataLength(totalDataLength); - i += sizeof(totalDataLength); - DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("NetPacket::readWrapperMessage - total data length = %d", totalDataLength)); - - // get the data length for this chunk - UnsignedInt dataLength = 0; - memcpy(&dataLength, data + i, sizeof(dataLength)); - i += sizeof(dataLength); - DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("NetPacket::readWrapperMessage - data length = %d", dataLength)); - - UnsignedInt dataOffset = 0; - memcpy(&dataOffset, data + i, sizeof(dataOffset)); - msg->setDataOffset(dataOffset); - i += sizeof(dataOffset); - DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("NetPacket::readWrapperMessage - data offset = %d", dataOffset)); - - msg->setData(data + i, dataLength); - i += dataLength; - - return msg; -} - -NetCommandMsg * NetPacket::readFileMessage(UnsignedByte *data, Int &i) { - NetFileCommandMsg *msg = newInstance(NetFileCommandMsg); - char filename[_MAX_PATH]; - char *c = filename; - - while (data[i] != 0) { - *c = data[i]; - ++c; - ++i; - } - *c = 0; - ++i; - msg->setPortableFilename(AsciiString(filename)); // it's transferred as a portable filename - - UnsignedInt dataLength = 0; - memcpy(&dataLength, data + i, sizeof(dataLength)); - i += sizeof(dataLength); - - UnsignedByte *buf = NEW UnsignedByte[dataLength]; - memcpy(buf, data + i, dataLength); - i += dataLength; - - msg->setFileData(buf, dataLength); - - return msg; -} - -NetCommandMsg * NetPacket::readFileAnnounceMessage(UnsignedByte *data, Int &i) { - NetFileAnnounceCommandMsg *msg = newInstance(NetFileAnnounceCommandMsg); - char filename[_MAX_PATH]; - char *c = filename; - - while (data[i] != 0) { - *c = data[i]; - ++c; - ++i; - } - *c = 0; - ++i; - msg->setPortableFilename(AsciiString(filename)); // it's transferred as a portable filename - - UnsignedShort fileID = 0; - memcpy(&fileID, data + i, sizeof(fileID)); - i += sizeof(fileID); - msg->setFileID(fileID); - - UnsignedByte playerMask = 0; - memcpy(&playerMask, data + i, sizeof(playerMask)); - i += sizeof(playerMask); - msg->setPlayerMask(playerMask); - - return msg; -} - -NetCommandMsg * NetPacket::readFileProgressMessage(UnsignedByte *data, Int &i) { - NetFileProgressCommandMsg *msg = newInstance(NetFileProgressCommandMsg); - - UnsignedShort fileID = 0; - memcpy(&fileID, data + i, sizeof(fileID)); - i += sizeof(fileID); - msg->setFileID(fileID); - - Int progress = 0; - memcpy(&progress, data + i, sizeof(progress)); - i += sizeof(progress); - msg->setProgress(progress); - - return msg; -} - -NetCommandMsg * NetPacket::readDisconnectFrameMessage(UnsignedByte *data, Int &i) { - NetDisconnectFrameCommandMsg *msg = newInstance(NetDisconnectFrameCommandMsg); - - UnsignedInt disconnectFrame = 0; - memcpy(&disconnectFrame, data + i, sizeof(disconnectFrame)); - i += sizeof(disconnectFrame); - msg->setDisconnectFrame(disconnectFrame); - - DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("NetPacket::readDisconnectFrameMessage - read disconnect frame for frame %d", disconnectFrame)); - - return msg; -} - -NetCommandMsg * NetPacket::readDisconnectScreenOffMessage(UnsignedByte *data, Int &i) { - NetDisconnectScreenOffCommandMsg *msg = newInstance(NetDisconnectScreenOffCommandMsg); - - UnsignedInt newFrame = 0; - memcpy(&newFrame, data + i, sizeof(newFrame)); - i += sizeof(newFrame); - msg->setNewFrame(newFrame); - - return msg; -} - -NetCommandMsg * NetPacket::readFrameResendRequestMessage(UnsignedByte *data, Int &i) { - NetFrameResendRequestCommandMsg *msg = newInstance(NetFrameResendRequestCommandMsg); - - UnsignedInt frameToResend = 0; - memcpy(&frameToResend, data + i, sizeof(frameToResend)); - i += sizeof(frameToResend); - msg->setFrameToResend(frameToResend); - - return msg; -} - -/** - * Returns the number of commands in this packet. Only valid if the packet is locally constructed. - */ -Int NetPacket::getNumCommands() { - return m_numCommands; -} - -/** - * Returns the address that this packet is to be sent to. Only valid if the packet is locally constructed. - */ -UnsignedInt NetPacket::getAddr() { - return m_addr; -} - -/** - * Returns the port that this packet is to be sent to. Only valid if the packet is locally constructed. - */ -UnsignedShort NetPacket::getPort() { - return m_port; -} - -/** - * Returns the data of this packet. - */ -UnsignedByte * NetPacket::getData() { - return m_packet; -} - -/** - * Returns the length of the packet. - */ -Int NetPacket::getLength() { - return m_packetLen; -} - -/** - * Dumps the packet to the debug log file - */ -void NetPacket::dumpPacketToLog() { - DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("NetPacket::dumpPacketToLog() - packet is %d bytes", m_packetLen)); - Int numLines = m_packetLen / 8; - if ((m_packetLen % 8) != 0) { - ++numLines; - } - for (Int dumpindex = 0; dumpindex < numLines; ++dumpindex) { - DEBUG_LOG_LEVEL_RAW(DEBUG_LEVEL_NET, ("\t%d\t", dumpindex*8)); - for (Int dumpindex2 = 0; (dumpindex2 < 8) && ((dumpindex*8 + dumpindex2) < m_packetLen); ++dumpindex2) { - DEBUG_LOG_LEVEL_RAW(DEBUG_LEVEL_NET, ("%02x '%c' ", m_packet[dumpindex*8 + dumpindex2], m_packet[dumpindex*8 + dumpindex2])); - } - DEBUG_LOG_LEVEL_RAW(DEBUG_LEVEL_NET, ("\n")); - } - DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("End of packet dump")); -} diff --git a/Generals/Code/GameEngine/Source/GameNetwork/Network.cpp b/Generals/Code/GameEngine/Source/GameNetwork/Network.cpp deleted file mode 100644 index 84fd67182a..0000000000 --- a/Generals/Code/GameEngine/Source/GameNetwork/Network.cpp +++ /dev/null @@ -1,1056 +0,0 @@ -/* -** 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. // -// // -//////////////////////////////////////////////////////////////////////////////// - -// FILE: Network.cpp //////////////////////////////////////////////////// -// Implementation of Network singleton -// Author: Matthew D. Campbell, July 2001 -/////////////////////////////////////////////////////////////////////////////// - -// SYSTEM INCLUDES //////////////////////////////////////////////////////////// - -// USER INCLUDES ////////////////////////////////////////////////////////////// -#include "PreRTS.h" // This must go first in EVERY cpp file in the GameEngine - -#include "Common/GameEngine.h" -#include "Common/MessageStream.h" -#include "Common/Player.h" -#include "Common/PlayerList.h" -#include "GameNetwork/NetworkInterface.h" -#include "GameNetwork/udp.h" -#include "GameNetwork/Transport.h" -#include "strtok_r.h" -#include "GameClient/Shell.h" -#include "Common/CRCDebug.h" -#include "GameLogic/GameLogic.h" - -#include "Common/RandomValue.h" - - -#include "GameLogic/ScriptActions.h" -#include "GameLogic/ScriptEngine.h" -#include "Common/Recorder.h" -#include "GameClient/MessageBox.h" - - -#if defined(DEBUG_CRC) -Int NET_CRC_INTERVAL = 1; -#else -Int NET_CRC_INTERVAL = 100; -#endif - -// DEFINES //////////////////////////////////////////////////////////////////// - -#define RESEND_INTERVAL 1 - -// PRIVATE TYPES ////////////////////////////////////////////////////////////// - -/** - * Connection message - encapsulating info kept by the connection layer about each - * packet. These structs make up the in/out buffers at the connection layer. - */ -#pragma pack(push, 1) -struct ConnectionMessage -{ - Int id; - NetMessageFlags flags; - UnsignedByte data[MAX_MESSAGE_LEN]; - time_t lastSendTime; - Int retries; - Int length; -}; -#pragma pack(pop) - -static const int CmdMsgLen = 6; //< Minimum size of a command packet (Int + Unsigned Short) - -// PRIVATE DATA /////////////////////////////////////////////////////////////// - - - -// PUBLIC DATA //////////////////////////////////////////////////////////////// - -/// The Network singleton instance -NetworkInterface *TheNetwork = NULL; - -// PRIVATE PROTOTYPES ///////////////////////////////////////////////////////// - -/** - * The Network class is used to instantiate a singleton which - * implements the interface to all Network operations such as message stream processing and network communications. - */ -class Network : public NetworkInterface -{ -public: - //--------------------------------------------------------------------------------------- - // Setup / Teardown functions - Network(); - ~Network(); - void init( void ); ///< Initialize or re-initialize the instance - void reset( void ); ///< Reinitialize the network - void update( void ); ///< Process command list - void liteupdate( void ); ///< Do a lightweight update to send packets and pass messages. - Bool deinit( void ); ///< Shutdown connections, release memory - - void setLocalAddress(UnsignedInt ip, UnsignedInt port); - inline UnsignedInt getRunAhead(void) { return m_runAhead; } - inline UnsignedInt getFrameRate(void) { return m_frameRate; } - UnsignedInt getPacketArrivalCushion(void); ///< Returns the smallest packet arrival cushion since this was last called. - Bool isFrameDataReady( void ); - virtual Bool isStalling(); - void parseUserList( const GameInfo *game ); - void startGame(void); ///< Sets the network game frame counter to -1 - - void sendChat(UnicodeString text, Int playerMask); - void sendDisconnectChat(UnicodeString text); - - void sendFile(AsciiString path, UnsignedByte playerMask, UnsignedShort commandID); - UnsignedShort sendFileAnnounce(AsciiString path, UnsignedByte playerMask); - Int getFileTransferProgress(Int playerID, AsciiString path); - Bool areAllQueuesEmpty(void); - - void quitGame(); - virtual void selfDestructPlayer(Int index); - - - void voteForPlayerDisconnect(Int slot); - virtual Bool isPacketRouter( void ); - - // Bandwidth metrics - Real getIncomingBytesPerSecond( void ); - Real getIncomingPacketsPerSecond( void ); - Real getOutgoingBytesPerSecond( void ); - Real getOutgoingPacketsPerSecond( void ); - Real getUnknownBytesPerSecond( void ); - Real getUnknownPacketsPerSecond( void ); - - // Multiplayer Load Progress Functions - void updateLoadProgress( Int percent ); - void loadProgressComplete( void ); - void sendTimeOutGameStart( void ); - -#if defined(RTS_DEBUG) - // Disconnect screen testing - virtual void toggleNetworkOn(); -#endif - - // Exposing some info contained in the Connection Manager - UnsignedInt getLocalPlayerID( void ); - UnicodeString getPlayerName(Int playerNum); - Int getNumPlayers(void ); - - Int getAverageFPS() { return m_conMgr->getAverageFPS(); } - Int getSlotAverageFPS(Int slot); - - void attachTransport(Transport *transport); - void initTransport(); - - void setSawCRCMismatch( void ); - Bool sawCRCMismatch( void ) { return m_sawCRCMismatch; } - Bool isPlayerConnected( Int playerID ); - - void notifyOthersOfCurrentFrame(); ///< Tells all the other players what frame we are on. - void notifyOthersOfNewFrame(UnsignedInt frame); ///< Tells all the other players that we are on a new frame. - - Int getExecutionFrame(); ///< Returns the next valid frame for simultaneous command execution. - - // For disconnect blame assignment - UnsignedInt getPingFrame(); - Int getPingsSent(); - Int getPingsRecieved(); - -protected: - void GetCommandsFromCommandList(); ///< Remove commands from TheCommandList and put them on the Network command list. - void SendCommandsToConnectionManager(); ///< Send the new commands to the ConnectionManager - Bool AllCommandsReady(UnsignedInt frame); ///< Do we have all the commands for the given frame? - void RelayCommandsToCommandList(UnsignedInt frame); ///< Put the commands for the given frame onto TheCommandList. - Bool isTransferCommand(GameMessage *msg); ///< Is this a command that needs to be transfered to the other clients? - Bool processCommand(GameMessage *msg); ///< Whatever needs to be done as a result of this command, do it now. - void processFrameSynchronizedNetCommand(NetCommandRef *msg); ///< If there is a network command that needs to be executed at the same frame number on all clients, it happens here. - void processRunAheadCommand(NetRunAheadCommandMsg *msg); ///< Do what needs to be done when we get a new run ahead command. - void processDestroyPlayerCommand(NetDestroyPlayerCommandMsg *msg); ///< Do what needs to be done when we need to destroy a player. - void endOfGameCheck(); ///< Checks to see if its ok to leave this game. If it is, send the apropriate command to the game logic. - Bool timeForNewFrame(); - - ConnectionManager *m_conMgr; ///< The connection manager object - - UnsignedInt m_lastFrame; ///< The last game logic frame that was processed. - - NetLocalStatus m_localStatus; ///< My local status as a player in this game. - - Int m_runAhead; ///< The current run ahead of the game. - Int m_frameRate; - Int m_lastExecutionFrame; ///< The highest frame number that a command could have been executed on. - Int m_lastFrameCompleted; - Bool m_didSelfSlug; - __int64 m_perfCountFreq; ///< The frequency of the performance counter. - - __int64 m_nextFrameTime; ///< When did we execute the last frame? For slugging the GameLogic... - - Bool m_frameDataReady; ///< Is the frame data for the next frame ready to be executed by TheGameLogic? - Bool m_isStalling; - - // CRC info - Bool m_checkCRCsThisFrame; - Bool m_sawCRCMismatch; - std::vector m_CRC[MAX_SLOTS]; - std::list m_playersToDisconnect; - GameWindow *m_messageWindow; - -#if defined(RTS_DEBUG) - Bool m_networkOn; -#endif -}; - -UnsignedInt Network::getPingFrame() -{ - return (m_conMgr)?m_conMgr->getPingFrame():0; -} - -Int Network::getPingsSent() -{ - return (m_conMgr)?m_conMgr->getPingsSent():0; -} - -Int Network::getPingsRecieved() -{ - return (m_conMgr)?m_conMgr->getPingsRecieved():0; -} - -Bool Network::isPlayerConnected( Int playerID ) { - if (playerID == getLocalPlayerID()) { - return m_localStatus == NETLOCALSTATUS_INGAME || m_localStatus == NETLOCALSTATUS_LEAVING; - } - return m_conMgr->isPlayerConnected(playerID); -} - - -// PRIVATE FUNCTIONS ////////////////////////////////////////////////////////// - -/////////////////////////////////////////////////////////////////////////////// -// PUBLIC FUNCTIONS /////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// - -/** - * This creates a network object and returns it. - */ -NetworkInterface *NetworkInterface::createNetwork() -{ - return NEW Network; -} - -//////////////////////////////////////////////////////////////////////////////// - -/** - * The constructor. - */ -Network::Network() -{ - //Added By Sadullah Nader - //Initializations inserted - m_checkCRCsThisFrame = FALSE; - m_didSelfSlug = FALSE; - m_frameDataReady = FALSE; - m_isStalling = FALSE; - m_sawCRCMismatch = FALSE; - // - - m_conMgr = NULL; - m_messageWindow = NULL; - -#if defined(RTS_DEBUG) - m_networkOn = TRUE; -#endif -} - -/** - * The destructor. - */ -Network::~Network() -{ - deinit(); -} - -/** - * This basically releases all the memory. - */ -Bool Network::deinit( void ) -{ - if (m_conMgr) - { - m_conMgr->destroyGameMessages(); - delete m_conMgr; - m_conMgr = NULL; - } - if (m_messageWindow) { - TheWindowManager->winDestroy(m_messageWindow); - m_messageWindow = NULL; - } - - return true; -} - -/** - * Takes the network back to the initial state. - */ -void Network::reset() { - init(); -} - -/** - * Initializes all the network subsystems. - */ -void Network::init() -{ - if (!deinit()) - { - DEBUG_LOG(("Could not deinit network prior to init!")); - return; - } - - m_conMgr = NEW ConnectionManager; - m_conMgr->init(); - - m_lastFrame = 0; - m_runAhead = min(max(30, MIN_RUNAHEAD), MAX_FRAMES_AHEAD/2); ///< @todo: don't hard-code the run-ahead. - m_frameRate = 30; - m_lastExecutionFrame = m_runAhead - 1; // subtract 1 since we're starting on frame 0 - m_lastFrameCompleted = m_runAhead - 1; // subtract 1 since we're starting on frame 0 - m_frameDataReady = FALSE; - m_isStalling = FALSE; - m_didSelfSlug = FALSE; - - m_localStatus = NETLOCALSTATUS_PREGAME; - - QueryPerformanceFrequency((LARGE_INTEGER *)&m_perfCountFreq); - m_nextFrameTime = 0; - m_sawCRCMismatch = FALSE; - m_checkCRCsThisFrame = FALSE; - - DEBUG_LOG(("Network timing values:")); - DEBUG_LOG(("NetworkFPSHistoryLength: %d", TheGlobalData->m_networkFPSHistoryLength)); - DEBUG_LOG(("NetworkLatencyHistoryLength: %d", TheGlobalData->m_networkLatencyHistoryLength)); - DEBUG_LOG(("NetworkRunAheadMetricsTime: %d", TheGlobalData->m_networkRunAheadMetricsTime)); - DEBUG_LOG(("NetworkCushionHistoryLength: %d", TheGlobalData->m_networkCushionHistoryLength)); - DEBUG_LOG(("NetworkRunAheadSlack: %d", TheGlobalData->m_networkRunAheadSlack)); - DEBUG_LOG(("NetworkKeepAliveDelay: %d", TheGlobalData->m_networkKeepAliveDelay)); - DEBUG_LOG(("NetworkDisconnectTime: %d", TheGlobalData->m_networkDisconnectTime)); - DEBUG_LOG(("NetworkPlayerTimeoutTime: %d", TheGlobalData->m_networkPlayerTimeoutTime)); - DEBUG_LOG(("NetworkDisconnectScreenNotifyTime: %d", TheGlobalData->m_networkDisconnectScreenNotifyTime)); - DEBUG_LOG(("Other network stuff:")); - DEBUG_LOG(("FRAME_DATA_LENGTH = %d", FRAME_DATA_LENGTH)); - DEBUG_LOG(("FRAMES_TO_KEEP = %d", FRAMES_TO_KEEP)); - - -#if defined(RTS_DEBUG) - m_networkOn = TRUE; -#endif - - return; -} - -void Network::setSawCRCMismatch( void ) -{ - m_sawCRCMismatch = TRUE; - - TheScriptActions->closeWindows( TRUE ); - m_messageWindow = TheWindowManager->winCreateFromScript("Menus/CRCMismatch.wnd"); - TheScriptEngine->startEndGameTimer(); - - TheRecorder->logCRCMismatch(); - - // dump GameLogic random seed - DEBUG_LOG(("Latest frame for mismatch = %d GameLogic frame = %d", - TheGameLogic->getFrame()-m_runAhead-1, TheGameLogic->getFrame())); - DEBUG_LOG(("GetGameLogicRandomSeedCRC() = %d", GetGameLogicRandomSeedCRC())); - - // dump CRCs - { - DEBUG_LOG(("--- GameState Dump ---")); -#ifdef DEBUG_CRC - outputCRCDumpLines(); -#endif - DEBUG_LOG(("------ End Dump ------")); - } - { - DEBUG_LOG(("--- DebugInfo Dump ---")); -#ifdef DEBUG_CRC - outputCRCDebugLines(); -#endif - DEBUG_LOG(("------ End Dump ------")); - } -} - -/** - * Take a user list and build the connection queues and player lists and stuff like that. - */ -void Network::parseUserList( const GameInfo *game ) -{ - if (!game) - { - DEBUG_LOG(("FAILED parseUserList with a NULL game")); - return; - } - - m_conMgr->parseUserList(game); - - // Now that we have the players in this game, we need to reset the FrameData stuff. - m_conMgr->destroyGameMessages(); - m_conMgr->zeroFrames(1, m_runAhead-1); ///< we zero out m_runAhead frames +1 because the game actually starts at frame 1. -} - -/** - * Guess what, we're starting a game! - */ -void Network::startGame() { -} - -/** - * Tell the network which ip address the user has chosen to use. Well ok, they probably didn't choose - * it explicitly, but regardless, this is the one we're going to use. - */ -void Network::setLocalAddress(UnsignedInt ip, UnsignedInt port) { - DEBUG_ASSERTCRASH(m_conMgr != NULL, ("Connection manager does not exist.")); - if (m_conMgr != NULL) { - m_conMgr->setLocalAddress(ip, port); - } -} - -/** - * Tell the network to initialize the transport object - */ -void Network::initTransport() { - DEBUG_ASSERTCRASH(m_conMgr != NULL, ("Connection manager does not exist.")); - if (m_conMgr != NULL) { - m_conMgr->initTransport(); - } -} - -void Network::attachTransport(Transport *transport) { - DEBUG_ASSERTCRASH(m_conMgr != NULL, ("Connection manager does not exist.")); - if (m_conMgr != NULL) { - m_conMgr->attachTransport(transport); - } -} - -/** - * Does this command need to be transfered to the other game clients? - */ -Bool Network::isTransferCommand(GameMessage *msg) { - if ((msg != NULL) && ((msg->getType() > GameMessage::MSG_BEGIN_NETWORK_MESSAGES) && (msg->getType() < GameMessage::MSG_END_NETWORK_MESSAGES))) { - return TRUE; - } - return FALSE; -} - -/** - * Take commands from TheCommandList and give them to the connection manager for transport. - */ -void Network::GetCommandsFromCommandList() { - GameMessage *msg = TheCommandList->getFirstMessage(); - GameMessage *next = NULL; - while (msg != NULL) { - next = msg->next(); - if (isTransferCommand(msg)) { // Is this something we should be sending to the other players? - if (m_localStatus == NETLOCALSTATUS_INGAME) { - m_conMgr->sendLocalGameMessage(msg, getExecutionFrame()); - } - TheCommandList->removeMessage(msg); // This does not destroy msg's prev and next pointers, so they should still be valid. - deleteInstance(msg); - } else { - if (processCommand(msg)) { - TheCommandList->removeMessage(msg); - deleteInstance(msg); - } - } - msg = next; - } -} - -Int Network::getExecutionFrame() { - Int logicFrame = TheGameLogic->getFrame() + m_runAhead; - if (logicFrame > m_lastExecutionFrame) { - m_lastExecutionFrame = logicFrame; - return (logicFrame); - } - return m_lastExecutionFrame; -} - -/** - * This is where any processing that needs to be done for specific game messages. - * Also check here to see if the logic frame number has changed to see if we need to - * send our info for the last frame to the other players. - * Return true if the message should be "eaten" by the network. - */ -Bool Network::processCommand(GameMessage *msg) -{ - if ((m_lastFrame != TheGameLogic->getFrame()) || (m_localStatus == NETLOCALSTATUS_PREGAME)) { - // If this is the start of a new game logic frame, then tell the connection manager that the last - // frame is over and that it should now produce a frame info packet for the other players. - - if (m_localStatus == NETLOCALSTATUS_PREGAME) { - // a sort-of-hack that prevents extraneous frames from being executed before the game actually starts. - // Idealy this shouldn't be necessary, but I don't think its hurting anything by being here. - if (TheGameLogic->getFrame() == 1) { - m_localStatus = NETLOCALSTATUS_INGAME; - NetCommandList *netcmdlist = m_conMgr->getFrameCommandList(0); // clear out frame 0 since we skipped it - deleteInstance(netcmdlist); - } else { - return FALSE; - } - } - - // Only send frame info packets for frames where we are actually going to be in the game. - // The reason is so we don't have to wait for frame info packets to be sent that aren't going to - // matter anyways when we actually try to leave the game ourselves. - if (m_localStatus == NETLOCALSTATUS_INGAME) { - Int executionFrame = getExecutionFrame(); - - // Send command counts for all the frames we can. - for (Int i = m_lastFrameCompleted + 1; i < executionFrame; ++i) { - m_conMgr->processFrameTick(i); - //DEBUG_LOG(("Network::processCommand - calling processFrameTick for frame %d", i)); - m_lastFrameCompleted = i; - } - } - - //DEBUG_LOG(("Next Execution Frame - %d, last frame completed - %d", getExecutionFrame(), m_lastFrameCompleted)); - m_lastFrame = TheGameLogic->getFrame(); - } - - // Are we leaving the game? - // This has to happen after the check to see if this is the start of a new logic frame. - // The reason is that we have to send all the frame info packets necessary to get to the - // frame where everyone else is going to see that we left. - if ((msg->getType() == GameMessage::MSG_CLEAR_GAME_DATA) && (m_localStatus == NETLOCALSTATUS_INGAME)) { - Int executionFrame = getExecutionFrame(); - DEBUG_LOG(("Network::processCommand - local player leaving, executionFrame = %d, player leaving on frame %d", executionFrame, executionFrame+1)); - - m_conMgr->handleLocalPlayerLeaving(executionFrame+1); - m_conMgr->processFrameTick(executionFrame); // This is the last command we will execute, so send the command count. - // Also, we are guaranteed not to send any more commands for this frame - // since the local status will change to "Leaving" so we don't have to - // worry about messing up the other players. - m_conMgr->processFrameTick(executionFrame+1); // since we send it for executionFrame+1, we need to process both ticks - m_lastFrameCompleted = executionFrame; - DEBUG_LOG(("Network::processCommand - player leaving on frame %d", executionFrame)); - m_localStatus = NETLOCALSTATUS_LEAVING; - return TRUE; - } - return FALSE; -} - -/** - * returns true if all the commands are ready for the given frame. - */ -Bool Network::AllCommandsReady(UnsignedInt frame) { - if (m_conMgr == NULL) { - return TRUE; - } - - if (m_localStatus == NETLOCALSTATUS_PREGAME) { - return TRUE; - } - - if (m_localStatus == NETLOCALSTATUS_POSTGAME) { - return TRUE; - } - - return m_conMgr->allCommandsReady(frame);// && m_conMgr->allCRCsReady(frame); -} - -/** - * Take commands from the connection manager and put them on TheCommandList. - * The commands need to be put on in the same order across all clients. - */ -void Network::RelayCommandsToCommandList(UnsignedInt frame) { - if ((m_conMgr == NULL) || (m_localStatus == NETLOCALSTATUS_PREGAME)) { - return; - } - m_checkCRCsThisFrame = FALSE; - NetCommandList *netcmdlist = m_conMgr->getFrameCommandList(frame); - NetCommandRef *msg = netcmdlist->getFirstMessage(); - while (msg != NULL) { - NetCommandType cmdType = msg->getCommand()->getNetCommandType(); - if (cmdType == NETCOMMANDTYPE_GAMECOMMAND) { - //DEBUG_LOG(("Network::RelayCommandsToCommandList - appending command %d of type %s to command list on frame %d", msg->getCommand()->getID(), ((NetGameCommandMsg *)msg->getCommand())->constructGameMessage()->getCommandAsString(), TheGameLogic->getFrame())); - TheCommandList->appendMessage(((NetGameCommandMsg *)msg->getCommand())->constructGameMessage()); - } else { - processFrameSynchronizedNetCommand(msg); - } - msg = msg->getNext(); - } - - for (std::list::iterator selfDestructIt = m_playersToDisconnect.begin(); selfDestructIt != m_playersToDisconnect.end(); ++selfDestructIt) - { - //Int playerToDisconnect = *selfDestructIt; - //GameMessage *msg = newInstance(GameMessage)( GameMessage::MSG_SELF_DESTRUCT ); - //msg->friend_setPlayerIndex(playerToDisconnect); - //msg->appendBooleanArgument(TRUE); - //TheCommandList->appendMessage(msg); - } - m_playersToDisconnect.clear(); - - deleteInstance(netcmdlist); -} - -/** - * This is where network commands that need to be executed on the same frame should be executed. - */ -void Network::processFrameSynchronizedNetCommand(NetCommandRef *msg) { - NetCommandMsg *cmdMsg = msg->getCommand(); - if (cmdMsg->getNetCommandType() == NETCOMMANDTYPE_PLAYERLEAVE) { - PlayerLeaveCode retval = m_conMgr->processPlayerLeave((NetPlayerLeaveCommandMsg *)cmdMsg); - if (retval == PLAYERLEAVECODE_LOCAL) { - DEBUG_LOG(("Network::processFrameSynchronizedNetCommand - Local player left the game on frame %d.", TheGameLogic->getFrame())); - m_localStatus = NETLOCALSTATUS_LEFT; - } else if (retval == PLAYERLEAVECODE_PACKETROUTER) { - DEBUG_LOG(("Network::processFrameSynchronizedNetCommand - Packet router left the game on frame %d", TheGameLogic->getFrame())); - } else { - DEBUG_LOG(("Network::processFrameSynchronizedNetCommand - Client left the game on frame %d", TheGameLogic->getFrame())); - } - } - else if (cmdMsg->getNetCommandType() == NETCOMMANDTYPE_RUNAHEAD) { - NetRunAheadCommandMsg *netmsg = (NetRunAheadCommandMsg *)cmdMsg; - processRunAheadCommand(netmsg); - DEBUG_LOG_LEVEL(DEBUG_LEVEL_NET, ("command to set run ahead to %d and frame rate to %d on frame %d actually executed on frame %d", netmsg->getRunAhead(), netmsg->getFrameRate(), netmsg->getExecutionFrame(), TheGameLogic->getFrame())); - } - else if (cmdMsg->getNetCommandType() == NETCOMMANDTYPE_DESTROYPLAYER) { - NetDestroyPlayerCommandMsg *netmsg = (NetDestroyPlayerCommandMsg *)cmdMsg; - processDestroyPlayerCommand(netmsg); - //DEBUG_LOG(("CRC command (%8.8X) on frame %d actually executed on frame %d", netmsg->getCRC(), netmsg->getExecutionFrame(), TheGameLogic->getFrame())); - } -} - -void Network::processRunAheadCommand(NetRunAheadCommandMsg *msg) { - m_runAhead = msg->getRunAhead(); - m_frameRate = msg->getFrameRate(); - time_t frameGrouping = (1000 * m_runAhead) / m_frameRate; // number of miliseconds between packet sends - frameGrouping = frameGrouping / 2; // since we only want the latency for one way to be a factor. -// DEBUG_LOG(("Network::processRunAheadCommand - trying to set frame grouping to %d. run ahead = %d, m_frameRate = %d", frameGrouping, m_runAhead, m_frameRate)); - if (frameGrouping < 1) { - frameGrouping = 1; // Having a value less than 1 doesn't make sense. - } - if (frameGrouping > 500) { - frameGrouping = 500; // Max of a half a second. - } - m_conMgr->setFrameGrouping(frameGrouping); -} - -void Network::processDestroyPlayerCommand(NetDestroyPlayerCommandMsg *msg) -{ - UnsignedInt playerIndex = msg->getPlayerIndex(); - DEBUG_ASSERTCRASH(playerIndex < MAX_SLOTS, ("Bad player index")); - if (playerIndex >= MAX_SLOTS) - return; - - AsciiString playerName; - playerName.format("player%d", playerIndex); - Player *pPlayer = ThePlayerList->findPlayerWithNameKey(NAMEKEY(playerName)); - if (pPlayer) - { - GameMessage *msg = newInstance(GameMessage)(GameMessage::MSG_SELF_DESTRUCT); -#if RETAIL_COMPATIBLE_CRC - const Bool transferAssets = FALSE; -#else - const Bool transferAssets = TRUE; -#endif - msg->appendBooleanArgument(transferAssets); - msg->friend_setPlayerIndex(pPlayer->getPlayerIndex()); - TheCommandList->appendMessage(msg); - } - - DEBUG_LOG(("Saw DestroyPlayer from %d about %d for frame %d on frame %d", msg->getPlayerID(), msg->getPlayerIndex(), - msg->getExecutionFrame(), TheGameLogic->getFrame())); -} - -/** - * Service queues, process message stream, etc - */ -void Network::update( void ) -{ -// -// 1. Take Commands off TheCommandList, hand them off to the ConnectionManager. -// 2. Call ConnectionManager->update; -// 3. Check to see if all the commands for the next frame are there. -// 4. If all commands are there, put that frame's commands on TheCommandList. -// - m_frameDataReady = FALSE; - m_isStalling = FALSE; - -#if defined(RTS_DEBUG) - if (m_networkOn == FALSE) { - return; - } -#endif - - GetCommandsFromCommandList(); // Remove commands from TheCommandList and send them to the connection manager. - if (m_conMgr != NULL) { - if (m_localStatus == NETLOCALSTATUS_INGAME) { - m_conMgr->updateRunAhead(m_runAhead, m_frameRate, m_didSelfSlug, getExecutionFrame()); - m_didSelfSlug = FALSE; - } - //m_conMgr->update(); // Do the priority thing, packetize thing. This also calls the Transport::update function. - // depacketizes the incoming packets and puts them on the Network command list. - } - - liteupdate(); - - if (m_localStatus == NETLOCALSTATUS_LEFT) {// || (m_localStatus == NETLOCALSTATUS_LEAVING)) { - endOfGameCheck(); - } - - if (AllCommandsReady(TheGameLogic->getFrame())) { // If all the commands are ready for the next frame... - m_conMgr->handleAllCommandsReady(); -// DEBUG_LOG(("Network::update - frame %d is ready", TheGameLogic->getFrame())); - if (timeForNewFrame()) { // This needs to come after any other pre-frame execution checks as this changes the timing variables. - RelayCommandsToCommandList(TheGameLogic->getFrame()); // Put the commands for the next frame on TheCommandList. - m_frameDataReady = TRUE; // Tell the GameEngine to run the commands for the new frame. - } - } - else { - __int64 curTime; - QueryPerformanceCounter((LARGE_INTEGER *)&curTime); - m_isStalling = curTime >= m_nextFrameTime; - } -} - -void Network::liteupdate() { - -#if defined(RTS_DEBUG) - if (m_networkOn == FALSE) { - return; - } -#endif - - if (m_conMgr != NULL) { - if (m_localStatus == NETLOCALSTATUS_PREGAME) { - m_conMgr->update(FALSE); - } else { - m_conMgr->update(TRUE); - } - } -} - -void Network::endOfGameCheck() { - if (m_conMgr != NULL) { - if (m_conMgr->canILeave()) { - m_conMgr->disconnectLocalPlayer(); - TheGameLogic->exitGame(); - m_localStatus = NETLOCALSTATUS_POSTGAME; - - DEBUG_LOG(("Network::endOfGameCheck - about to show the shell")); - } -#if defined(RTS_DEBUG) - else { - m_conMgr->debugPrintConnectionCommands(); - } -#endif - } -} - -Bool Network::timeForNewFrame() { - __int64 curTime; - QueryPerformanceCounter((LARGE_INTEGER *)&curTime); - __int64 frameDelay = m_perfCountFreq / m_frameRate; - - /* - * If we're pushing up against the edge of our run ahead, we should slow the framerate down a bit - * to avoid being frozen by spikes in network lag. This will happen if another user's computer is - * running too far behind us, so we need to slow down to let them catch up. - */ - if (m_conMgr != NULL) { - Real cushion = m_conMgr->getMinimumCushion(); - Real runAheadPercentage = m_runAhead * (TheGlobalData->m_networkRunAheadSlack / (Real)100.0); // If we are at least 50% into our slack, we need to slow down. - if (cushion < runAheadPercentage) { - __int64 oldFrameDelay = frameDelay; - frameDelay += oldFrameDelay / 10; // temporarily decrease the frame rate by 20%. -// DEBUG_LOG(("Average cushion = %f, run ahead percentage = %f. Adjusting frameDelay from %I64d to %I64d", cushion, runAheadPercentage, oldFrameDelay, frameDelay)); - m_didSelfSlug = TRUE; -// } else { -// DEBUG_LOG(("Average cushion = %f, run ahead percentage = %f", cushion, runAheadPercentage)); - } - } - - // Check to see if we can run another frame. - if (curTime >= m_nextFrameTime) { -// DEBUG_LOG(("Allowing a new frame, frameDelay = %I64d, curTime - m_nextFrameTime = %I64d", frameDelay, curTime - m_nextFrameTime)); - -// if (m_nextFrameTime + frameDelay < curTime) { - if ((m_nextFrameTime + (2 * frameDelay)) < curTime) { - // If we get too far behind on our framerate we need to reset the nextFrameTime thing. - m_nextFrameTime = curTime; -// DEBUG_LOG(("Initializing m_nextFrameTime to %I64d", m_nextFrameTime)); - } else { - // Set the soonest possible starting time for the next frame. - m_nextFrameTime += frameDelay; -// DEBUG_LOG(("m_nextFrameTime = %I64d", m_nextFrameTime)); - } - - return TRUE; - } -// DEBUG_LOG(("Slowing down frame rate. frame rate = %d, frame delay = %I64d, curTime - m_nextFrameTime = %I64d", m_frameRate, frameDelay, curTime - m_nextFrameTime)); - return FALSE; -} - -/** - * Returns true if the game commands for the next frame have been put on the command list. - */ -Bool Network::isFrameDataReady() { - return (m_frameDataReady || (m_localStatus == NETLOCALSTATUS_LEFT)); -} - -Bool Network::isStalling() -{ - return m_isStalling; -} - -/** - * returns the number of incoming bytes per second averaged over the last 30 sec. - */ -Real Network::getIncomingBytesPerSecond( void ) -{ - if (m_conMgr) - return m_conMgr->getIncomingBytesPerSecond(); - else - return 0.0; -} - -/** - * returns the number of incoming packets per second averaged over the last 30 sec. - */ -Real Network::getIncomingPacketsPerSecond( void ) -{ - if (m_conMgr) - return m_conMgr->getIncomingPacketsPerSecond(); - else - return 0.0; -} - -/** - * returns the number of outgoing bytes per second averaged over the last 30 sec. - */ -Real Network::getOutgoingBytesPerSecond( void ) -{ - if (m_conMgr) - return m_conMgr->getOutgoingBytesPerSecond(); - else - return 0.0; -} - -/** - * returns the number of outgoing packets per second averaged over the last 30 sec. - */ -Real Network::getOutgoingPacketsPerSecond( void ) -{ - if (m_conMgr) - return m_conMgr->getOutgoingPacketsPerSecond(); - else - return 0.0; -} - -/** - * returns the number of bytes received per second that are not from a generals client averaged over 30 sec. - */ -Real Network::getUnknownBytesPerSecond( void ) -{ - if (m_conMgr) - return m_conMgr->getUnknownBytesPerSecond(); - else - return 0.0; -} - -/** - * returns the number of packets received per second that are not from a generals client averaged over 30 sec. - */ -Real Network::getUnknownPacketsPerSecond( void ) -{ - if (m_conMgr) - return m_conMgr->getUnknownPacketsPerSecond(); - else - return 0.0; -} - -/** - * returns the smallest packet arrival cushion since this was last called. - */ -UnsignedInt Network::getPacketArrivalCushion( void ) -{ - if (m_conMgr) - return m_conMgr->getPacketArrivalCushion(); - else - return 0; -} - -/** - * Sends a line of chat to the other players - */ -void Network::sendChat(UnicodeString text, Int playerMask) { - Int executionFrame = getExecutionFrame(); - m_conMgr->sendChat(text, playerMask, executionFrame); -} - -/** - * Sends a line of chat to the other players using the disconnect manager. - */ -void Network::sendDisconnectChat(UnicodeString text) { - m_conMgr->sendDisconnectChat(text); -} - -// send a file. woohoo. -void Network::sendFile(AsciiString path, UnsignedByte playerMask, UnsignedShort commandID) -{ - m_conMgr->sendFile(path, playerMask, commandID); -} - -// send a file. woohoo. -UnsignedShort Network::sendFileAnnounce(AsciiString path, UnsignedByte playerMask) -{ - return m_conMgr->sendFileAnnounce(path, playerMask); -} - -Int Network::getFileTransferProgress(Int playerID, AsciiString path) -{ - return m_conMgr->getFileTransferProgress(playerID, path); -} - -Bool Network::areAllQueuesEmpty(void) -{ - return m_conMgr->canILeave(); -} - -/** - * Quit the game now. This should only be called from the disconnect screen. - */ -void Network::quitGame() { - if (m_conMgr != NULL) { - m_conMgr->quitGame(); - } - -#if !RTS_GENERALS || !RETAIL_COMPATIBLE_CRC - // Blow up / Transfer your units when you quit. Like a normal quit menu quit. - GameMessage *msg = TheMessageStream->appendMessage(GameMessage::MSG_SELF_DESTRUCT); - msg->appendBooleanArgument(TRUE); -#endif - - TheGameLogic->exitGame(); - m_localStatus = NETLOCALSTATUS_POSTGAME; - DEBUG_LOG(("Network::quitGame - quitting game...")); -} - -void Network::selfDestructPlayer(Int index) -{ - m_playersToDisconnect.push_back(index); -} - - -Bool Network::isPacketRouter( void ) -{ - return m_conMgr && m_conMgr->isPacketRouter(); -} - -/** - * Register a vote towards a player being disconnected. - */ -void Network::voteForPlayerDisconnect(Int slot) { - if (m_conMgr != NULL) { - m_conMgr->voteForPlayerDisconnect(slot); - } -} - -void Network::updateLoadProgress( Int percent ) -{ - if (m_conMgr != NULL) { - m_conMgr->updateLoadProgress( percent ); - } -} - -void Network::loadProgressComplete( void ) -{ - if (m_conMgr != NULL) { - m_conMgr->loadProgressComplete(); - } -} - -void Network::sendTimeOutGameStart( void ) -{ - if (m_conMgr != NULL) { - m_conMgr->sendTimeOutGameStart(); - } -} - - -UnsignedInt Network::getLocalPlayerID() -{ -if (m_conMgr != NULL) { - return m_conMgr->getLocalPlayerID(); - } - return 49; -} -UnicodeString Network::getPlayerName(Int playerNum) -{ - if (playerNum == m_conMgr->getLocalPlayerID()) { - if (m_localStatus != NETLOCALSTATUS_INGAME) { - return UnicodeString::TheEmptyString; - } - } - if (m_conMgr != NULL) { - return m_conMgr->getPlayerName( playerNum ); - } - return UnicodeString::TheEmptyString; -} -Int Network::getNumPlayers() -{ - if (m_conMgr != NULL) { - return m_conMgr->getNumPlayers(); - } - return -1; -} - -Int Network::getSlotAverageFPS(Int slot) { - if (m_conMgr != NULL) { - return m_conMgr->getSlotAverageFPS(slot); - } - return -1; -} - -#if defined(RTS_DEBUG) -void Network::toggleNetworkOn() { - if (m_networkOn == TRUE) { - m_networkOn = FALSE; - } else { - m_networkOn = TRUE; - } -} -#endif - -void Network::notifyOthersOfCurrentFrame() { - if (m_conMgr != NULL) { - m_conMgr->notifyOthersOfCurrentFrame(TheGameLogic->getFrame()); - } -} - -void Network::notifyOthersOfNewFrame(UnsignedInt frame) { - if (m_conMgr != NULL) { - m_conMgr->notifyOthersOfNewFrame(frame); - } -} diff --git a/Generals/Code/GameEngine/Source/GameNetwork/NetworkUtil.cpp b/Generals/Code/GameEngine/Source/GameNetwork/NetworkUtil.cpp deleted file mode 100644 index 332c2d8f01..0000000000 --- a/Generals/Code/GameEngine/Source/GameNetwork/NetworkUtil.cpp +++ /dev/null @@ -1,275 +0,0 @@ -/* -** 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 in the GameEngine - -#include "GameNetwork/networkutil.h" - -// TheSuperHackers @tweak Mauller 26/08/2025 reduce the minimum runahead from 10 -// This lets network games run at latencies down to 133ms when the network conditions allow -Int MIN_LOGIC_FRAMES = 5; -Int MAX_FRAMES_AHEAD = 128; -Int MIN_RUNAHEAD = 4; -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 =======", len)); - DEBUG_LOG(("Source: %s:%d", 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_RAW(("\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_RAW(("%02X ", c)); - } - for (; dumpindex2 < 8; ++dumpindex2) - { - DEBUG_LOG_RAW((" ")); - } - DEBUG_LOG_RAW((" | ")); - for (dumpindex2 = 0; dumpindex2 < numBytesThisLine; ++dumpindex2) - { - char c = buf[offset + dumpindex2]; - DEBUG_LOG_RAW(("%c", (isprint(c)?c:'.'))); - } - DEBUG_LOG_RAW(("\n")); - } - DEBUG_LOG(("End of packet dump")); -} - -#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")); - 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", 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; -} - -const char* GetNetCommandTypeAsString(NetCommandType type) { - - switch (type) { - case NETCOMMANDTYPE_ACKBOTH: - return "NETCOMMANDTYPE_ACKBOTH"; - case NETCOMMANDTYPE_ACKSTAGE1: - return "NETCOMMANDTYPE_ACKSTAGE1"; - case NETCOMMANDTYPE_ACKSTAGE2: - return "NETCOMMANDTYPE_ACKSTAGE2"; - case NETCOMMANDTYPE_FRAMEINFO: - return "NETCOMMANDTYPE_FRAMEINFO"; - case NETCOMMANDTYPE_GAMECOMMAND: - return "NETCOMMANDTYPE_GAMECOMMAND"; - case NETCOMMANDTYPE_PLAYERLEAVE: - return "NETCOMMANDTYPE_PLAYERLEAVE"; - case NETCOMMANDTYPE_RUNAHEADMETRICS: - return "NETCOMMANDTYPE_RUNAHEADMETRICS"; - case NETCOMMANDTYPE_RUNAHEAD: - return "NETCOMMANDTYPE_RUNAHEAD"; - case NETCOMMANDTYPE_DESTROYPLAYER: - return "NETCOMMANDTYPE_DESTROYPLAYER"; - case NETCOMMANDTYPE_KEEPALIVE: - return "NETCOMMANDTYPE_KEEPALIVE"; - case NETCOMMANDTYPE_DISCONNECTCHAT: - return "NETCOMMANDTYPE_DISCONNECTCHAT"; - case NETCOMMANDTYPE_CHAT: - return "NETCOMMANDTYPE_CHAT"; - case NETCOMMANDTYPE_MANGLERQUERY: - return "NETCOMMANDTYPE_MANGLERQUERY"; - case NETCOMMANDTYPE_MANGLERRESPONSE: - return "NETCOMMANDTYPE_MANGLERRESPONSE"; - case NETCOMMANDTYPE_PROGRESS: - return "NETCOMMANDTYPE_PROGRESS"; - case NETCOMMANDTYPE_LOADCOMPLETE: - return "NETCOMMANDTYPE_LOADCOMPLETE"; - case NETCOMMANDTYPE_TIMEOUTSTART: - return "NETCOMMANDTYPE_TIMEOUTSTART"; - case NETCOMMANDTYPE_WRAPPER: - return "NETCOMMANDTYPE_WRAPPER"; - case NETCOMMANDTYPE_FILE: - return "NETCOMMANDTYPE_FILE"; - case NETCOMMANDTYPE_FILEANNOUNCE: - return "NETCOMMANDTYPE_FILEANNOUNCE"; - case NETCOMMANDTYPE_FILEPROGRESS: - return "NETCOMMANDTYPE_FILEPROGRESS"; - case NETCOMMANDTYPE_DISCONNECTKEEPALIVE: - return "NETCOMMANDTYPE_DISCONNECTKEEPALIVE"; - case NETCOMMANDTYPE_DISCONNECTPLAYER: - return "NETCOMMANDTYPE_DISCONNECTPLAYER"; - case NETCOMMANDTYPE_PACKETROUTERQUERY: - return "NETCOMMANDTYPE_PACKETROUTERQUERY"; - case NETCOMMANDTYPE_PACKETROUTERACK: - return "NETCOMMANDTYPE_PACKETROUTERACK"; - case NETCOMMANDTYPE_DISCONNECTVOTE: - return "NETCOMMANDTYPE_DISCONNECTVOTE"; - case NETCOMMANDTYPE_DISCONNECTFRAME: - return "NETCOMMANDTYPE_DISCONNECTFRAME"; - case NETCOMMANDTYPE_DISCONNECTSCREENOFF: - return "NETCOMMANDTYPE_DISCONNECTSCREENOFF"; - case NETCOMMANDTYPE_FRAMERESENDREQUEST: - return "NETCOMMANDTYPE_FRAMERESENDREQUEST"; - default: - DEBUG_CRASH(("Unknown NetCommandType in GetNetCommandTypeAsString")); - return "UNKNOWN"; - } - -} diff --git a/Generals/Code/GameEngine/Source/GameNetwork/Transport.cpp b/Generals/Code/GameEngine/Source/GameNetwork/Transport.cpp deleted file mode 100644 index eedbe729c8..0000000000 --- a/Generals/Code/GameEngine/Source/GameNetwork/Transport.cpp +++ /dev/null @@ -1,504 +0,0 @@ -/* -** 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 in the GameEngine - -#include "Common/crc.h" -#include "GameNetwork/Transport.h" -#include "GameNetwork/NetworkInterface.h" - - -//-------------------------------------------------------------------------- -// Packet-level encryption is an XOR operation, for speed reasons. To get -// the max throughput, we only XOR whole 4-byte words, so the last bytes -// can be non-XOR'd. - -// This assumes the buf is a multiple of 4 bytes. Extra is not encrypted. -static inline void encryptBuf( unsigned char *buf, Int len ) -{ - UnsignedInt mask = 0x0000Fade; - - UnsignedInt *uintPtr = (UnsignedInt *) (buf); - - for (int i=0 ; iBind(ip, port); - } - - if (retval != 0) { - DEBUG_CRASH(("Could not bind to 0x%8.8X:%d", ip, port)); - DEBUG_LOG(("Transport::init - Failure to bind socket with error code %x", retval)); - delete m_udpsock; - m_udpsock = NULL; - return false; - } - - // ------- Clear buffers -------- - int i=0; - for (; im_latencyAverage > 0 || TheGlobalData->m_latencyNoise) - m_useLatency = true; - - if (TheGlobalData->m_packetLoss) - m_usePacketLoss = true; -#endif - - return true; -} - -void Transport::reset( void ) -{ - delete m_udpsock; - m_udpsock = NULL; - - if (m_winsockInit) - { - WSACleanup(); - m_winsockInit = false; - } -} - -Bool Transport::update( void ) -{ - Bool retval = TRUE; - if (doRecv() == FALSE && m_udpsock && m_udpsock->GetStatus() == UDP::ADDRNOTAVAIL) - { - retval = FALSE; - } - DEBUG_ASSERTLOG(retval, ("WSA error is %s", GetWSAErrorString(WSAGetLastError()).str())); - if (doSend() == FALSE && m_udpsock && m_udpsock->GetStatus() == UDP::ADDRNOTAVAIL) - { - retval = FALSE; - } - DEBUG_ASSERTLOG(retval, ("WSA error is %s", GetWSAErrorString(WSAGetLastError()).str())); - return retval; -} - -Bool Transport::doSend() { - if (!m_udpsock) - { - DEBUG_LOG(("Transport::doSend() - m_udpSock is NULL!")); - return FALSE; - } - - Bool retval = TRUE; - - // Statistics gathering - UnsignedInt now = timeGetTime(); - if (m_lastSecond + 1000 < now) - { - m_lastSecond = now; - m_statisticsSlot = (m_statisticsSlot + 1) % MAX_TRANSPORT_STATISTICS_SECONDS; - m_outgoingPackets[m_statisticsSlot] = 0; - m_outgoingBytes[m_statisticsSlot] = 0; - m_incomingPackets[m_statisticsSlot] = 0; - m_incomingBytes[m_statisticsSlot] = 0; - m_unknownPackets[m_statisticsSlot] = 0; - m_unknownBytes[m_statisticsSlot] = 0; - } - - // Send all messages - int i; - for (i=0; iWrite((unsigned char *)(&m_outBuffer[i]), bytesToSend, m_outBuffer[i].addr, m_outBuffer[i].port)) > 0) - { - //DEBUG_LOG(("Sending %d bytes to %d.%d.%d.%d:%d", bytesToSend, PRINTF_IP_AS_4_INTS(m_outBuffer[i].addr), m_outBuffer[i].port)); - m_outgoingPackets[m_statisticsSlot]++; - m_outgoingBytes[m_statisticsSlot] += m_outBuffer[i].length + sizeof(TransportMessageHeader); - m_outBuffer[i].length = 0; // Remove from queue - if (bytesSent != bytesToSend) - { - DEBUG_LOG(("Transport::doSend - wanted to send %d bytes, only sent %d bytes to %d.%d.%d.%d:%d", - bytesToSend, bytesSent, - PRINTF_IP_AS_4_INTS(m_outBuffer[i].addr), m_outBuffer[i].port)); - } - } - else - { - //DEBUG_LOG(("Could not write to socket!!! Not discarding message!")); - retval = FALSE; - //DEBUG_LOG(("Transport::doSend returning FALSE")); - } - } - } - -#if defined(RTS_DEBUG) - // Latency simulation - deliver anything we're holding on to that is ready - if (m_useLatency) - { - for (i=0; iRead(buf, MAX_MESSAGE_LEN, &from)) > 0 ) - { -#if defined(RTS_DEBUG) - // Packet loss simulation - if (m_usePacketLoss) - { - if ( TheGlobalData->m_packetLoss >= GameClientRandomValue(0, 100) ) - { - continue; - } - } -#endif - -// DEBUG_LOG(("Transport::doRecv - Got something! len = %d", len)); - // Decrypt the packet -// DEBUG_LOG_RAW(("buffer = ")); -// for (Int munkee = 0; munkee < len; ++munkee) { -// DEBUG_LOG_RAW(("%02x", *(buf + munkee))); -// } -// DEBUG_LOG_RAW(("\n")); - decryptBuf(buf, len); - - incomingMessage.length = len - sizeof(TransportMessageHeader); - - if (len <= sizeof(TransportMessageHeader) || !isGeneralsPacket( &incomingMessage )) - { - DEBUG_LOG(("Transport::doRecv - unknownPacket! len = %d", len)); - m_unknownPackets[m_statisticsSlot]++; - m_unknownBytes[m_statisticsSlot] += len; - continue; - } - - // Something there; stick it somewhere -// DEBUG_LOG(("Saw %d bytes from %d:%d", len, ntohl(from.sin_addr.S_un.S_addr), ntohs(from.sin_port))); - m_incomingPackets[m_statisticsSlot]++; - m_incomingBytes[m_statisticsSlot] += len; - - for (int i=0; im_latencyAverage + - (Int)(TheGlobalData->m_latencyAmplitude * sin(now * TheGlobalData->m_latencyPeriod)) + - GameClientRandomValue(-TheGlobalData->m_latencyNoise, TheGlobalData->m_latencyNoise); - m_delayedInBuffer[i].message.length = incomingMessage.length; - m_delayedInBuffer[i].message.addr = ntohl(from.sin_addr.S_un.S_addr); - m_delayedInBuffer[i].message.port = ntohs(from.sin_port); - memcpy(&m_delayedInBuffer[i].message, buf, len); - break; - } - } - else - { -#endif - if (m_inBuffer[i].length == 0) - { - // Empty slot; use it - m_inBuffer[i].length = incomingMessage.length; - m_inBuffer[i].addr = ntohl(from.sin_addr.S_un.S_addr); - m_inBuffer[i].port = ntohs(from.sin_port); - memcpy(&m_inBuffer[i], buf, len); - break; - } -#if defined(RTS_DEBUG) - } -#endif - } - //DEBUG_ASSERTCRASH(i MAX_PACKET_SIZE) - { - DEBUG_LOG(("Transport::queueSend - Invalid Packet size")); - return false; - } - - for (i=0; ilength < 0 || msg->length > MAX_MESSAGE_LEN) - return false; - - CRC crc; -// crc.computeCRC( (unsigned char *)msg->data, msg->length ); - crc.computeCRC( (unsigned char *)(&(msg->header.magic)), msg->length + sizeof(TransportMessageHeader) - sizeof(UnsignedInt) ); - - if (crc.get() != msg->header.crc) - return false; - - if (msg->header.magic != GENERALS_MAGIC_NUMBER) - return false; - - return true; -} - -// Statistics --------------------------------------------------- -Real Transport::getIncomingBytesPerSecond( void ) -{ - Real val = 0.0; - for (int i=0; i. -*/ - -//////////////////////////////////////////////////////////////////////////////// -// // -// (c) 2001-2003 Electronic Arts Inc. // -// // -//////////////////////////////////////////////////////////////////////////////// - -//////////////////////////////////////////////////////////////////////////////// -// User class copy and comparisons - -#include "PreRTS.h" // This must go first in EVERY cpp file in the GameEngine - -#include "GameNetwork/User.h" - -/** - * Constructor. Sets up the member variables with the appropriate values. - */ -User::User(UnicodeString name, UnsignedInt addr, UnsignedInt port) { - m_name.set(name); - m_ipaddr = addr; - m_port = port; -} - -/** - * The assignment operator. - */ -User & User::operator= (const User *other) -{ - m_name = other->m_name; - m_ipaddr = other->m_ipaddr; - m_port = other->m_port; - - return *this; -} - -/** - * The equality operator. - */ -Bool User::operator== (const User *other) -{ - return (m_name.compare(other->m_name) == 0); -} - -/** - * The inequality operator. - */ -Bool User::operator!= (const User *other) -{ - return (m_name.compare(other->m_name) != 0); -} - -/** - * Set the name of this user. - */ -void User::setName(UnicodeString name) { - m_name.set(name); -} diff --git a/Generals/Code/GameEngine/Source/GameNetwork/WOLBrowser/WebBrowser.cpp b/Generals/Code/GameEngine/Source/GameNetwork/WOLBrowser/WebBrowser.cpp deleted file mode 100644 index c3b0bf2e46..0000000000 --- a/Generals/Code/GameEngine/Source/GameNetwork/WOLBrowser/WebBrowser.cpp +++ /dev/null @@ -1,310 +0,0 @@ -/* -** 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. // -// // -//////////////////////////////////////////////////////////////////////////////// - -/****************************************************************************** -* -* NAME -* $Archive: $ -* -* DESCRIPTION -* -* PROGRAMMER -* Bryan Cleveland -* $Author: $ -* -* VERSION INFO -* $Revision: $ -* $Modtime: $ -* -******************************************************************************/ - -#include "PreRTS.h" // This must go first in EVERY cpp file in the GameEngine - -//#include "WinMain.h" -#include "GameNetwork/WOLBrowser/WebBrowser.h" -#include "GameClient/GameWindow.h" -#include "GameClient/Display.h" - - -/** - * OLEInitializer class - Init and shutdown OLE & COM as a global - * object. Scary, nasty stuff, COM. /me shivers. - */ -class OLEInitializer -{ -public: - OLEInitializer() - { - // Initialize this instance - OleInitialize(NULL); - } - ~OLEInitializer() - { - OleUninitialize(); - } -}; -OLEInitializer g_OLEInitializer; -CComModule _Module; - -CComObject * TheWebBrowser = NULL; - - -/****************************************************************************** -* -* NAME -* WebBrowser::WebBrowser -* -* DESCRIPTION -* Default constructor -* -* INPUTS -* NONE -* -* RESULT -* NONE -* -******************************************************************************/ - -WebBrowser::WebBrowser() : - mRefCount(1) -{ - DEBUG_LOG(("Instantiating embedded WebBrowser")); - m_urlList = NULL; -} - - -/****************************************************************************** -* -* NAME -* WebBrowser::~WebBrowser -* -* DESCRIPTION -* Destructor -* -* INPUTS -* NONE -* -* RESULT -* NONE -* -******************************************************************************/ - -WebBrowser::~WebBrowser() -{ - DEBUG_LOG(("Destructing embedded WebBrowser")); - if (this == TheWebBrowser) { - DEBUG_LOG(("WebBrowser::~WebBrowser - setting TheWebBrowser to NULL")); - TheWebBrowser = NULL; - } - WebBrowserURL *url = m_urlList; - while (url != NULL) { - WebBrowserURL *temp = url; - url = url->m_next; - deleteInstance(temp); - temp = NULL; - } -} - -//------------------------------------------------------------------------------------------------- -/** The INI data fields for Webpage URL's */ -//------------------------------------------------------------------------------------------------- -const FieldParse WebBrowserURL::m_URLFieldParseTable[] = -{ - - { "URL", INI::parseAsciiString, NULL, offsetof( WebBrowserURL, m_url ) }, - { NULL, NULL, NULL, 0 }, - -}; - -WebBrowserURL::WebBrowserURL() -{ - m_next = NULL; - m_tag.clear(); - m_url.clear(); -} - -WebBrowserURL::~WebBrowserURL() -{ -} -/****************************************************************************** -* -* NAME -* WebBrowser::init -* -* DESCRIPTION -* Perform post creation initialization. -* -* INPUTS -* NONE -* -* RESULT -* NONE -* -******************************************************************************/ - -void WebBrowser::init() -{ - m_urlList = NULL; - INI ini; - ini.loadFileDirectory( AsciiString( "Data\\INI\\Webpages" ), INI_LOAD_OVERWRITE, NULL ); -} - -/****************************************************************************** -* -* NAME -* WebBrowser::reset -* -* DESCRIPTION -* Perform post creation initialization. -* -* INPUTS -* NONE -* -* RESULT -* NONE -* -******************************************************************************/ - -void WebBrowser::reset() -{ -} - -void WebBrowser::update( void ) -{ -} - -WebBrowserURL * WebBrowser::findURL(AsciiString tag) -{ - WebBrowserURL *retval = m_urlList; - - while ((retval != NULL) && tag.compareNoCase(retval->m_tag.str())) - { - retval = retval->m_next; - } - - return retval; -} - -WebBrowserURL * WebBrowser::makeNewURL(AsciiString tag) -{ - WebBrowserURL *newURL = newInstance(WebBrowserURL); - - newURL->m_tag = tag; - - newURL->m_next = m_urlList; - m_urlList = newURL; - - return newURL; -} - -/****************************************************************************** -* -* NAME -* IUnknown::QueryInterface -* -* DESCRIPTION -* -* INPUTS -* IID - Interface ID -* -* RESULT -* -******************************************************************************/ - -STDMETHODIMP WebBrowser::QueryInterface(REFIID iid, void** ppv) IUNKNOWN_NOEXCEPT -{ - *ppv = NULL; - - if ((iid == IID_IUnknown) || (iid == IID_IBrowserDispatch)) - { - *ppv = static_cast(this); - } - else - { - return E_NOINTERFACE; - } - - static_cast(*ppv)->AddRef(); - - return S_OK; -} - - -/****************************************************************************** -* -* NAME -* IUnknown::AddRef -* -* DESCRIPTION -* -* INPUTS -* NONE -* -* RESULT -* -******************************************************************************/ - -ULONG STDMETHODCALLTYPE WebBrowser::AddRef(void) IUNKNOWN_NOEXCEPT -{ - return ++mRefCount; -} - - -/****************************************************************************** -* -* NAME -* IUnknown::Release -* -* DESCRIPTION -* -* INPUTS -* NONE -* -* RESULT -* -******************************************************************************/ - -ULONG STDMETHODCALLTYPE WebBrowser::Release(void) IUNKNOWN_NOEXCEPT -{ - DEBUG_ASSERTCRASH(mRefCount > 0, ("Negative reference count")); - --mRefCount; - - if (mRefCount == 0) - { - DEBUG_LOG(("WebBrowser::Release - all references released, deleting the object.")); - if (this == TheWebBrowser) { - TheWebBrowser = NULL; - } - delete this; - return 0; - } - - return mRefCount; -} - -STDMETHODIMP WebBrowser::TestMethod(Int num1) -{ - DEBUG_LOG(("WebBrowser::TestMethod - num1 = %d", num1)); - return S_OK; -} diff --git a/Generals/Code/GameEngine/Source/GameNetwork/udp.cpp b/Generals/Code/GameEngine/Source/GameNetwork/udp.cpp deleted file mode 100644 index 469e6f1c38..0000000000 --- a/Generals/Code/GameEngine/Source/GameNetwork/udp.cpp +++ /dev/null @@ -1,534 +0,0 @@ -/* -** 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. // -// // -//////////////////////////////////////////////////////////////////////////////// - -// FILE: Udp.cpp ////////////////////////////////////////////////////////////// -// Implementation of UDP socket wrapper class (taken from wnet lib) -// Author: Matthew D. Campbell, July 2001 -/////////////////////////////////////////////////////////////////////////////// - -// SYSTEM INCLUDES //////////////////////////////////////////////////////////// -#include "PreRTS.h" // This must go first in EVERY cpp file in the GameEngine - -// USER INCLUDES ////////////////////////////////////////////////////////////// -#include "Common/GameEngine.h" -//#include "GameNetwork/NetworkInterface.h" -#include "GameNetwork/udp.h" - - -//------------------------------------------------------------------------- - -#ifdef DEBUG_LOGGING - -#define CASE(x) case (x): return #x; - -AsciiString GetWSAErrorString( Int error ) -{ - switch (error) - { - CASE(WSABASEERR) - CASE(WSAEINTR) - CASE(WSAEBADF) - CASE(WSAEACCES) - CASE(WSAEFAULT) - CASE(WSAEINVAL) - CASE(WSAEMFILE) - CASE(WSAEWOULDBLOCK) - CASE(WSAEINPROGRESS) - CASE(WSAEALREADY) - CASE(WSAENOTSOCK) - CASE(WSAEDESTADDRREQ) - CASE(WSAEMSGSIZE) - CASE(WSAEPROTOTYPE) - CASE(WSAENOPROTOOPT) - CASE(WSAEPROTONOSUPPORT) - CASE(WSAESOCKTNOSUPPORT) - CASE(WSAEOPNOTSUPP) - CASE(WSAEPFNOSUPPORT) - CASE(WSAEAFNOSUPPORT) - CASE(WSAEADDRINUSE) - CASE(WSAEADDRNOTAVAIL) - CASE(WSAENETDOWN) - CASE(WSAENETUNREACH) - CASE(WSAENETRESET) - CASE(WSAECONNABORTED) - CASE(WSAECONNRESET) - CASE(WSAENOBUFS) - CASE(WSAEISCONN) - CASE(WSAENOTCONN) - CASE(WSAESHUTDOWN) - CASE(WSAETOOMANYREFS) - CASE(WSAETIMEDOUT) - CASE(WSAECONNREFUSED) - CASE(WSAELOOP) - CASE(WSAENAMETOOLONG) - CASE(WSAEHOSTDOWN) - CASE(WSAEHOSTUNREACH) - CASE(WSAENOTEMPTY) - CASE(WSAEPROCLIM) - CASE(WSAEUSERS) - CASE(WSAEDQUOT) - CASE(WSAESTALE) - CASE(WSAEREMOTE) - CASE(WSAEDISCON) - CASE(WSASYSNOTREADY) - CASE(WSAVERNOTSUPPORTED) - CASE(WSANOTINITIALISED) - CASE(WSAHOST_NOT_FOUND) - CASE(WSATRY_AGAIN) - CASE(WSANO_RECOVERY) - CASE(WSANO_DATA) - default: - { - AsciiString ret; - ret.format("Not a Winsock error (%d)", error); - return ret; - } - } - return AsciiString::TheEmptyString; // will not be hit, ever. -} - -#undef CASE - -#endif // defined(RTS_DEBUG) - -//------------------------------------------------------------------------- - -UDP::UDP() -{ - fd=0; -} - -UDP::~UDP() -{ - if (fd) - closesocket(fd); -} - -Int UDP::Bind(const char *Host,UnsignedShort port) -{ - struct hostent *hostStruct; - struct in_addr *hostNode; - - if (isdigit(Host[0])) - return ( Bind( ntohl(inet_addr(Host)), port) ); - - hostStruct = gethostbyname(Host); - if (hostStruct == NULL) - return (0); - hostNode = (struct in_addr *) hostStruct->h_addr; - return ( Bind(ntohl(hostNode->s_addr),port) ); -} - -// You must call bind, implicit binding is for sissies -// Well... you can get implicit binding if you pass 0 for either arg -Int UDP::Bind(UnsignedInt IP,UnsignedShort Port) -{ - int retval; - int status; - - IP=htonl(IP); - Port=htons(Port); - - addr.sin_family=AF_INET; - addr.sin_port=Port; - addr.sin_addr.s_addr=IP; - fd=socket(AF_INET,SOCK_DGRAM,DEFAULT_PROTOCOL); - #ifdef _WINDOWS - if (fd==SOCKET_ERROR) - fd=-1; - #endif - if (fd==-1) - return(UNKNOWN); - - retval=bind(fd,(struct sockaddr *)&addr,sizeof(addr)); - - #ifdef _WINDOWS - if (retval==SOCKET_ERROR) - { - retval=-1; - m_lastError = WSAGetLastError(); - } - #endif - if (retval==-1) - { - status=GetStatus(); - //CERR("Bind failure (" << status << ") IP " << IP << " PORT " << Port ) - return(status); - } - - int namelen=sizeof(addr); - getsockname(fd, (struct sockaddr *)&addr, &namelen); - - myIP=ntohl(addr.sin_addr.s_addr); - myPort=ntohs(addr.sin_port); - - retval=SetBlocking(FALSE); - if (retval==-1) - fprintf(stderr,"Couldn't set nonblocking mode!\n"); - - return(OK); -} - -Int UDP::getLocalAddr(UnsignedInt &ip, UnsignedShort &port) -{ - ip=myIP; - port=myPort; - return(OK); -} - - -// private function -Int UDP::SetBlocking(Int block) -{ - #ifdef _WINDOWS - unsigned long flag=1; - if (block) - flag=0; - int retval; - retval=ioctlsocket(fd,FIONBIO,&flag); - if (retval==SOCKET_ERROR) - return(UNKNOWN); - else - return(OK); - #else // UNIX - int flags = fcntl(fd, F_GETFL, 0); - if (block==FALSE) // set nonblocking - flags |= O_NONBLOCK; - else // set blocking - flags &= ~(O_NONBLOCK); - - if (fcntl(fd, F_SETFL, flags) < 0) - { - return(UNKNOWN); - } - return(OK); - #endif -} - - -Int UDP::Write(const unsigned char *msg,UnsignedInt len,UnsignedInt IP,UnsignedShort port) -{ - Int retval; - struct sockaddr_in to; - - // This happens frequently - if ((IP==0)||(port==0)) return(ADDRNOTAVAIL); - -#ifdef _UNIX - errno=0; -#endif - to.sin_port=htons(port); - to.sin_addr.s_addr=htonl(IP); - to.sin_family=AF_INET; - - ClearStatus(); - retval=sendto(fd,(const char *)msg,len,0,(struct sockaddr *)&to,sizeof(to)); - #ifdef _WINDOWS - if (retval==SOCKET_ERROR) - { - retval=-1; - m_lastError = WSAGetLastError(); -#ifdef DEBUG_LOGGING - static Int errCount = 0; -#endif - DEBUG_ASSERTLOG(errCount++ > 100, ("UDP::Write() - WSA error is %s", GetWSAErrorString(WSAGetLastError()).str())); - } - #endif - - return(retval); -} - -Int UDP::Read(unsigned char *msg,UnsignedInt len,sockaddr_in *from) -{ - Int retval; - int alen=sizeof(sockaddr_in); - - if (from!=NULL) - { - retval=recvfrom(fd,(char *)msg,len,0,(struct sockaddr *)from,&alen); - #ifdef _WINDOWS - if (retval == SOCKET_ERROR) - { - if (WSAGetLastError() != WSAEWOULDBLOCK) - { - // failing because of a blocking error isn't really such a bad thing. - m_lastError = WSAGetLastError(); -#ifdef DEBUG_LOGGING - static Int errCount = 0; -#endif - DEBUG_ASSERTLOG(errCount++ > 100, ("UDP::Read() - WSA error is %s", GetWSAErrorString(WSAGetLastError()).str())); - retval = -1; - } else { - retval = 0; - } - } - #endif - } - else - { - retval=recvfrom(fd,(char *)msg,len,0,NULL,NULL); - #ifdef _WINDOWS - if (retval==SOCKET_ERROR) - { - if (WSAGetLastError() != WSAEWOULDBLOCK) - { - // failing because of a blocking error isn't really such a bad thing. - m_lastError = WSAGetLastError(); -#ifdef DEBUG_LOGGING - static Int errCount = 0; -#endif - DEBUG_ASSERTLOG(errCount++ > 100, ("UDP::Read() - WSA error is %s", GetWSAErrorString(WSAGetLastError()).str())); - retval = -1; - } else { - retval = 0; - } - } - #endif - } - return(retval); -} - - -void UDP::ClearStatus(void) -{ - #ifndef _WINDOWS - errno=0; - #endif - - m_lastError = 0; -} - -UDP::sockStat UDP::GetStatus(void) -{ - Int status = m_lastError; - #ifdef _WINDOWS - //int status=WSAGetLastError(); - switch (status) { - case NO_ERROR: - return OK; - case WSAEINTR: - return INTR; - case WSAEINPROGRESS: - return INPROGRESS; - case WSAECONNREFUSED: - return CONNREFUSED; - case WSAEINVAL: - return INVAL; - case WSAEISCONN: - return ISCONN; - case WSAENOTSOCK: - return NOTSOCK; - case WSAETIMEDOUT: - return TIMEDOUT; - case WSAEALREADY: - return ALREADY; - case WSAEWOULDBLOCK: - return WOULDBLOCK; - case WSAEBADF: - return BADF; - default: - return (UDP::sockStat)status; - } - #else - //int status=errno; - switch (status) { - case 0: - return OK; - case EINTR: - return INTR; - case EINPROGRESS: - return INPROGRESS; - case ECONNREFUSED: - return CONNREFUSED; - case EINVAL: - return INVAL; - case EISCONN: - return ISCONN; - case ENOTSOCK: - return NOTSOCK; - case ETIMEDOUT: - return TIMEDOUT; - case EALREADY: - return ALREADY; - case EAGAIN: - return AGAIN; - case EWOULDBLOCK: - return WOULDBLOCK; - case EBADF: - return BADF; - default: - return UNKNOWN; - } - #endif -} - - - -/* -// -// Wait for net activity on this socket -// -int UDP::Wait(Int sec,Int usec,fd_set &returnSet) -{ - fd_set inputSet; - - FD_ZERO(&inputSet); - FD_SET(fd,&inputSet); - - return(Wait(sec,usec,inputSet,returnSet)); -} -*/ - -/* -// -// Wait for net activity on a list of sockets -// -int UDP::Wait(Int sec,Int usec,fd_set &givenSet,fd_set &returnSet) -{ - Wtime timeout,timenow,timethen; - fd_set backupSet; - int retval=0,done,givenMax; - Bool noTimeout=FALSE; - timeval tv; - - returnSet=givenSet; - backupSet=returnSet; - - if ((sec==-1)&&(usec==-1)) - noTimeout=TRUE; - - timeout.SetSec(sec); - timeout.SetUsec(usec); - timethen+=timeout; - - givenMax=fd; - for (UnsignedInt i=0; i<(sizeof(fd_set)*8); i++) // i=maxFD+1 - { - if (FD_ISSET(i,&givenSet)) - givenMax=i; - } - ///DBGMSG("WAIT fd="< Date: Sun, 9 Nov 2025 14:43:04 -0500 Subject: [PATCH 2/4] fix(unify): Move obsolete GameSpy files (GameSpyChat, GameSpyGP, GameSpyGameInfo) back to Generals-only --- Core/GameEngine/CMakeLists.txt | 12 +- Generals/Code/GameEngine/CMakeLists.txt | 12 +- .../Include/GameNetwork/GameSpyChat.h | 2 +- .../Include/GameNetwork/GameSpyGP.h | 2 +- .../Include/GameNetwork/GameSpyGameInfo.h | 2 +- .../Source/GameNetwork/GameSpyChat.cpp | 0 .../Source/GameNetwork/GameSpyGP.cpp | 0 .../Source/GameNetwork/GameSpyGameInfo.cpp | 0 scripts/cpp/unify_move_files.py | 144 +++++------------- 9 files changed, 53 insertions(+), 121 deletions(-) rename {Core => Generals/Code}/GameEngine/Include/GameNetwork/GameSpyChat.h (98%) rename {Core => Generals/Code}/GameEngine/Include/GameNetwork/GameSpyGP.h (97%) rename {Core => Generals/Code}/GameEngine/Include/GameNetwork/GameSpyGameInfo.h (98%) rename {Core => Generals/Code}/GameEngine/Source/GameNetwork/GameSpyChat.cpp (100%) rename {Core => Generals/Code}/GameEngine/Source/GameNetwork/GameSpyGP.cpp (100%) rename {Core => Generals/Code}/GameEngine/Source/GameNetwork/GameSpyGameInfo.cpp (100%) diff --git a/Core/GameEngine/CMakeLists.txt b/Core/GameEngine/CMakeLists.txt index fbeaaeffd2..8bf3158e5b 100644 --- a/Core/GameEngine/CMakeLists.txt +++ b/Core/GameEngine/CMakeLists.txt @@ -527,9 +527,9 @@ set(GAMEENGINE_SRC Include/GameNetwork/GameSpy/PingThread.h Include/GameNetwork/GameSpy/StagingRoomGameInfo.h Include/GameNetwork/GameSpy/ThreadUtils.h - Include/GameNetwork/GameSpyChat.h - Include/GameNetwork/GameSpyGameInfo.h - Include/GameNetwork/GameSpyGP.h +# Include/GameNetwork/GameSpyChat.h # unused +# Include/GameNetwork/GameSpyGameInfo.h # unused +# Include/GameNetwork/GameSpyGP.h # unused Include/GameNetwork/GameSpyOverlay.h Include/GameNetwork/GameSpyThread.h # Include/GameNetwork/GUIUtil.h @@ -1102,9 +1102,9 @@ set(GAMEENGINE_SRC Source/GameNetwork/FrameMetrics.cpp Source/GameNetwork/GameInfo.cpp Source/GameNetwork/GameMessageParser.cpp - Source/GameNetwork/GameSpyChat.cpp # unused - Source/GameNetwork/GameSpyGameInfo.cpp # unused - Source/GameNetwork/GameSpyGP.cpp # unused + #Source/GameNetwork/GameSpyChat.cpp # unused + #Source/GameNetwork/GameSpyGameInfo.cpp # unused + #Source/GameNetwork/GameSpyGP.cpp # unused Source/GameNetwork/GameSpy/Chat.cpp Source/GameNetwork/GameSpy/GSConfig.cpp Source/GameNetwork/GameSpy/LadderDefs.cpp diff --git a/Generals/Code/GameEngine/CMakeLists.txt b/Generals/Code/GameEngine/CMakeLists.txt index cd24fd95c9..a9395f9b12 100644 --- a/Generals/Code/GameEngine/CMakeLists.txt +++ b/Generals/Code/GameEngine/CMakeLists.txt @@ -484,9 +484,9 @@ set(GAMEENGINE_SRC # Include/GameNetwork/GameSpy/PingThread.h # Include/GameNetwork/GameSpy/StagingRoomGameInfo.h # Include/GameNetwork/GameSpy/ThreadUtils.h -# Include/GameNetwork/GameSpyChat.h -# Include/GameNetwork/GameSpyGameInfo.h -# Include/GameNetwork/GameSpyGP.h + Include/GameNetwork/GameSpyChat.h + Include/GameNetwork/GameSpyGameInfo.h + Include/GameNetwork/GameSpyGP.h # Include/GameNetwork/GameSpyOverlay.h Include/GameNetwork/GameSpyPersistentStorage.h # Include/GameNetwork/GameSpyThread.h @@ -1017,9 +1017,9 @@ set(GAMEENGINE_SRC # Source/GameNetwork/GameInfo.cpp # Source/GameNetwork/GameMessageParser.cpp #Source/GameNetwork/GameSpy.cpp -# #Source/GameNetwork/GameSpyChat.cpp -# #Source/GameNetwork/GameSpyGameInfo.cpp -# #Source/GameNetwork/GameSpyGP.cpp + #Source/GameNetwork/GameSpyChat.cpp + #Source/GameNetwork/GameSpyGameInfo.cpp + #Source/GameNetwork/GameSpyGP.cpp #Source/GameNetwork/GameSpyPersistentStorage.cpp # Source/GameNetwork/GameSpy/Chat.cpp # Source/GameNetwork/GameSpy/GSConfig.cpp diff --git a/Core/GameEngine/Include/GameNetwork/GameSpyChat.h b/Generals/Code/GameEngine/Include/GameNetwork/GameSpyChat.h similarity index 98% rename from Core/GameEngine/Include/GameNetwork/GameSpyChat.h rename to Generals/Code/GameEngine/Include/GameNetwork/GameSpyChat.h index cf149df174..4b56c34b8e 100644 --- a/Core/GameEngine/Include/GameNetwork/GameSpyChat.h +++ b/Generals/Code/GameEngine/Include/GameNetwork/GameSpyChat.h @@ -1,5 +1,5 @@ /* -** Command & Conquer Generals Zero Hour(tm) +** Command & Conquer Generals(tm) ** Copyright 2025 Electronic Arts Inc. ** ** This program is free software: you can redistribute it and/or modify diff --git a/Core/GameEngine/Include/GameNetwork/GameSpyGP.h b/Generals/Code/GameEngine/Include/GameNetwork/GameSpyGP.h similarity index 97% rename from Core/GameEngine/Include/GameNetwork/GameSpyGP.h rename to Generals/Code/GameEngine/Include/GameNetwork/GameSpyGP.h index 6ce6092a55..df001959ed 100644 --- a/Core/GameEngine/Include/GameNetwork/GameSpyGP.h +++ b/Generals/Code/GameEngine/Include/GameNetwork/GameSpyGP.h @@ -1,5 +1,5 @@ /* -** Command & Conquer Generals Zero Hour(tm) +** Command & Conquer Generals(tm) ** Copyright 2025 Electronic Arts Inc. ** ** This program is free software: you can redistribute it and/or modify diff --git a/Core/GameEngine/Include/GameNetwork/GameSpyGameInfo.h b/Generals/Code/GameEngine/Include/GameNetwork/GameSpyGameInfo.h similarity index 98% rename from Core/GameEngine/Include/GameNetwork/GameSpyGameInfo.h rename to Generals/Code/GameEngine/Include/GameNetwork/GameSpyGameInfo.h index 36dccb48e1..daba3ca64f 100644 --- a/Core/GameEngine/Include/GameNetwork/GameSpyGameInfo.h +++ b/Generals/Code/GameEngine/Include/GameNetwork/GameSpyGameInfo.h @@ -1,5 +1,5 @@ /* -** Command & Conquer Generals Zero Hour(tm) +** Command & Conquer Generals(tm) ** Copyright 2025 Electronic Arts Inc. ** ** This program is free software: you can redistribute it and/or modify diff --git a/Core/GameEngine/Source/GameNetwork/GameSpyChat.cpp b/Generals/Code/GameEngine/Source/GameNetwork/GameSpyChat.cpp similarity index 100% rename from Core/GameEngine/Source/GameNetwork/GameSpyChat.cpp rename to Generals/Code/GameEngine/Source/GameNetwork/GameSpyChat.cpp diff --git a/Core/GameEngine/Source/GameNetwork/GameSpyGP.cpp b/Generals/Code/GameEngine/Source/GameNetwork/GameSpyGP.cpp similarity index 100% rename from Core/GameEngine/Source/GameNetwork/GameSpyGP.cpp rename to Generals/Code/GameEngine/Source/GameNetwork/GameSpyGP.cpp diff --git a/Core/GameEngine/Source/GameNetwork/GameSpyGameInfo.cpp b/Generals/Code/GameEngine/Source/GameNetwork/GameSpyGameInfo.cpp similarity index 100% rename from Core/GameEngine/Source/GameNetwork/GameSpyGameInfo.cpp rename to Generals/Code/GameEngine/Source/GameNetwork/GameSpyGameInfo.cpp diff --git a/scripts/cpp/unify_move_files.py b/scripts/cpp/unify_move_files.py index ec6584bd07..d43aa33496 100644 --- a/scripts/cpp/unify_move_files.py +++ b/scripts/cpp/unify_move_files.py @@ -127,112 +127,44 @@ def unify_move_file(fromGame: Game, fromFile: str, toGame: Game, toFile: str): def main(): - # GameNetwork Headers - unify_file(Game.ZEROHOUR, "GameEngine/Include/GameNetwork/Connection.h", Game.CORE, "GameEngine/Include/GameNetwork/Connection.h") - unify_file(Game.ZEROHOUR, "GameEngine/Include/GameNetwork/ConnectionManager.h", Game.CORE, "GameEngine/Include/GameNetwork/ConnectionManager.h") - unify_file(Game.ZEROHOUR, "GameEngine/Include/GameNetwork/DisconnectManager.h", Game.CORE, "GameEngine/Include/GameNetwork/DisconnectManager.h") - unify_file(Game.ZEROHOUR, "GameEngine/Include/GameNetwork/DownloadManager.h", Game.CORE, "GameEngine/Include/GameNetwork/DownloadManager.h") - unify_file(Game.ZEROHOUR, "GameEngine/Include/GameNetwork/FileTransfer.h", Game.CORE, "GameEngine/Include/GameNetwork/FileTransfer.h") - unify_file(Game.ZEROHOUR, "GameEngine/Include/GameNetwork/FirewallHelper.h", Game.CORE, "GameEngine/Include/GameNetwork/FirewallHelper.h") - unify_file(Game.ZEROHOUR, "GameEngine/Include/GameNetwork/FrameData.h", Game.CORE, "GameEngine/Include/GameNetwork/FrameData.h") - unify_file(Game.ZEROHOUR, "GameEngine/Include/GameNetwork/FrameDataManager.h", Game.CORE, "GameEngine/Include/GameNetwork/FrameDataManager.h") - unify_file(Game.ZEROHOUR, "GameEngine/Include/GameNetwork/FrameMetrics.h", Game.CORE, "GameEngine/Include/GameNetwork/FrameMetrics.h") - unify_file(Game.ZEROHOUR, "GameEngine/Include/GameNetwork/GameInfo.h", Game.CORE, "GameEngine/Include/GameNetwork/GameInfo.h") - unify_file(Game.ZEROHOUR, "GameEngine/Include/GameNetwork/GameMessageParser.h", Game.CORE, "GameEngine/Include/GameNetwork/GameMessageParser.h") - unify_file(Game.ZEROHOUR, "GameEngine/Include/GameNetwork/GameSpyChat.h", Game.CORE, "GameEngine/Include/GameNetwork/GameSpyChat.h") - unify_file(Game.ZEROHOUR, "GameEngine/Include/GameNetwork/GameSpyGP.h", Game.CORE, "GameEngine/Include/GameNetwork/GameSpyGP.h") - unify_file(Game.ZEROHOUR, "GameEngine/Include/GameNetwork/GameSpyGameInfo.h", Game.CORE, "GameEngine/Include/GameNetwork/GameSpyGameInfo.h") - unify_file(Game.ZEROHOUR, "GameEngine/Include/GameNetwork/GameSpyOverlay.h", Game.CORE, "GameEngine/Include/GameNetwork/GameSpyOverlay.h") - unify_file(Game.ZEROHOUR, "GameEngine/Include/GameNetwork/GameSpyThread.h", Game.CORE, "GameEngine/Include/GameNetwork/GameSpyThread.h") - unify_file(Game.ZEROHOUR, "GameEngine/Include/GameNetwork/IPEnumeration.h", Game.CORE, "GameEngine/Include/GameNetwork/IPEnumeration.h") - unify_file(Game.ZEROHOUR, "GameEngine/Include/GameNetwork/LANAPI.h", Game.CORE, "GameEngine/Include/GameNetwork/LANAPI.h") - unify_file(Game.ZEROHOUR, "GameEngine/Include/GameNetwork/LANAPICallbacks.h", Game.CORE, "GameEngine/Include/GameNetwork/LANAPICallbacks.h") - unify_file(Game.ZEROHOUR, "GameEngine/Include/GameNetwork/LANGameInfo.h", Game.CORE, "GameEngine/Include/GameNetwork/LANGameInfo.h") - unify_file(Game.ZEROHOUR, "GameEngine/Include/GameNetwork/LANPlayer.h", Game.CORE, "GameEngine/Include/GameNetwork/LANPlayer.h") - unify_file(Game.ZEROHOUR, "GameEngine/Include/GameNetwork/NAT.h", Game.CORE, "GameEngine/Include/GameNetwork/NAT.h") - unify_file(Game.ZEROHOUR, "GameEngine/Include/GameNetwork/NetCommandList.h", Game.CORE, "GameEngine/Include/GameNetwork/NetCommandList.h") - unify_file(Game.ZEROHOUR, "GameEngine/Include/GameNetwork/NetCommandMsg.h", Game.CORE, "GameEngine/Include/GameNetwork/NetCommandMsg.h") - unify_file(Game.ZEROHOUR, "GameEngine/Include/GameNetwork/NetCommandRef.h", Game.CORE, "GameEngine/Include/GameNetwork/NetCommandRef.h") - unify_file(Game.ZEROHOUR, "GameEngine/Include/GameNetwork/NetCommandWrapperList.h", Game.CORE, "GameEngine/Include/GameNetwork/NetCommandWrapperList.h") - unify_file(Game.ZEROHOUR, "GameEngine/Include/GameNetwork/NetPacket.h", Game.CORE, "GameEngine/Include/GameNetwork/NetPacket.h") - unify_file(Game.ZEROHOUR, "GameEngine/Include/GameNetwork/NetworkDefs.h", Game.CORE, "GameEngine/Include/GameNetwork/NetworkDefs.h") - unify_file(Game.ZEROHOUR, "GameEngine/Include/GameNetwork/NetworkInterface.h", Game.CORE, "GameEngine/Include/GameNetwork/NetworkInterface.h") - unify_file(Game.ZEROHOUR, "GameEngine/Include/GameNetwork/RankPointValue.h", Game.CORE, "GameEngine/Include/GameNetwork/RankPointValue.h") - unify_file(Game.ZEROHOUR, "GameEngine/Include/GameNetwork/Transport.h", Game.CORE, "GameEngine/Include/GameNetwork/Transport.h") - unify_file(Game.ZEROHOUR, "GameEngine/Include/GameNetwork/User.h", Game.CORE, "GameEngine/Include/GameNetwork/User.h") - unify_file(Game.ZEROHOUR, "GameEngine/Include/GameNetwork/WOLBrowser/FEBDispatch.h", Game.CORE, "GameEngine/Include/GameNetwork/WOLBrowser/FEBDispatch.h") - unify_file(Game.ZEROHOUR, "GameEngine/Include/GameNetwork/WOLBrowser/WebBrowser.h", Game.CORE, "GameEngine/Include/GameNetwork/WOLBrowser/WebBrowser.h") - unify_file(Game.ZEROHOUR, "GameEngine/Include/GameNetwork/networkutil.h", Game.CORE, "GameEngine/Include/GameNetwork/networkutil.h") - unify_file(Game.ZEROHOUR, "GameEngine/Include/GameNetwork/udp.h", Game.CORE, "GameEngine/Include/GameNetwork/udp.h") - - # GameSpy Headers - unify_file(Game.ZEROHOUR, "GameEngine/Include/GameNetwork/GameSpy/BuddyDefs.h", Game.CORE, "GameEngine/Include/GameNetwork/GameSpy/BuddyDefs.h") - unify_file(Game.ZEROHOUR, "GameEngine/Include/GameNetwork/GameSpy/BuddyThread.h", Game.CORE, "GameEngine/Include/GameNetwork/GameSpy/BuddyThread.h") - unify_file(Game.ZEROHOUR, "GameEngine/Include/GameNetwork/GameSpy/GSConfig.h", Game.CORE, "GameEngine/Include/GameNetwork/GameSpy/GSConfig.h") - unify_file(Game.ZEROHOUR, "GameEngine/Include/GameNetwork/GameSpy/GameResultsThread.h", Game.CORE, "GameEngine/Include/GameNetwork/GameSpy/GameResultsThread.h") - unify_file(Game.ZEROHOUR, "GameEngine/Include/GameNetwork/GameSpy/LadderDefs.h", Game.CORE, "GameEngine/Include/GameNetwork/GameSpy/LadderDefs.h") - unify_file(Game.ZEROHOUR, "GameEngine/Include/GameNetwork/GameSpy/LobbyUtils.h", Game.CORE, "GameEngine/Include/GameNetwork/GameSpy/LobbyUtils.h") - unify_file(Game.ZEROHOUR, "GameEngine/Include/GameNetwork/GameSpy/MainMenuUtils.h", Game.CORE, "GameEngine/Include/GameNetwork/GameSpy/MainMenuUtils.h") - unify_file(Game.ZEROHOUR, "GameEngine/Include/GameNetwork/GameSpy/PeerDefs.h", Game.CORE, "GameEngine/Include/GameNetwork/GameSpy/PeerDefs.h") - unify_file(Game.ZEROHOUR, "GameEngine/Include/GameNetwork/GameSpy/PeerDefsImplementation.h", Game.CORE, "GameEngine/Include/GameNetwork/GameSpy/PeerDefsImplementation.h") - unify_file(Game.ZEROHOUR, "GameEngine/Include/GameNetwork/GameSpy/PeerThread.h", Game.CORE, "GameEngine/Include/GameNetwork/GameSpy/PeerThread.h") - unify_file(Game.ZEROHOUR, "GameEngine/Include/GameNetwork/GameSpy/PersistentStorageDefs.h", Game.CORE, "GameEngine/Include/GameNetwork/GameSpy/PersistentStorageDefs.h") - unify_file(Game.ZEROHOUR, "GameEngine/Include/GameNetwork/GameSpy/PersistentStorageThread.h", Game.CORE, "GameEngine/Include/GameNetwork/GameSpy/PersistentStorageThread.h") - unify_file(Game.ZEROHOUR, "GameEngine/Include/GameNetwork/GameSpy/PingThread.h", Game.CORE, "GameEngine/Include/GameNetwork/GameSpy/PingThread.h") - unify_file(Game.ZEROHOUR, "GameEngine/Include/GameNetwork/GameSpy/StagingRoomGameInfo.h", Game.CORE, "GameEngine/Include/GameNetwork/GameSpy/StagingRoomGameInfo.h") - unify_file(Game.ZEROHOUR, "GameEngine/Include/GameNetwork/GameSpy/ThreadUtils.h", Game.CORE, "GameEngine/Include/GameNetwork/GameSpy/ThreadUtils.h") - - # GameNetwork Source - unify_file(Game.ZEROHOUR, "GameEngine/Source/GameNetwork/Connection.cpp", Game.CORE, "GameEngine/Source/GameNetwork/Connection.cpp") - unify_file(Game.ZEROHOUR, "GameEngine/Source/GameNetwork/ConnectionManager.cpp", Game.CORE, "GameEngine/Source/GameNetwork/ConnectionManager.cpp") - unify_file(Game.ZEROHOUR, "GameEngine/Source/GameNetwork/DisconnectManager.cpp", Game.CORE, "GameEngine/Source/GameNetwork/DisconnectManager.cpp") - unify_file(Game.ZEROHOUR, "GameEngine/Source/GameNetwork/DownloadManager.cpp", Game.CORE, "GameEngine/Source/GameNetwork/DownloadManager.cpp") - unify_file(Game.ZEROHOUR, "GameEngine/Source/GameNetwork/FileTransfer.cpp", Game.CORE, "GameEngine/Source/GameNetwork/FileTransfer.cpp") - unify_file(Game.ZEROHOUR, "GameEngine/Source/GameNetwork/FirewallHelper.cpp", Game.CORE, "GameEngine/Source/GameNetwork/FirewallHelper.cpp") - unify_file(Game.ZEROHOUR, "GameEngine/Source/GameNetwork/FrameData.cpp", Game.CORE, "GameEngine/Source/GameNetwork/FrameData.cpp") - unify_file(Game.ZEROHOUR, "GameEngine/Source/GameNetwork/FrameDataManager.cpp", Game.CORE, "GameEngine/Source/GameNetwork/FrameDataManager.cpp") - unify_file(Game.ZEROHOUR, "GameEngine/Source/GameNetwork/FrameMetrics.cpp", Game.CORE, "GameEngine/Source/GameNetwork/FrameMetrics.cpp") - unify_file(Game.ZEROHOUR, "GameEngine/Source/GameNetwork/GameInfo.cpp", Game.CORE, "GameEngine/Source/GameNetwork/GameInfo.cpp") - unify_file(Game.ZEROHOUR, "GameEngine/Source/GameNetwork/GameMessageParser.cpp", Game.CORE, "GameEngine/Source/GameNetwork/GameMessageParser.cpp") - unify_file(Game.ZEROHOUR, "GameEngine/Source/GameNetwork/GameSpyChat.cpp", Game.CORE, "GameEngine/Source/GameNetwork/GameSpyChat.cpp") - unify_file(Game.ZEROHOUR, "GameEngine/Source/GameNetwork/GameSpyGP.cpp", Game.CORE, "GameEngine/Source/GameNetwork/GameSpyGP.cpp") - unify_file(Game.ZEROHOUR, "GameEngine/Source/GameNetwork/GameSpyGameInfo.cpp", Game.CORE, "GameEngine/Source/GameNetwork/GameSpyGameInfo.cpp") - unify_file(Game.ZEROHOUR, "GameEngine/Source/GameNetwork/GameSpyOverlay.cpp", Game.CORE, "GameEngine/Source/GameNetwork/GameSpyOverlay.cpp") - unify_file(Game.ZEROHOUR, "GameEngine/Source/GameNetwork/IPEnumeration.cpp", Game.CORE, "GameEngine/Source/GameNetwork/IPEnumeration.cpp") - unify_file(Game.ZEROHOUR, "GameEngine/Source/GameNetwork/LANAPI.cpp", Game.CORE, "GameEngine/Source/GameNetwork/LANAPI.cpp") - unify_file(Game.ZEROHOUR, "GameEngine/Source/GameNetwork/LANAPICallbacks.cpp", Game.CORE, "GameEngine/Source/GameNetwork/LANAPICallbacks.cpp") - unify_file(Game.ZEROHOUR, "GameEngine/Source/GameNetwork/LANAPIhandlers.cpp", Game.CORE, "GameEngine/Source/GameNetwork/LANAPIhandlers.cpp") - unify_file(Game.ZEROHOUR, "GameEngine/Source/GameNetwork/LANGameInfo.cpp", Game.CORE, "GameEngine/Source/GameNetwork/LANGameInfo.cpp") - unify_file(Game.ZEROHOUR, "GameEngine/Source/GameNetwork/NAT.cpp", Game.CORE, "GameEngine/Source/GameNetwork/NAT.cpp") - unify_file(Game.ZEROHOUR, "GameEngine/Source/GameNetwork/NetCommandList.cpp", Game.CORE, "GameEngine/Source/GameNetwork/NetCommandList.cpp") - unify_file(Game.ZEROHOUR, "GameEngine/Source/GameNetwork/NetCommandMsg.cpp", Game.CORE, "GameEngine/Source/GameNetwork/NetCommandMsg.cpp") - unify_file(Game.ZEROHOUR, "GameEngine/Source/GameNetwork/NetCommandRef.cpp", Game.CORE, "GameEngine/Source/GameNetwork/NetCommandRef.cpp") - unify_file(Game.ZEROHOUR, "GameEngine/Source/GameNetwork/NetCommandWrapperList.cpp", Game.CORE, "GameEngine/Source/GameNetwork/NetCommandWrapperList.cpp") - unify_file(Game.ZEROHOUR, "GameEngine/Source/GameNetwork/NetMessageStream.cpp", Game.CORE, "GameEngine/Source/GameNetwork/NetMessageStream.cpp") - unify_file(Game.ZEROHOUR, "GameEngine/Source/GameNetwork/NetPacket.cpp", Game.CORE, "GameEngine/Source/GameNetwork/NetPacket.cpp") - unify_file(Game.ZEROHOUR, "GameEngine/Source/GameNetwork/Network.cpp", Game.CORE, "GameEngine/Source/GameNetwork/Network.cpp") - unify_file(Game.ZEROHOUR, "GameEngine/Source/GameNetwork/NetworkUtil.cpp", Game.CORE, "GameEngine/Source/GameNetwork/NetworkUtil.cpp") - unify_file(Game.ZEROHOUR, "GameEngine/Source/GameNetwork/Transport.cpp", Game.CORE, "GameEngine/Source/GameNetwork/Transport.cpp") - unify_file(Game.ZEROHOUR, "GameEngine/Source/GameNetwork/User.cpp", Game.CORE, "GameEngine/Source/GameNetwork/User.cpp") - unify_file(Game.ZEROHOUR, "GameEngine/Source/GameNetwork/WOLBrowser/WebBrowser.cpp", Game.CORE, "GameEngine/Source/GameNetwork/WOLBrowser/WebBrowser.cpp") - unify_file(Game.ZEROHOUR, "GameEngine/Source/GameNetwork/udp.cpp", Game.CORE, "GameEngine/Source/GameNetwork/udp.cpp") - - # GameSpy Source files - unify_file(Game.ZEROHOUR, "GameEngine/Source/GameNetwork/GameSpy/Chat.cpp", Game.CORE, "GameEngine/Source/GameNetwork/GameSpy/Chat.cpp") - unify_file(Game.ZEROHOUR, "GameEngine/Source/GameNetwork/GameSpy/GSConfig.cpp", Game.CORE, "GameEngine/Source/GameNetwork/GameSpy/GSConfig.cpp") - unify_file(Game.ZEROHOUR, "GameEngine/Source/GameNetwork/GameSpy/LadderDefs.cpp", Game.CORE, "GameEngine/Source/GameNetwork/GameSpy/LadderDefs.cpp") - unify_file(Game.ZEROHOUR, "GameEngine/Source/GameNetwork/GameSpy/LobbyUtils.cpp", Game.CORE, "GameEngine/Source/GameNetwork/GameSpy/LobbyUtils.cpp") - unify_file(Game.ZEROHOUR, "GameEngine/Source/GameNetwork/GameSpy/MainMenuUtils.cpp", Game.CORE, "GameEngine/Source/GameNetwork/GameSpy/MainMenuUtils.cpp") - unify_file(Game.ZEROHOUR, "GameEngine/Source/GameNetwork/GameSpy/PeerDefs.cpp", Game.CORE, "GameEngine/Source/GameNetwork/GameSpy/PeerDefs.cpp") - unify_file(Game.ZEROHOUR, "GameEngine/Source/GameNetwork/GameSpy/StagingRoomGameInfo.cpp", Game.CORE, "GameEngine/Source/GameNetwork/GameSpy/StagingRoomGameInfo.cpp") - - # GameSpy Thread files - unify_file(Game.ZEROHOUR, "GameEngine/Source/GameNetwork/GameSpy/Thread/BuddyThread.cpp", Game.CORE, "GameEngine/Source/GameNetwork/GameSpy/Thread/BuddyThread.cpp") - unify_file(Game.ZEROHOUR, "GameEngine/Source/GameNetwork/GameSpy/Thread/GameResultsThread.cpp", Game.CORE, "GameEngine/Source/GameNetwork/GameSpy/Thread/GameResultsThread.cpp") - unify_file(Game.ZEROHOUR, "GameEngine/Source/GameNetwork/GameSpy/Thread/PeerThread.cpp", Game.CORE, "GameEngine/Source/GameNetwork/GameSpy/Thread/PeerThread.cpp") - unify_file(Game.ZEROHOUR, "GameEngine/Source/GameNetwork/GameSpy/Thread/PersistentStorageThread.cpp", Game.CORE, "GameEngine/Source/GameNetwork/GameSpy/Thread/PersistentStorageThread.cpp") - unify_file(Game.ZEROHOUR, "GameEngine/Source/GameNetwork/GameSpy/Thread/PingThread.cpp", Game.CORE, "GameEngine/Source/GameNetwork/GameSpy/Thread/PingThread.cpp") - unify_file(Game.ZEROHOUR, "GameEngine/Source/GameNetwork/GameSpy/Thread/ThreadUtils.cpp", Game.CORE, "GameEngine/Source/GameNetwork/GameSpy/Thread/ThreadUtils.cpp") + + #unify_file(Game.ZEROHOUR, "GameEngine/Include/Common/crc.h", Game.CORE, "GameEngine/Include/Common/crc.h") + #unify_file(Game.ZEROHOUR, "GameEngine/Include/Common/CRCDebug.h", Game.CORE, "GameEngine/Include/Common/CRCDebug.h") + #unify_file(Game.ZEROHOUR, "GameEngine/Source/Common/crc.cpp", Game.CORE, "GameEngine/Source/Common/crc.cpp") + #unify_file(Game.ZEROHOUR, "GameEngine/Source/Common/CRCDebug.cpp", Game.CORE, "GameEngine/Source/Common/CRCDebug.cpp") + + #unify_file(Game.ZEROHOUR, "GameEngine/Include/Common/RandomValue.h", Game.CORE, "GameEngine/Include/Common/RandomValue.h") + #unify_file(Game.ZEROHOUR, "GameEngine/Include/GameClient/ClientRandomValue.h", Game.CORE, "GameEngine/Include/GameClient/ClientRandomValue.h") + #unify_file(Game.ZEROHOUR, "GameEngine/Include/GameLogic/LogicRandomValue.h", Game.CORE, "GameEngine/Include/GameLogic/LogicRandomValue.h") + #unify_file(Game.ZEROHOUR, "GameEngine/Source/Common/RandomValue.cpp", Game.CORE, "GameEngine/Source/Common/RandomValue.cpp") + + #unify_file(Game.ZEROHOUR, "GameEngine/Include/Common/Debug.h", Game.CORE, "GameEngine/Include/Common/Debug.h") + #unify_file(Game.ZEROHOUR, "GameEngine/Source/Common/System/Debug.cpp", Game.CORE, "GameEngine/Source/Common/System/Debug.cpp") + + #unify_file(Game.ZEROHOUR, "GameEngine/Include/GameClient/VideoPlayer.h", Game.CORE, "GameEngine/Include/GameClient/VideoPlayer.h") + #unify_file(Game.ZEROHOUR, "GameEngine/Source/GameClient/VideoPlayer.cpp", Game.CORE, "GameEngine/Source/GameClient/VideoPlayer.cpp") + #unify_file(Game.ZEROHOUR, "GameEngine/Source/GameClient/VideoStream.cpp", Game.CORE, "GameEngine/Source/GameClient/VideoStream.cpp") + #unify_file(Game.ZEROHOUR, "GameEngine/Include/GameClient/WindowVideoManager.h", Game.CORE, "GameEngine/Include/GameClient/WindowVideoManager.h") + #unify_file(Game.ZEROHOUR, "GameEngine/Source/GameClient/GUI/WindowVideoManager.cpp", Game.CORE, "GameEngine/Source/GameClient/GUI/WindowVideoManager.cpp") + #unify_file(Game.ZEROHOUR, "GameEngine/Source/Common/INI/INIVideo.cpp", Game.CORE, "GameEngine/Source/Common/INI/INIVideo.cpp") + #unify_file(Game.ZEROHOUR, "GameEngineDevice/Include/VideoDevice/Bink/BinkVideoPlayer.h", Game.CORE, "GameEngineDevice/Include/VideoDevice/Bink/BinkVideoPlayer.h") + #unify_file(Game.ZEROHOUR, "GameEngineDevice/Source/VideoDevice/Bink/BinkVideoPlayer.cpp", Game.CORE, "GameEngineDevice/Source/VideoDevice/Bink/BinkVideoPlayer.cpp") + #unify_file(Game.ZEROHOUR, "GameEngineDevice/Include/W3DDevice/GameClient/W3DVideoBuffer.h", Game.CORE, "GameEngineDevice/Include/W3DDevice/GameClient/W3DVideoBuffer.h") + #unify_file(Game.ZEROHOUR, "GameEngineDevice/Source/W3DDevice/GameClient/W3DVideoBuffer.cpp", Game.CORE, "GameEngineDevice/Source/W3DDevice/GameClient/W3DVideoBuffer.cpp") + #unify_move_file(Game.ZEROHOUR, "GameEngineDevice/Include/VideoDevice/FFmpeg/FFmpegFile.h", Game.CORE, "GameEngineDevice/Include/VideoDevice/FFmpeg/FFmpegFile.h") + #unify_move_file(Game.ZEROHOUR, "GameEngineDevice/Include/VideoDevice/FFmpeg/FFmpegVideoPlayer.h", Game.CORE, "GameEngineDevice/Include/VideoDevice/FFmpeg/FFmpegVideoPlayer.h") + #unify_move_file(Game.ZEROHOUR, "GameEngineDevice/Source/VideoDevice/FFmpeg/FFmpegFile.cpp", Game.CORE, "GameEngineDevice/Source/VideoDevice/FFmpeg/FFmpegFile.cpp") + #unify_move_file(Game.ZEROHOUR, "GameEngineDevice/Source/VideoDevice/FFmpeg/FFmpegVideoPlayer.cpp", Game.CORE, "GameEngineDevice/Source/VideoDevice/FFmpeg/FFmpegVideoPlayer.cpp") + + #unify_file(Game.ZEROHOUR, "GameEngine/Include/Common/GameMemory.h", Game.CORE, "GameEngine/Include/Common/GameMemory.h") + #unify_file(Game.ZEROHOUR, "GameEngine/Include/Common/GameMemoryNull.h", Game.CORE, "GameEngine/Include/Common/GameMemoryNull.h") + #unify_file(Game.ZEROHOUR, "GameEngine/Source/Common/System/GameMemory.cpp", Game.CORE, "GameEngine/Source/Common/System/GameMemory.cpp") + #unify_file(Game.ZEROHOUR, "GameEngine/Source/Common/System/GameMemoryNull.cpp", Game.CORE, "GameEngine/Source/Common/System/GameMemoryNull.cpp") + #unify_file(Game.ZEROHOUR, "GameEngine/Source/Common/System/MemoryInit.cpp", Game.CORE, "GameEngine/Source/Common/System/GameMemoryInit.cpp") + #unify_move_file(Game.GENERALS, "GameEngine/Source/Common/System/GameMemoryInitDMA_Generals.inl", Game.CORE, "GameEngine/Source/Common/System/GameMemoryInitDMA_Generals.inl") + #unify_move_file(Game.ZEROHOUR, "GameEngine/Source/Common/System/GameMemoryInitDMA_GeneralsMD.inl", Game.CORE, "GameEngine/Source/Common/System/GameMemoryInitDMA_GeneralsMD.inl") + #unify_move_file(Game.GENERALS, "GameEngine/Source/Common/System/GameMemoryInitPools_Generals.inl", Game.CORE, "GameEngine/Source/Common/System/GameMemoryInitPools_Generals.inl") + #unify_move_file(Game.ZEROHOUR, "GameEngine/Source/Common/System/GameMemoryInitPools_GeneralsMD.inl", Game.CORE, "GameEngine/Source/Common/System/GameMemoryInitPools_GeneralsMD.inl") return From 419ea74f586250e0472992ad7d1f49920cb912bc Mon Sep 17 00:00:00 2001 From: Bobby Battista Date: Mon, 10 Nov 2025 15:10:27 -0500 Subject: [PATCH 3/4] fix(network): restore GameSpy .cpp files without unwanted edits --- Generals/Code/GameEngine/Source/GameNetwork/GameSpyChat.cpp | 2 +- Generals/Code/GameEngine/Source/GameNetwork/GameSpyGP.cpp | 2 +- Generals/Code/GameEngine/Source/GameNetwork/GameSpyGameInfo.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Generals/Code/GameEngine/Source/GameNetwork/GameSpyChat.cpp b/Generals/Code/GameEngine/Source/GameNetwork/GameSpyChat.cpp index a34441f6a4..a567fd126c 100644 --- a/Generals/Code/GameEngine/Source/GameNetwork/GameSpyChat.cpp +++ b/Generals/Code/GameEngine/Source/GameNetwork/GameSpyChat.cpp @@ -1,5 +1,5 @@ /* -** Command & Conquer Generals Zero Hour(tm) +** Command & Conquer Generals(tm) ** Copyright 2025 Electronic Arts Inc. ** ** This program is free software: you can redistribute it and/or modify diff --git a/Generals/Code/GameEngine/Source/GameNetwork/GameSpyGP.cpp b/Generals/Code/GameEngine/Source/GameNetwork/GameSpyGP.cpp index 602d1f2d08..be309ddae3 100644 --- a/Generals/Code/GameEngine/Source/GameNetwork/GameSpyGP.cpp +++ b/Generals/Code/GameEngine/Source/GameNetwork/GameSpyGP.cpp @@ -1,5 +1,5 @@ /* -** Command & Conquer Generals Zero Hour(tm) +** Command & Conquer Generals(tm) ** Copyright 2025 Electronic Arts Inc. ** ** This program is free software: you can redistribute it and/or modify diff --git a/Generals/Code/GameEngine/Source/GameNetwork/GameSpyGameInfo.cpp b/Generals/Code/GameEngine/Source/GameNetwork/GameSpyGameInfo.cpp index 5cfe1211d0..92dc5ddd07 100644 --- a/Generals/Code/GameEngine/Source/GameNetwork/GameSpyGameInfo.cpp +++ b/Generals/Code/GameEngine/Source/GameNetwork/GameSpyGameInfo.cpp @@ -1,5 +1,5 @@ /* -** Command & Conquer Generals Zero Hour(tm) +** Command & Conquer Generals(tm) ** Copyright 2025 Electronic Arts Inc. ** ** This program is free software: you can redistribute it and/or modify From bdd2d31bf52653fde5980292ab691abd841500c7 Mon Sep 17 00:00:00 2001 From: Bobby Battista Date: Mon, 10 Nov 2025 18:17:45 -0500 Subject: [PATCH 4/4] fix(unify): restore GeneralsMD GameSpy files - cannot be unified yet --- .../Include/GameNetwork/GameSpyChat.h | 55 ++ .../Include/GameNetwork/GameSpyGP.h | 42 + .../Include/GameNetwork/GameSpyGameInfo.h | 92 +++ .../Source/GameNetwork/GameSpyChat.cpp | 455 +++++++++++ .../Source/GameNetwork/GameSpyGP.cpp | 162 ++++ .../Source/GameNetwork/GameSpyGameInfo.cpp | 751 ++++++++++++++++++ 6 files changed, 1557 insertions(+) create mode 100644 GeneralsMD/Code/GameEngine/Include/GameNetwork/GameSpyChat.h create mode 100644 GeneralsMD/Code/GameEngine/Include/GameNetwork/GameSpyGP.h create mode 100644 GeneralsMD/Code/GameEngine/Include/GameNetwork/GameSpyGameInfo.h create mode 100644 GeneralsMD/Code/GameEngine/Source/GameNetwork/GameSpyChat.cpp create mode 100644 GeneralsMD/Code/GameEngine/Source/GameNetwork/GameSpyGP.cpp create mode 100644 GeneralsMD/Code/GameEngine/Source/GameNetwork/GameSpyGameInfo.cpp diff --git a/GeneralsMD/Code/GameEngine/Include/GameNetwork/GameSpyChat.h b/GeneralsMD/Code/GameEngine/Include/GameNetwork/GameSpyChat.h new file mode 100644 index 0000000000..cf149df174 --- /dev/null +++ b/GeneralsMD/Code/GameEngine/Include/GameNetwork/GameSpyChat.h @@ -0,0 +1,55 @@ +/* +** Command & Conquer Generals Zero Hour(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. // +// // +//////////////////////////////////////////////////////////////////////////////// + +// FILE: GameSpyChat.h ////////////////////////////////////////////////////// +// Generals GameSpy Chat +// Author: Matthew D. Campbell, February 2002 + +#pragma once + +#include "gamespy/peer/peer.h" + +class GameWindow; +class WindowLayout; + +Bool GameSpySendChat(UnicodeString message, Bool isEmote, GameWindow *playerListbox = NULL); +void GameSpyAddText( UnicodeString message, GameSpyColors color = GSCOLOR_DEFAULT ); + +extern GameWindow *progressTextWindow; ///< Text box on the progress screen +extern GameWindow *quickmatchTextWindow; ///< Text box on the quickmatch screen +extern GameWindow *quickmatchTextWindow; ///< Text box on the quickmatch screen +extern GameWindow *listboxLobbyChat; ///< Chat box on the custom lobby screen +extern GameWindow *listboxLobbyPlayers; ///< Player box on the custom lobby screen +extern GameWindow *listboxLobbyGames; ///< Game box on the custom lobby screen +extern GameWindow *listboxLobbyChatChannels; ///< Chat channel box on the custom lobby screen +extern GameWindow *listboxGameSetupChat; ///< Chat box on the custom game setup screen +extern WindowLayout *WOLMapSelectLayout; ///< Map selection overlay + +void RoomMessageCallback(PEER peer, RoomType roomType, + const char * nick, const char * message, + MessageType messageType, void * param); ///< Called when a message arrives in a room. + +void PlayerMessageCallback(PEER peer, const char * nick, + const char * message, MessageType messageType, + void * param); ///< Called when a private message is received from another player. diff --git a/GeneralsMD/Code/GameEngine/Include/GameNetwork/GameSpyGP.h b/GeneralsMD/Code/GameEngine/Include/GameNetwork/GameSpyGP.h new file mode 100644 index 0000000000..6ce6092a55 --- /dev/null +++ b/GeneralsMD/Code/GameEngine/Include/GameNetwork/GameSpyGP.h @@ -0,0 +1,42 @@ +/* +** Command & Conquer Generals Zero Hour(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. // +// // +//////////////////////////////////////////////////////////////////////////////// + +// FILE: GameSpyGP.h ////////////////////////////////////////////////////// +// Generals GameSpy GP (Buddy) +// Author: Matthew D. Campbell, March 2002 + +#pragma once + +#include "gamespy/gp/gp.h" + +void GPRecvBuddyRequestCallback(GPConnection * connection, GPRecvBuddyRequestArg * arg, void * param); +void GPRecvBuddyMessageCallback(GPConnection * pconnection, GPRecvBuddyMessageArg * arg, void * param); +void GPRecvBuddyStatusCallback(GPConnection * connection, GPRecvBuddyStatusArg * arg, void * param); +void GPErrorCallback(GPConnection * pconnection, GPErrorArg * arg, void * param); +void GPConnectCallback(GPConnection * pconnection, GPConnectResponseArg * arg, void * param); +void GameSpyUpdateBuddyOverlay(void); + +extern GPConnection *TheGPConnection; + +Bool IsGameSpyBuddy(GPProfile id); diff --git a/GeneralsMD/Code/GameEngine/Include/GameNetwork/GameSpyGameInfo.h b/GeneralsMD/Code/GameEngine/Include/GameNetwork/GameSpyGameInfo.h new file mode 100644 index 0000000000..36dccb48e1 --- /dev/null +++ b/GeneralsMD/Code/GameEngine/Include/GameNetwork/GameSpyGameInfo.h @@ -0,0 +1,92 @@ +/* +** Command & Conquer Generals Zero Hour(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. // +// // +//////////////////////////////////////////////////////////////////////////////// + +// FILE: GameSpyGameInfo.h ////////////////////////////////////////////////////// +// Generals GameSpy game setup information +// Author: Matthew D. Campbell, February 2002 + +#pragma once + +#error this file is obsolete +#include "gamespy/peer/peer.h" + +#include "GameNetwork/GameInfo.h" + +class Transport; +class NAT; + +class GameSpyGameSlot : public GameSlot +{ +public: + GameSpyGameSlot(); + Int getProfileID( void ) { return m_profileID; } + void setProfileID( Int id ) { m_profileID = id; } + AsciiString getLoginName( void ) { return m_gameSpyLogin; } + void setLoginName( AsciiString name ) { m_gameSpyLogin = name; } + AsciiString getLocale( void ) { return m_gameSpyLocale; } + void setLocale( AsciiString name ) { m_gameSpyLocale = name; } +protected: + Int m_profileID; + AsciiString m_gameSpyLogin; + AsciiString m_gameSpyLocale; +}; + +/** + * GameSpyGameInfo class - maintains information about the GameSpy game and + * the contents of its slot list throughout the game. + */ +class GameSpyGameInfo : public GameInfo +{ +private: + GameSpyGameSlot m_GameSpySlot[MAX_SLOTS]; ///< The GameSpy Games Slot List + SBServer m_server; + Bool m_hasBeenQueried; + Transport *m_transport; + Bool m_isQM; + +public: + GameSpyGameInfo(); + + inline void setServer(SBServer server) { m_server = server; } + inline SBServer getServer( void ) { return m_server; } + + AsciiString generateGameResultsPacket( void ); + + virtual void init(void); + virtual void resetAccepted(void); ///< Reset the accepted flag on all players + + void markGameAsQM( void ) { m_isQM = TRUE; } + virtual void startGame(Int gameID); ///< Mark our game as started and record the game ID. + virtual Int getLocalSlotNum( void ) const; ///< Get the local slot number, or -1 if we're not present + + void gotGOACall( void ); ///< Mark the game info as having been queried +}; + +extern GameSpyGameInfo *TheGameSpyGame; + +void WOLDisplayGameOptions( void ); +void WOLDisplaySlotList( void ); +void GameSpyStartGame( void ); +void GameSpyLaunchGame( void ); +Bool GetLocalChatConnectionAddress(AsciiString serverName, UnsignedShort serverPort, UnsignedInt& localIP); diff --git a/GeneralsMD/Code/GameEngine/Source/GameNetwork/GameSpyChat.cpp b/GeneralsMD/Code/GameEngine/Source/GameNetwork/GameSpyChat.cpp new file mode 100644 index 0000000000..a34441f6a4 --- /dev/null +++ b/GeneralsMD/Code/GameEngine/Source/GameNetwork/GameSpyChat.cpp @@ -0,0 +1,455 @@ +/* +** Command & Conquer Generals Zero Hour(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. // +// // +//////////////////////////////////////////////////////////////////////////////// + +// FILE: GameSpyChat.cpp ////////////////////////////////////////////////////// +// GameSpy chat handlers +// Author: Matthew D. Campbell, February 2002 + +#include "PreRTS.h" // This must go first in EVERY cpp file in the GameEngine + +#include "GameClient/GameText.h" +#include "GameClient/GadgetListBox.h" +#include "GameClient/LanguageFilter.h" +#include "GameNetwork/GameSpy.h" +#include "GameNetwork/GameSpyChat.h" +#include "Common/QuotedPrintable.h" + +typedef set::const_iterator AsciiSetIter; + +/** + * handleSlashCommands looks for slash ccommands and handles them, + * returning true if it found one, false otherwise. + * /i,/ignore list ignored players + * /i,/ignore +name1 -name2 ignore name1, stop ignoring name2 + * /m,/me: shorthand for an action + * /o,/on: find command to look up a user's location + * /f,/find: find command to look up a user's location + * /p,/page: page user(s) + * /r,/reply: reply to last page + * /raw: raw IRC command (only in debug & internal) + * /oper: become an IRC op (only in debug & internal) + * /quit: send the IRC quit command to exit WOL + */ +static Bool handleSlashCommands( UnicodeString message, Bool isAction, GameWindow *playerListbox ) +{ + /* + if (message.getCharAt(0) == L'/') + { + UnicodeString remainder = UnicodeString(message.str() + 1); + UnicodeString token; + + switch (message.getCharAt(1)) + { + case L'i': + case L'I': + remainder.nextToken(&token); + if (token.compareNoCase(L"i") == 0 || token.compareNoCase(L"ignore") == 0) + { + if (remainder.isEmpty()) + { + // List the people we're ignoring + TheWOL->addText(TheGameText->fetch("WOL:BeginIgnoreList")); + set *ignoreList = getIgnoreList(); + if (ignoreList) + { + UnicodeString msg; + UnicodeString uName; + AsciiSetIter iter = ignoreList->begin(); + while (iter != ignoreList->end()) + { + uName.translate(*iter); + msg.format(TheGameText->fetch("WOL:IgnoredUser"), uName.str()); + TheWOL->addText(msg); + iter++; + } + } + TheWOL->addText(TheGameText->fetch("WOL:EndIgnoreList")); + } + + while ( remainder.nextToken(&token) ) + { + AsciiString name; + int doIgnore = 0; + if (token.getCharAt(0) == L'+') + { + // Ignore somebody + token = UnicodeString(token.str() + 1); + name.translate(token); + doIgnore = 1; + } + else if (token.getCharAt(0) == L'-') + { + // Listen to someone again + token = UnicodeString(token.str() + 1); + name.translate(token); + doIgnore = 0; + } + else + { + // Ignore somebody + token = UnicodeString(token.str()); + name.translate(token); + doIgnore = 1; + } + IChat *ichat = TheWOL->getIChat(); + User user; + strncpy((char *)user.name, name.str(), 9); + user.name[9] = 0; + ichat->SetSquelch(&user, doIgnore); + + if (doIgnore) + addIgnore(name); + else + removeIgnore(name); + + UnicodeString msg; + UnicodeString uName; + uName.translate(name); + msg.format(TheGameText->fetch("WOL:IgnoredUser"), uName.str()); + TheWOL->addText(msg); + } + return true; + } + break; + case L'r': + case L'R': + remainder.nextToken(&token); +#if defined(RTS_DEBUG) + if (token.compareNoCase(L"raw") == 0) + { + // Send raw IRC commands (Ascii only) + AsciiString str; + str.translate(remainder); + str.concat('\n'); + IChat *ichat = TheWOL->getIChat(); + ichat->RequestRawMessage(str.str()); + TheWOL->addText(remainder); + return true; // show it anyway + } +#endif + break; +#if defined(RTS_DEBUG) + case L'k': + case L'K': + remainder.nextToken(&token); + if (token.compareNoCase(L"kick") == 0) + { + + while ( remainder.nextToken(&token) ) + { + AsciiString name; + name.translate(token); + IChat *ichat = TheWOL->getIChat(); + User user; + strncpy((char *)user.name, name.str(), 9); + user.name[9] = 0; + ichat->RequestUserKick(&user); + } + return true; + } + break; +#endif + case L'o': + case L'O': + remainder.nextToken(&token); + if (token.compareNoCase(L"on") == 0 || token.compareNoCase(L"o") == 0) + { + remainder.nextToken(&token); + AsciiString userName; + userName.translate(token); + User user; + strncpy((char *)user.name, userName.str(), 10); + user.name[9] = 0; + if (user.name[0] == 0) + { + // didn't enter a name + TheWOL->addText(message); + } + else + { + // Send find command + IChat *ichat = TheWOL->getIChat(); + ichat->RequestGlobalFind(&user); + } + return true; // show it anyway + } +#if defined(RTS_DEBUG) + else if (token.compareNoCase(L"oper") == 0) + { + // Send raw IRC oper command + AsciiString str; + str.translate(message); + str.concat('\n'); + IChat *ichat = TheWOL->getIChat(); + ichat->RequestRawMessage(str.str()); + TheWOL->addText(message); + return true; // show it anyway + } +#endif + break; + case L'p': + case L'P': + remainder.nextToken(&token); + if (token.compareNoCase(L"page") == 0 || token.compareNoCase(L"p") == 0) + { + remainder.nextToken(&token); + AsciiString userName; + userName.translate(token); + User user; + strncpy((char *)user.name, userName.str(), 10); + user.name[9] = 0; + remainder.trim(); + if (user.name[0] == 0 || remainder.isEmpty()) + { + // didn't enter a name or message + TheWOL->addText(message); + } + else + { + // Send page command + IChat *ichat = TheWOL->getIChat(); + ichat->RequestGlobalUnicodePage(&user, remainder.str()); + } + return true; // show it anyway + } + break; + case L'q': + case L'Q': + remainder.nextToken(&token); + if (token.compareNoCase(L"quit") == 0) + { + TheWOL->setState(WOLAPI_LOGIN); + TheWOL->addCommand(WOLCOMMAND_LOGOUT); + //TheWOL->setScreen(WOLAPI_MENU_WELCOME); + return true; // show it anyway + } + break; +#if defined(RTS_DEBUG) + case L'c': + case L'C': + remainder.nextToken(&token); + if (token.compareNoCase(L"colortest") == 0) + { + addColorText(token, 0xDD, 0xE2, 0x0D, 0xff); + addColorText(token, 0xFF, 0x19, 0x19, 0xff); + addColorText(token, 0x2A, 0x74, 0xE2, 0xff); + addColorText(token, 0x3E, 0xD1, 0x2E, 0xff); + addColorText(token, 0xFF, 0xA0, 0x19, 0xff); + addColorText(token, 0x32, 0xD7, 0xE6, 0xff); + addColorText(token, 0x95, 0x28, 0xBD, 0xff); + addColorText(token, 0xFF, 0x9A, 0xEB, 0xff); + return true; // show it anyway + } + break; +#endif // RTS_DEBUG + } + } + */ + return false; +} + +static handleUnicodeMessage( const char *nick, UnicodeString msg, Bool isPublic, Bool isAction ); + +Bool GameSpySendChat( UnicodeString message, Bool isAction, GameWindow *playerListbox ) +{ + RoomType roomType = StagingRoom; + if (TheGameSpyChat->getCurrentGroupRoomID()) + roomType = GroupRoom; + + message.trim(); + // Echo the user's input to the chat window + if (!message.isEmpty()) + { + // Check for slash commands + if (handleSlashCommands(message, isAction, playerListbox)) + { + return false; // already handled + } + + if (!playerListbox) + { + // Public message + if (isAction) + { + peerMessageRoom(TheGameSpyChat->getPeer(), roomType, UnicodeStringToQuotedPrintable(message).str(), ActionMessage); + //if (roomType == StagingRoom) + //handleUnicodeMessage(TheGameSpyChat->getloginName().str(), message, true, true); + } + else + { + peerMessageRoom(TheGameSpyChat->getPeer(), roomType, UnicodeStringToQuotedPrintable(message).str(), NormalMessage); + //if (roomType == StagingRoom) + //handleUnicodeMessage(TheGameSpyChat->getloginName().str(), message, true, false); + } + return false; + } + + // Get the selections (is this a private message?) + Int maxSel = GadgetListBoxGetListLength(playerListbox); + Int *selections; + GadgetListBoxGetSelected(playerListbox, (Int *)&selections); + + if (selections[0] == -1) + { + // Public message + if (isAction) + { + peerMessageRoom(TheGameSpyChat->getPeer(), roomType, UnicodeStringToQuotedPrintable(message).str(), ActionMessage); + //if (roomType == StagingRoom) + //handleUnicodeMessage(TheGameSpyChat->getloginName().str(), message, true, true); + } + else + { + peerMessageRoom(TheGameSpyChat->getPeer(), roomType, UnicodeStringToQuotedPrintable(message).str(), NormalMessage); + //if (roomType == StagingRoom) + //handleUnicodeMessage(TheGameSpyChat->getloginName().str(), message, true, false); + } + return false; + } + else + { + // Private message + + // Construct a list + AsciiString names = AsciiString::TheEmptyString; + AsciiString tmp = AsciiString::TheEmptyString; + AsciiString aStr; // AsciiString buf for translating Unicode entries + names.format("%s", TheGameSpyChat->getLoginName().str()); + for (int i=0; igetLoginName())) + { + tmp.format(",%s", aStr.str()); + names.concat(tmp); + } + } + else + { + break; + } + } + + if (!names.isEmpty()) + { + if (isAction) + { + peerMessagePlayer(TheGameSpyChat->getPeer(), names.str(), UnicodeStringToQuotedPrintable(message).str(), ActionMessage); + } + else + { + peerMessagePlayer(TheGameSpyChat->getPeer(), names.str(), UnicodeStringToQuotedPrintable(message).str(), NormalMessage); + } + } + + return true; + } + } + return false; +} + +void RoomMessageCallback(PEER peer, RoomType roomType, + const char * nick, const char * message, + MessageType messageType, void * param) +{ + DEBUG_LOG(("RoomMessageCallback")); + handleUnicodeMessage(nick, QuotedPrintableToUnicodeString(message), true, (messageType == ActionMessage)); +} + +void PlayerMessageCallback(PEER peer, + const char * nick, const char * message, + MessageType messageType, void * param) +{ + DEBUG_LOG(("PlayerMessageCallback")); + handleUnicodeMessage(nick, QuotedPrintableToUnicodeString(message), false, (messageType == ActionMessage)); +} + +static handleUnicodeMessage( const char *nick, UnicodeString msg, Bool isPublic, Bool isAction ) +{ + GameSpyColors style; + + Bool isOwner = false; + Int flags = 0; + if (TheGameSpyChat->getCurrentGroupRoomID()) + peerGetPlayerFlags(TheGameSpyChat->getPeer(), nick, GroupRoom, &flags); + else + peerGetPlayerFlags(TheGameSpyChat->getPeer(), nick, StagingRoom, &flags); + isOwner = flags & PEER_FLAG_OP; + + if (isPublic && isAction) + { + style = (isOwner)?GSCOLOR_CHAT_OWNER_EMOTE:GSCOLOR_CHAT_EMOTE; + } + else if (isPublic) + { + style = (isOwner)?GSCOLOR_CHAT_OWNER:GSCOLOR_CHAT_NORMAL; + } + else if (isAction) + { + style = (isOwner)?GSCOLOR_CHAT_PRIVATE_OWNER_EMOTE:GSCOLOR_CHAT_PRIVATE_EMOTE; + } + else + { + style = (isOwner)?GSCOLOR_CHAT_PRIVATE_OWNER:GSCOLOR_CHAT_PRIVATE; + } + + UnicodeString name; + name.translate(nick); + + // filters language +// if( TheGlobalData->m_languageFilterPref ) +// { + TheLanguageFilter->filterLine(msg); +// } + + UnicodeString fullMsg; + if (isAction) + { + fullMsg.format( L"%ls %ls", name.str(), msg.str() ); + } + else + { + fullMsg.format( L"[%ls] %ls", name.str(), msg.str() ); + } + GameSpyAddText(fullMsg, style); +} + +void GameSpyAddText( UnicodeString message, GameSpyColors color ) +{ + GameWindow *textWindow = NULL; + + if (!textWindow) + textWindow = listboxLobbyChat; + if (!textWindow) + textWindow = listboxGameSetupChat; + + if (!textWindow) + return; + + GadgetListBoxAddEntryText(textWindow, message, GameSpyColor[color], -1, -1); + +} + diff --git a/GeneralsMD/Code/GameEngine/Source/GameNetwork/GameSpyGP.cpp b/GeneralsMD/Code/GameEngine/Source/GameNetwork/GameSpyGP.cpp new file mode 100644 index 0000000000..602d1f2d08 --- /dev/null +++ b/GeneralsMD/Code/GameEngine/Source/GameNetwork/GameSpyGP.cpp @@ -0,0 +1,162 @@ +/* +** Command & Conquer Generals Zero Hour(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. // +// // +//////////////////////////////////////////////////////////////////////////////// + +// FILE: GameSpyGP.cpp ////////////////////////////////////////////////////// +// GameSpy GP callbacks, utils, etc +// Author: Matthew D. Campbell, February 2002 + +#include "PreRTS.h" // This must go first in EVERY cpp file in the GameEngine + +#include "GameClient/GameText.h" +#include "GameNetwork/GameSpy.h" +#include "GameNetwork/GameSpyGP.h" +#include "GameNetwork/GameSpyOverlay.h" + +GPConnection TheGPConnectionObj; +GPConnection *TheGPConnection = &TheGPConnectionObj; +GPProfile GameSpyLocalProfile = 0; +char GameSpyProfilePassword[64]; + +void GPRecvBuddyMessageCallback(GPConnection * pconnection, GPRecvBuddyMessageArg * arg, void * param) +{ + DEBUG_LOG(("GPRecvBuddyMessageCallback: message from %d is %s", arg->profile, arg->message)); + + //gpGetInfo(pconn, arg->profile, GP_DONT_CHECK_CACHE, GP_BLOCKING, (GPCallback)Whois, NULL); + //printf("MESSAGE (%d): %s: %s\n", msgCount,whois, arg->message); +} + +static void buddyTryReconnect( void ) +{ + TheGameSpyChat->reconnectProfile(); +} + +void GPErrorCallback(GPConnection * pconnection, GPErrorArg * arg, void * param) +{ + DEBUG_LOG(("GPErrorCallback")); + + AsciiString errorCodeString; + AsciiString resultString; + + #define RESULT(x) case x: resultString = #x; break; + switch(arg->result) + { + RESULT(GP_NO_ERROR) + RESULT(GP_MEMORY_ERROR) + RESULT(GP_PARAMETER_ERROR) + RESULT(GP_NETWORK_ERROR) + RESULT(GP_SERVER_ERROR) + default: + resultString = "Unknown result!"; + } + #undef RESULT + + #define ERRORCODE(x) case x: errorCodeString = #x; break; + switch(arg->errorCode) + { + ERRORCODE(GP_GENERAL) + ERRORCODE(GP_PARSE) + ERRORCODE(GP_NOT_LOGGED_IN) + ERRORCODE(GP_BAD_SESSKEY) + ERRORCODE(GP_DATABASE) + ERRORCODE(GP_NETWORK) + ERRORCODE(GP_FORCED_DISCONNECT) + ERRORCODE(GP_CONNECTION_CLOSED) + ERRORCODE(GP_LOGIN) + ERRORCODE(GP_LOGIN_TIMEOUT) + ERRORCODE(GP_LOGIN_BAD_NICK) + ERRORCODE(GP_LOGIN_BAD_EMAIL) + ERRORCODE(GP_LOGIN_BAD_PASSWORD) + ERRORCODE(GP_LOGIN_BAD_PROFILE) + ERRORCODE(GP_LOGIN_PROFILE_DELETED) + ERRORCODE(GP_LOGIN_CONNECTION_FAILED) + ERRORCODE(GP_LOGIN_SERVER_AUTH_FAILED) + ERRORCODE(GP_NEWUSER) + ERRORCODE(GP_NEWUSER_BAD_NICK) + ERRORCODE(GP_NEWUSER_BAD_PASSWORD) + ERRORCODE(GP_UPDATEUI) + ERRORCODE(GP_UPDATEUI_BAD_EMAIL) + ERRORCODE(GP_NEWPROFILE) + ERRORCODE(GP_NEWPROFILE_BAD_NICK) + ERRORCODE(GP_NEWPROFILE_BAD_OLD_NICK) + ERRORCODE(GP_UPDATEPRO) + ERRORCODE(GP_UPDATEPRO_BAD_NICK) + ERRORCODE(GP_ADDBUDDY) + ERRORCODE(GP_ADDBUDDY_BAD_FROM) + ERRORCODE(GP_ADDBUDDY_BAD_NEW) + ERRORCODE(GP_ADDBUDDY_ALREADY_BUDDY) + ERRORCODE(GP_AUTHADD) + ERRORCODE(GP_AUTHADD_BAD_FROM) + ERRORCODE(GP_AUTHADD_BAD_SIG) + ERRORCODE(GP_STATUS) + ERRORCODE(GP_BM) + ERRORCODE(GP_BM_NOT_BUDDY) + ERRORCODE(GP_GETPROFILE) + ERRORCODE(GP_GETPROFILE_BAD_PROFILE) + ERRORCODE(GP_DELBUDDY) + ERRORCODE(GP_DELBUDDY_NOT_BUDDY) + ERRORCODE(GP_DELPROFILE) + ERRORCODE(GP_DELPROFILE_LAST_PROFILE) + ERRORCODE(GP_SEARCH) + ERRORCODE(GP_SEARCH_CONNECTION_FAILED) + default: + errorCodeString = "Unknown error code!"; + } + #undef ERRORCODE + + if(arg->fatal) + { + DEBUG_LOG(( "-----------")); + DEBUG_LOG(( "GP FATAL ERROR")); + DEBUG_LOG(( "-----------")); + + // if we're still connected to the chat server, tell the user. He can always hit the buddy + // button to try reconnecting. Oh yes, also hide the buddy popup. + GameSpyCloseOverlay(GSOVERLAY_BUDDY); + if (TheGameSpyChat->isConnected()) + { + GSMessageBoxYesNo(TheGameText->fetch("GUI:GPErrorTitle"), TheGameText->fetch("GUI:GPDisconnected"), buddyTryReconnect, NULL); + } + } + else + { + DEBUG_LOG(( "-----")); + DEBUG_LOG(( "GP ERROR")); + DEBUG_LOG(( "-----")); + } + DEBUG_LOG(( "RESULT: %s (%d)", resultString.str(), arg->result)); + DEBUG_LOG(( "ERROR CODE: %s (0x%X)", errorCodeString.str(), arg->errorCode)); + DEBUG_LOG(( "ERROR STRING: %s", arg->errorString)); +} + +void GPRecvBuddyStatusCallback(GPConnection * connection, GPRecvBuddyStatusArg * arg, void * param) +{ + DEBUG_LOG(("GPRecvBuddyStatusCallback: info on %d is in %d", arg->profile, arg->index)); + + //GameSpyUpdateBuddyOverlay(); +} + +void GPRecvBuddyRequestCallback(GPConnection * connection, GPRecvBuddyRequestArg * arg, void * param) +{ + DEBUG_LOG(("GPRecvBuddyRequestCallback: %d wants to be our buddy because '%s'", arg->profile, arg->reason)); +} diff --git a/GeneralsMD/Code/GameEngine/Source/GameNetwork/GameSpyGameInfo.cpp b/GeneralsMD/Code/GameEngine/Source/GameNetwork/GameSpyGameInfo.cpp new file mode 100644 index 0000000000..5cfe1211d0 --- /dev/null +++ b/GeneralsMD/Code/GameEngine/Source/GameNetwork/GameSpyGameInfo.cpp @@ -0,0 +1,751 @@ +/* +** Command & Conquer Generals Zero Hour(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. // +// // +//////////////////////////////////////////////////////////////////////////////// + +// FILE: GameSpyGameInfo.cpp ////////////////////////////////////////////////////// +// GameSpy game setup state info +// Author: Matthew D. Campbell, December 2001 + +#include "PreRTS.h" // This must go first in EVERY cpp file in the GameEngine + +#include "Common/GameEngine.h" +#include "Common/Player.h" +#include "Common/PlayerList.h" +#include "Common/RandomValue.h" +#include "Common/ScoreKeeper.h" +#include "GameClient/Shell.h" +#include "GameClient/GameText.h" +#include "GameNetwork/GameSpy/PeerDefs.h" +#include "GameNetwork/GameSpyGameInfo.h" +#include "GameNetwork/NetworkInterface.h" +#include "GameNetwork/networkutil.h" +#include "GameNetwork/NetworkDefs.h" +#include "GameNetwork/NAT.h" +#include "GameLogic/GameLogic.h" +#include "GameLogic/VictoryConditions.h" + +// Singleton ------------------------------------------ + +GameSpyGameInfo *TheGameSpyGame = NULL; + +// Helper Functions ---------------------------------------- + +GameSpyGameSlot::GameSpyGameSlot() +{ + GameSlot(); + m_gameSpyLogin.clear(); + m_gameSpyLocale.clear(); + m_profileID = 0; +} + +// Helper Functions ---------------------------------------- +/* +** Function definitions for the MIB-II entry points. +*/ + +BOOL (__stdcall *SnmpExtensionInitPtr)(IN DWORD dwUpTimeReference, OUT HANDLE *phSubagentTrapEvent, OUT AsnObjectIdentifier *pFirstSupportedRegion); +BOOL (__stdcall *SnmpExtensionQueryPtr)(IN BYTE bPduType, IN OUT RFC1157VarBindList *pVarBindList, OUT AsnInteger32 *pErrorStatus, OUT AsnInteger32 *pErrorIndex); +LPVOID (__stdcall *SnmpUtilMemAllocPtr)(IN DWORD bytes); +VOID (__stdcall *SnmpUtilMemFreePtr)(IN LPVOID pMem); + +typedef struct tConnInfoStruct { + unsigned int State; + unsigned long LocalIP; + unsigned short LocalPort; + unsigned long RemoteIP; + unsigned short RemotePort; +} ConnInfoStruct; + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0])) +#endif + +/*********************************************************************************************** + * Get_Local_Chat_Connection_Address -- Which address are we using to talk to the chat server? * + * * + * * + * * + * INPUT: Ptr to address to return local address * * + * * + * OUTPUT: True if success * + * * + * WARNINGS: None * + * * + * HISTORY: * + * 10/27/00 3:24PM ST : Created * + *=============================================================================================*/ +Bool GetLocalChatConnectionAddress(AsciiString serverName, UnsignedShort serverPort, UnsignedInt& localIP) +{ + //return false; + /* + ** Local defines. + */ + enum { + CLOSED = 1, + LISTENING, + SYN_SENT, + SEN_RECEIVED, + ESTABLISHED, + FIN_WAIT, + FIN_WAIT2, + CLOSE_WAIT, + LAST_ACK, + CLOSING, + TIME_WAIT, + DELETE_TCB + }; + + enum { + tcpConnState = 1, + tcpConnLocalAddress, + tcpConnLocalPort, + tcpConnRemAddress, + tcpConnRemPort + }; + + + /* + ** Locals. + */ + unsigned char serverAddress[4]; + unsigned char remoteAddress[4]; + HANDLE trap_handle; + AsnObjectIdentifier first_supported_region; + std::vector connectionVector; + int last_field; + int index; + AsnInteger error_status; + AsnInteger error_index; + int conn_entry_type_index; + int conn_entry_type; + Bool found; + + /* + ** Statics. + */ + static char _conn_state[][32] = { + "?", + "CLOSED", + "LISTENING", + "SYN_SENT", + "SEN_RECEIVED", + "ESTABLISHED", + "FIN_WAIT", + "FIN_WAIT2", + "CLOSE_WAIT", + "LAST_ACK", + "CLOSING", + "TIME_WAIT", + "DELETE_TCB" + }; + + DEBUG_LOG(("Finding local address used to talk to the chat server")); + DEBUG_LOG(("Current chat server name is %s", serverName.str())); + DEBUG_LOG(("Chat server port is %d", serverPort)); + + /* + ** Get the address of the chat server. + */ + DEBUG_LOG( ("About to call gethostbyname")); + struct hostent *host_info = gethostbyname(serverName.str()); + + if (!host_info) { + DEBUG_LOG( ("gethostbyname failed! Error code %d", WSAGetLastError())); + return(false); + } + + memcpy(serverAddress, &host_info->h_addr_list[0][0], 4); + unsigned long temp = *((unsigned long*)(&serverAddress[0])); + temp = ntohl(temp); + *((unsigned long*)(&serverAddress[0])) = temp; + + DEBUG_LOG(("Host address is %d.%d.%d.%d", serverAddress[3], serverAddress[2], serverAddress[1], serverAddress[0])); + + /* + ** Load the MIB-II SNMP DLL. + */ + DEBUG_LOG(("About to load INETMIB1.DLL")); + + HINSTANCE mib_ii_dll = LoadLibrary("inetmib1.dll"); + if (mib_ii_dll == NULL) { + DEBUG_LOG(("Failed to load INETMIB1.DLL")); + return(false); + } + + DEBUG_LOG(("About to load SNMPAPI.DLL")); + + HINSTANCE snmpapi_dll = LoadLibrary("snmpapi.dll"); + if (snmpapi_dll == NULL) { + DEBUG_LOG(("Failed to load SNMPAPI.DLL")); + FreeLibrary(mib_ii_dll); + return(false); + } + + /* + ** Get the function pointers into the .dll + */ + SnmpExtensionInitPtr = (int (__stdcall *)(unsigned long,void ** ,AsnObjectIdentifier *)) GetProcAddress(mib_ii_dll, "SnmpExtensionInit"); + SnmpExtensionQueryPtr = (int (__stdcall *)(unsigned char,SnmpVarBindList *,long *,long *)) GetProcAddress(mib_ii_dll, "SnmpExtensionQuery"); + SnmpUtilMemAllocPtr = (void *(__stdcall *)(unsigned long)) GetProcAddress(snmpapi_dll, "SnmpUtilMemAlloc"); + SnmpUtilMemFreePtr = (void (__stdcall *)(void *)) GetProcAddress(snmpapi_dll, "SnmpUtilMemFree"); + if (SnmpExtensionInitPtr == NULL || SnmpExtensionQueryPtr == NULL || SnmpUtilMemAllocPtr == NULL || SnmpUtilMemFreePtr == NULL) { + DEBUG_LOG(("Failed to get proc addresses for linked functions")); + FreeLibrary(snmpapi_dll); + FreeLibrary(mib_ii_dll); + return(false); + } + + + RFC1157VarBindList *bind_list_ptr = (RFC1157VarBindList *) SnmpUtilMemAllocPtr(sizeof(RFC1157VarBindList)); + RFC1157VarBind *bind_ptr = (RFC1157VarBind *) SnmpUtilMemAllocPtr(sizeof(RFC1157VarBind)); + + /* + ** OK, here we go. Try to initialise the .dll + */ + DEBUG_LOG(("About to init INETMIB1.DLL")); + int ok = SnmpExtensionInitPtr(GetCurrentTime(), &trap_handle, &first_supported_region); + + if (!ok) { + /* + ** Aw crap. + */ + DEBUG_LOG(("Failed to init the .dll")); + SnmpUtilMemFreePtr(bind_list_ptr); + SnmpUtilMemFreePtr(bind_ptr); + FreeLibrary(snmpapi_dll); + FreeLibrary(mib_ii_dll); + return(false); + } + + /* + ** Name of mib_ii object we want to query. See RFC 1213. + ** + ** iso.org.dod.internet.mgmt.mib-2.tcp.tcpConnTable.TcpConnEntry.tcpConnState + ** 1 3 6 1 2 1 6 13 1 1 + */ + unsigned int mib_ii_name[] = {1,3,6,1,2,1,6,13,1,1}; + unsigned int *mib_ii_name_ptr = (unsigned int *) SnmpUtilMemAllocPtr(sizeof(mib_ii_name)); + memcpy(mib_ii_name_ptr, mib_ii_name, sizeof(mib_ii_name)); + + /* + ** Get the index of the conn entry data. + */ + conn_entry_type_index = ARRAY_SIZE(mib_ii_name) - 1; + + /* + ** Set up the bind list. + */ + bind_ptr->name.idLength = ARRAY_SIZE(mib_ii_name); + bind_ptr->name.ids = mib_ii_name; + bind_list_ptr->list = bind_ptr; + bind_list_ptr->len = 1; + + + /* + ** We start with the tcpConnLocalAddress field. + */ + last_field = 1; + + /* + ** First connection. + */ + index = 0; + + /* + ** Suck out that tcp connection info.... + */ + while (true) { + + if (!SnmpExtensionQueryPtr(SNMP_PDU_GETNEXT, bind_list_ptr, &error_status, &error_index)) { + //if (!SnmpExtensionQueryPtr(ASN_RFC1157_GETNEXTREQUEST, bind_list_ptr, &error_status, &error_index)) { + DEBUG_LOG(("SnmpExtensionQuery returned false")); + SnmpUtilMemFreePtr(bind_list_ptr); + SnmpUtilMemFreePtr(bind_ptr); + FreeLibrary(snmpapi_dll); + FreeLibrary(mib_ii_dll); + return(false); + } + + /* + ** If this is something new we aren't looking for then we are done. + */ + if (bind_ptr->name.idLength < ARRAY_SIZE(mib_ii_name)) { + break; + } + + /* + ** Get the type of info we are looking at. See RFC1213. + ** + ** 1 = tcpConnState + ** 2 = tcpConnLocalAddress + ** 3 = tcpConnLocalPort + ** 4 = tcpConnRemAddress + ** 5 = tcpConnRemPort + ** + ** tcpConnState is one of the following... + ** + ** 1 closed + ** 2 listen + ** 3 synSent + ** 4 synReceived + ** 5 established + ** 6 finWait1 + ** 7 finWait2 + ** 8 closeWait + ** 9 lastAck + ** 10 closing + ** 11 timeWait + ** 12 deleteTCB + */ + conn_entry_type = bind_ptr->name.ids[conn_entry_type_index]; + + if (last_field != conn_entry_type) { + index = 0; + last_field = conn_entry_type; + } + + switch (conn_entry_type) { + + /* + ** 1. First field in the entry. Need to create a new connection info struct + ** here to store this connection in. + */ + case tcpConnState: + { + ConnInfoStruct new_conn; + new_conn.State = bind_ptr->value.asnValue.number; + connectionVector.push_back(new_conn); + break; + } + + /* + ** 2. Local address field. + */ + case tcpConnLocalAddress: + DEBUG_ASSERTCRASH(index < connectionVector.size(), ("Bad connection index")); + connectionVector[index].LocalIP = *((unsigned long*)bind_ptr->value.asnValue.address.stream); + index++; + break; + + /* + ** 3. Local port field. + */ + case tcpConnLocalPort: + DEBUG_ASSERTCRASH(index < connectionVector.size(), ("Bad connection index")); + connectionVector[index].LocalPort = bind_ptr->value.asnValue.number; + //connectionVector[index]->LocalPort = ntohs(connectionVector[index]->LocalPort); + index++; + break; + + /* + ** 4. Remote address field. + */ + case tcpConnRemAddress: + DEBUG_ASSERTCRASH(index < connectionVector.size(), ("Bad connection index")); + connectionVector[index].RemoteIP = *((unsigned long*)bind_ptr->value.asnValue.address.stream); + index++; + break; + + /* + ** 5. Remote port field. + */ + case tcpConnRemPort: + DEBUG_ASSERTCRASH(index < connectionVector.size(), ("Bad connection index")); + connectionVector[index].RemotePort = bind_ptr->value.asnValue.number; + //connectionVector[index]->RemotePort = ntohs(connectionVector[index]->RemotePort); + index++; + break; + } + } + + SnmpUtilMemFreePtr(bind_list_ptr); + SnmpUtilMemFreePtr(bind_ptr); + SnmpUtilMemFreePtr(mib_ii_name_ptr); + + DEBUG_LOG(("Got %d connections in list, parsing...", connectionVector.size())); + + /* + ** Right, we got the lot. Lets see if any of them have the same address as the chat + ** server we think we are talking to. + */ + found = false; + for (Int i=0; igetSlot(i); + if (slot && slot->isOccupied()) + numUsers++; + } + + if (numUsers < 2) + { + if (TheGameSpyGame->amIHost()) + { + UnicodeString text; + text.format(TheGameText->fetch("LAN:NeedMorePlayers"),numUsers); + TheGameSpyInfo->addText(text, GSCOLOR_DEFAULT, NULL); + } + return; + } + + TheGameSpyGame->startGame(0); + } +} + +void GameSpyLaunchGame( void ) +{ + if (TheGameSpyGame) + { + + // Set up the game network + AsciiString user; + AsciiString userList; + DEBUG_ASSERTCRASH(TheNetwork == NULL, ("For some reason TheNetwork isn't NULL at the start of this game. Better look into that.")); + + if (TheNetwork != NULL) { + delete TheNetwork; + TheNetwork = NULL; + } + + // Time to initialize TheNetwork for this game. + TheNetwork = NetworkInterface::createNetwork(); + TheNetwork->init(); + /* + if (!TheGameSpyGame->amIHost()) + TheNetwork->setLocalAddress((207<<24) | (138<<16) | (47<<8) | 15, 8088); + else + */ + TheNetwork->setLocalAddress(TheGameSpyGame->getLocalIP(), TheNAT->getSlotPort(TheGameSpyGame->getLocalSlotNum())); + TheNetwork->attachTransport(TheNAT->getTransport()); + + user = TheGameSpyInfo->getLocalName(); + for (Int i=0; igetSlot(i); + if (!slot) + { + DEBUG_CRASH(("No GameSlot[%d]!", i)); + delete TheNetwork; + TheNetwork = NULL; + return; + } + +// UnsignedInt ip = htonl(slot->getIP()); + UnsignedInt ip = slot->getIP(); + AsciiString tmpUserName; + tmpUserName.translate(slot->getName()); + if (ip) + { + /* + if (i == 1) + { + user.format(",%s@207.138.47.15:8088", tmpUserName.str()); + } + else + */ + { + user.format(",%s@%d.%d.%d.%d:%d", tmpUserName.str(), + PRINTF_IP_AS_4_INTS(ip), + TheNAT->getSlotPort(i) + ); + } + userList.concat(user); + } + } + userList.trim(); + + TheNetwork->parseUserList(TheGameSpyGame); + + // shutdown the top, but do not pop it off the stack +// TheShell->hideShell(); + // setup the Global Data with the Map and Seed + TheGlobalData->m_pendingFile = TheGameSpyGame->getMap(); + + if (TheGameLogic->isInGame()) { + TheGameLogic->clearGameData(); + } + // send a message to the logic for a new game + GameMessage *msg = TheMessageStream->appendMessage( GameMessage::MSG_NEW_GAME ); + msg->appendIntegerArgument(GAME_INTERNET); + + TheGlobalData->m_useFpsLimit = false; + + // Set the random seed + InitGameLogicRandom( TheGameSpyGame->getSeed() ); + DEBUG_LOG(("InitGameLogicRandom( %d )", TheGameSpyGame->getSeed())); + + if (TheNAT != NULL) { + delete TheNAT; + TheNAT = NULL; + } + } +} + +void GameSpyGameInfo::init( void ) +{ + GameInfo::init(); + + m_hasBeenQueried = false; +} + +void GameSpyGameInfo::resetAccepted( void ) +{ + GameInfo::resetAccepted(); + + if (m_hasBeenQueried && amIHost()) + { + // ANCIENTMUNKEE peerStateChanged(TheGameSpyChat->getPeer()); + m_hasBeenQueried = false; + DEBUG_LOG(("resetAccepted() called peerStateChange()")); + } +} + +Int GameSpyGameInfo::getLocalSlotNum( void ) const +{ + DEBUG_ASSERTCRASH(m_inGame, ("Looking for local game slot while not in game")); + if (!m_inGame) + return -1; + + AsciiString localName = TheGameSpyInfo->getLocalName(); + + for (Int i=0; iisPlayer(localName)) + return i; + } + return -1; +} + +void GameSpyGameInfo::gotGOACall( void ) +{ + DEBUG_LOG(("gotGOACall()")); + m_hasBeenQueried = true; +} + +void GameSpyGameInfo::startGame(Int gameID) +{ + DEBUG_LOG(("GameSpyGameInfo::startGame - game id = %d", gameID)); + DEBUG_ASSERTCRASH(m_transport == NULL, ("m_transport is not NULL when it should be")); + DEBUG_ASSERTCRASH(TheNAT == NULL, ("TheNAT is not NULL when it should be")); + + // fill in GS-specific info + for (Int i=0; igetPlayerInfoMap(); + PlayerInfoMap::iterator it = pInfoMap->find(gsName); + if (it != pInfoMap->end()) + { + m_GameSpySlot[i].setProfileID(it->second.m_profileID); + m_GameSpySlot[i].setLocale(it->second.m_locale); + } + else + { + DEBUG_CRASH(("No player info for %s", gsName.str())); + } + } + } + + if (TheNAT != NULL) { + delete TheNAT; + TheNAT = NULL; + } + TheNAT = NEW NAT(); + TheNAT->attachSlotList(m_slot, getLocalSlotNum(), m_localIP); + TheNAT->establishConnectionPaths(); +} + +AsciiString GameSpyGameInfo::generateGameResultsPacket( void ) +{ + Int i; + Int endFrame = TheVictoryConditions->getEndFrame(); + Int localSlotNum = getLocalSlotNum(); + //GameSlot *localSlot = getSlot(localSlotNum); + Bool sawGameEnd = (endFrame > 0);// && localSlot->lastFrameInGame() <= endFrame); + Int winningTeam = -1; + Int numPlayers = 0; + Int numTeamsAtGameEnd = 0; + Int lastTeamAtGameEnd = -1; + for (i=0; ifindPlayerWithNameKey(NAMEKEY(playerName)); + if (p) + { + ++numPlayers; + if (TheVictoryConditions->hasAchievedVictory(p)) + { + winningTeam = getSlot(i)->getTeamNumber(); + } + + // check if he lasted + GameSlot *slot = getSlot(i); + if (!slot->disconnected()) + { + if (slot->getTeamNumber() != lastTeamAtGameEnd || numTeamsAtGameEnd == 0) + { + lastTeamAtGameEnd = slot->getTeamNumber(); + ++numTeamsAtGameEnd; + } + } + } + } + + AsciiString results; + results.format("seed=%d,slotNum=%d,sawDesync=%d,sawGameEnd=%d,winningTeam=%d,disconEnd=%d,duration=%d,numPlayers=%d,isQM=%d", + getSeed(), localSlotNum, TheNetwork->sawCRCMismatch(), sawGameEnd, winningTeam, (numTeamsAtGameEnd != 0), + endFrame, numPlayers, m_isQM); + + Int playerID = 0; + for (i=0; ifindPlayerWithNameKey(NAMEKEY(playerName)); + if (p) + { + GameSpyGameSlot *slot = &(m_GameSpySlot[i]); + ScoreKeeper *keeper = p->getScoreKeeper(); + AsciiString playerName = slot->getLoginName(); + Int gsPlayerID = slot->getProfileID(); + AsciiString locale = slot->getLocale(); + Int fps = TheNetwork->getAverageFPS(); + Int unitsKilled = keeper->getTotalUnitsDestroyed(); + Int unitsLost = keeper->getTotalUnitsLost(); + Int unitsBuilt = keeper->getTotalUnitsBuilt(); + Int buildingsKilled = keeper->getTotalBuildingsDestroyed(); + Int buildingsLost = keeper->getTotalBuildingsLost(); + Int buildingsBuilt = keeper->getTotalBuildingsBuilt(); + Int earnings = keeper->getTotalMoneyEarned(); + Int techCaptured = keeper->getTotalTechBuildingsCaptured(); + Bool disconnected = slot->disconnected(); + + AsciiString playerStr; + playerStr.format(",player%d=%s,playerID%d=%d,locale%d=%s", + playerID, playerName.str(), playerID, gsPlayerID, playerID, locale.str()); + results.concat(playerStr); + playerStr.format(",unitsKilled%d=%d,unitsLost%d=%d,unitsBuilt%d=%d", + playerID, unitsKilled, playerID, unitsLost, playerID, unitsBuilt); + results.concat(playerStr); + playerStr.format(",buildingsKilled%d=%d,buildingsLost%d=%d,buildingsBuilt%d=%d", + playerID, buildingsKilled, playerID, buildingsLost, playerID, buildingsBuilt); + results.concat(playerStr); + playerStr.format(",fps%d=%d,cash%d=%d,capturedTech%d=%d,discon%d=%d", + playerID, fps, playerID, earnings, playerID, techCaptured, playerID, disconnected); + results.concat(playerStr); + + ++playerID; + } + } + + // Add a trailing size value (so the server can ensure it got the entire packet) + int resultsLen = results.getLength()+10; + AsciiString tail; + tail.format("%10.10d", resultsLen); + results.concat(tail); + + return results; +} +