Skip to content

Commit 06af70b

Browse files
committed
feat(matchmaking): support mesh retries and requeue
1 parent c929fa0 commit 06af70b

5 files changed

Lines changed: 173 additions & 23 deletions

File tree

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

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -91,10 +91,12 @@ enum EWebSocketMessageID
9191
SOCIAL_FRIENDS_LIST_DIRTY = 37,
9292
SOCIAL_CANT_ADD_FRIEND_LIST_FULL = 38,
9393
PROBE_RESP = 39,
94-
AC_REGISTER_PLAYER = 40,
95-
AC_DEREGISTER_PLAYER = 41,
96-
WS_KEEPALIVE = 42,
97-
WS_KEEPALIVE_CLIENT = 43
94+
AC_REGISTER_PLAYER = 40,
95+
AC_DEREGISTER_PLAYER = 41,
96+
WS_KEEPALIVE = 42,
97+
WS_KEEPALIVE_CLIENT = 43,
98+
MATCHMAKING_ACTION_REQUEUE = 44,
99+
MATCHMAKING_ACTION_SETUP_PROGRESS = 45
98100
};
99101

100102
enum class EQoSRegions

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

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include "Common/Player.h"
99
#include "GameClient/InGameUI.h"
1010
#include "GameLogic/VictoryConditions.h"
11+
#include <atomic>
1112

1213
extern NGMPGame* TheNGMPGame;
1314

@@ -165,6 +166,44 @@ class NGMP_OnlineServices_LobbyInterface
165166
m_fnCallbackMatchmakingMatchFound();
166167
}
167168
}
169+
170+
std::function<void()> m_fnCallbackMatchmakingRequeue = nullptr;
171+
void RegisterForMatchmakingRequeueCallback(std::function<void()> cb)
172+
{
173+
m_fnCallbackMatchmakingRequeue = cb;
174+
}
175+
176+
void DeregisterForMatchmakingRequeueCallback()
177+
{
178+
m_fnCallbackMatchmakingRequeue = nullptr;
179+
}
180+
181+
void InvokeMatchmakingRequeueCallback()
182+
{
183+
if (m_fnCallbackMatchmakingRequeue != nullptr)
184+
{
185+
m_fnCallbackMatchmakingRequeue();
186+
}
187+
}
188+
189+
std::function<void(int)> m_fnCallbackMatchmakingSetupProgress = nullptr;
190+
void RegisterForMatchmakingSetupProgressCallback(std::function<void(int)> cb)
191+
{
192+
m_fnCallbackMatchmakingSetupProgress = cb;
193+
}
194+
195+
void DeregisterForMatchmakingSetupProgressCallback()
196+
{
197+
m_fnCallbackMatchmakingSetupProgress = nullptr;
198+
}
199+
200+
void InvokeMatchmakingSetupProgressCallback(int timeoutMs)
201+
{
202+
if (m_fnCallbackMatchmakingSetupProgress != nullptr)
203+
{
204+
m_fnCallbackMatchmakingSetupProgress(timeoutMs);
205+
}
206+
}
168207

169208

170209
// updates
@@ -396,6 +435,7 @@ class NGMP_OnlineServices_LobbyInterface
396435
void JoinLobby(LobbyEntry lobby, std::string strPassword);
397436

398437
void LeaveCurrentLobby();
438+
void ResetForMatchmakingRequeue();
399439

400440
void ResetHostMigrationFlags()
401441
{
@@ -471,6 +511,8 @@ class NGMP_OnlineServices_LobbyInterface
471511
#endif
472512

473513
bool m_bAttemptingToJoinLobby = false;
514+
// Invalidates asynchronous callbacks left behind by an abandoned lobby join.
515+
std::atomic<uint64_t> m_LobbyJoinGeneration = 0;
474516
LobbyEntry m_LobbyTryingToJoin;
475517

476518
bool m_bSearchInProgress = false;

GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLQuickMatchMenu.cpp

Lines changed: 33 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -151,8 +151,9 @@ static Int maxPingEntries = 0;
151151
static Int maxPoints= 100;
152152
static Int minPoints = 0;
153153

154-
static Int matchFoundTimeoutStart = 0;
155-
static const Int lobbyTimeoutMs = 10000;
154+
static Int matchFoundTimeoutStart = 0;
155+
static const Int lobbyTimeoutMs = 10000;
156+
static Int matchFoundTimeoutDurationMs = lobbyTimeoutMs;
156157

157158
static const LadderInfo * getLadderInfo();
158159

@@ -1215,19 +1216,35 @@ void WOLQuickMatchMenuInit( WindowLayout *layout, void *userData )
12151216
GadgetListBoxSetItemData(quickmatchTextWindow, (void*)-1, index);
12161217
});
12171218

1218-
pLobbyInterface->RegisterForMatchmakingMatchFoundCallback([]()
1219-
{
1220-
buttonBack->winEnable(FALSE);
1221-
buttonStop->winEnable(FALSE);
1222-
matchFoundTimeoutStart = timeGetTime();
1219+
pLobbyInterface->RegisterForMatchmakingMatchFoundCallback([]()
1220+
{
1221+
buttonBack->winEnable(FALSE);
1222+
buttonStop->winEnable(FALSE);
1223+
matchFoundTimeoutDurationMs = lobbyTimeoutMs;
1224+
matchFoundTimeoutStart = timeGetTime();
12231225
if (TheAudio)
12241226
{
12251227
AudioEventRTS evt("GUICommunicatorOpen");
12261228
TheAudio->addAudioEvent(&evt);
12271229
}
1228-
});
1229-
1230-
pLobbyInterface->RegisterForMatchmakingStartGameCallback([]()
1230+
});
1231+
1232+
pLobbyInterface->RegisterForMatchmakingRequeueCallback([]()
1233+
{
1234+
matchFoundTimeoutStart = 0;
1235+
matchFoundTimeoutDurationMs = lobbyTimeoutMs;
1236+
buttonBack->winEnable(TRUE);
1237+
buttonStop->winEnable(TRUE);
1238+
buttonWiden->winEnable(TRUE);
1239+
});
1240+
1241+
pLobbyInterface->RegisterForMatchmakingSetupProgressCallback([](int timeoutMs)
1242+
{
1243+
matchFoundTimeoutDurationMs = timeoutMs;
1244+
matchFoundTimeoutStart = timeGetTime();
1245+
});
1246+
1247+
pLobbyInterface->RegisterForMatchmakingStartGameCallback([]()
12311248
{
12321249
matchFoundTimeoutStart = 0;
12331250
NetworkLog(ELogVerbosity::LOG_DEBUG, "[QUICKMATCH] GOT START GAME EVENT");
@@ -1448,9 +1465,11 @@ void WOLQuickMatchMenuShutdown( WindowLayout *layout, void *userData )
14481465
NGMP_OnlineServices_LobbyInterface* pLobbyInterface = NGMP_OnlineServicesManager::GetInterface<NGMP_OnlineServices_LobbyInterface>();
14491466
if (pLobbyInterface != nullptr)
14501467
{
1451-
pLobbyInterface->DeregisterForMatchmakingMessageCallback();
1452-
pLobbyInterface->DeRegisterForMatchmakingMatchFoundCallback();
1453-
pLobbyInterface->DeregisterForMatchmakingStartGameCallback();
1468+
pLobbyInterface->DeregisterForMatchmakingMessageCallback();
1469+
pLobbyInterface->DeRegisterForMatchmakingMatchFoundCallback();
1470+
pLobbyInterface->DeregisterForMatchmakingRequeueCallback();
1471+
pLobbyInterface->DeregisterForMatchmakingSetupProgressCallback();
1472+
pLobbyInterface->DeregisterForMatchmakingStartGameCallback();
14541473

14551474
pLobbyInterface->DeregisterForJoinLobbyCallback();
14561475
pLobbyInterface->DeregisterForCannotConnectToLobbyCallback();
@@ -1578,7 +1597,7 @@ void WOLQuickMatchMenuUpdate( WindowLayout * layout, void *userData)
15781597
HandleBuddyResponses();
15791598
#endif
15801599

1581-
if (matchFoundTimeoutStart != 0 && timeGetTime() - matchFoundTimeoutStart >= lobbyTimeoutMs)
1600+
if (matchFoundTimeoutStart != 0 && timeGetTime() - matchFoundTimeoutStart >= matchFoundTimeoutDurationMs)
15821601
{
15831602
matchFoundTimeoutStart = 0;
15841603
buttonBack->winEnable(TRUE);

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

Lines changed: 52 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -794,13 +794,14 @@ void NGMP_OnlineServices_LobbyInterface::UpdateRoomDataCache(std::function<void(
794794
// refresh lobby
795795
if (m_CurrentLobby.lobbyID != -1 && TheNGMPGame != nullptr)
796796
{
797-
std::string strURI = std::format("{}/{}", NGMP_OnlineServicesManager::GetAPIEndpoint("Lobby"), m_CurrentLobby.lobbyID);
797+
const int64_t requestedLobbyID = m_CurrentLobby.lobbyID;
798+
std::string strURI = std::format("{}/{}", NGMP_OnlineServicesManager::GetAPIEndpoint("Lobby"), requestedLobbyID);
798799
std::map<std::string, std::string> mapHeaders;
799800

800801
NGMP_OnlineServicesManager::GetInstance()->GetHTTPManager()->SendGETRequest(strURI.c_str(), EIPProtocolVersion::DONT_CARE, mapHeaders, [=](bool bSuccess, int statusCode, std::string strBody, HTTPRequest* pReq)
801802
{
802803
// safety, lobby could've been torn down by the time we get our response
803-
if (m_CurrentLobby.lobbyID != -1 && TheNGMPGame != nullptr)
804+
if (m_CurrentLobby.lobbyID == requestedLobbyID && TheNGMPGame != nullptr)
804805
{
805806
// TODO_NGMP: Error handling
806807
try
@@ -1057,13 +1058,21 @@ void NGMP_OnlineServices_LobbyInterface::JoinLobby(LobbyEntry lobbyInfo, std::st
10571058
return;
10581059
}
10591060

1061+
const uint64_t lobbyJoinGeneration = ++m_LobbyJoinGeneration;
1062+
10601063
AnticheatPlugInterface::EndSession();
10611064

10621065
m_bAttemptingToJoinLobby = true;
10631066
m_CurrentLobby = LobbyEntry();
10641067

10651068
NGMP_OnlineServicesManager::GetInstance()->GetAndParseServiceConfig([=]()
10661069
{
1070+
NGMP_OnlineServices_LobbyInterface* pLobbyInterface = NGMP_OnlineServicesManager::GetInterface<NGMP_OnlineServices_LobbyInterface>();
1071+
if (pLobbyInterface == nullptr || pLobbyInterface != this || pLobbyInterface->m_LobbyJoinGeneration.load() != lobbyJoinGeneration)
1072+
{
1073+
return;
1074+
}
1075+
10671076
std::string strURI = std::format("{}/{}", NGMP_OnlineServicesManager::GetAPIEndpoint("Lobby"), lobbyInfo.lobbyID);
10681077
std::map<std::string, std::string> mapHeaders;
10691078

@@ -1095,8 +1104,11 @@ void NGMP_OnlineServices_LobbyInterface::JoinLobby(LobbyEntry lobbyInfo, std::st
10951104
// convert
10961105
NGMP_OnlineServicesManager::GetInstance()->GetHTTPManager()->SendPUTRequest(strURI.c_str(), EIPProtocolVersion::DONT_CARE, mapHeaders, strPostData.c_str(), [=](bool bSuccess, int statusCode, std::string strBody, HTTPRequest* pReq)
10971106
{
1098-
if (NGMP_OnlineServicesManager::GetInterface<NGMP_OnlineServices_LobbyInterface>() == nullptr)
1107+
NGMP_OnlineServices_LobbyInterface* pLobbyInterface = NGMP_OnlineServicesManager::GetInterface<NGMP_OnlineServices_LobbyInterface>();
1108+
if (pLobbyInterface == nullptr || pLobbyInterface != this || pLobbyInterface->m_LobbyJoinGeneration.load() != lobbyJoinGeneration)
1109+
{
10991110
return;
1111+
}
11001112

11011113
// reset trying to join
11021114
ResetLobbyTryingToJoin();
@@ -1184,9 +1196,14 @@ void NGMP_OnlineServices_LobbyInterface::JoinLobby(LobbyEntry lobbyInfo, std::st
11841196

11851197
OnJoinedOrCreatedLobby(false, [=](bool bSuccess)
11861198
{
1187-
m_bAttemptingToJoinLobby = false;
11881199
NGMP_OnlineServices_LobbyInterface* pLobbyInterface = NGMP_OnlineServicesManager::GetInterface<NGMP_OnlineServices_LobbyInterface>();
1189-
if (pLobbyInterface != nullptr && pLobbyInterface->m_callbackJoinedLobby != nullptr)
1200+
if (pLobbyInterface == nullptr || pLobbyInterface != this || pLobbyInterface->m_LobbyJoinGeneration.load() != lobbyJoinGeneration)
1201+
{
1202+
return;
1203+
}
1204+
1205+
pLobbyInterface->m_bAttemptingToJoinLobby = false;
1206+
if (pLobbyInterface->m_callbackJoinedLobby != nullptr)
11901207
{
11911208
pLobbyInterface->m_callbackJoinedLobby(bSuccess ? EJoinLobbyResult::JoinLobbyResult_Success : EJoinLobbyResult::JoinLobbyResult_JoinFailed);
11921209
}
@@ -1270,6 +1287,36 @@ void NGMP_OnlineServices_LobbyInterface::LeaveCurrentLobby()
12701287
ResetCachedRoomData();
12711288
}
12721289

1290+
void NGMP_OnlineServices_LobbyInterface::ResetForMatchmakingRequeue()
1291+
{
1292+
// The service has already removed us from the failed temporary lobby. Tear down only
1293+
// local state here; sending the normal DELETE would cancel the server-side requeue.
1294+
++m_LobbyJoinGeneration;
1295+
ResetHostMigrationFlags();
1296+
AnticheatPlugInterface::EndSession();
1297+
1298+
if (m_pLobbyMesh != nullptr)
1299+
{
1300+
m_pLobbyMesh->Disconnect();
1301+
delete m_pLobbyMesh;
1302+
m_pLobbyMesh = nullptr;
1303+
}
1304+
1305+
if (TheNGMPGame != nullptr)
1306+
{
1307+
delete TheNGMPGame;
1308+
TheNGMPGame = nullptr;
1309+
}
1310+
1311+
#if !defined(GENERALS_ONLINE_DISABLE_AUTO_ACCEPT)
1312+
m_timeStartAutoReadyCountdown = -1;
1313+
#endif
1314+
1315+
m_bAttemptingToJoinLobby = false;
1316+
ResetLobbyTryingToJoin();
1317+
ResetCachedRoomData();
1318+
}
1319+
12731320

12741321
LobbyEntry NGMP_OnlineServices_LobbyInterface::GetLobbyFromID(int64_t lobbyID)
12751322
{

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

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -995,6 +995,17 @@ void WebSocket::Tick()
995995

996996
case EWebSocketMessageID::FULL_MESH_CONNECTIVITY_CHECK_RESPONSE:
997997
{
998+
int64_t meshCheckID = 0;
999+
int meshCheckAttempt = 0;
1000+
if (jsonObject.contains("mesh_check_id") && jsonObject["mesh_check_id"].is_number_integer())
1001+
{
1002+
meshCheckID = jsonObject["mesh_check_id"].get<int64_t>();
1003+
}
1004+
if (jsonObject.contains("attempt") && jsonObject["attempt"].is_number_integer())
1005+
{
1006+
meshCheckAttempt = jsonObject["attempt"].get<int>();
1007+
}
1008+
9981009
// respond with our state
9991010
std::vector<int64_t> connectivityMap;
10001011
NetworkMesh* pMesh = nullptr;
@@ -1025,6 +1036,8 @@ void WebSocket::Tick()
10251036
// send response
10261037
nlohmann::json j;
10271038
j["msg_id"] = EWebSocketMessageID::FULL_MESH_CONNECTIVITY_CHECK_RESPONSE;
1039+
j["mesh_check_id"] = meshCheckID;
1040+
j["attempt"] = meshCheckAttempt;
10281041
j["connectivity_map"] = connectivityMap;
10291042
std::string strBody = j.dump();
10301043

@@ -1367,6 +1380,33 @@ void WebSocket::Tick()
13671380
}
13681381
break;
13691382

1383+
case EWebSocketMessageID::MATCHMAKING_ACTION_REQUEUE:
1384+
{
1385+
NGMP_OnlineServices_LobbyInterface* pLobbyInterface = NGMP_OnlineServicesManager::GetInterface<NGMP_OnlineServices_LobbyInterface>();
1386+
if (pLobbyInterface != nullptr)
1387+
{
1388+
pLobbyInterface->ResetForMatchmakingRequeue();
1389+
pLobbyInterface->InvokeMatchmakingRequeueCallback();
1390+
}
1391+
}
1392+
break;
1393+
1394+
case EWebSocketMessageID::MATCHMAKING_ACTION_SETUP_PROGRESS:
1395+
{
1396+
int timeoutMs = 0;
1397+
if (jsonObject.contains("timeout_ms") && jsonObject["timeout_ms"].is_number_integer())
1398+
{
1399+
timeoutMs = jsonObject["timeout_ms"].get<int>();
1400+
}
1401+
1402+
NGMP_OnlineServices_LobbyInterface* pLobbyInterface = NGMP_OnlineServicesManager::GetInterface<NGMP_OnlineServices_LobbyInterface>();
1403+
if (pLobbyInterface != nullptr && timeoutMs > 0)
1404+
{
1405+
pLobbyInterface->InvokeMatchmakingSetupProgressCallback(timeoutMs);
1406+
}
1407+
}
1408+
break;
1409+
13701410
case EWebSocketMessageID::MATCHMAKING_MESSAGE:
13711411
{
13721412
WebSocketMessage_MatchmakingMessage matchmakingMsg;

0 commit comments

Comments
 (0)