diff --git a/src/layers/ChatPanel.cpp b/src/layers/ChatPanel.cpp index 9174ded..db6a48a 100755 --- a/src/layers/ChatPanel.cpp +++ b/src/layers/ChatPanel.cpp @@ -18,6 +18,7 @@ void ChatPanel::initialize() { auto& nm = NetworkManager::get(); nm.on([](MessageSentPacket packet) { messages.push_back(packet.message); + showMessageNotification(packet.message); messagesQueue.push_back(std::move(packet.message)); }); @@ -127,6 +128,22 @@ void ChatPanel::updateMessages(float dt) { messagesQueue.clear(); } +void ChatPanel::showMessageNotification(Message const& message) { + auto gm = GameManager::get(); + if (message.author.userID == gm->m_playerUserID.value()) return; + + auto text = message.message; + if (text.size() > 48) { + text = text.substr(0, 45) + "..."; + } + + Notification::create( + fmt::format("{}: {}", message.author.name.empty() ? "Unknown" : message.author.name, text), + NotificationIcon::Info, + 3.f + )->show(); +} + void ChatPanel::clearMessages() { messages.clear(); diff --git a/src/layers/ChatPanel.hpp b/src/layers/ChatPanel.hpp index cd4de96..d39bf45 100755 --- a/src/layers/ChatPanel.hpp +++ b/src/layers/ChatPanel.hpp @@ -21,6 +21,7 @@ class ChatPanel : public geode::Popup { void sendMessage(); void renderMessage(Message const& message); void updateMessages(float dt); + static void showMessageNotification(Message const& message); void keyDown(cocos2d::enumKeyCodes, double) override; public: diff --git a/src/layers/Lobby.cpp b/src/layers/Lobby.cpp index 0f2f0d4..e49357f 100755 --- a/src/layers/Lobby.cpp +++ b/src/layers/Lobby.cpp @@ -8,7 +8,8 @@ #include "LobbySettings.hpp" #include "ChatPanel.hpp" -#include +#include +#include PlayerCell* PlayerCell::create(Account account, float width, bool canKick) { auto ret = new PlayerCell; @@ -27,6 +28,8 @@ PlayerCell* PlayerCell::create(Account account, float width, bool canKick) { bool PlayerCell::init(Account account, float width, bool canKick) { m_account = account; + if (!CCLayer::init()) return false; + this->setContentSize({ width, CELL_HEIGHT @@ -51,15 +54,24 @@ bool PlayerCell::init(Account account, float width, bool canKick) { this->addChild(player); - auto nameLabel = CCLabelBMFont::create(account.name.c_str(), "bigFont.fnt"); + auto nameLabel = CCLabelBMFont::create(account.name.empty() ? "Unknown" : account.name.c_str(), "bigFont.fnt"); nameLabel->limitLabelWidth(225.f, 0.8f, 0.1f); - nameLabel->setPosition({ - 45.f, CELL_HEIGHT / 2.f - }); nameLabel->setAnchorPoint({ 0.f, 0.5f }); nameLabel->ignoreAnchorPointForPosition(false); - this->addChild(nameLabel); + auto nameBtn = CCMenuItemSpriteExtra::create( + nameLabel, + this, + menu_selector(PlayerCell::onOpenProfile) + ); + nameBtn->setAnchorPoint({ 0.f, 0.5f }); + nameBtn->setPosition({ 45.f, CELL_HEIGHT / 2.f }); + auto profileMenu = CCMenu::create(); + profileMenu->setPosition({ 0.f, 0.f }); + profileMenu->setAnchorPoint({ 0.f, 0.f }); + profileMenu->addChild(nameBtn); + + this->addChild(profileMenu); if (canKick && account.userID != GameManager::get()->m_playerUserID.value()) { auto kickSpr = CCSprite::createWithSpriteFrameName("accountBtn_removeFriend_001.png"); @@ -93,6 +105,15 @@ void PlayerCell::onKickUser(CCObject* sender) { ); } +void PlayerCell::onOpenProfile(CCObject*) { + if (m_account.accountID <= 0) { + Notification::create("This player has no valid account ID", NotificationIcon::Warning, 2.f)->show(); + return; + } + + ProfilePage::create(m_account.accountID, false)->show(); +} + LobbyLayer* LobbyLayer::create(std::string code) { auto ret = new LobbyLayer(); if (ret->init(code)) { @@ -273,6 +294,10 @@ LobbyLayer::~LobbyLayer() { } void LobbyLayer::refresh(LobbyInfo info, bool isFirstRefresh) { + if (!mainLayer) return; + + showLobbyDiffNotifications(info); + isOwner = GameManager::get()->m_playerUserID == info.settings.owner.userID; // loadingCircle = LoadingCircle::create(); @@ -283,12 +308,11 @@ void LobbyLayer::refresh(LobbyInfo info, bool isFirstRefresh) { auto size = CCDirector::sharedDirector()->getWinSize(); auto listWidth = size.width / 1.5f; - if (!mainLayer) return; // mainLayer->retain(); - if (isFirstRefresh) { + if (isFirstRefresh || !titleLabel) { titleLabel = CCLabelBMFont::create( - info.settings.name.c_str(), + info.settings.name.empty() ? "Unnamed Lobby" : info.settings.name.c_str(), "bigFont.fnt" ); titleLabel->limitLabelWidth(275.f, 1.f, 0.1f); @@ -313,28 +337,49 @@ void LobbyLayer::refresh(LobbyInfo info, bool isFirstRefresh) { mainLayer->addChild(menu); } + if (!lobbySettingsLabel) { + lobbySettingsLabel = CCLabelBMFont::create("", "goldFont.fnt"); + lobbySettingsLabel->setScale(0.45f); + lobbySettingsLabel->setAnchorPoint({ 0.5f, 0.5f }); + lobbySettingsLabel->setPosition({ size.width / 2, size.height - 47.f }); + mainLayer->addChild(lobbySettingsLabel); + } + if (titleLabel) titleLabel->setString( fmt::format("{} ({})", - info.settings.name, + info.settings.name.empty() ? "Unnamed Lobby" : info.settings.name, Mod::get()->getSettingValue("hide-code") ? "......" : info.code ).c_str() ); - if (!playerList && !isFirstRefresh) return; - if (playerList) playerList->removeFromParent(); + if (lobbySettingsLabel) { + lobbySettingsLabel->setString( + fmt::format( + "{} turns • {} min/turn", + info.settings.turns, + info.settings.minutesPerTurn + ).c_str() + ); + } + + if (playerList) { + playerList->removeFromParentAndCleanup(true); + playerList = nullptr; + } using namespace geode::utils; playerListItems = CCArray::create(); for (auto acc : info.accounts) { - playerListItems->addObject( - PlayerCell::create( + if (auto cell = PlayerCell::create( acc, listWidth, isOwner - ) - ); + )) { + playerListItems->addObject(cell); + } } playerList = ListView::create(playerListItems, PlayerCell::CELL_HEIGHT, listWidth); + if (!playerList) return; playerList->setPosition({ size.width / 2, size.height / 2 - 10.f }); playerList->setAnchorPoint({ 0.5f, 0.5f }); playerList->ignoreAnchorPointForPosition(false); @@ -343,25 +388,62 @@ void LobbyLayer::refresh(LobbyInfo info, bool isFirstRefresh) { mainLayer->addChild(playerList); - if (!mainLayer->getChildByIDRecursive("list-bg")) { - auto listBG = CCLayerColor::create({ 0, 0, 0, 85 }); + auto listBG = typeinfo_cast(mainLayer->getChildByIDRecursive("list-bg")); + if (!listBG) { + listBG = CCLayerColor::create({ 0, 0, 0, 85 }); listBG->ignoreAnchorPointForPosition(false); listBG->setAnchorPoint({ 0.5f, 0.5f }); - listBG->setPosition( - playerList->getPosition() - ); listBG->setZOrder(-1); listBG->setID("list-bg"); - listBG->setContentSize(playerList->getContentSize()); mainLayer->addChild(listBG); } + listBG->setPosition(playerList->getPosition()); + listBG->setContentSize(playerList->getContentSize()); - settingsBtn->setVisible(isOwner); - startBtn->setVisible(isOwner); + if (settingsBtn) settingsBtn->setVisible(isOwner); + if (startBtn) startBtn->setVisible(isOwner); // loadingCircle->fadeAndRemove(); } +void LobbyLayer::showLobbyDiffNotifications(LobbyInfo const& info) { + std::vector currentUserIDs; + std::unordered_map currentNamesByUserID; + + for (auto const& account : info.accounts) { + if (account.userID <= 0) continue; + + currentUserIDs.push_back(account.userID); + currentNamesByUserID[account.userID] = account.name.empty() ? "Unknown" : account.name; + } + + if (hasSeenLobbySnapshot) { + for (auto userID : currentUserIDs) { + if (std::find(knownLobbyUserIDs.begin(), knownLobbyUserIDs.end(), userID) == knownLobbyUserIDs.end()) { + Notification::create( + fmt::format("{} joined the lobby", currentNamesByUserID[userID]), + NotificationIcon::Success, + 2.f + )->show(); + } + } + + for (auto userID : knownLobbyUserIDs) { + if (std::find(currentUserIDs.begin(), currentUserIDs.end(), userID) == currentUserIDs.end()) { + Notification::create( + fmt::format("{} left the lobby", knownLobbyNames.contains(userID) ? knownLobbyNames[userID] : "A player"), + NotificationIcon::Info, + 2.f + )->show(); + } + } + } + + knownLobbyUserIDs = std::move(currentUserIDs); + knownLobbyNames = std::move(currentNamesByUserID); + hasSeenLobbySnapshot = true; +} + void LobbyLayer::onStart(CCObject* sender) { if (!isOwner) return; diff --git a/src/layers/Lobby.hpp b/src/layers/Lobby.hpp index 254c9f4..b75f84a 100755 --- a/src/layers/Lobby.hpp +++ b/src/layers/Lobby.hpp @@ -1,5 +1,7 @@ #include +#include #include +#include #include @@ -11,6 +13,7 @@ class CR_DLL PlayerCell : public CCLayer { bool init(Account account, float width, bool canKick); void onKickUser(CCObject*); + void onOpenProfile(CCObject*); public: static constexpr int CELL_HEIGHT = 50.f; static PlayerCell* create(Account account, float width, bool canKick); @@ -23,23 +26,29 @@ class CR_DLL LobbyLayer : public CCLayer { std::string lobbyNspace; - CCMenuItemSpriteExtra* closeBtn; - CCSprite* background; + CCMenuItemSpriteExtra* closeBtn = nullptr; + CCSprite* background = nullptr; - CCArray* playerListItems; - CustomListView* playerList; + CCArray* playerListItems = nullptr; + CustomListView* playerList = nullptr; - CCLabelBMFont* titleLabel; + CCLabelBMFont* titleLabel = nullptr; + CCLabelBMFont* lobbySettingsLabel = nullptr; - CCMenuItemSpriteExtra* settingsBtn; - CCMenuItemSpriteExtra* startBtn; + CCMenuItemSpriteExtra* settingsBtn = nullptr; + CCMenuItemSpriteExtra* startBtn = nullptr; - LoadingCircle* loadingCircle; - CCNode* mainLayer; + LoadingCircle* loadingCircle = nullptr; + CCNode* mainLayer = nullptr; + + std::vector knownLobbyUserIDs = {}; + std::unordered_map knownLobbyNames = {}; + bool hasSeenLobbySnapshot = false; bool init(std::string code); void keyBackClicked(); void createBorders(); + void showLobbyDiffNotifications(LobbyInfo const& info); void refresh(LobbyInfo info, bool isFirstRefresh = false); @@ -55,3 +64,5 @@ class CR_DLL LobbyLayer : public CCLayer { static LobbyLayer* create(std::string code); }; + + diff --git a/src/layers/LobbySelectPopup.cpp b/src/layers/LobbySelectPopup.cpp index 2c58d28..10f7ca2 100755 --- a/src/layers/LobbySelectPopup.cpp +++ b/src/layers/LobbySelectPopup.cpp @@ -38,6 +38,16 @@ class LobbyItem : public CCLayer { }); authorLabel->setScale(0.5f); + auto settingsLabel = CCLabelBMFont::create( + fmt::format("{} turns • {} min/turn", lobby.settings.turns, lobby.settings.minutesPerTurn).c_str(), + "chatFont.fnt" + ); + settingsLabel->setPosition({ 10.f, 7.f }); + settingsLabel->setAnchorPoint({ + 0.f, 0.5f + }); + settingsLabel->setScale(0.45f); + auto joinSpr = ButtonSprite::create( "Join", "bigFont.fnt", @@ -64,6 +74,7 @@ class LobbyItem : public CCLayer { this->addChild(nameLabel); this->addChild(authorLabel); + this->addChild(settingsLabel); this->addChild(joinMenu); this->setContentSize({ width, CELL_HEIGHT }); @@ -71,7 +82,7 @@ class LobbyItem : public CCLayer { return true; } public: - static constexpr float CELL_HEIGHT = 40.f; + static constexpr float CELL_HEIGHT = 48.f; static LobbyItem* create(float width, LobbyInfo lobby, std::function callback) { auto ret = new LobbyItem;