1 /*****************************************************************************
2 * Copyright (c) 2014-2020 OpenRCT2 developers
3 *
4 * For a complete list of all authors, please refer to contributors.md
5 * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
6 *
7 * OpenRCT2 is licensed under the GNU General Public License version 3.
8 *****************************************************************************/
9
10 #ifdef __ENABLE_DISCORD__
11
12 # include "DiscordService.h"
13
14 # include "../Context.h"
15 # include "../GameState.h"
16 # include "../OpenRCT2.h"
17 # include "../core/Console.hpp"
18 # include "../core/String.hpp"
19 # include "../localisation/Localisation.h"
20 # include "../world/Park.h"
21 # include "network.h"
22
23 # include <discord_rpc.h>
24
25 constexpr const char* APPLICATION_ID = "378612438200877056";
26 constexpr const char* STEAM_APP_ID = nullptr;
27 constexpr const uint32_t REFRESH_INTERVAL = 5 * GAME_UPDATE_FPS; // 5 seconds
28
OnReady(const DiscordUser * request)29 static void OnReady([[maybe_unused]] const DiscordUser* request)
30 {
31 log_verbose("DiscordService::OnReady()");
32 }
33
OnDisconnected(int errorCode,const char * message)34 static void OnDisconnected(int errorCode, const char* message)
35 {
36 Console::Error::WriteLine("DiscordService::OnDisconnected(%d, %s)", errorCode, message);
37 }
38
OnErrored(int errorCode,const char * message)39 static void OnErrored(int errorCode, const char* message)
40 {
41 Console::Error::WriteLine("DiscordService::OnErrored(%d, %s)", errorCode, message);
42 }
43
DiscordService()44 DiscordService::DiscordService()
45 {
46 DiscordEventHandlers handlers = {};
47 handlers.ready = OnReady;
48 handlers.disconnected = OnDisconnected;
49 handlers.errored = OnErrored;
50 Discord_Initialize(APPLICATION_ID, &handlers, 1, STEAM_APP_ID);
51 }
52
~DiscordService()53 DiscordService::~DiscordService()
54 {
55 Discord_Shutdown();
56 }
57
GetParkName()58 static std::string GetParkName()
59 {
60 auto gameState = OpenRCT2::GetContext()->GetGameState();
61 if (gameState != nullptr)
62 {
63 return gameState->GetPark().Name;
64 }
65 return {};
66 }
67
Update()68 void DiscordService::Update()
69 {
70 Discord_RunCallbacks();
71
72 if (_ticksSinceLastRefresh >= REFRESH_INTERVAL)
73 {
74 _ticksSinceLastRefresh = 0;
75 RefreshPresence();
76 }
77 else
78 {
79 _ticksSinceLastRefresh++;
80 }
81 }
82
RefreshPresence()83 void DiscordService::RefreshPresence()
84 {
85 DiscordRichPresence discordPresence = {};
86 discordPresence.largeImageKey = "logo";
87
88 std::string state;
89 std::string details;
90 switch (gScreenFlags)
91 {
92 default:
93 details = GetParkName();
94 if (network_get_mode() == NETWORK_MODE_NONE)
95 {
96 state = "Playing Solo";
97 }
98 else
99 {
100 state = String::ToStd(network_get_server_name());
101
102 // NOTE: the party size is displayed next to state
103 discordPresence.partyId = network_get_server_name();
104 discordPresence.partySize = network_get_num_players();
105 discordPresence.partyMax = 256;
106
107 // TODO generate secrets for the server
108 discordPresence.matchSecret = nullptr;
109 discordPresence.spectateSecret = nullptr;
110 discordPresence.instance = 1;
111 }
112 break;
113 case SCREEN_FLAGS_TITLE_DEMO:
114 details = "In Menus";
115 break;
116 case SCREEN_FLAGS_SCENARIO_EDITOR:
117 details = "In Scenario Editor";
118 break;
119 case SCREEN_FLAGS_TRACK_DESIGNER:
120 details = "In Track Designer";
121 break;
122 case SCREEN_FLAGS_TRACK_MANAGER:
123 details = "In Track Designs Manager";
124 break;
125 }
126
127 discordPresence.state = state.c_str();
128 discordPresence.details = details.c_str();
129
130 Discord_UpdatePresence(&discordPresence);
131 }
132
133 #endif
134