diff --git a/distribution/changelog.txt b/distribution/changelog.txt
index 81e8b15d5b..24a1e7245d 100644
--- a/distribution/changelog.txt
+++ b/distribution/changelog.txt
@@ -19,6 +19,7 @@
- Feature: [#6433] Turn 'unlock all prices' into a regular (non-cheat, persistent) option.
- Feature: [#6530] Land rights tool no longer blocks when a tile is not for purchase.
- Feature: [#6568] Add smooth nearest neighbour scaling.
+- Feature: [#6651] Integrate Discord Rich Presence.
- Feature: Allow using object files from RCT Classic.
- Feature: Title sequences now testable in-game.
- Fix: [#816] In the map window, there are more peeps flickering than there are selected (original bug).
diff --git a/openrct2.proj b/openrct2.proj
index 50b38a049c..cd345a6d56 100644
--- a/openrct2.proj
+++ b/openrct2.proj
@@ -21,7 +21,7 @@
0.1.2
-$(GIT_BRANCH)-$(GIT_COMMIT_SHA1_SHORT)
- 13
+ 14
/D "OPENRCT2_BUILD_SERVER=\"$(BUILD_SERVER)\"" $(OPENRCT2_CL_ADDITIONALOPTIONS)
@@ -63,7 +63,7 @@
$(RootDir).dependencies
https://github.com/OpenRCT2/Dependencies/releases/download/v$(TargetLibsVersion)/openrct2-libs-vs2017.zip
- 00d4eaf3ed7653a1abf82df0c255338fa0d6f9b0
+ f9bee9fa8ae8c5f12ca3c603ef2aa3fc179e48fc
1.8.0
https://github.com/google/googletest/archive/release-1.8.0.zip
667f873ab7a4d246062565fad32fb6d8e203ee73
diff --git a/src/openrct2/Context.cpp b/src/openrct2/Context.cpp
index 64987cdbe1..bc98f21de3 100644
--- a/src/openrct2/Context.cpp
+++ b/src/openrct2/Context.cpp
@@ -59,6 +59,7 @@
#include "intro.h"
#include "localisation/date.h"
#include "localisation/language.h"
+#include "network/DiscordService.h"
#include "network/http.h"
#include "network/network.h"
#include "network/twitch.h"
@@ -87,6 +88,9 @@ namespace OpenRCT2
IObjectManager * _objectManager = nullptr;
ITrackDesignRepository * _trackDesignRepository = nullptr;
IScenarioRepository * _scenarioRepository = nullptr;
+#ifdef __ENABLE_DISCORD__
+ DiscordService * _discordService = nullptr;
+#endif
// Game states
TitleScreen * _titleScreen = nullptr;
@@ -133,6 +137,9 @@ namespace OpenRCT2
delete _titleScreen;
+#ifdef __ENABLE_DISCORD__
+ delete _discordService;
+#endif
delete _scenarioRepository;
delete _trackDesignRepository;
delete _objectManager;
@@ -298,6 +305,9 @@ namespace OpenRCT2
_objectManager = CreateObjectManager(_objectRepository);
_trackDesignRepository = CreateTrackDesignRepository(_env);
_scenarioRepository = CreateScenarioRepository(_env);
+#ifdef __ENABLE_DISCORD__
+ _discordService = new DiscordService();
+#endif
if (!language_open(gConfigGeneral.language))
{
@@ -771,6 +781,13 @@ namespace OpenRCT2
game_update();
}
+#ifdef __ENABLE_DISCORD__
+ if (_discordService != nullptr)
+ {
+ _discordService->Update();
+ }
+#endif
+
twitch_update();
chat_update();
console_update();
diff --git a/src/openrct2/libopenrct2.vcxproj b/src/openrct2/libopenrct2.vcxproj
index b883a94b2d..e53bc9f93c 100644
--- a/src/openrct2/libopenrct2.vcxproj
+++ b/src/openrct2/libopenrct2.vcxproj
@@ -32,7 +32,7 @@
- __ENABLE_LIGHTFX__;%(PreprocessorDefinitions)
+ __ENABLE_DISCORD__;__ENABLE_LIGHTFX__;%(PreprocessorDefinitions)
USE_BREAKPAD;%(PreprocessorDefinitions)
diff --git a/src/openrct2/network/DiscordService.cpp b/src/openrct2/network/DiscordService.cpp
new file mode 100644
index 0000000000..41c8dac808
--- /dev/null
+++ b/src/openrct2/network/DiscordService.cpp
@@ -0,0 +1,134 @@
+#pragma region Copyright (c) 2014-2017 OpenRCT2 Developers
+/*****************************************************************************
+* OpenRCT2, an open source clone of Roller Coaster Tycoon 2.
+*
+* OpenRCT2 is the work of many authors, a full list can be found in contributors.md
+* For more information, visit https://github.com/OpenRCT2/OpenRCT2
+*
+* OpenRCT2 is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* A full copy of the GNU General Public License can be found in licence.txt
+*****************************************************************************/
+#pragma endregion
+
+#ifdef __ENABLE_DISCORD__
+
+#include
+#include "../Context.h"
+#include "../core/Console.hpp"
+#include "../core/String.hpp"
+#include "../localisation/localisation.h"
+#include "../OpenRCT2.h"
+#include "../world/park.h"
+#include "DiscordService.h"
+#include "network.h"
+
+constexpr const char * APPLICATION_ID = "378612438200877056";
+constexpr const char * STEAM_APP_ID = nullptr;
+constexpr const uint32 REFRESH_INTERVAL = 5 * GAME_UPDATE_FPS; // 5 seconds
+
+static void OnReady()
+{
+ log_verbose("DiscordService::OnReady()");
+}
+
+static void OnDisconnected(int errorCode, const char * message)
+{
+ Console::Error::WriteLine("DiscordService::OnDisconnected(%d, %s)", errorCode, message);
+}
+
+static void OnErrored(int errorCode, const char * message)
+{
+ Console::Error::WriteLine("DiscordService::OnErrored(%d, %s)", errorCode, message);
+}
+
+DiscordService::DiscordService()
+{
+ DiscordEventHandlers handlers = {};
+ handlers.ready = OnReady;
+ handlers.disconnected = OnDisconnected;
+ handlers.errored = OnErrored;
+ Discord_Initialize(APPLICATION_ID, &handlers, 1, STEAM_APP_ID);
+}
+
+DiscordService::~DiscordService()
+{
+ Discord_Shutdown();
+}
+
+static std::string GetParkName()
+{
+ utf8 parkName[128] = {};
+ format_string(parkName, sizeof(parkName), gParkName, &gParkNameArgs);
+ return std::string(parkName);
+}
+
+void DiscordService::Update()
+{
+ Discord_RunCallbacks();
+
+ if (_ticksSinceLastRefresh >= REFRESH_INTERVAL)
+ {
+ _ticksSinceLastRefresh = 0;
+ RefreshPresence();
+ }
+ else
+ {
+ _ticksSinceLastRefresh++;
+ }
+}
+
+void DiscordService::RefreshPresence()
+{
+ DiscordRichPresence discordPresence = {};
+ discordPresence.largeImageKey = "logo";
+
+ std::string state;
+ std::string details;
+ switch (gScreenFlags)
+ {
+ default:
+ details = GetParkName();
+ if (network_get_mode() == NETWORK_MODE_NONE)
+ {
+ state = "Playing Solo";
+ }
+ else
+ {
+ state = String::ToStd(network_get_server_name());
+
+ // NOTE: the party size is displayed next to state
+ discordPresence.partyId = network_get_server_name();
+ discordPresence.partySize = network_get_num_players();
+ discordPresence.partyMax = 256;
+
+ // TODO generate secrets for the server
+ discordPresence.matchSecret = nullptr;
+ discordPresence.spectateSecret = nullptr;
+ discordPresence.instance = 1;
+ }
+ break;
+ case SCREEN_FLAGS_TITLE_DEMO:
+ details = "In Menus";
+ break;
+ case SCREEN_FLAGS_SCENARIO_EDITOR:
+ details = "In Scenario Editor";
+ break;
+ case SCREEN_FLAGS_TRACK_DESIGNER:
+ details = "In Track Designer";
+ break;
+ case SCREEN_FLAGS_TRACK_MANAGER:
+ details = "In Track Designs Manager";
+ break;
+ }
+
+ discordPresence.state = state.c_str();
+ discordPresence.details = details.c_str();
+
+ Discord_UpdatePresence(&discordPresence);
+}
+
+#endif
diff --git a/src/openrct2/network/DiscordService.h b/src/openrct2/network/DiscordService.h
new file mode 100644
index 0000000000..96b127836b
--- /dev/null
+++ b/src/openrct2/network/DiscordService.h
@@ -0,0 +1,39 @@
+#pragma region Copyright (c) 2014-2017 OpenRCT2 Developers
+/*****************************************************************************
+* OpenRCT2, an open source clone of Roller Coaster Tycoon 2.
+*
+* OpenRCT2 is the work of many authors, a full list can be found in contributors.md
+* For more information, visit https://github.com/OpenRCT2/OpenRCT2
+*
+* OpenRCT2 is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* A full copy of the GNU General Public License can be found in licence.txt
+*****************************************************************************/
+#pragma endregion
+
+#pragma once
+
+#ifdef __ENABLE_DISCORD__
+
+#include "../common.h"
+#include
+
+class DiscordService final
+{
+private:
+ uint32 _ticksSinceLastRefresh = std::numeric_limits::max();
+
+public:
+ DiscordService();
+ ~DiscordService();
+
+ void Update();
+
+private:
+ void RefreshPresence();
+};
+
+#endif