diff --git a/client/globalLobby/GlobalLobbyClient.cpp b/client/globalLobby/GlobalLobbyClient.cpp index ecdb3c5fc..60fde94f2 100644 --- a/client/globalLobby/GlobalLobbyClient.cpp +++ b/client/globalLobby/GlobalLobbyClient.cpp @@ -285,13 +285,15 @@ void GlobalLobbyClient::receiveInviteReceived(const JsonNode & json) auto lobbyWindowPtr = lobbyWindow.lock(); std::string gameRoomID = json["gameRoomID"].String(); std::string accountID = json["accountID"].String(); + + activeInvites.insert(gameRoomID); if(lobbyWindowPtr) { std::string message = MetaString::createFromTextID("vcmi.lobby.invite.notification").toString(); std::string time = getCurrentTimeFormatted(); lobbyWindowPtr->onGameChatMessage("System", message, time, "player", accountID); - lobbyWindowPtr->onInviteReceived(gameRoomID, accountID); + lobbyWindowPtr->onInviteReceived(gameRoomID); } CCS->soundh->playSound(AudioPath::builtin("CHAT")); @@ -299,8 +301,6 @@ void GlobalLobbyClient::receiveInviteReceived(const JsonNode & json) void GlobalLobbyClient::receiveJoinRoomSuccess(const JsonNode & json) { - currentGameRoomUUID = json["gameRoomID"].String(); - if (json["proxyMode"].Bool()) { CSH->resetStateForLobby(EStartMode::NEW_GAME, ESelectionScreen::newGame, EServerMode::LOBBY_GUEST, {}); @@ -310,6 +310,9 @@ void GlobalLobbyClient::receiveJoinRoomSuccess(const JsonNode & json) int16_t port = settings["lobby"]["port"].Integer(); CSH->connectToServer(hostname, port); } + + // NOTE: must be set after CSH->resetStateForLobby call + currentGameRoomUUID = json["gameRoomID"].String(); } void GlobalLobbyClient::onConnectionEstablished(const std::shared_ptr & connection) @@ -500,7 +503,7 @@ void GlobalLobbyClient::sendProxyConnectionLogin(const NetworkConnectionPtr & ne toSend["type"].String() = "clientProxyLogin"; toSend["accountID"] = settings["lobby"]["accountID"]; toSend["accountCookie"] = settings["lobby"]["accountCookie"]; - toSend["gameRoomID"] = settings["session"]["lobby"]["roomID"]; + toSend["gameRoomID"].String() = currentGameRoomUUID; assert(JsonUtils::validate(toSend, "vcmi:lobbyProtocol/" + toSend["type"].String(), toSend["type"].String() + " pack")); netConnection->sendPacket(toSend.toBytes()); @@ -527,3 +530,8 @@ void GlobalLobbyClient::sendMatchChatMessage(const std::string & messageText) CSH->getGlobalLobby().sendMessage(toSend); } + +bool GlobalLobbyClient::isInvitedToRoom(const std::string & gameRoomID) +{ + return activeInvites.count(gameRoomID) > 0; +} diff --git a/client/globalLobby/GlobalLobbyClient.h b/client/globalLobby/GlobalLobbyClient.h index ac11614e4..4a6d4450e 100644 --- a/client/globalLobby/GlobalLobbyClient.h +++ b/client/globalLobby/GlobalLobbyClient.h @@ -24,6 +24,7 @@ class GlobalLobbyClient final : public INetworkClientListener, boost::noncopyabl std::vector activeAccounts; std::vector activeRooms; std::vector activeChannels; + std::set activeInvites; std::vector matchesHistory; /// Contains known history of each channel @@ -82,4 +83,5 @@ public: void connect(); bool isConnected() const; + bool isInvitedToRoom(const std::string & gameRoomID); }; diff --git a/client/globalLobby/GlobalLobbyWidget.cpp b/client/globalLobby/GlobalLobbyWidget.cpp index 2c236f936..1b28d1d59 100644 --- a/client/globalLobby/GlobalLobbyWidget.cpp +++ b/client/globalLobby/GlobalLobbyWidget.cpp @@ -217,23 +217,35 @@ GlobalLobbyRoomCard::GlobalLobbyRoomCard(GlobalLobbyWindow * window, const Globa window->doJoinRoom(roomID); }; + bool publicRoom = roomDescription.statusID == "public"; + bool hasInvite = CSH->getGlobalLobby().isInvitedToRoom(roomDescription.gameRoomID); + bool canJoin = publicRoom || hasInvite; + auto roomSizeText = MetaString::createFromRawString("%d/%d"); roomSizeText.replaceNumber(roomDescription.participants.size()); roomSizeText.replaceNumber(roomDescription.playerLimit); - auto roomStatusText = MetaString::createFromTextID("vcmi.lobby.room.state." + roomDescription.statusID); + MetaString roomStatusText; + if (roomDescription.statusID == "private" && hasInvite) + roomStatusText.appendTextID("vcmi.lobby.room.state.invited"); + else + roomStatusText.appendTextID("vcmi.lobby.room.state." + roomDescription.statusID); pos.w = 230; pos.h = 40; - backgroundOverlay = std::make_shared(Rect(0, 0, pos.w, pos.h), ColorRGBA(0, 0, 0, 128), ColorRGBA(64, 64, 64, 64)); + if (window->isInviteUnread(roomDescription.gameRoomID)) + backgroundOverlay = std::make_shared(Rect(0, 0, pos.w, pos.h), ColorRGBA(0, 0, 0, 128), Colors::WHITE, 1); + else + backgroundOverlay = std::make_shared(Rect(0, 0, pos.w, pos.h), ColorRGBA(0, 0, 0, 128), ColorRGBA(64, 64, 64, 64), 1); + labelName = std::make_shared(5, 10, FONT_SMALL, ETextAlignment::CENTERLEFT, Colors::WHITE, roomDescription.hostAccountDisplayName); labelDescription = std::make_shared(5, 30, FONT_SMALL, ETextAlignment::CENTERLEFT, Colors::YELLOW, roomDescription.description); labelRoomSize = std::make_shared(178, 10, FONT_SMALL, ETextAlignment::CENTERRIGHT, Colors::YELLOW, roomSizeText.toString()); labelRoomStatus = std::make_shared(190, 30, FONT_SMALL, ETextAlignment::CENTERRIGHT, Colors::YELLOW, roomStatusText.toString()); iconRoomSize = std::make_shared(ImagePath::builtin("lobby/iconPlayer"), Point(180, 5)); - if(!CSH->inGame() && roomDescription.statusID == "public") + if(!CSH->inGame() && canJoin) { buttonJoin = std::make_shared(Point(194, 4), AnimationPath::builtin("lobbyJoinRoom"), CButton::tooltip(), onJoinClicked); buttonJoin->setOverlay(std::make_shared(ImagePath::builtin("lobby/iconEnter"))); diff --git a/client/globalLobby/GlobalLobbyWindow.cpp b/client/globalLobby/GlobalLobbyWindow.cpp index 65632dbfe..b10f73ab8 100644 --- a/client/globalLobby/GlobalLobbyWindow.cpp +++ b/client/globalLobby/GlobalLobbyWindow.cpp @@ -101,6 +101,8 @@ void GlobalLobbyWindow::doInviteAccount(const std::string & accountID) void GlobalLobbyWindow::doJoinRoom(const std::string & roomID) { + unreadInvites.erase(roomID); + JsonNode toSend; toSend["type"].String() = "joinGameRoom"; toSend["gameRoomID"].String() = roomID; @@ -172,11 +174,17 @@ void GlobalLobbyWindow::onMatchesHistory(const std::vector & hi widget->getMatchListHeader()->setText(text.toString()); } -void GlobalLobbyWindow::onInviteReceived(const std::string & invitedRoomID, const std::string & invitedByAccountID) +void GlobalLobbyWindow::onInviteReceived(const std::string & invitedRoomID) { + unreadInvites.insert(invitedRoomID); widget->getRoomList()->reset(); } +bool GlobalLobbyWindow::isInviteUnread(const std::string & gameRoomID) +{ + return unreadInvites.count(gameRoomID) > 0; +} + void GlobalLobbyWindow::onJoinedRoom() { widget->getAccountList()->reset(); diff --git a/client/globalLobby/GlobalLobbyWindow.h b/client/globalLobby/GlobalLobbyWindow.h index c013edb47..17c0cbbef 100644 --- a/client/globalLobby/GlobalLobbyWindow.h +++ b/client/globalLobby/GlobalLobbyWindow.h @@ -23,6 +23,7 @@ class GlobalLobbyWindow : public CWindowObject std::shared_ptr widget; std::set unreadChannels; + std::set unreadInvites; public: GlobalLobbyWindow(); @@ -38,6 +39,7 @@ public: /// Returns true if provided chat channel is the one that is currently open in UI bool isChannelOpen(const std::string & channelType, const std::string & channelName); bool isChannelUnread(const std::string & channelType, const std::string & channelName); + bool isInviteUnread(const std::string & gameRoomID); // Callbacks for network packs @@ -45,7 +47,7 @@ public: void onActiveAccounts(const std::vector & accounts); void onActiveRooms(const std::vector & rooms); void onMatchesHistory(const std::vector & history); - void onInviteReceived(const std::string & invitedRoomID, const std::string & invitedByAccountID); + void onInviteReceived(const std::string & invitedRoomID); void onJoinedRoom(); void onLeftRoom(); }; diff --git a/config/schemas/lobbyProtocol/clientProxyLogin.json b/config/schemas/lobbyProtocol/clientProxyLogin.json index 5b4d5d05b..8bc8f93f9 100644 --- a/config/schemas/lobbyProtocol/clientProxyLogin.json +++ b/config/schemas/lobbyProtocol/clientProxyLogin.json @@ -10,7 +10,7 @@ "type" : { "type" : "string", - "const" : "clientLogin" + "const" : "clientProxyLogin" }, "accountID" : {