Improve Discord activity info

requested by Omeruin!
This commit is contained in:
Kae 2024-08-03 18:51:19 +10:00
parent bef86811c9
commit 20de634a06
7 changed files with 99 additions and 14 deletions

View File

@ -81,7 +81,11 @@ void PcP2PNetworkingService::setJoinRemote(HostAddressWithPort location) {
setJoinLocation(JoinRemote(location));
}
void Star::PcP2PNetworkingService::setActivityData([[maybe_unused]] String const& title, [[maybe_unused]] Maybe<pair<uint16_t, uint16_t>> party) {
void Star::PcP2PNetworkingService::setActivityData(
[[maybe_unused]] const char* title,
[[maybe_unused]] const char* details,
[[maybe_unused]] int64_t startTime,
[[maybe_unused]] Maybe<pair<uint16_t, uint16_t>> 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)

View File

@ -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<pair<uint16_t, uint16_t>>) override;
void setActivityData(const char* title, const char* details, int64_t startTime, Maybe<pair<uint16_t, uint16_t>>) override;
MVariant<P2PNetworkingPeerId, HostAddressWithPort> pullPendingJoin() override;
Maybe<pair<String, RpcPromiseKeeper<P2PJoinRequestReply>>> pullJoinRequest() override;
@ -125,6 +125,8 @@ private:
HashMap<discord::UserId, DiscordP2PSocket*> m_discordOpenSockets;
String m_discordActivityTitle;
String m_discordActivityDetails;
int64_t m_discordActivityStartTime = 0;
Maybe<pair<uint16_t, uint16_t>> m_discordPartySize;
bool m_discordForceUpdateActivity = false;
bool m_discordUpdatingActivity = false;

View File

@ -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<ClientShipWorldId>())
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) {

View File

@ -121,6 +121,7 @@ private:
Maybe<PendingMultiPlayerConnection> m_pendingMultiPlayerConnection;
Maybe<HostAddressWithPort> m_currentRemoteJoin;
int64_t m_timeSinceJoin = 0;
};
}

View File

@ -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, "");
}

View File

@ -99,6 +99,10 @@ R"JSON(
"inventory" : {
"pickupToActionBar" : true
},
"discord" : {
"activityDetails" : "<playerName> | <worldName>"
}
}
)JSON");

View File

@ -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<pair<uint16_t, uint16_t>>) = 0;
virtual void setActivityData(const char* title, const char* details, int64_t startTime, Maybe<pair<uint16_t, uint16_t>>) = 0;
// If this player joins another peer's game using the P2P UI, this will return
// a pending join location