/* ** 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 #ifndef __CONNECTION_H #define __CONNECTION_H #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(_DEBUG) || defined(_INTERNAL) 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. }; #endif