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