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