Skip to content

Commit 5d9aa65

Browse files
authored
bugfix(network): Increase message buffer and max packet sizes to reduce connection issues (TheSuperHackers#2277)
1 parent 182bf28 commit 5d9aa65

File tree

6 files changed

+51
-15
lines changed

6 files changed

+51
-15
lines changed

Core/GameEngine/Include/Common/GameDefines.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,11 @@
4545
#define RETAIL_COMPATIBLE_PATHFINDING_ALLOCATION (1)
4646
#endif
4747

48+
// Disable non retail fixes in the networking, such as putting more data per UDP packet
49+
#ifndef RETAIL_COMPATIBLE_NETWORKING
50+
#define RETAIL_COMPATIBLE_NETWORKING (1)
51+
#endif
52+
4853
// This is essentially synonymous for RETAIL_COMPATIBLE_CRC. There is a lot wrong with AIGroup, such as use-after-free, double-free, leaks,
4954
// but we cannot touch it much without breaking retail compatibility. Do not shy away from using massive hacks when fixing issues with AIGroup,
5055
// but put them behind this macro.

Core/GameEngine/Include/GameNetwork/LANAPI.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ static const Int g_lanHostNameLength = 1;
4444
static const Int g_lanGameNameLength = 16; // reduced length because of game option length
4545
static const Int g_lanGameNameReservedLength = 16; // save N wchars for ID info
4646
static const Int g_lanMaxChatLength = 100;
47-
static const Int m_lanMaxOptionsLength = MAX_PACKET_SIZE - ( 8 + (g_lanGameNameLength+1)*2 + 4 + (g_lanPlayerNameLength+1)*2
47+
static const Int m_lanMaxOptionsLength = MAX_LANAPI_PACKET_SIZE - ( 8 + (g_lanGameNameLength+1)*2 + 4 + (g_lanPlayerNameLength+1)*2
4848
+ (g_lanLoginNameLength+1) + (g_lanHostNameLength+1) );
4949
static const Int g_maxSerialLength = 23; // including the trailing '\0'
5050

@@ -271,7 +271,7 @@ struct LANMessage
271271
};
272272
#pragma pack(pop)
273273

274-
static_assert(sizeof(LANMessage) <= MAX_PACKET_SIZE, "LANMessage struct cannot be larger than the max packet size");
274+
static_assert(sizeof(LANMessage) <= MAX_LANAPI_PACKET_SIZE, "LANMessage struct cannot be larger than the max packet size");
275275

276276

277277
/**

Core/GameEngine/Include/GameNetwork/NetworkDefs.h

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,18 +48,35 @@ enum ConnectionNumbers CPP_11(: Int)
4848
NUM_CONNECTIONS
4949
};
5050

51-
static const Int MAX_SLOTS = MAX_PLAYER+1;
51+
static constexpr const Int MAX_SLOTS = MAX_PLAYER+1;
5252

53+
// TheSuperHackers @info As we are not detecting for network fragmentation and dynamically adjusting payload sizes, we set an 1100 bytes UDP payload as a safe upper limit for various networks
54+
// We chose 1100 bytes as when taking mobile networks into account, maximum transmission unit sizes can vary from 1340 - 1500 bytes
55+
// and when the packet headers for PPPOE, IPV6 and other virtual network encapsulation are considered, we need a lower safe UDP payload to prevent fragmentation.
56+
static constexpr const Int MAX_UDP_PAYLOAD_SIZE = 1100;
5357
// UDP (8 bytes) + IP header (28 bytes) = 36 bytes total. We want a total packet size of 512, so 512 - 36 = 476
54-
static const Int MAX_PACKET_SIZE = 476;
58+
static constexpr const Int RETAIL_GAME_PACKET_SIZE = 476;
59+
60+
// TheSuperHackers @info The legacy lanapi cannot use a larger packet size without breaking the gameinfo command
61+
static constexpr const Int MAX_LANAPI_PACKET_SIZE = RETAIL_GAME_PACKET_SIZE;
62+
63+
// TheSuperHackers @bugfix Mauller 08/02/2026 Allow larger ethernet UDP payload to be used for game messages, this fixes connection issues and eliminates disconnection bugs
64+
#if RETAIL_COMPATIBLE_NETWORKING
65+
static constexpr const Int MAX_PACKET_SIZE = RETAIL_GAME_PACKET_SIZE;
66+
static constexpr const Int MAX_NETWORK_MESSAGE_LEN = 1024;
67+
#else
68+
static constexpr const Int MAX_PACKET_SIZE = MAX_UDP_PAYLOAD_SIZE - sizeof(TransportMessageHeader);
69+
static constexpr const Int MAX_NETWORK_MESSAGE_LEN = MAX_UDP_PAYLOAD_SIZE;
70+
#endif
71+
72+
// TheSuperHackers @bugfix Mauller 08/02/2026 Double send and receive buffer sizes to alleviate the occurance of disconnection issues in retail and non retail code.
73+
static constexpr const Int MAX_MESSAGES = 256;
5574

5675
/**
5776
* Command packet - contains frame #, total # of commands, and each command. This is what gets sent
5877
* to each player every frame
5978
*/
60-
#define MAX_MESSAGE_LEN 1024
61-
#define MAX_MESSAGES 128
62-
static const Int numCommandsPerCommandPacket = (MAX_MESSAGE_LEN - sizeof(UnsignedInt) - sizeof(UnsignedShort))/sizeof(GameMessage);
79+
static const Int numCommandsPerCommandPacket = (MAX_NETWORK_MESSAGE_LEN - sizeof(UnsignedInt) - sizeof(UnsignedShort))/sizeof(GameMessage);
6380
#pragma pack(push, 1)
6481
struct CommandPacket
6582
{
@@ -89,7 +106,14 @@ struct TransportMessageHeader
89106
struct TransportMessage
90107
{
91108
TransportMessageHeader header;
92-
UnsignedByte data[MAX_MESSAGE_LEN];
109+
#if RETAIL_COMPATIBLE_NETWORKING
110+
// TheSuperHackers @info This value is not the correct one that should be used here, it should have been max packet size
111+
// The non retail max network message len takes the extra bytes of the network message header into account when handling UDP payload data
112+
// In retail this only works since no data larger than the retail game packet size is put into a network message
113+
UnsignedByte data[MAX_NETWORK_MESSAGE_LEN];
114+
#else
115+
UnsignedByte data[MAX_PACKET_SIZE];
116+
#endif
93117
Int length;
94118
UnsignedInt addr;
95119
UnsignedShort port;

Core/GameEngine/Source/GameNetwork/LANAPI.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,8 @@ LANGame::LANGame( void )
6767

6868
LANAPI::LANAPI( void ) : m_transport(nullptr)
6969
{
70-
DEBUG_LOG(("LANAPI::LANAPI() - max game option size is %d, sizeof(LANMessage)=%d, MAX_PACKET_SIZE=%d",
71-
m_lanMaxOptionsLength, sizeof(LANMessage), MAX_PACKET_SIZE));
70+
DEBUG_LOG(("LANAPI::LANAPI() - max game option size is %d, sizeof(LANMessage)=%d, MAX_LANAPI_PACKET_SIZE=%d",
71+
m_lanMaxOptionsLength, sizeof(LANMessage), MAX_LANAPI_PACKET_SIZE));
7272

7373
m_lastResendTime = 0;
7474
//

Core/GameEngine/Source/GameNetwork/Network.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ struct ConnectionMessage
7474
{
7575
Int id;
7676
NetMessageFlags flags;
77-
UnsignedByte data[MAX_MESSAGE_LEN];
77+
UnsignedByte data[MAX_NETWORK_MESSAGE_LEN];
7878
time_t lastSendTime;
7979
Int retries;
8080
Int length;

Core/GameEngine/Source/GameNetwork/Transport.cpp

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,10 @@ Bool Transport::doSend() {
217217
if (m_outBuffer[i].length != 0)
218218
{
219219
int bytesSent = 0;
220+
// TheSuperHackers @info The handling of data sizing of the payload within a UDP packet is confusing due to the current networking implementation
221+
// The max game packet size needs to be smaller than max udp payload by sizeof(TransportMessageHeader)
222+
// But the max network message size needs to include the bytes of the transport message header and equal the max udp payload
223+
// Therefore, transmitted data needs to add the extra bytes of the network header to the payloads length
220224
int bytesToSend = m_outBuffer[i].length + sizeof(TransportMessageHeader);
221225
// Send this message
222226
if ((bytesSent = m_udpsock->Write((unsigned char *)(&m_outBuffer[i]), bytesToSend, m_outBuffer[i].addr, m_outBuffer[i].port)) > 0)
@@ -281,12 +285,15 @@ Bool Transport::doRecv()
281285
#if defined(RTS_DEBUG)
282286
UnsignedInt now = timeGetTime();
283287
#endif
284-
288+
// TheSuperHackers @info The handling of data sizing of the payload within a UDP packet is confusing due to the current networking implementation
289+
// The max game packet size needs to be smaller than max udp payload by sizeof(TransportMessageHeader)
290+
// But the max network message size needs to include the bytes of the transport message header and equal the max udp payload
291+
// Therefore, when receiving data we use the max udp payload size to receive the game packet payload and network header
285292
TransportMessage incomingMessage;
286293
unsigned char *buf = (unsigned char *)&incomingMessage;
287-
int len = MAX_MESSAGE_LEN;
294+
int len = MAX_NETWORK_MESSAGE_LEN;
288295
// DEBUG_LOG(("Transport::doRecv - checking"));
289-
while ( (len=m_udpsock->Read(buf, MAX_MESSAGE_LEN, &from)) > 0 )
296+
while ( (len=m_udpsock->Read(buf, MAX_NETWORK_MESSAGE_LEN, &from)) > 0 )
290297
{
291298
#if defined(RTS_DEBUG)
292299
// Packet loss simulation
@@ -417,7 +424,7 @@ Bool Transport::isGeneralsPacket( TransportMessage *msg )
417424
if (!msg)
418425
return false;
419426

420-
if (msg->length < 0 || msg->length > MAX_MESSAGE_LEN)
427+
if (msg->length < 0 || msg->length > MAX_NETWORK_MESSAGE_LEN)
421428
return false;
422429

423430
CRC crc;

0 commit comments

Comments
 (0)