From 20de634a06c0053aad4b1a0017cae4ed023b6e94 Mon Sep 17 00:00:00 2001 From: Kae <80987908+Novaenia@users.noreply.github.com> Date: Sat, 3 Aug 2024 18:51:19 +1000 Subject: [PATCH] Improve Discord activity info requested by Omeruin! --- .../StarP2PNetworkingService_pc.cpp | 24 ++++-- .../StarP2PNetworkingService_pc.hpp | 4 +- source/client/StarClientApplication.cpp | 76 +++++++++++++++++-- source/client/StarClientApplication.hpp | 1 + source/core/StarText.cpp | 2 + source/game/StarRootLoader.cpp | 4 + source/platform/StarP2PNetworkingService.hpp | 2 +- 7 files changed, 99 insertions(+), 14 deletions(-) diff --git a/source/application/StarP2PNetworkingService_pc.cpp b/source/application/StarP2PNetworkingService_pc.cpp index 2d20415..0e13dee 100644 --- a/source/application/StarP2PNetworkingService_pc.cpp +++ b/source/application/StarP2PNetworkingService_pc.cpp @@ -81,7 +81,11 @@ void PcP2PNetworkingService::setJoinRemote(HostAddressWithPort location) { setJoinLocation(JoinRemote(location)); } -void Star::PcP2PNetworkingService::setActivityData([[maybe_unused]] String const& title, [[maybe_unused]] Maybe> party) { +void Star::PcP2PNetworkingService::setActivityData( + [[maybe_unused]] const char* title, + [[maybe_unused]] const char* details, + [[maybe_unused]] int64_t startTime, + [[maybe_unused]] Maybe> party) { #ifdef STAR_ENABLE_DISCORD_INTEGRATION MutexLocker discordLocker(m_state->discordMutex); #endif @@ -92,19 +96,25 @@ void Star::PcP2PNetworkingService::setActivityData([[maybe_unused]] String const if (m_discordUpdatingActivity) return; - if (title != m_discordActivityTitle || party != m_discordPartySize || m_discordForceUpdateActivity) { + if (title != m_discordActivityTitle + || details != m_discordActivityDetails + || startTime != m_discordActivityStartTime || party != m_discordPartySize || m_discordForceUpdateActivity) { m_discordForceUpdateActivity = false; m_discordPartySize = party; m_discordActivityTitle = title; + m_discordActivityDetails = details; + m_discordActivityStartTime = startTime; discord::Activity activity = {}; activity.SetType(discord::ActivityType::Playing); activity.SetName("Starbound"); - activity.SetState(title.utf8Ptr()); - - if (auto p = party) { - activity.GetParty().GetSize().SetCurrentSize(p->first); - activity.GetParty().GetSize().SetMaxSize(p->second); + activity.SetState(title); + activity.SetDetails(details); + activity.GetTimestamps().SetStart(startTime); + if (party) { + auto& size = activity.GetParty().GetSize(); + size.SetCurrentSize(party->first); + size.SetMaxSize(party->second); } if (auto lobby = m_discordServerLobby) diff --git a/source/application/StarP2PNetworkingService_pc.hpp b/source/application/StarP2PNetworkingService_pc.hpp index 20fbefb..293b6bf 100644 --- a/source/application/StarP2PNetworkingService_pc.hpp +++ b/source/application/StarP2PNetworkingService_pc.hpp @@ -18,7 +18,7 @@ public: void setJoinUnavailable() override; void setJoinLocal(uint32_t capacity) override; void setJoinRemote(HostAddressWithPort location) override; - void setActivityData(String const& title, Maybe>) override; + void setActivityData(const char* title, const char* details, int64_t startTime, Maybe>) override; MVariant pullPendingJoin() override; Maybe>> pullJoinRequest() override; @@ -125,6 +125,8 @@ private: HashMap m_discordOpenSockets; String m_discordActivityTitle; + String m_discordActivityDetails; + int64_t m_discordActivityStartTime = 0; Maybe> m_discordPartySize; bool m_discordForceUpdateActivity = false; bool m_discordUpdatingActivity = false; diff --git a/source/client/StarClientApplication.cpp b/source/client/StarClientApplication.cpp index b3460c1..7faf7ec 100644 --- a/source/client/StarClientApplication.cpp +++ b/source/client/StarClientApplication.cpp @@ -584,6 +584,7 @@ void ClientApplication::changeState(MainAppState newState) { m_mainMixer->setUniverseClient(m_universeClient); m_universeClient->setMainPlayer(m_player); m_cinematicOverlay->setPlayer(m_player); + m_timeSinceJoin = (int64_t)Time::millisecondsSinceEpoch() / 1000; auto assets = m_root->assets(); String loadingCinematic = assets->json("/client.config:loadingCinematic").toString(); @@ -748,8 +749,36 @@ void ClientApplication::updateTitle(float dt) { appController()->setAcceptingTextInput(m_titleScreen->textInputActive()); auto p2pNetworkingService = appController()->p2pNetworkingService(); - if (p2pNetworkingService) - p2pNetworkingService->setActivityData("In Main Menu", {}); + if (p2pNetworkingService) { + auto getStateString = [](TitleState state) -> const char* { + switch (state) { + case TitleState::Main: + return "In Main Menu"; + case TitleState::Options: + return "In Options"; + case TitleState::Mods: + return "In Mods"; + case TitleState::SinglePlayerSelectCharacter: + return "Selecting a character for singleplayer"; + case TitleState::SinglePlayerCreateCharacter: + return "Creating a character for singleplayer"; + case TitleState::MultiPlayerSelectCharacter: + return "Selecting a character for multiplayer"; + case TitleState::MultiPlayerCreateCharacter: + return "Creating a character for multiplayer"; + case TitleState::MultiPlayerConnect: + return "Awaiting multiplayer connection info"; + case TitleState::StartSinglePlayer: + return "Loading Singleplayer"; + case TitleState::StartMultiPlayer: + return "Connecting to Multiplayer"; + default: + return ""; + } + }; + + p2pNetworkingService->setActivityData("Not In Game", getStateString(m_titleScreen->currentState()), 0, {}); + } if (m_titleScreen->currentState() == TitleState::StartSinglePlayer) { changeState(MainAppState::SinglePlayer); @@ -791,6 +820,7 @@ void ClientApplication::updateTitle(float dt) { void ClientApplication::updateRunning(float dt) { try { + auto worldClient = m_universeClient->worldClient(); auto p2pNetworkingService = appController()->p2pNetworkingService(); bool clientIPJoinable = m_root->configuration()->get("clientIPJoinable").toBool(); bool clientP2PJoinable = m_root->configuration()->get("clientP2PJoinable").toBool(); @@ -817,8 +847,44 @@ void ClientApplication::updateRunning(float dt) { } } - if (p2pNetworkingService) - p2pNetworkingService->setActivityData("In Game", party); + if (p2pNetworkingService) { + auto getActivityDetail = [&](String const& tag) -> String { + if (tag == "playerName") + return Text::stripEscapeCodes(m_player->name()); + if (tag == "playerHealth") + return strf("{}/{} HP", m_player->health(), m_player->maxHealth()); + if (tag == "playerEnergy") + return strf("{}/{} HP", m_player->energy(), m_player->maxEnergy()); + if (tag == "playerBreath") + return strf("{}/{} HP", m_player->breath(), m_player->maxBreath()); + if (tag == "worldName") { + if (m_universeClient->clientContext()->playerWorldId().is()) + return "Player Ship"; + else if (WorldTemplate const* worldTemplate = worldClient ? worldClient->currentTemplate().get() : nullptr) { + auto worldName = worldTemplate->worldName(); + if (worldName.empty()) + return "In World"; + else + return Text::stripEscapeCodes(worldName); + } + else + return "Nowhere"; + } + return ""; + }; + + String finalDetails = ""; + Json activityDetails = m_root->configuration()->getPath("discord.activityDetails"); + if (activityDetails.isType(Json::Type::Array)) { + StringList detailsList; + for (auto& detail : activityDetails.iterateArray()) + detailsList.append(getActivityDetail(*detail.stringPtr())); + finalDetails = detailsList.join("\n"); + } else if (activityDetails.isType(Json::Type::String)) + finalDetails = activityDetails.toString().lookupTags(getActivityDetail); + + p2pNetworkingService->setActivityData("In Game", finalDetails.utf8Ptr(), m_timeSinceJoin, party); + } if (!m_mainInterface->inputFocus() && !m_cinematicOverlay->suppressInput()) { m_player->setShifting(isActionTaken(InterfaceAction::PlayerShifting)); @@ -932,7 +998,7 @@ void ClientApplication::updateRunning(float dt) { if (checkDisconnection()) return; - if (auto worldClient = m_universeClient->worldClient()) { + if (worldClient) { m_worldPainter->update(dt); auto& broadcastCallback = worldClient->broadcastCallback(); if (!broadcastCallback) { diff --git a/source/client/StarClientApplication.hpp b/source/client/StarClientApplication.hpp index f0eacb0..58abb9d 100644 --- a/source/client/StarClientApplication.hpp +++ b/source/client/StarClientApplication.hpp @@ -121,6 +121,7 @@ private: Maybe m_pendingMultiPlayerConnection; Maybe m_currentRemoteJoin; + int64_t m_timeSinceJoin = 0; }; } diff --git a/source/core/StarText.cpp b/source/core/StarText.cpp index d507fd4..749fd90 100644 --- a/source/core/StarText.cpp +++ b/source/core/StarText.cpp @@ -36,6 +36,8 @@ namespace Text { static auto stripEscapeRegex = std::regex(strf("\\{:c}[^;]*{:c}", CmdEsc, EndEsc)); String stripEscapeCodes(String const& s) { + if (s.empty()) + return s; return std::regex_replace(s.utf8(), stripEscapeRegex, ""); } diff --git a/source/game/StarRootLoader.cpp b/source/game/StarRootLoader.cpp index 1643791..b2be4e9 100644 --- a/source/game/StarRootLoader.cpp +++ b/source/game/StarRootLoader.cpp @@ -99,6 +99,10 @@ R"JSON( "inventory" : { "pickupToActionBar" : true + }, + + "discord" : { + "activityDetails" : " | " } } )JSON"); diff --git a/source/platform/StarP2PNetworkingService.hpp b/source/platform/StarP2PNetworkingService.hpp index 288902c..134e1b1 100644 --- a/source/platform/StarP2PNetworkingService.hpp +++ b/source/platform/StarP2PNetworkingService.hpp @@ -44,7 +44,7 @@ public: // P2P friends can join this player at the given remote server virtual void setJoinRemote(HostAddressWithPort location) = 0; // Updates rich presence activity info - virtual void setActivityData(String const& title, Maybe>) = 0; + virtual void setActivityData(const char* title, const char* details, int64_t startTime, Maybe>) = 0; // If this player joins another peer's game using the P2P UI, this will return // a pending join location