Initial commit of Command & Conquer Generals and Command & Conquer Generals Zero Hour source code.

This commit is contained in:
LFeenanEA 2025-02-27 17:34:39 +00:00
parent 2e338c00cb
commit 3d0ee53a05
No known key found for this signature in database
GPG key ID: C6EBE8C2EA08F7E0
6072 changed files with 2283311 additions and 0 deletions

View file

@ -0,0 +1,106 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
/**
* 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

View file

@ -0,0 +1,221 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (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
#ifndef __CONNECTIONMANAGER_H
#define __CONNECTIONMANAGER_H
#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<UnsignedShort, AsciiString> FileCommandMap;
typedef std::map<UnsignedShort, UnsignedByte> FileMaskMap;
typedef std::map<UnsignedShort, Int> 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(_DEBUG) || defined(_INTERNAL)
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(); ///< This actually sums the two biggest latencies in the m_latencyAverages list.
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];
// -----------------------------------------------------------------------------
};
#endif

View file

@ -0,0 +1,133 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
#pragma once
#ifndef __DISCONNECTMANAGER_H
#define __DISCONNECTMANAGER_H
#include "GameNetwork/NetCommandRef.h"
#include "Lib/BaseType.h"
//#include "GameNetwork/ConnectionManager.h"
enum DisconnectStateType {
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;
};
#endif // #ifndef __DISCONNECTMANAGER_H

View file

@ -0,0 +1,98 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: DownloadManager.h //////////////////////////////////////////////////////
// Generals download class definitions
// Author: Matthew D. Campbell, July 2002
#pragma once
#ifndef __DOWNLOADMANAGER_H__
#define __DOWNLOADMANAGER_H__
#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<QueuedDownload> m_queuedDownloads;
};
extern DownloadManager *TheDownloadManager;
#endif // __DOWNLOADMANAGER_H__

View file

@ -0,0 +1,52 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////
// FILE: FileTransfer.h
// Author: Matthew D. Campbell, December 2002
// Description: File Transfer wrapper using TheNetwork
///////////////////////////////////////////////////////////////////////////////////////
#pragma once
#ifndef __FILE_TRANSFER_H__
#define __FILE_TRANSFER_H__
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);
#endif // __FILE_TRANSFER_H__

View file

@ -0,0 +1,314 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (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
#ifndef __FIREWALLHELPER_H
#define __FIREWALLHELPER_H
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 {
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();
#endif // __FIREWALLHELPER_H

View file

@ -0,0 +1,69 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
#pragma once
#ifndef __FRAMEDATA_H
#define __FRAMEDATA_H
#include "Lib/BaseType.h"
#include "GameNetwork/NetCommandList.h"
enum FrameDataReturnType {
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;
};
#endif

View file

@ -0,0 +1,67 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
#pragma once
#ifndef __FRAMEDATAMANAGER_H
#define __FRAMEDATAMANAGER_H
#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;
};
#endif

View file

@ -0,0 +1,74 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
/** FrameMetrics.h */
#pragma once
#ifndef __FRAMEMETRICS_H
#define __FRAMEMETRICS_H
#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.
};
#endif // __FRAMEMETRICS_H

View file

@ -0,0 +1,56 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: GUIUtil.h //////////////////////////////////////////////////////
// Author: Matthew D. Campbell, Sept 2002
#pragma once
#ifndef __GUIUTIL_H__
#define __GUIUTIL_H__
class GameWindow;
class GameInfo;
void ShowUnderlyingGUIElements( Bool show, const char *layoutFilename, const char *parentName,
const char **gadgetsToHide, const char **perPlayerGadgetsToHide );
void PopulateColorComboBox(Int comboBox, GameWindow *comboArray[], GameInfo *myGame, Bool isObserver = FALSE);
void PopulatePlayerTemplateComboBox(Int comboBox, GameWindow *comboArray[], GameInfo *myGame, Bool allowObservers);
void PopulateTeamComboBox(Int comboBox, GameWindow *comboArray[], GameInfo *myGame, Bool isObserver = FALSE);
void EnableSlotListUpdates( Bool val );
Bool AreSlotListUpdatesEnabled( void );
void UpdateSlotList( GameInfo *myGame, GameWindow *comboPlayer[],
GameWindow *comboColor[], GameWindow *comboPlayerTemplate[],
GameWindow *comboTeam[], GameWindow *buttonAccept[],
GameWindow *buttonStart, GameWindow *buttonMapStartPosition[] );
void EnableAcceptControls(Bool Enabled, GameInfo *myGame, GameWindow *comboPlayer[],
GameWindow *comboColor[], GameWindow *comboPlayerTemplate[],
GameWindow *comboTeam[], GameWindow *buttonAccept[], GameWindow *buttonStart,
GameWindow *buttonMapStartPosition[], Int slotNum = -1);
#endif // __GUIUTIL_H__

View file

@ -0,0 +1,288 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: GameInfo.h //////////////////////////////////////////////////////
// Generals game setup information
// Author: Matthew D. Campbell, December 2001
#pragma once
#ifndef __GAMEINFO_H__
#define __GAMEINFO_H__
#include "Common/Snapshot.h"
#include "GameNetwork/NetworkDefs.h"
#include "GameNetwork/FirewallHelper.h"
enum SlotState
{
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
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);
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;
};
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; }
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;
#endif // __GAMEINFO_H__

View file

@ -0,0 +1,105 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (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;
}

View file

@ -0,0 +1,148 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: GameSpy.h //////////////////////////////////////////////////////
// Generals GameSpy stuff
// Author: Matthew D. Campbell, February 2002
#pragma once
#ifndef __GameSpy_H__
#define __GameSpy_H__
#include "GameSpy/Peer/Peer.h"
#include "GameClient/Color.h"
#include "Common/STLTypedefs.h"
class GameSpyGroupRoom
{
public:
GameSpyGroupRoom() { m_name = AsciiString::TheEmptyString; m_groupID = m_numWaiting = m_maxWaiting = m_numGames = m_numPlaying = 0; }
AsciiString m_name;
Int m_groupID;
Int m_numWaiting;
Int m_maxWaiting;
Int m_numGames;
Int m_numPlaying;
};
typedef std::map<Int, GameSpyGroupRoom> GroupRoomMap;
class GameSpyChatInterface : public SubsystemInterface
{
public:
virtual ~GameSpyChatInterface() { };
virtual void init( void ) = 0;
virtual void reset( void ) = 0;
virtual void update( void ) = 0;
virtual Bool isConnected( void ) = 0;
virtual void login(AsciiString loginName, AsciiString password = AsciiString::TheEmptyString, AsciiString email = AsciiString::TheEmptyString) = 0;
virtual void reconnectProfile( void ) = 0;
virtual void disconnectFromChat( void ) = 0;
virtual void UTMRoom( RoomType roomType, const char *key, const char *val, Bool authenticate = FALSE ) = 0;
virtual void UTMPlayer( const char *name, const char *key, const char *val, Bool authenticate = FALSE ) = 0;
virtual void startGame( void ) = 0;
virtual void leaveRoom( RoomType roomType ) = 0;
virtual void setReady( Bool ready ) = 0;
virtual void enumPlayers( RoomType roomType, peerEnumPlayersCallback callback, void *userData ) = 0;
virtual void startListingGames( peerListingGamesCallback callback ) = 0;
virtual void stopListingGames( void ) = 0;
virtual void joinGroupRoom( Int ID ) = 0;
virtual void joinStagingRoom( GServer server, AsciiString password ) = 0;
virtual void createStagingRoom( AsciiString gameName, AsciiString password, Int maxPlayers ) = 0;
virtual void joinBestGroupRoom( void ) = 0;
inline PEER getPeer( void ) { return m_peer; }
inline AsciiString getLoginName( void ) { return m_loginName; }
inline AsciiString getPassword( void ) { return m_password; }
inline GroupRoomMap* getGroupRooms( void ) { return &m_groupRooms; }
inline Int getCurrentGroupRoomID( void ) { return m_currentGroupRoomID; }
inline Bool getUsingProfile( void ) { return m_usingProfiles; }
inline Int getProfileID( void ) { return m_profileID; }
inline void setCurrentGroupRoomID( Int ID ) { m_currentGroupRoomID = ID; }
void clearGroupRoomList(void);
inline Int getNumGroupRooms( void ) { return m_groupRooms.size(); }
protected:
AsciiString m_loginName;
AsciiString m_password;
AsciiString m_email;
Bool m_usingProfiles;
Int m_profileID;
PEER m_peer;
GroupRoomMap m_groupRooms;
Int m_currentGroupRoomID;
};
GameSpyChatInterface *createGameSpyChat( void );
extern GameSpyChatInterface *TheGameSpyChat;
void JoinRoomCallback(PEER peer, PEERBool success,
PEERJoinResult result, RoomType roomType,
void *param); ///< Called when we (fail to) join a room. param is address of Bool to store result
void ListGroupRoomsCallback(PEER peer, PEERBool success,
int groupID, GServer server,
const char * name, int numWaiting,
int maxWaiting, int numGames,
int numPlaying, void * param); ///< Called while listing group rooms
enum GameSpyColors {
GSCOLOR_DEFAULT = 0,
GSCOLOR_CURRENTROOM,
GSCOLOR_ROOM,
GSCOLOR_GAME,
GSCOLOR_PLAYER_NORMAL,
GSCOLOR_PLAYER_OWNER,
GSCOLOR_PLAYER_BUDDY,
GSCOLOR_PLAYER_SELF,
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_MAX
};
extern const Color GameSpyColor[GSCOLOR_MAX];
#endif // __GameSpy_H__

View file

@ -0,0 +1,37 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: BuddyDefs.h //////////////////////////////////////////////////////
// Generals GameSpy Buddy (GP) definitions
// Author: Matthew D. Campbell, July 2002
#pragma once
#ifndef __BUDDYDEFS_H__
#define __BUDDYDEFS_H__
void HandleBuddyResponses(void);
void PopulateOldBuddyMessages(void);
#endif // __BUDDYDEFS_H__

View file

@ -0,0 +1,179 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: BuddyThread.h //////////////////////////////////////////////////////
// Generals GameSpy BuddyList thread class interface
// Author: Matthew D. Campbell, June 2002
#pragma once
#ifndef __BUDDYTHREAD_H__
#define __BUDDYTHREAD_H__
#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
BUDDYREQUEST_MAX
} 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,
BUDDYRESPONSE_MAX
} 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;
#endif // __BUDDYTHREAD_H__

View file

@ -0,0 +1,82 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: GSConfig.h ///////////////////////////////////////////////////////////
// Author: Matthew D. Campbell, Sept 2002
// Description: GameSpy online config
///////////////////////////////////////////////////////////////////////////////
#pragma once
#ifndef __GSCONFIG_H__
#define __GSCONFIG_H__
#include "Common/AsciiString.h"
#include "Common/STLTypedefs.h"
class GameSpyConfigInterface
{
public:
virtual ~GameSpyConfigInterface() {}
// Pings
virtual std::list<AsciiString> 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<AsciiString> 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;
#endif // __GSCONFIG_H__

View file

@ -0,0 +1,81 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: GameResultsThread.h //////////////////////////////////////////////////////
// Generals game results thread class interface
// Author: Matthew D. Campbell, August 2002
#pragma once
#ifndef __GAMERESULTSTHREAD_H__
#define __GAMERESULTSTHREAD_H__
#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;
#endif // __GAMERESULTSTHREAD_H__

View file

@ -0,0 +1,88 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: LadderDefs.h //////////////////////////////////////////////////////
// Generals ladder definitions
// Author: Matthew D. Campbell, August 2002
#pragma once
#ifndef __LADDERDEFS_H__
#define __LADDERDEFS_H__
#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<AsciiString> validMaps;
std::list<AsciiString> validFactions;
AsciiString cryptedPassword;
AsciiString address;
UnsignedShort port;
AsciiString homepageURL;
Bool submitReplay; // with game results
Int index;
};
typedef std::list<LadderInfo *> 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;
#endif // __LADDERDEFS_H__

View file

@ -0,0 +1,58 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: LobbyUtils.h //////////////////////////////////////////////////////
// Generals lobby utils
// Author: Matthew D. Campbell, Sept 2002
#pragma once
#ifndef __LOBBYUTILS_H__
#define __LOBBYUTILS_H__
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 );
enum GameSortType
{
GAMESORT_ALPHA_ASCENDING = 0,
GAMESORT_ALPHA_DESCENDING,
GAMESORT_PING_ASCENDING,
GAMESORT_PING_DESCENDING,
GAMESORT_MAX,
};
Bool HandleSortButton( NameKeyType sortButton );
void PopulateLobbyPlayerListbox(void);
#endif // __LOBBYUTILS_H__

View file

@ -0,0 +1,64 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (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
#ifndef __MAINMENUUTILS_H__
#define __MAINMENUUTILS_H__
void HTTPThinkWrapper( void );
void StopAsyncDNSCheck( void );
void StartPatchCheck( void );
void CancelPatchCheckCallback( void );
void StartDownloadingPatches( void );
void HandleCanceledDownload( Bool resetDropDown = TRUE );
enum OverallStatsPeriod
{
STATS_TODAY = 0,
STATS_YESTERDAY,
STATS_ALLTIME,
STATS_LASTWEEK,
STATS_MAX
};
struct OverallStats
{
OverallStats();
Int wins[STATS_MAX];
Int losses[STATS_MAX];
};
void CheckOverallStats( void );
void HandleOverallStats( const OverallStats& USA, const OverallStats& China, const OverallStats& GLA );
void CheckNumPlayersOnline( void );
void HandleNumPlayersOnline( Int numPlayersOnline );
#endif // __MAINMENUUTILS_H__

View file

@ -0,0 +1,303 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: PeerDefs.h //////////////////////////////////////////////////////
// Generals GameSpy Peer (chat) definitions
// Author: Matthew D. Campbell, June 2002
#pragma once
#ifndef __PEERDEFS_H__
#define __PEERDEFS_H__
#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<AsciiString> IgnoreList;
typedef std::map<Int, AsciiString> SavedIgnoreMap;
enum RCItemType
{
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<GPProfile, BuddyInfo> 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<BuddyMessage> 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<Int, GameSpyGroupRoom> GroupRoomMap;
class Transport;
class NAT;
typedef std::map<Int, GameSpyStagingRoom *> 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<AsciiString, PlayerInfo, AsciiComparator> PlayerInfoMap;
enum GameSpyColors {
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 {
BUDDY_OFFLINE,
BUDDY_ONLINE,
BUDDY_LOBBY,
BUDDY_STAGING,
BUDDY_LOADING,
BUDDY_PLAYING,
BUDDY_MATCHING,
BUDDY_MAX
};
// ---------------------------------------------------
// 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 );
#endif // __PEERDEFS_H__

View file

@ -0,0 +1,184 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: PeerDefsImplementation.h //////////////////////////////////////////////////////
// Generals GameSpy Peer (chat) implementation definitions
// Author: Matthew D. Campbell, Sept 2002
#pragma once
#ifndef __PEERDEFSIMPLEMENTATION_H__
#define __PEERDEFSIMPLEMENTATION_H__
#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<GameWindow *> m_textWindows;
std::set<Int> m_preorderPlayers;
Int m_additionalDisconnects;
};
#endif // __PEERDEFS_H__

View file

@ -0,0 +1,390 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (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
#ifndef __PEERTHREAD_H__
#define __PEERTHREAD_H__
#include "GameSpy/Peer/Peer.h"
#include "GameNetwork/NetworkDefs.h"
enum SerialAuthResult
{
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<bool> 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;
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
{
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,
DISCONNECT_MAX,
};
enum QMStatus
{
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;
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;
#endif // __PEERTHREAD_H__

View file

@ -0,0 +1,47 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: PersistentStorageDefs.h //////////////////////////////////////////////////////
// Generals GameSpy Persistent Storage definitions
// Author: Matthew D. Campbell, July 2002
#pragma once
#ifndef __PERSISTENTSTORAGEDEFS_H__
#define __PERSISTENTSTORAGEDEFS_H__
enum LocaleType
{
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 );
#endif // __PERSISTENTSTORAGEDEFS_H__

View file

@ -0,0 +1,187 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: PersistentStorageThread.h //////////////////////////////////////////////////////
// Generals GameSpy Persistent Storage thread class interface
// Author: Matthew D. Campbell, July 2002
#pragma once
#ifndef __PERSISTENTSTORAGETHREAD_H__
#define __PERSISTENTSTORAGETHREAD_H__
#include "GameSpy/gstats/gpersist.h"
#define MAX_BUDDY_CHAT_LEN 128
typedef std::map<Int, UnsignedInt> 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;
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;
#endif // __PERSISTENTSTORAGETHREAD_H__

View file

@ -0,0 +1,83 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (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
#ifndef __PINGTHREAD_H__
#define __PINGTHREAD_H__
// 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;
#endif // __PINGTHREAD_H__

View file

@ -0,0 +1,161 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: StagingRoomGameInfo.h //////////////////////////////////////////////////////
// Generals GameSpy GameInfo
// Author: Matthew D. Campbell, Sept 2002
#pragma once
#ifndef __STAGINGROOMGAMEINFO_H__
#define __STAGINGROOMGAMEINFO_H__
#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;
#endif // __STAGINGROOMGAMEINFO_H__

View file

@ -0,0 +1,37 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: ThreadUtils.h //////////////////////////////////////////////////////
// Generals GameSpy thread utils
// Author: Matthew D. Campbell, July 2002
#pragma once
#ifndef __GAMESPY_THREADUTILS_H__
#define __GAMESPY_THREADUTILS_H__
std::wstring MultiByteToWideCharSingleLine( const char *orig );
std::string WideCharStringToMultiByte( const WideChar *orig );
#endif // __GAMESPY_THREADUTILS_H__

View file

@ -0,0 +1,60 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: GameSpyChat.h //////////////////////////////////////////////////////
// Generals GameSpy Chat
// Author: Matthew D. Campbell, February 2002
#pragma once
#ifndef __GAMESPYCHAT_H__
#define __GAMESPYCHAT_H__
#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.
#endif // __GAMESPYCHAT_H__

View file

@ -0,0 +1,47 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: GameSpyGP.h //////////////////////////////////////////////////////
// Generals GameSpy GP (Buddy)
// Author: Matthew D. Campbell, March 2002
#pragma once
#ifndef __GAMESPYGP_H__
#define __GAMESPYGP_H__
#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);
#endif // __GAMESPYGP_H__

View file

@ -0,0 +1,98 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (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
#ifndef __GAMESPYGAMEINFO_H__
#define __GAMESPYGAMEINFO_H__
#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);
#endif // __LANGAMEINFO_H__

View file

@ -0,0 +1,69 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: GamespyOverlay.h //////////////////////////////////////////////////////
// Generals GameSpy overlay screens
// Author: Matthew D. Campbell, March 2002
#pragma once
#ifndef __GAMESPYOVERLAY_H__
#define __GAMESPYOVERLAY_H__
#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
{
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 );
#endif // __GAMESPYOVERLAY_H__

View file

@ -0,0 +1,62 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: GameSpyPersistentStorage.h //////////////////////////////////////////////////////
// Generals GameSpy Persistent Storage
// Author: Matthew D. Campbell, March 2002
#pragma once
#ifndef __GAMESPYPersistentStorage_H__
#define __GAMESPYPersistentStorage_H__
class GameSpyPlayerInfoInterface : public SubsystemInterface
{
public:
virtual ~GameSpyPlayerInfoInterface() { };
virtual void init( void ) = 0;
virtual void reset( void ) = 0;
virtual void update( void ) = 0;
virtual void setLocale( AsciiString locale, Bool setOnServer = true ) = 0;
virtual AsciiString getLocale( void ) = 0;
virtual void setWins( Int wins, Bool setOnServer = true ) = 0;
virtual Int getWins( void ) = 0;
virtual void setLosses( Int losses, Bool setOnServer = true ) = 0;
virtual Int getLosses( void ) = 0;
virtual void readFromServer( void ) = 0;
virtual void threadReadFromServer( void ) = 0;
virtual void threadSetLocale( AsciiString val ) = 0;
virtual void threadSetWins ( AsciiString val ) = 0;
virtual void threadSetLosses( AsciiString val ) = 0;
};
GameSpyPlayerInfoInterface *createGameSpyPlayerInfo( void );
extern GameSpyPlayerInfoInterface *TheGameSpyPlayerInfo;
#endif // __GAMESPYPersistentStorage_H__

View file

@ -0,0 +1,67 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: GameSpyThread.h //////////////////////////////////////////////////////
// Generals GameSpy thread class
// Author: Matthew D. Campbell, March 2002
#pragma once
#ifndef __GAMESPYTHREAD_H__
#define __GAMESPYTHREAD_H__
#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;
#endif // __GAMESPYTHREAD_H__

View file

@ -0,0 +1,82 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// IPEnumeration.h ///////////////////////////////////////////////////////////////
// Class for enumerating IP addresses
// Author: Matthew D. Campbell, October 2001
#pragma once
#ifndef _IPENUMERATION_H_
#define _IPENUMERATION_H_
#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:
EnumeratedIP *m_IPlist;
Bool m_isWinsockInitialized;
};
#endif // _IPENUMERATION_H_

View file

@ -0,0 +1,423 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (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
#ifndef _LANAPI_H_
#define _LANAPI_H_
#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,
LANCHAT_MAX
};
// 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
RET_MAX
};
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,
ACT_MAX
};
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 ///< 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
MSG_MAX
} LANMessageType;
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)
#endif // _LANAPI_H_

View file

@ -0,0 +1,89 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////
// FILE: LANAPICallbacks.h
// Author: Chris Huybregts, October 2001
// Description: LAN API Callbacks header
///////////////////////////////////////////////////////////////////////////////////////
#pragma once
#ifndef _LANAPI_CALLBACKS_H_
#define _LANAPI_CALLBACKS_H_
#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 );
//Enum is used for the utility function so other windows do not need
//to know about controls on LanGameOptions window.
enum PostToLanGameType{ SEND_GAME_OPTS = 0,
MAP_BACK,
POST_TO_LAN_GAME_TYPE_COUNT };
//the utility function mentioned above
void PostToLanGameOptions(PostToLanGameType post);
#endif //_LANAPI_CALLBACKS_H_

View file

@ -0,0 +1,185 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: LANGameInfo.h //////////////////////////////////////////////////////
// Generals LAN game setup information
// Author: Matthew D. Campbell, December 2001
#pragma once
#ifndef __LANGAMEINFO_H__
#define __LANGAMEINFO_H__
#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\n", 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);
#endif // __LANGAMEINFO_H__

View file

@ -0,0 +1,69 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (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
#ifndef _LANPLAYER_H_
#define _LANPLAYER_H_
/**
* 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
};
#endif //_LANPLAYER_H_

View file

@ -0,0 +1,162 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (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
#ifndef __NAT_H
#define __NAT_H
#include "Lib\BaseType.h"
#include "GameNetwork/NetworkInterface.h"
#include "GameNetwork/FirewallHelper.h"
class Transport;
class GameSlot;
enum NATStateType {
NATSTATE_IDLE,
NATSTATE_DOCONNECTIONPATHS,
NATSTATE_WAITFORSTATS,
NATSTATE_DONE,
NATSTATE_FAILED
};
enum NATConnectionState {
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;
#endif // #ifndef __NAT_H

View file

@ -0,0 +1,74 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
#pragma once
#ifndef __NETCOMMANDLIST_H
#define __NETCOMMANDLIST_H
#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.
};
#endif

View file

@ -0,0 +1,526 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (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
#ifndef __NETCOMMANDMSG_H
#define __NETCOMMANDMSG_H
#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();
// For debugging purposes
virtual AsciiString getContentsAsAsciiString(void) { return AsciiString::TheEmptyString; }
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);
// For debugging purposes
virtual AsciiString getContentsAsAsciiString(void);
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;
};
#endif

View file

@ -0,0 +1,152 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
#pragma once
#ifndef __NETCOMMANDREF_H
#define __NETCOMMANDREF_H
#include "GameNetwork/NetCommandMsg.h"
#include "Common/GameMemory.h"
#if defined(_INTERNAL) || defined(_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;
}
#endif // #ifndef __NETCOMMANDREF_H

View file

@ -0,0 +1,83 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
////// NetCommandWrapperList.h ////////////////////////////////
// Bryan Cleveland
#pragma once
#ifndef __NETCOMMANDWRAPPERLIST_H
#define __NETCOMMANDWRAPPERLIST_H
#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;
};
#endif

View file

@ -0,0 +1,240 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (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
#ifndef __NETPACKET_H
#define __NETPACKET_H
#include "NetworkDefs.h"
#include "GameNetwork/NetCommandList.h"
#include "Common/MessageStream.h"
#include "Common/GameMemory.h"
class NetPacket;
typedef std::list<NetPacket *> NetPacketList;
typedef std::list<NetPacket *>::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;
};
#endif // __NETPACKET_H

View file

@ -0,0 +1,216 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
#pragma once
#ifndef __NETWORKDEFS_H
#define __NETWORKDEFS_H
#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 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
{
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(_DEBUG) || defined(_INTERNAL)
#pragma pack(push, 1)
struct DelayedTransportMessage
{
UnsignedInt deliveryTime;
TransportMessage message;
};
#pragma pack(pop)
#endif
/**
* Message types
*/
enum NetMessageFlag {
MSG_ACK = 1,
MSG_NEEDACK = 2,
MSG_SEQUENCED = 4,
MSG_SUPERCEDING = 8
};
typedef UnsignedByte NetMessageFlags;
enum NetCommandType {
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,
NETCOMMANDTYPE_MAX
};
enum NetLocalStatus {
NETLOCALSTATUS_PREGAME = 0,
NETLOCALSTATUS_INGAME,
NETLOCALSTATUS_LEAVING,
NETLOCALSTATUS_LEFT,
NETLOCALSTATUS_POSTGAME
};
enum PlayerLeaveCode {
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;
#endif

View file

@ -0,0 +1,140 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// NetworkInterface.h ///////////////////////////////////////////////////////////////
// Network singleton class - defines interface to Network methods
// Author: Matthew D. Campbell, July 2001
#pragma once
#ifndef _NETWORK_INTERFACE_H_
#define _NETWORK_INTERFACE_H_
#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 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(_DEBUG) || defined(_INTERNAL)
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);
#endif // _NETWORK_INTERFACE_H_

View file

@ -0,0 +1,105 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (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
#ifndef __RANK_POINT_VALUE_H_
#define __RANK_POINT_VALUE_H_
//-----------------------------------------------------------------------------
// 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 // keep last
};
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;
#endif // __RANK_POINT_VALUE_H_

View file

@ -0,0 +1,105 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (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
#ifndef _TRANSPORT_H_
#define _TRANSPORT_H_
#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(_DEBUG) || defined(_INTERNAL)
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 );
};
#endif // _TRANSPORT_H_

View file

@ -0,0 +1,62 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
/**
* User class used by the network.
*/
#pragma once
#ifndef __USER_H
#define __USER_H
#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)
#endif

View file

@ -0,0 +1,106 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (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.
//
#ifndef _FEBDISPATCH_H__
#define _FEBDISPATCH_H__
#include <atlbase.h>
extern CComModule _Module;
#include <atlcom.h>
#include <comutil.h> // For _bstr_t.
#include "oleauto.h"
template <class T, class C, const IID *I>
class FEBDispatch :
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<T>,
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<IUnknown*>(this), static_cast<C*>(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\n"));
}
}
virtual ~FEBDispatch()
{
if (m_ptinfo)
m_ptinfo->Release();
if (m_dispatch)
m_dispatch->Release();
}
IUnknown *m_dispatch;
private:
ITypeInfo *m_ptinfo;
};
#endif

View file

@ -0,0 +1,127 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
/******************************************************************************
*
* NAME
* $Archive: $
*
* DESCRIPTION
* Web Browser
*
* PROGRAMMER
* Bryan Cleveland
* $Author: $
*
* VERSION INFO
* $Revision: $
* $Modtime: $
*
******************************************************************************/
#pragma once
#ifndef __WEBBROWSER_H__
#define __WEBBROWSER_H__
#include "Common/SubsystemInterface.h"
#include <atlbase.h>
#include <windows.h>
#include <Common/GameMemory.h>
#include "EABrowserDispatch/BrowserDispatch.h"
#include "FEBDispatch.h"
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<WebBrowser, IBrowserDispatch, &IID_IBrowserDispatch>,
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(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);
ULONG STDMETHODCALLTYPE AddRef(void);
ULONG STDMETHODCALLTYPE Release(void);
//---------------------------------------------------------------------------
// IBrowserDispatch methods
//---------------------------------------------------------------------------
public:
STDMETHOD(TestMethod)(Int num1);
};
extern CComObject<WebBrowser> *TheWebBrowser;
#endif // __WEBBROWSER_H__

View file

@ -0,0 +1,48 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
#pragma once
#ifndef __NETWORKUTIL_H
#define __NETWORKUTIL_H
#include "GameNetwork/NetworkDefs.h"
#include "GameNetwork/NetworkInterface.h"
UnsignedInt ResolveIP(AsciiString host);
UnsignedShort GenerateNextCommandID();
Bool DoesCommandRequireACommandID(NetCommandType type);
Bool CommandRequiresAck(NetCommandMsg *msg);
Bool CommandRequiresDirectSend(NetCommandMsg *msg);
Bool IsCommandSynchronized(NetCommandType type);
AsciiString GetAsciiNetCommandType(NetCommandType type);
#ifdef DEBUG_LOGGING
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
#endif

View file

@ -0,0 +1,129 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
#pragma once
#ifndef UDP_HEADER
#define UDP_HEADER
#ifdef _UNIX
#include <errno.h>
#endif
#ifdef _WINDOWS
#include <winsock.h>
#include <io.h>
//#define close _close
//#define read _read
//#define write _write
#else //UNIX
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/time.h>
#include <fcntl.h>
#include <limits.h>
#endif
#ifdef AIX
#include <sys/select.h>
#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
{
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);
};
AsciiString GetWSAErrorString( Int error );
#endif