Skip to content

Commit 795060c

Browse files
committed
feat: add legacy protocol compatibility mode for network packet headers and transport handling
1 parent 31e9d97 commit 795060c

5 files changed

Lines changed: 172 additions & 14 deletions

File tree

Core/GameEngine/Include/Common/Debug.h

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,11 @@ class AsciiString;
164164

165165
#else
166166

167-
#define DEBUG_LOG(m) ((void)0)
167+
#ifdef DEBUG_LOG_FLAG_V2
168+
#define DEBUG_LOG(m) MAC_LOG_TAG("DEBUG_LOG_V2", m)
169+
#else
170+
#define DEBUG_LOG(m) ((void)0)
171+
#endif
168172
#define DEBUG_LOG_RAW(m) ((void)0)
169173
#define DEBUG_LOG_LEVEL(l, m) ((void)0)
170174
#define DEBUG_LOG_LEVEL_RAW(l, m) ((void)0)
@@ -281,13 +285,14 @@ class SimpleProfiler
281285
#define DEBUG_CRASH_MAC(m) ((void)0)
282286
#endif
283287

284-
#define DEBUG_BUILDMAPCACHE_FLAG
285-
#define DEBUG_INFO_MAC_FLAG
286-
#define DEBUG_FILESYSTEM_MAC_FLAG
287-
#define DEBUG_RENDER_CORE_MAC_FLAG
288-
#define DEBUG_NETWORK_MAC_FLAG
289-
#define DEBUG_AUTH_MAC_FLAG
290-
#define DEBUG_EAC_MAC_FLAG
288+
// #define DEBUG_BUILDMAPCACHE_FLAG
289+
// #define DEBUG_INFO_MAC_FLAG
290+
// #define DEBUG_FILESYSTEM_MAC_FLAG
291+
// #define DEBUG_RENDER_CORE_MAC_FLAG
292+
// #define DEBUG_NETWORK_MAC_FLAG
293+
// #define DEBUG_AUTH_MAC_FLAG
294+
// #define DEBUG_EAC_MAC_FLAG
295+
// #define DEBUG_LOG_FLAG_V2
291296

292297
#ifdef DEBUG_BUILDMAPCACHE_FLAG
293298
#define DEBUG_BUILDMAPCACHE(m) MAC_LOG_TAG("DEBUG_BUILDMAPCACHE", m)

GeneralsMD/Code/GameEngine/Include/GameNetwork/GeneralsOnline/NGMP_include.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,15 @@ enum class ELogVerbosity
77
LOG_RELEASE = 1
88
};
99

10+
// TODO(PS_PATH): Remove NGMP_COMPAT_OLD_CHANNEL_PROTOCOL when GO production Windows client
11+
// updates past commit 28c93dd89 ("Cleanup of network transport and header code", May 10 2026).
12+
// Production build as of May 25 2026 is from April 28 2026 — uses old 3-byte AC header [9,1,2]
13+
// and sends game packets WITHOUT a channel header byte.
14+
// grep "NGMP_COMPAT_OLD_CHANNEL_PROTOCOL" to find all affected locations.
15+
#ifdef __APPLE__
16+
#define NGMP_COMPAT_OLD_CHANNEL_PROTOCOL
17+
#endif
18+
1019
enum class ENetworkChannel : BYTE
1120
{
1221
NETWORK_CHANNEL_GAME = 0,

GeneralsMD/Code/GameEngine/Source/GameNetwork/GeneralsOnline/NGMP_Helpers.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,8 +115,15 @@ void NetworkLog(ELogVerbosity logVerbosity, const char* fmt, ...)
115115
DevConsole.AddLog(strLogBuffer.c_str());
116116
#endif
117117

118+
#ifdef __APPLE__
119+
#ifdef DEBUG_NETWORK_MAC_FLAG
120+
printf("[NetworkLog] %s\n", strLogBuffer.c_str());
121+
fflush(stdout);
122+
#endif
123+
#else
118124
OutputDebugString(strLogBuffer.c_str());
119125
OutputDebugString("\n");
126+
#endif
120127
}
121128

122129
std::string Base64Encode(const std::vector<uint8_t>& data)

GeneralsMD/Code/GameEngine/Source/GameNetwork/GeneralsOnline/NetworkMesh.cpp

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1158,6 +1158,37 @@ void PlayerConnection::LiteUpdateForAC()
11581158
memcpy(vecData.data(), msg->GetData(), numBytes);
11591159

11601160
// Check minimum packet size for AC header
1161+
#ifdef NGMP_COMPAT_OLD_CHANNEL_PROTOCOL
1162+
// TODO(PS_PATH): Old protocol compat — 3-byte AC header [9,1,2]
1163+
if (numBytes >= 3)
1164+
{
1165+
BYTE b1 = (BYTE)vecData[0];
1166+
BYTE b2 = (BYTE)vecData[1];
1167+
BYTE b3 = (BYTE)vecData[2];
1168+
if (b1 == 9 && b2 == 1 && b3 == 2)
1169+
{
1170+
NetworkLog(ELogVerbosity::LOG_RELEASE, "[AC PACKET] Received AC message of size %u from user %lld", numBytes, static_cast<long long>(m_userID));
1171+
1172+
#ifdef __APPLE__
1173+
std::vector<uint8_t> vecDataAC;
1174+
#else
1175+
std::vector<byte> vecDataAC;
1176+
#endif
1177+
vecDataAC.resize(numBytes - 3);
1178+
memcpy(vecDataAC.data(), (char*)msg->GetData() + 3, numBytes - 3);
1179+
1180+
AnticheatPlugInterface::AC_NetworkMessageArrived(m_userID, vecDataAC.data(), numBytes - 3);
1181+
msg->Release();
1182+
continue;
1183+
}
1184+
}
1185+
else if (numBytes > 0 && numBytes < 3)
1186+
{
1187+
NetworkLog(ELogVerbosity::LOG_RELEASE, "[AC PACKET] Dropping malformed AC packet - size %u is less than header size 3 from user %lld", numBytes, static_cast<long long>(m_userID));
1188+
msg->Release();
1189+
continue;
1190+
}
1191+
#else
11611192
if (numBytes >= sizeof(ENetworkChannel))
11621193
{
11631194
ENetworkChannel netChannel = (ENetworkChannel)vecData[0];
@@ -1181,13 +1212,13 @@ void PlayerConnection::LiteUpdateForAC()
11811212
continue;
11821213
}
11831214
}
1184-
else if (numBytes != -1 && numBytes < sizeof(ENetworkChannel))
1215+
else if (numBytes > 0 && numBytes < sizeof(ENetworkChannel))
11851216
{
1186-
// Malformed AC packet - too small for header
1187-
NetworkLog(ELogVerbosity::LOG_RELEASE, "[AC PACKET] Dropping malformed AC packet - size %u is less than header size 3 from user %lld", numBytes, static_cast<long long>(m_userID));
1217+
NetworkLog(ELogVerbosity::LOG_RELEASE, "[AC PACKET] Dropping malformed AC packet - size %u is less than header size from user %lld", numBytes, static_cast<long long>(m_userID));
11881218
msg->Release();
11891219
continue;
11901220
}
1221+
#endif
11911222

11921223
// not an AC packet, we dont care
11931224
NetworkLog(ELogVerbosity::LOG_DEBUG, "[AC PACKET] Received NON AC message");
@@ -1261,6 +1292,12 @@ int PlayerConnection::SendGamePacket(void* pBuffer, uint32_t totalDataSize)
12611292
}
12621293
}
12631294

1295+
#ifdef NGMP_COMPAT_OLD_CHANNEL_PROTOCOL
1296+
// TODO(PS_PATH): Old protocol compat — send game packets raw, no channel header
1297+
NetworkLog(ELogVerbosity::LOG_DEBUG, "[GAME PACKET] Sending msg of size %ld to user %lld\n", totalDataSize, m_userID);
1298+
EResult r = SteamNetworkingSockets()->SendMessageToConnection(
1299+
m_hSteamConnection, pBuffer, (int)totalDataSize, sendFlags, nullptr);
1300+
#else
12641301
ENetworkChannel netChannel = ENetworkChannel::NETWORK_CHANNEL_GAME;
12651302
std::vector<BYTE> vecData;
12661303
vecData.resize(totalDataSize + sizeof(ENetworkChannel));
@@ -1270,6 +1307,7 @@ int PlayerConnection::SendGamePacket(void* pBuffer, uint32_t totalDataSize)
12701307
NetworkLog(ELogVerbosity::LOG_DEBUG, "[GAME PACKET] Sending msg of size %ld to user %lld\n", totalDataSize, m_userID);
12711308
EResult r = SteamNetworkingSockets()->SendMessageToConnection(
12721309
m_hSteamConnection, vecData.data(), vecData.size(), sendFlags, nullptr);
1310+
#endif
12731311

12741312
if (r != k_EResultOK)
12751313
{
@@ -1294,11 +1332,21 @@ void PlayerConnection::SendACPacket(const void* pData, uint32_t dataLen)
12941332
return;
12951333
}
12961334

1335+
#ifdef NGMP_COMPAT_OLD_CHANNEL_PROTOCOL
1336+
// TODO(PS_PATH): Old protocol compat — 3-byte AC header [9,1,2]
1337+
std::vector<BYTE> vecData;
1338+
vecData.resize(dataLen + 3);
1339+
memcpy(vecData.data() + 3, pData, dataLen);
1340+
vecData[0] = 9;
1341+
vecData[1] = 1;
1342+
vecData[2] = 2;
1343+
#else
12971344
ENetworkChannel netChannel = ENetworkChannel::NETWORK_CHANNEL_AC;
12981345
std::vector<BYTE> vecData;
12991346
vecData.resize(dataLen + sizeof(ENetworkChannel));
13001347
memcpy(vecData.data() + sizeof(ENetworkChannel), pData, dataLen);
13011348
vecData[0] = (BYTE)netChannel;
1349+
#endif
13021350

13031351
NetworkLog(ELogVerbosity::LOG_RELEASE, "[AC PACKET] Sending AC msg of size %ld to user %ld\n", dataLen, m_userID);
13041352
EResult r = SteamNetworkingSockets()->SendMessageToConnection(m_hSteamConnection, vecData.data(), vecData.size(), k_nSteamNetworkingSend_Reliable, nullptr);

GeneralsMD/Code/GameEngine/Source/GameNetwork/GeneralsOnline/NextGenTransport.cpp

Lines changed: 92 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,92 @@ Bool NextGenTransport::doRecv(void)
149149
memcpy(vecDataWithHeader.data(), msg->GetData(), numBytesWithHeader);
150150

151151
// all packets must have at least 1 byte to indicate channel
152+
#ifdef NGMP_COMPAT_OLD_CHANNEL_PROTOCOL
153+
// TODO(PS_PATH): Old protocol compat — 3-byte AC header [9,1,2], game packets have no channel header
154+
if (numBytesWithHeader >= 3)
155+
{
156+
BYTE b1 = (BYTE)vecDataWithHeader[0];
157+
BYTE b2 = (BYTE)vecDataWithHeader[1];
158+
BYTE b3 = (BYTE)vecDataWithHeader[2];
159+
if (b1 == 9 && b2 == 1 && b3 == 2)
160+
{
161+
NetworkLog(ELogVerbosity::LOG_RELEASE,"[AC PACKET] Received AC message of size %u from user %lld", numBytesWithHeader, static_cast<long long>(kvPair.second.m_userID));
162+
163+
std::vector<uint8_t> vecDataAC;
164+
vecDataAC.resize(numBytesWithHeader - 3);
165+
memcpy(vecDataAC.data(), (char*)msg->GetData() + 3, numBytesWithHeader - 3);
166+
167+
AnticheatPlugInterface::AC_NetworkMessageArrived(kvPair.second.m_userID, vecDataAC.data(), numBytesWithHeader - 3);
168+
msg->Release();
169+
continue;
170+
}
171+
}
172+
else if (numBytesWithHeader > 0 && numBytesWithHeader < 3)
173+
{
174+
NetworkLog(ELogVerbosity::LOG_RELEASE, "[AC PACKET] Dropping malformed AC packet - size %u is less than header size 3 from user %lld", numBytesWithHeader, static_cast<long long>(kvPair.second.m_userID));
175+
msg->Release();
176+
continue;
177+
}
178+
179+
// Not AC — treat as raw game packet (no channel header to strip)
180+
{
181+
const uint32_t numBytes = numBytesWithHeader;
182+
183+
NetworkLog(ELogVerbosity::LOG_DEBUG,
184+
"[GAME PACKET] Received message of size %u from user %lld",
185+
numBytes, static_cast<long long>(kvPair.second.m_userID));
186+
187+
if (numBytes < sizeof(TransportMessageHeader))
188+
{
189+
NetworkLog(ELogVerbosity::LOG_RELEASE,
190+
"Game Packet Recv: Dropping packet smaller than header (%u < %zu)",
191+
numBytes, sizeof(TransportMessageHeader));
192+
msg->Release();
193+
continue;
194+
}
195+
196+
const uint32_t maxWireSize =
197+
static_cast<uint32_t>(sizeof(TransportMessageHeader) + MAX_MESSAGE_LEN);
198+
199+
if (numBytes > maxWireSize)
200+
{
201+
NetworkLog(ELogVerbosity::LOG_RELEASE,
202+
"Game Packet Recv: Dropping packet too large (%u > %u)",
203+
numBytes, maxWireSize);
204+
msg->Release();
205+
continue;
206+
}
207+
208+
std::memset(&incomingMessage, 0, sizeof(incomingMessage));
209+
210+
std::memcpy(&incomingMessage.header,
211+
msg->m_pData,
212+
sizeof(TransportMessageHeader));
213+
214+
const uint32_t payloadLen =
215+
numBytes - static_cast<uint32_t>(sizeof(TransportMessageHeader));
216+
217+
if (payloadLen > sizeof(incomingMessage.data))
218+
{
219+
NetworkLog(ELogVerbosity::LOG_RELEASE,
220+
"Game Packet Recv: Dropping packet, payloadLen (%u) > incoming buffer (%zu)",
221+
payloadLen, sizeof(incomingMessage.data));
222+
msg->Release();
223+
continue;
224+
}
225+
226+
if (payloadLen > 0)
227+
{
228+
std::memcpy(incomingMessage.data,
229+
static_cast<unsigned char*>(msg->m_pData) + sizeof(TransportMessageHeader),
230+
payloadLen);
231+
}
232+
233+
incomingMessage.length = static_cast<Int>(payloadLen);
234+
235+
msg->Release();
236+
237+
#else // New protocol: 1-byte ENetworkChannel header
152238
if (numBytesWithHeader >= sizeof(ENetworkChannel))
153239
{
154240
ENetworkChannel netChannel = (ENetworkChannel)vecDataWithHeader[0];
@@ -234,6 +320,7 @@ Bool NextGenTransport::doRecv(void)
234320

235321
msg->Release();
236322

323+
#endif // NGMP_COMPAT_OLD_CHANNEL_PROTOCOL
237324
#if defined(RTS_DEBUG) || defined(RTS_INTERNAL)
238325
if (m_usePacketLoss)
239326
{
@@ -254,7 +341,7 @@ Bool NextGenTransport::doRecv(void)
254341

255342
if (!isGenerals)
256343
{
257-
DEBUG_INFO_MAC(("[NET_RECV] DROP: not a generals packet, size=%u from uid=%lld", vecPacketDataWithoutHeader.size(), (long long)kvPair.second.m_userID));
344+
DEBUG_INFO_MAC(("[NET_RECV] DROP: not a generals packet, size=%u from uid=%lld", numBytesWithHeader, (long long)kvPair.second.m_userID));
258345
// Check if it's a CRC failure or magic number failure to help diagnose corruption
259346
if (incomingMessage.header.magic != GENERALS_MAGIC_NUMBER)
260347
{
@@ -273,12 +360,12 @@ Bool NextGenTransport::doRecv(void)
273360
static_cast<long long>(kvPair.second.m_userID), incomingMessage.length);
274361
}
275362
m_unknownPackets[m_statisticsSlot]++;
276-
m_unknownBytes[m_statisticsSlot] += vecPacketDataWithoutHeader.size();
363+
m_unknownBytes[m_statisticsSlot] += numBytesWithHeader;
277364
continue;
278365
}
279366

280367
m_incomingPackets[m_statisticsSlot]++;
281-
m_incomingBytes[m_statisticsSlot] += vecPacketDataWithoutHeader.size();
368+
m_incomingBytes[m_statisticsSlot] += numBytesWithHeader;
282369

283370
// Store into first free slot in m_inBuffer
284371
bool stored = false;
@@ -355,6 +442,7 @@ Bool NextGenTransport::doRecv(void)
355442
bRet = TRUE;
356443
}
357444
}
445+
#ifndef NGMP_COMPAT_OLD_CHANNEL_PROTOCOL
358446
}
359447
else if (vecDataWithHeader.size() != -1)
360448
{
@@ -363,6 +451,7 @@ Bool NextGenTransport::doRecv(void)
363451
msg->Release();
364452
continue;
365453
}
454+
#endif
366455
}
367456
}
368457

0 commit comments

Comments
 (0)