Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Core/GameEngine/Include/GameNetwork/GameSpy/LobbyUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,5 @@ enum LobbyGameModeFilter CPP_11(: Int)
LOBBY_FILTER_TEAM,
LOBBY_FILTER_FFA,
LOBBY_FILTER_AOD,
LOBBY_FILTER_BUDDIES,
};
86 changes: 60 additions & 26 deletions Core/GameEngine/Source/GameNetwork/GameSpy/LobbyUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,45 +110,50 @@ static GameWindow *windowSortBuddies = nullptr;

static GameSortType theGameSortType = GAMESORT_MAP_ASCENDING; // was ping
static Bool sortBuddies = TRUE;

// The .wnd supplies the ascending arrow as the enabled image and the descending arrow as the disabled image.
static void showSortArrow(GameWindow *window, Bool ascending)
{
if (window == nullptr)
return;

window->winHide(FALSE);
window->winEnable(ascending);
}

static void showSortIcons()
{
if (windowSortAlpha && windowSortPing)
{
switch (theGameSortType)
{
case GAMESORT_AGE_ASCENDING: // was alpha
windowSortAlpha->winHide(FALSE);
windowSortAlpha->winEnable(TRUE);
showSortArrow(windowSortAlpha, TRUE);
windowSortPing->winHide(TRUE);
break;
case GAMESORT_AGE_DESCENDING: // was alpha
windowSortAlpha->winHide(FALSE);
windowSortAlpha->winEnable(FALSE);
showSortArrow(windowSortAlpha, FALSE);
windowSortPing->winHide(TRUE);
break;
case GAMESORT_MAP_ASCENDING: // was ping
windowSortPing->winHide(FALSE);
windowSortPing->winEnable(TRUE);
showSortArrow(windowSortPing, TRUE);
windowSortAlpha->winHide(TRUE);
break;
case GAMESORT_MAP_DESCENDING: // was ping
windowSortPing->winHide(FALSE);
windowSortPing->winEnable(FALSE);
showSortArrow(windowSortPing, FALSE);
windowSortAlpha->winHide(TRUE);
break;
}
}

if (sortBuddies)
if (windowSortBuddies)
{
if (windowSortBuddies)
if (sortBuddies)
{
windowSortBuddies->winHide(FALSE);
// true sorts before false.
showSortArrow(windowSortBuddies, FALSE);
}
}
else
{
if (windowSortBuddies)
else
{
windowSortBuddies->winHide(TRUE);
}
Expand Down Expand Up @@ -596,6 +601,19 @@ typedef std::set<GameSpyStagingRoom*> BuddyGameSet;
#endif

static BuddyGameSet *theBuddyGames = nullptr;

#if defined(GENERALS_ONLINE)
static Bool lobbyHasBuddy(int64_t lobbyID)
{
return theBuddyGames != nullptr && theBuddyGames->count(lobbyID) != 0;
}
#else
static Bool lobbyHasBuddy(GameSpyStagingRoom *room)
{
return theBuddyGames->find(room) != theBuddyGames->end();
}
#endif

#if defined(GENERALS_ONLINE)
static void populateBuddyGames(std::vector<LobbyEntry>& vecLobbies)
#else
Expand All @@ -611,18 +629,25 @@ static void populateBuddyGames(void)
return;
}

for (LobbyEntry& lobby : vecLobbies)
// Snapshot once, the map is rebuilt on the HTTP thread and every lobby must be tested against the same list.
const auto mapFriends = pSocialInterface->GetCachedFriendsList();
if (mapFriends.empty())
{
return;
}

for (const LobbyEntry& lobby : vecLobbies)
{
// is host our friend?
if (pSocialInterface->IsUserFriend(lobby.owner))
if (mapFriends.contains(lobby.owner))
{
theBuddyGames->insert(lobby.lobbyID);
}
else // does the lobby contain any of our friends
{
for (auto member : lobby.members)
for (const LobbyMemberEntry& member : lobby.members)
{
if (pSocialInterface->IsUserFriend(member.user_id))
if (mapFriends.contains(member.user_id))
{
theBuddyGames->insert(lobby.lobbyID);
break; // its binary, we don't care how many friends
Expand Down Expand Up @@ -678,8 +703,8 @@ struct GameSortStruct

if (sortBuddies)
{
const bool g1Buddy = (theBuddyGames && theBuddyGames->count(g1.lobbyID));
const bool g2Buddy = (theBuddyGames && theBuddyGames->count(g2.lobbyID));
const Bool g1Buddy = lobbyHasBuddy(g1.lobbyID);
const Bool g2Buddy = lobbyHasBuddy(g2.lobbyID);

if (g1Buddy != g2Buddy)
return g1Buddy && !g2Buddy;
Expand Down Expand Up @@ -751,8 +776,8 @@ struct GameSortStruct

if (sortBuddies)
{
Bool g1HasBuddies = (theBuddyGames->find(g1) != theBuddyGames->end());
Bool g2HasBuddies = (theBuddyGames->find(g2) != theBuddyGames->end());
Bool g1HasBuddies = lobbyHasBuddy(g1);
Bool g2HasBuddies = lobbyHasBuddy(g2);
if ( g1HasBuddies ^ g2HasBuddies )
{
return g1HasBuddies;
Expand Down Expand Up @@ -788,7 +813,7 @@ static Int insertGame(GameWindow* win, LobbyEntry& lobbyInfo, Bool showMap)
}
#if defined(GENERALS_ONLINE)
// Buddy lobby highlight:
if (theBuddyGames && theBuddyGames->count(lobbyInfo.lobbyID))
if (lobbyHasBuddy(lobbyInfo.lobbyID))
{
const bool nonJoinable =
(gameColor == GameSpyColor[GSCOLOR_GAME_CRCMISMATCH]);
Expand Down Expand Up @@ -1187,28 +1212,35 @@ void RefreshGameListBox(GameWindow* win, Bool showMap)
{
win->winEnable(true);

populateBuddyGames(vecLobbies);

// filter lobbies by game mode
if (theLobbyFilter != LOBBY_FILTER_ALL)
{
std::vector<LobbyEntry> filtered;
filtered.reserve(vecLobbies.size());
for (Int i = 0; i < (Int)vecLobbies.size(); ++i)
{
if (detectGameMode(vecLobbies[i].name) == theLobbyFilter)
const Bool matchesFilter = (theLobbyFilter == LOBBY_FILTER_BUDDIES)
? lobbyHasBuddy(vecLobbies[i].lobbyID)
: (detectGameMode(vecLobbies[i].name) == theLobbyFilter);

if (matchesFilter)
filtered.push_back(vecLobbies[i]);
}
vecLobbies = filtered;
if (vecLobbies.empty())
{
GadgetListBoxAddEntryText(win, UnicodeString(L"No lobbies currently match this filter"), GameMakeColor(255, 194, 15, 255), -1, -1);
GadgetListBoxSetSelected(win, -1);
clearBuddyGames();
return;
}
}

// sort our games
typedef std::multiset<LobbyEntry, GameSortStruct> SortedGameList;
SortedGameList sgl;
populateBuddyGames(vecLobbies);
for (LobbyEntry& lobby : vecLobbies)
{
sgl.insert(lobby);
Expand All @@ -1231,6 +1263,8 @@ void RefreshGameListBox(GameWindow* win, Bool showMap)
++i;
}

clearBuddyGames();

// restore selection
GadgetListBoxSetSelected(win, indexToSelect); // even for -1, so we can disable the 'Join Game' button
// if(prevPos > 10)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ class WebSocket
void SendData_RoomChatMessage(UnicodeString& msg, bool bIsAction);
void SendData_FriendMessage(UnicodeString& msg, int64_t target_user_id);
void SendData_LobbyChatMessage(UnicodeString& msg, bool bIsAction, bool bIsAnnouncement, bool bShowAnnouncementToHost);
void SendData_JoinNetworkRoom(int roomID);
void SendData_JoinNetworkRoom(int roomID, uint64_t requestID = 0);
void SendData_LeaveNetworkRoom();
void SendData_MarkReady(bool bReady);

Expand Down Expand Up @@ -230,11 +230,12 @@ enum class ERoomFlags : int
class NetworkRoom
{
public:
NetworkRoom(int roomID, std::string strRoomName, ERoomFlags roomFlags)
NetworkRoom(int roomID, std::string strRoomName, ERoomFlags roomFlags, int parentRoomID = -1)
{
m_RoomID = roomID;
m_strRoomDisplayName.translate(AsciiString(strRoomName.c_str()));
m_RoomFlags = roomFlags;
m_ParentRoomID = parentRoomID;
}

~NetworkRoom()
Expand All @@ -243,13 +244,15 @@ class NetworkRoom
}

int GetRoomID() const { return m_RoomID; }
UnicodeString GetRoomDisplayName() const { return m_strRoomDisplayName; }
const UnicodeString& GetRoomDisplayName() const { return m_strRoomDisplayName; }
ERoomFlags GetRoomFlags() const { return m_RoomFlags; }
int GetParentRoomID() const { return m_ParentRoomID; }

private:
int m_RoomID;
UnicodeString m_strRoomDisplayName;
ERoomFlags m_RoomFlags = ERoomFlags::ROOM_FLAGS_DEFAULT;
int m_ParentRoomID = -1;
};

struct RegionResponse
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
#include "OnlineServices_Init.h"
#include "Common/MultiplayerSettings.h"

#include <chrono>
#include <optional>

extern NGMPGame* TheNGMPGame;

enum class EChatMessageType
Expand Down Expand Up @@ -98,18 +101,32 @@ class NetworkRoomMember : public NetworkMemberBase
bool IsValid() const { return user_id != -1; }
};

struct RoomSelectionResult
{
std::optional<uint64_t> requestID;
std::optional<int> selectedRoomID;
std::optional<int> effectiveRoomID;
std::optional<int> rejectedRoomID;
std::string error;
};

class NGMP_OnlineServices_RoomsInterface
{
public:
NGMP_OnlineServices_RoomsInterface();

void GetRoomList(std::function<void(void)> cb);
void GetRoomList(std::function<void(bool)> cb);

std::function<void()> m_PendingRoomJoinCompleteCallback = nullptr;
void JoinRoom(int roomIndex, std::function<void()> onStartCallback, std::function<void()> onCompleteCallback);
void JoinRoom(int roomIndex);

void LeaveRoom()
{
m_CurrentRoomIndex = -1;
m_EffectiveRoomID.reset();
m_PendingRoomChange.reset();
m_bRoomSelectionResultsSupported = false;
m_vecRooms.clear();

std::shared_ptr<WebSocket> pWS = NGMP_OnlineServicesManager::GetWebSocket();
if (pWS != nullptr)
{
Expand Down Expand Up @@ -142,6 +159,16 @@ class NGMP_OnlineServices_RoomsInterface
m_RosterNeedsRefreshCallback = nullptr;
}

void RegisterForRoomChangedCallback(std::function<void(int, bool)> cb)
{
m_RoomChangedCallback = std::move(cb);
}

void DeregisterForRoomChangedCallback()
{
m_RoomChangedCallback = nullptr;
}

NetworkRoomMember* GetRoomMemberFromIndex(int index)
{
if (m_mapMembers.size() > index)
Expand Down Expand Up @@ -180,23 +207,30 @@ class NGMP_OnlineServices_RoomsInterface
}
}

void Tick()
{
void Tick();

}
const std::vector<NetworkRoom>& GetGroupRooms() const { return m_vecRooms; }

std::vector<NetworkRoom> GetGroupRooms()
{
return m_vecRooms;
}

void OnRosterUpdated(std::unordered_map<uint64_t, NetworkRoomMember> mapMembers);

int GetCurrentRoomID() const { return m_CurrentRoomID; }
void OnRosterUpdated(std::unordered_map<uint64_t, NetworkRoomMember> mapMembers, const RoomSelectionResult& selectionResult);

int GetCurrentRoomIndex() const { return m_CurrentRoomIndex; }

private:
int m_CurrentRoomID = -1;
struct PendingRoomChange
{
int roomIndex;
int roomID;
uint64_t requestID;
std::chrono::steady_clock::time_point deadline;
};

int m_CurrentRoomIndex = -1;
std::optional<int> m_EffectiveRoomID;
std::optional<PendingRoomChange> m_PendingRoomChange;
uint64_t m_NextRoomChangeRequestID = 1;
bool m_bRoomSelectionResultsSupported = false;
std::function<void(int, bool)> m_RoomChangedCallback = nullptr;
void ReportRoomJoinFailure(const std::string& error);

std::vector<NetworkRoom> m_vecRooms;

Expand Down
Loading
Loading