|
| 1 | +/* |
| 2 | +** Command & Conquer Generals(tm) |
| 3 | +** Copyright 2025 Electronic Arts Inc. |
| 4 | +** |
| 5 | +** This program is free software: you can redistribute it and/or modify |
| 6 | +** it under the terms of the GNU General Public License as published by |
| 7 | +** the Free Software Foundation, either version 3 of the License, or |
| 8 | +** (at your option) any later version. |
| 9 | +** |
| 10 | +** This program is distributed in the hope that it will be useful, |
| 11 | +** but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 12 | +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 13 | +** GNU General Public License for more details. |
| 14 | +** |
| 15 | +** You should have received a copy of the GNU General Public License |
| 16 | +** along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 17 | +*/ |
| 18 | + |
| 19 | +//////////////////////////////////////////////////////////////////////////////// |
| 20 | +// // |
| 21 | +// (c) 2001-2003 Electronic Arts Inc. // |
| 22 | +// // |
| 23 | +//////////////////////////////////////////////////////////////////////////////// |
| 24 | + |
| 25 | +/** |
| 26 | + * The connection manager maintains a collection of Connections to each player. Messages are queued up |
| 27 | + * from here, as well as removed through here. |
| 28 | + */ |
| 29 | + |
| 30 | +#pragma once |
| 31 | + |
| 32 | +#include "GameNetwork/Connection.h" |
| 33 | +#include "GameNetwork/NetCommandList.h" |
| 34 | +#include "GameNetwork/Transport.h" |
| 35 | +#include "GameNetwork/FrameDataManager.h" |
| 36 | +#include "GameNetwork/FrameMetrics.h" |
| 37 | +#include "GameNetwork/NetworkDefs.h" |
| 38 | +#include "GameNetwork/DisconnectManager.h" |
| 39 | + |
| 40 | +class GameInfo; |
| 41 | +class NetCommandWrapperList; |
| 42 | + |
| 43 | +typedef std::map<UnsignedShort, AsciiString> FileCommandMap; |
| 44 | +typedef std::map<UnsignedShort, UnsignedByte> FileMaskMap; |
| 45 | +typedef std::map<UnsignedShort, Int> FileProgressMap; |
| 46 | + |
| 47 | +class ConnectionManager |
| 48 | +{ |
| 49 | +public: |
| 50 | + ConnectionManager(); |
| 51 | + ~ConnectionManager(); |
| 52 | + |
| 53 | + virtual void init(); ///< Initialize this instance. |
| 54 | + virtual void reset(); ///< Take this instance back to the initial state. |
| 55 | + virtual void update(Bool isInGame); ///< Service the Connections being managed by this instance. |
| 56 | + |
| 57 | + // End SubsystemInterface functions |
| 58 | + |
| 59 | + 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. |
| 60 | + |
| 61 | + void attachTransport(Transport *transport); |
| 62 | + |
| 63 | + void parseUserList(const GameInfo *game); |
| 64 | + void sendChat(UnicodeString text, Int playerMask, UnsignedInt executionFrame); |
| 65 | + void sendDisconnectChat(UnicodeString text); |
| 66 | + void sendLocalCommand(NetCommandMsg *msg, UnsignedByte relay = 0xff); ///< Send command to the players specified in the relay, goes through packet router. |
| 67 | + void sendLocalCommandDirect(NetCommandMsg *msg, UnsignedByte relay); ///< Send command directly to the players specified, doesn't go through packet router. |
| 68 | + void sendLocalGameMessage(GameMessage *msg, UnsignedInt frame); |
| 69 | + void sendCommand(NetCommandMsg *msg); |
| 70 | + Bool allCommandsReady(UnsignedInt frame, Bool justTesting = FALSE); |
| 71 | + void handleAllCommandsReady(void); |
| 72 | + NetCommandList *getFrameCommandList(UnsignedInt frame); |
| 73 | +// void AddConnection(User *user, UnsignedInt slot); |
| 74 | + void determineRouterFallbackPlan(); |
| 75 | + void zeroFrames(UnsignedInt startingFrame, UnsignedInt numFrames); |
| 76 | + void destroyGameMessages(); |
| 77 | +// void createConnections(UnsignedInt numberOfPlayers, UnsignedInt localSlot); |
| 78 | + void setLocalAddress(UnsignedInt ip, UnsignedInt port); |
| 79 | + void initTransport(); |
| 80 | + void processFrameTick(UnsignedInt frame); |
| 81 | + void handleLocalPlayerLeaving(UnsignedInt frame); |
| 82 | + |
| 83 | + void sendFile(AsciiString path, UnsignedByte playerMask, UnsignedShort commandID); |
| 84 | + UnsignedShort sendFileAnnounce(AsciiString path, UnsignedByte playerMask); |
| 85 | + Int getFileTransferProgress(Int playerID, AsciiString path); |
| 86 | + Bool areAllQueuesEmpty(void); |
| 87 | + |
| 88 | + UnsignedInt getLocalPlayerID(); |
| 89 | + UnicodeString getPlayerName(Int playerNum); |
| 90 | + Int getNumPlayers(); |
| 91 | + |
| 92 | + UnsignedInt getPacketRouterFallbackSlot(Int packetRouterNumber); ///< Returns the slot of the given packet router number in the fallback plan. |
| 93 | + UnsignedInt getPacketRouterSlot(); ///< Returns the current packet router's slot. |
| 94 | + PlayerLeaveCode disconnectPlayer(Int slot); ///< Disconnect this player immediately. This should only be called by the disconnect manager. |
| 95 | + void disconnectLocalPlayer(); ///< Does whatever is necessary to get TheNetwork to realize that it should be leaving the game now. |
| 96 | + void quitGame(); ///< Disconnect from the game RIGHT NOW!! Tell everyone else we are disconnecting. |
| 97 | + |
| 98 | + void voteForPlayerDisconnect(Int slot); ///< Register a vote for a player to be disconnected. |
| 99 | + |
| 100 | + void resendPendingCommands(); ///< Resend the pending commands to the packet router. |
| 101 | + |
| 102 | + void setFrameGrouping(time_t frameGrouping); ///< Set the number of frames that are grouped together into packets. |
| 103 | + |
| 104 | + PlayerLeaveCode processPlayerLeave(NetPlayerLeaveCommandMsg *msg); |
| 105 | + Bool canILeave(); ///< Returns true if the local player is allowed to leave. |
| 106 | + |
| 107 | + // Bandwidth metrics |
| 108 | + Real getIncomingBytesPerSecond( void ); |
| 109 | + Real getIncomingPacketsPerSecond( void ); |
| 110 | + Real getOutgoingBytesPerSecond( void ); |
| 111 | + Real getOutgoingPacketsPerSecond( void ); |
| 112 | + Real getUnknownBytesPerSecond( void ); |
| 113 | + Real getUnknownPacketsPerSecond( void ); |
| 114 | + UnsignedInt getPacketArrivalCushion( void ); |
| 115 | + |
| 116 | + UnsignedInt getMinimumCushion(); |
| 117 | + |
| 118 | + void flushConnections(); |
| 119 | + |
| 120 | + void processChat(NetChatCommandMsg *msg); // this actually needs to be public because it is frame-synchronized |
| 121 | + |
| 122 | + void updateLoadProgress( Int progress ); |
| 123 | + void loadProgressComplete( void ); |
| 124 | + void sendTimeOutGameStart( void ); |
| 125 | + |
| 126 | + Bool isPacketRouter( void ); |
| 127 | + |
| 128 | + Bool isPlayerConnected( Int playerID ); |
| 129 | + |
| 130 | + void notifyOthersOfCurrentFrame(Int frame); |
| 131 | + void sendFrameDataToPlayer(UnsignedInt playerID, UnsignedInt startingFrame); |
| 132 | + void sendSingleFrameToPlayer(UnsignedInt playerID, UnsignedInt frame); |
| 133 | + void notifyOthersOfNewFrame(UnsignedInt frame); |
| 134 | + |
| 135 | + UnsignedInt getNextPacketRouterSlot(UnsignedInt playerID); ///< returns the packet router player that comes after the given player. |
| 136 | + |
| 137 | + Int getAverageFPS( void ); |
| 138 | + Int getSlotAverageFPS(Int slot); |
| 139 | + |
| 140 | +#if defined(RTS_DEBUG) |
| 141 | + void debugPrintConnectionCommands(); |
| 142 | +#endif |
| 143 | + |
| 144 | + // For disconnect blame assignment |
| 145 | + UnsignedInt getPingFrame(); |
| 146 | + Int getPingsSent(); |
| 147 | + Int getPingsRecieved(); |
| 148 | + |
| 149 | +private: |
| 150 | + void doRelay(); |
| 151 | + void doKeepAlive(); |
| 152 | + void sendRemoteCommand(NetCommandRef *msg); |
| 153 | + void ackCommand(NetCommandRef *ref, UnsignedInt localSlot); |
| 154 | + |
| 155 | + Bool processNetCommand(NetCommandRef *ref); |
| 156 | + void processAckStage1(NetCommandMsg *msg); |
| 157 | + void processAckStage2(NetCommandMsg *msg); |
| 158 | + void processAck(NetCommandMsg *msg); |
| 159 | + void processFrameInfo(NetFrameCommandMsg *msg); |
| 160 | + void processRunAheadMetrics(NetRunAheadMetricsCommandMsg *msg); |
| 161 | + void processDisconnectChat(NetDisconnectChatCommandMsg *msg); |
| 162 | + void processProgress( NetProgressCommandMsg *msg ); |
| 163 | + void processLoadComplete( NetCommandMsg *msg ); |
| 164 | + void processTimeOutGameStart( NetCommandMsg *msg ); |
| 165 | + void processWrapper(NetCommandRef *ref); |
| 166 | + void processFrameResendRequest(NetFrameResendRequestCommandMsg *msg); |
| 167 | + |
| 168 | + void processFile(NetFileCommandMsg *ref); |
| 169 | + void processFileAnnounce(NetFileAnnounceCommandMsg *ref); |
| 170 | + void processFileProgress(NetFileProgressCommandMsg *ref); |
| 171 | + |
| 172 | + // void doPerFrameMetrics(UnsignedInt frame); |
| 173 | + void getMinimumFps(Int &minFps, Int &minFpsPlayer); ///< Returns the smallest FPS in the m_fpsAverages list. |
| 174 | + Real getMaximumLatency(); ///< Returns the highest average latency between players. |
| 175 | + |
| 176 | + void requestFrameDataResend(Int playerID, UnsignedInt frame); ///< request of this player that he send the specified frame's data. |
| 177 | + |
| 178 | + // The connections are set up like the slot list. The connection corresponding to the local |
| 179 | + // player's position in the slot list will be NULL. Connections corresponding to slots that |
| 180 | + // do not have a player will also be NULL. |
| 181 | + Connection *m_connections[MAX_SLOTS]; |
| 182 | + |
| 183 | + Transport *m_transport; |
| 184 | + UnsignedInt m_localSlot; |
| 185 | + UnsignedInt m_packetRouterSlot; |
| 186 | + UnsignedInt m_packetRouterFallback[MAX_SLOTS]; |
| 187 | + UnsignedInt m_localAddr; |
| 188 | + UnsignedInt m_localPort; |
| 189 | + User* m_localUser; |
| 190 | + |
| 191 | + DisconnectManager *m_disconnectManager; ///< Controls the disconnect dialog. |
| 192 | + |
| 193 | + FrameDataManager *m_frameData[MAX_SLOTS]; |
| 194 | + |
| 195 | + NetCommandList *m_pendingCommands; |
| 196 | + NetCommandList *m_relayedCommands; |
| 197 | + |
| 198 | + FrameMetrics m_frameMetrics; |
| 199 | + |
| 200 | + NetCommandWrapperList *m_netCommandWrapperList; |
| 201 | + |
| 202 | + // These variables are used to keep track of the other players' average fps and latency. |
| 203 | + // yup. |
| 204 | + Real m_latencyAverages[MAX_SLOTS]; |
| 205 | + Int m_fpsAverages[MAX_SLOTS]; |
| 206 | + Int m_minFpsPlayer; |
| 207 | + Int m_minFps; |
| 208 | + UnsignedInt m_smallestPacketArrivalCushion; |
| 209 | + Bool m_didSelfSlug; |
| 210 | + |
| 211 | + // ----------------------------------------------------------------------------- |
| 212 | + FileCommandMap s_fileCommandMap; |
| 213 | + FileMaskMap s_fileRecipientMaskMap; |
| 214 | + FileProgressMap s_fileProgressMap[MAX_SLOTS]; |
| 215 | + // ----------------------------------------------------------------------------- |
| 216 | +}; |
0 commit comments