From c2026dc254a81e7c11fbff48230ca57fe979e3d8 Mon Sep 17 00:00:00 2001 From: teinarss Date: Wed, 25 Mar 2020 19:44:14 +0100 Subject: [PATCH] Add Discord Rich Presence --- AUTHORS | 6 + Makefile | 4 +- OpenRA.Game/Manifest.cs | 12 +- OpenRA.Game/ModData.cs | 2 + OpenRA.Mods.Common/DiscordService.cs | 201 ++++++++++++++++++ OpenRA.Mods.Common/OpenRA.Mods.Common.csproj | 1 + .../Widgets/Logic/Lobby/LobbyLogic.cs | 50 +++++ .../Widgets/Logic/MainMenuLogic.cs | 6 + .../Widgets/Logic/MissionBrowserLogic.cs | 3 + .../Widgets/Logic/MultiplayerLogic.cs | 2 + .../Widgets/Logic/ReplayBrowserLogic.cs | 3 + mods/all/mod.yaml | 3 + mods/cnc/mod.yaml | 3 + mods/d2k/mod.yaml | 3 + mods/ra/mod.yaml | 3 + mods/ts/mod.yaml | 3 + packaging/linux/buildpackage.sh | 9 +- packaging/linux/openra.desktop.in | 2 +- packaging/macos/buildpackage.sh | 10 +- packaging/windows/OpenRA.nsi | 27 +++ 20 files changed, 342 insertions(+), 11 deletions(-) create mode 100644 OpenRA.Mods.Common/DiscordService.cs diff --git a/AUTHORS b/AUTHORS index aee8fcc5f1..a9b79e4a99 100644 --- a/AUTHORS +++ b/AUTHORS @@ -180,6 +180,12 @@ Krueger and distributed under the GNU GPL terms. Using rix0rrr.BeaconLib developed by Rico Huijbers distributed under MIT License. +Using DiscordRichPresence developed by Lachee +distributed under MIT License. + +Using Json.NET developed by James Newton-King +distributed under MIT License. + This site or product includes IP2Location LITE data available from http://www.ip2location.com. diff --git a/Makefile b/Makefile index 4f8d442251..e91280634d 100644 --- a/Makefile +++ b/Makefile @@ -39,7 +39,7 @@ WHITELISTED_OPENRA_ASSEMBLIES = OpenRA.Game.exe OpenRA.Utility.exe OpenRA.Platforms.Default.dll OpenRA.Mods.Common.dll OpenRA.Mods.Cnc.dll OpenRA.Mods.D2k.dll OpenRA.Game.dll # These are explicitly shipped alongside our core files by the packaging script -WHITELISTED_THIRDPARTY_ASSEMBLIES = ICSharpCode.SharpZipLib.dll FuzzyLogicLibrary.dll Eluant.dll BeaconLib.dll Open.Nat.dll SDL2-CS.dll OpenAL-CS.Core.dll +WHITELISTED_THIRDPARTY_ASSEMBLIES = ICSharpCode.SharpZipLib.dll FuzzyLogicLibrary.dll Eluant.dll BeaconLib.dll Open.Nat.dll SDL2-CS.dll OpenAL-CS.Core.dll DiscordRPC.dll Newtonsoft.Json.dll # These are shipped in our custom minimal mono runtime and also available in the full system-installed .NET/mono stack # This list *must* be kept in sync with the files packaged by the AppImageSupport and OpenRALauncherOSX repositories @@ -210,6 +210,8 @@ endif @$(INSTALL_PROGRAM) FuzzyLogicLibrary.dll "$(DATA_INSTALL_DIR)" @$(INSTALL_PROGRAM) Open.Nat.dll "$(DATA_INSTALL_DIR)" @$(INSTALL_PROGRAM) BeaconLib.dll "$(DATA_INSTALL_DIR)" + @$(INSTALL_PROGRAM) DiscordRPC.dll "$(DATA_INSTALL_DIR)" + @$(INSTALL_PROGRAM) Newtonsoft.Json.dll "$(DATA_INSTALL_DIR)" install-common-mod-files: @-echo "Installing OpenRA common mod files to $(DATA_INSTALL_DIR)" diff --git a/OpenRA.Game/Manifest.cs b/OpenRA.Game/Manifest.cs index 611c467269..fc1ed2b4ca 100644 --- a/OpenRA.Game/Manifest.cs +++ b/OpenRA.Game/Manifest.cs @@ -52,7 +52,7 @@ namespace OpenRA } /// Describes what is to be loaded in order to run a mod. - public class Manifest + public class Manifest : IDisposable { public readonly string Id; public readonly IReadOnlyPackage Package; @@ -241,5 +241,15 @@ namespace OpenRA return (T)module; } + + public void Dispose() + { + foreach (var module in modules) + { + var disposableModule = module as IDisposable; + if (disposableModule != null) + disposableModule.Dispose(); + } + } } } diff --git a/OpenRA.Game/ModData.cs b/OpenRA.Game/ModData.cs index 92bf09d475..35090ebbd4 100644 --- a/OpenRA.Game/ModData.cs +++ b/OpenRA.Game/ModData.cs @@ -208,6 +208,8 @@ namespace OpenRA if (ObjectCreator != null) ObjectCreator.Dispose(); + + Manifest.Dispose(); } } diff --git a/OpenRA.Mods.Common/DiscordService.cs b/OpenRA.Mods.Common/DiscordService.cs new file mode 100644 index 0000000000..5e78c8be66 --- /dev/null +++ b/OpenRA.Mods.Common/DiscordService.cs @@ -0,0 +1,201 @@ +#region Copyright & License Information +/* + * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you 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. For more + * information, see COPYING. + */ +#endregion + +using System; +using DiscordRPC; +using DiscordRPC.Message; +using OpenRA.Network; + +namespace OpenRA.Mods.Common +{ + public enum DiscordState + { + Unknown, + InMenu, + InMapEditor, + InSkirmishLobby, + InMultiplayerLobby, + PlayingMultiplayer, + WatchingReplay, + PlayingCampaign, + PlayingSkirmish + } + + public sealed class DiscordService : IGlobalModData, IDisposable + { + public readonly string ApplicationId = null; + readonly DiscordRpcClient client; + DiscordState currentState; + + static readonly Lazy Service = Exts.Lazy(() => + { + if (!Game.ModData.Manifest.Contains()) + return null; + + return Game.ModData.Manifest.Get(); + }); + + public DiscordService(MiniYaml yaml) + { + FieldLoader.Load(this, yaml); + + // HACK: Prevent service from starting when launching the utility or server. + if (Game.Renderer == null) + return; + + client = new DiscordRpcClient(ApplicationId, autoEvents: true) + { + SkipIdenticalPresence = false + }; + + client.OnJoin += OnJoin; + client.OnJoinRequested += OnJoinRequested; + + // HACK: We need to set HasRegisteredUriScheme to bypass the check that is done when calling SetPresence with a joinSecret. + // DiscordRpc lib expect us to register uri handlers with RegisterUriScheme(), we are doing it ourselves in our installers/launchers. + client.GetType().GetProperty("HasRegisteredUriScheme").SetValue(client, true); + + client.SetSubscription(EventType.Join | EventType.JoinRequest); + client.Initialize(); + } + + void OnJoinRequested(object sender, JoinRequestMessage args) + { + var client = (DiscordRpcClient)sender; + client.Respond(args, true); + } + + void OnJoin(object sender, JoinMessage args) + { + if (currentState != DiscordState.InMenu) + return; + + var server = args.Secret.Split('|'); + Game.RunAfterTick(() => + { + Game.RemoteDirectConnect(new ConnectionTarget(server[0], int.Parse(server[1]))); + }); + } + + void SetStatus(DiscordState state, string details = null, string secret = null, int? players = null, int? slots = null) + { + if (currentState == state) + return; + + if (Service.Value == null) + return; + + string stateText; + DateTime? timestamp = null; + Party party = null; + Secrets secrets = null; + + switch (state) + { + case DiscordState.InMenu: + stateText = "In menu"; + break; + case DiscordState.InMapEditor: + stateText = "In Map Editor"; + break; + case DiscordState.InSkirmishLobby: + stateText = "In Skirmish Lobby"; + break; + case DiscordState.InMultiplayerLobby: + stateText = "In Multiplayer Lobby"; + timestamp = DateTime.UtcNow; + party = new Party + { + ID = Secrets.CreateFriendlySecret(new Random()), + Size = players.Value, + Max = slots.Value + }; + secrets = new Secrets + { + JoinSecret = secret + }; + break; + case DiscordState.PlayingMultiplayer: + stateText = "Playing Multiplayer"; + timestamp = DateTime.UtcNow; + break; + case DiscordState.PlayingCampaign: + stateText = "Playing Campaign"; + timestamp = DateTime.UtcNow; + break; + case DiscordState.WatchingReplay: + stateText = "Watching Replay"; + timestamp = DateTime.UtcNow; + break; + case DiscordState.PlayingSkirmish: + stateText = "Playing Skirmish"; + timestamp = DateTime.UtcNow; + break; + default: + throw new ArgumentOutOfRangeException("state", state, null); + } + + var richPresence = new RichPresence + { + Details = details, + State = stateText, + Assets = new Assets + { + LargeImageKey = "large", + LargeImageText = Game.ModData.Manifest.Metadata.Title, + }, + Timestamps = timestamp.HasValue ? new Timestamps(timestamp.Value) : null, + Party = party, + Secrets = secrets + }; + + client.SetPresence(richPresence); + currentState = state; + } + + public void Dispose() + { + if (client != null) + client.Dispose(); + } + + public static void UpdateStatus(DiscordState state, string details = null, string secret = null, int? players = null, int? slots = null) + { + if (Service.Value != null) + Service.Value.SetStatus(state, details, secret, players, slots); + } + + public static void SetPlayers(int players, int slots) + { + if (Service.Value != null) + { + Service.Value.client.UpdateParty(new Party + { + ID = Secrets.CreateFriendlySecret(new Random()), + Size = players, + Max = slots + }); + } + } + + public static void UpdatePlayers(int players, int slots) + { + if (Service.Value != null) + Service.Value.client.UpdatePartySize(players, slots); + } + + public static void UpdateDetails(string details) + { + if (Service.Value != null) + Service.Value.client.UpdateDetails(details); + } + } +} diff --git a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj index ced131ea4e..ca73d91a97 100644 --- a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj +++ b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj @@ -25,6 +25,7 @@ False + diff --git a/OpenRA.Mods.Common/Widgets/Logic/Lobby/LobbyLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/Lobby/LobbyLogic.cs index 0957bfa0f5..0896a4af7c 100644 --- a/OpenRA.Mods.Common/Widgets/Logic/Lobby/LobbyLogic.cs +++ b/OpenRA.Mods.Common/Widgets/Logic/Lobby/LobbyLogic.cs @@ -61,6 +61,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic bool addBotOnMapLoad; bool disableTeamChat; bool teamChat; + bool updateDiscordStatus = true; readonly string chatLineSound = ChromeMetrics.Get("ChatLineSound"); @@ -116,6 +117,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic orderManager.AddChatLine += AddChatLine; Game.LobbyInfoChanged += UpdateCurrentMap; Game.LobbyInfoChanged += UpdatePlayerList; + Game.LobbyInfoChanged += UpdateDiscordStatus; Game.BeforeGameStart += OnGameStart; Game.ConnectionStateChanged += ConnectionStateChanged; @@ -462,6 +464,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic orderManager.AddChatLine -= AddChatLine; Game.LobbyInfoChanged -= UpdateCurrentMap; Game.LobbyInfoChanged -= UpdatePlayerList; + Game.LobbyInfoChanged -= UpdateDiscordStatus; Game.BeforeGameStart -= OnGameStart; Game.ConnectionStateChanged -= ConnectionStateChanged; } @@ -743,9 +746,56 @@ namespace OpenRA.Mods.Common.Widgets.Logic tabCompletion.Names = orderManager.LobbyInfo.Clients.Select(c => c.Name).Distinct().ToList(); } + void UpdateDiscordStatus() + { + var mapTitle = map.Title; + var numberOfPlayers = 0; + var slots = 0; + + if (!skirmishMode) + { + foreach (var kv in orderManager.LobbyInfo.Slots) + { + if (kv.Value.Closed) + continue; + + slots++; + var client = orderManager.LobbyInfo.ClientInSlot(kv.Key); + + if (client != null) + numberOfPlayers++; + } + } + + if (updateDiscordStatus) + { + string secret = null; + if (orderManager.LobbyInfo.GlobalSettings.Dedicated) + { + var endpoint = orderManager.Endpoint.GetConnectEndPoints().First(); + secret = string.Concat(endpoint.Address, "|", endpoint.Port); + } + + var state = skirmishMode ? DiscordState.InSkirmishLobby : DiscordState.InMultiplayerLobby; + DiscordService.UpdateStatus(state, mapTitle, secret, numberOfPlayers, slots); + + updateDiscordStatus = false; + } + else + { + if (!skirmishMode) + DiscordService.UpdatePlayers(numberOfPlayers, slots); + DiscordService.UpdateDetails(mapTitle); + } + } + void OnGameStart() { Ui.CloseWindow(); + + var state = skirmishMode ? DiscordState.PlayingSkirmish : DiscordState.PlayingMultiplayer; + DiscordService.UpdateStatus(state); + onStart(); } } diff --git a/OpenRA.Mods.Common/Widgets/Logic/MainMenuLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/MainMenuLogic.cs index 39ff958223..946d658970 100644 --- a/OpenRA.Mods.Common/Widgets/Logic/MainMenuLogic.cs +++ b/OpenRA.Mods.Common/Widgets/Logic/MainMenuLogic.cs @@ -46,6 +46,8 @@ namespace OpenRA.Mods.Common.Widgets.Logic { menuType = type; + DiscordService.UpdateStatus(DiscordState.InMenu); + // Update button mouseover Game.RunAfterTick(Ui.ResetTooltips); } @@ -258,6 +260,8 @@ namespace OpenRA.Mods.Common.Widgets.Logic onIntroductionComplete(); Game.OnShellmapLoaded += OpenMenuBasedOnLastGame; + + DiscordService.UpdateStatus(DiscordState.InMenu); } void LoadAndDisplayNews(string newsURL, Widget newsBG) @@ -317,6 +321,8 @@ namespace OpenRA.Mods.Common.Widgets.Logic () => { Game.LoadEditor(uid); }, () => { Game.CloseServer(); SwitchMenu(MenuType.MapEditor); }); + DiscordService.UpdateStatus(DiscordState.InMapEditor); + lastGameState = MenuPanel.MapEditor; } diff --git a/OpenRA.Mods.Common/Widgets/Logic/MissionBrowserLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/MissionBrowserLogic.cs index 0a255fb324..a7140fa95b 100644 --- a/OpenRA.Mods.Common/Widgets/Logic/MissionBrowserLogic.cs +++ b/OpenRA.Mods.Common/Widgets/Logic/MissionBrowserLogic.cs @@ -164,6 +164,9 @@ namespace OpenRA.Mods.Common.Widgets.Logic void OnGameStart() { Ui.CloseWindow(); + + DiscordService.UpdateStatus(DiscordState.PlayingCampaign); + onStart(); } diff --git a/OpenRA.Mods.Common/Widgets/Logic/MultiplayerLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/MultiplayerLogic.cs index 1999281f2e..da403446a5 100644 --- a/OpenRA.Mods.Common/Widgets/Logic/MultiplayerLogic.cs +++ b/OpenRA.Mods.Common/Widgets/Logic/MultiplayerLogic.cs @@ -95,6 +95,8 @@ namespace OpenRA.Mods.Common.Widgets.Logic }); Game.Disconnect(); + + DiscordService.UpdateStatus(DiscordState.InMenu); }; Game.OpenWindow("SERVER_LOBBY", new WidgetArgs diff --git a/OpenRA.Mods.Common/Widgets/Logic/ReplayBrowserLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/ReplayBrowserLogic.cs index da5ee14d49..dceb1ff605 100644 --- a/OpenRA.Mods.Common/Widgets/Logic/ReplayBrowserLogic.cs +++ b/OpenRA.Mods.Common/Widgets/Logic/ReplayBrowserLogic.cs @@ -688,6 +688,9 @@ namespace OpenRA.Mods.Common.Widgets.Logic if (selectedReplay != null && ReplayUtils.PromptConfirmReplayCompatibility(selectedReplay)) { cancelLoadingReplays = true; + + DiscordService.UpdateStatus(DiscordState.WatchingReplay); + Game.JoinReplay(selectedReplay.FilePath); } } diff --git a/mods/all/mod.yaml b/mods/all/mod.yaml index 47b3e269a0..c2f9d0ef58 100644 --- a/mods/all/mod.yaml +++ b/mods/all/mod.yaml @@ -32,3 +32,6 @@ SpriteFormats: SpriteSequenceFormat: DefaultSpriteSequence ModelSequenceFormat: PlaceholderModelSequence + +DiscordService: + ApplicationId: 699222659766026240 diff --git a/mods/cnc/mod.yaml b/mods/cnc/mod.yaml index 59ed129dd8..a8c5062db0 100644 --- a/mods/cnc/mod.yaml +++ b/mods/cnc/mod.yaml @@ -288,3 +288,6 @@ ModContent: cnc|installer/gdi95.yaml cnc|installer/nod95.yaml cnc|installer/origin.yaml + +DiscordService: + ApplicationId: 699223250181292033 diff --git a/mods/d2k/mod.yaml b/mods/d2k/mod.yaml index cd1128d0e4..bb3feb3e69 100644 --- a/mods/d2k/mod.yaml +++ b/mods/d2k/mod.yaml @@ -264,3 +264,6 @@ ModContent: d2k|installer/d2k-e.yaml d2k|installer/downloads.yaml d2k|installer/gruntmods.yaml + +DiscordService: + ApplicationId: 712711732770111550 diff --git a/mods/ra/mod.yaml b/mods/ra/mod.yaml index 0531773526..a772bda763 100644 --- a/mods/ra/mod.yaml +++ b/mods/ra/mod.yaml @@ -305,3 +305,6 @@ ModContent: ra|installer/firstdecade.yaml ra|installer/origin.yaml ra|installer/soviet95.yaml + +DiscordService: + ApplicationId: 699222659766026240 diff --git a/mods/ts/mod.yaml b/mods/ts/mod.yaml index dfb45f200d..259c4a8cd4 100644 --- a/mods/ts/mod.yaml +++ b/mods/ts/mod.yaml @@ -323,3 +323,6 @@ ModContent: ts|installer/firstdecade.yaml ts|installer/origin.yaml ts|installer/tibsun.yaml + +DiscordService: + ApplicationId: 712713986558394399 diff --git a/packaging/linux/buildpackage.sh b/packaging/linux/buildpackage.sh index 6ef8c32729..3a8d00fcaf 100755 --- a/packaging/linux/buildpackage.sh +++ b/packaging/linux/buildpackage.sh @@ -93,6 +93,7 @@ rm -rf libs mono.tar.bz2 build_appimage() { MOD_ID=${1} DISPLAY_NAME=${2} + DISCORD_ID=${3} APPDIR="$(pwd)/${MOD_ID}.appdir" APPIMAGE="OpenRA-$(echo "${DISPLAY_NAME}" | sed 's/ /-/g')${SUFFIX}-x86_64.AppImage" @@ -107,7 +108,7 @@ build_appimage() { sed "s/{MODID}/${MOD_ID}/g" AppRun.in | sed "s/{MODNAME}/${DISPLAY_NAME}/g" > AppRun.temp install -m 0755 AppRun.temp "${APPDIR}/AppRun" - sed "s/{MODID}/${MOD_ID}/g" openra.desktop.in | sed "s/{MODNAME}/${DISPLAY_NAME}/g" | sed "s/{TAG}/${TAG}/g" > temp.desktop + sed "s/{MODID}/${MOD_ID}/g" openra.desktop.in | sed "s/{MODNAME}/${DISPLAY_NAME}/g" | sed "s/{TAG}/${TAG}/g" | sed "s/{DISCORDAPPID}/${DISCORD_ID}/g" > temp.desktop echo "StartupWMClass=openra-${MOD_ID}-${TAG}" >> temp.desktop install -Dm 0755 temp.desktop "${APPDIR}/usr/share/applications/openra-${MOD_ID}.desktop" @@ -154,9 +155,9 @@ build_appimage() { rm -rf "${APPDIR}" } -build_appimage "ra" "Red Alert" -build_appimage "cnc" "Tiberian Dawn" -build_appimage "d2k" "Dune 2000" +build_appimage "ra" "Red Alert" "699222659766026240" +build_appimage "cnc" "Tiberian Dawn" "699223250181292033" +build_appimage "d2k" "Dune 2000" "712711732770111550" # Clean up rm -rf openra-mod.temp openra-mod-server.temp openra-mod-utility.temp temp.desktop temp.xml AppRun.temp appimagetool-x86_64.AppImage squashfs-root "${BUILTDIR}" diff --git a/packaging/linux/openra.desktop.in b/packaging/linux/openra.desktop.in index f4f5013f9b..42e21aafa0 100644 --- a/packaging/linux/openra.desktop.in +++ b/packaging/linux/openra.desktop.in @@ -9,4 +9,4 @@ Icon=openra-{MODID} Exec=openra-{MODID} %U Terminal=false Categories=Game;StrategyGame; -MimeType=x-scheme-handler/openra-{MODID}-{TAG}; +MimeType=x-scheme-handler/openra-{MODID}-{TAG};x-scheme-handler/discord-{DISCORDAPPID}; diff --git a/packaging/macos/buildpackage.sh b/packaging/macos/buildpackage.sh index 91568fe81e..cad5fe56ed 100755 --- a/packaging/macos/buildpackage.sh +++ b/packaging/macos/buildpackage.sh @@ -13,7 +13,7 @@ # MACOS_DEVELOPER_PASSWORD: App-specific password for the developer account # -LAUNCHER_TAG="osx-launcher-20200328" +LAUNCHER_TAG="osx-launcher-20200525" if [ $# -ne "2" ]; then echo "Usage: $(basename "$0") tag outputdir" @@ -54,6 +54,7 @@ populate_bundle() { TEMPLATE_DIR="${BUILTDIR}/${1}" MOD_ID=${2} MOD_NAME=${3} + DISCORD_APPID=${4} cp -r "${BUILTDIR}/OpenRA.app" "${TEMPLATE_DIR}" # Assemble multi-resolution icon @@ -63,6 +64,7 @@ populate_bundle() { modify_plist "{MOD_ID}" "${MOD_ID}" "${TEMPLATE_DIR}/Contents/Info.plist" modify_plist "{MOD_NAME}" "${MOD_NAME}" "${TEMPLATE_DIR}/Contents/Info.plist" modify_plist "{JOIN_SERVER_URL_SCHEME}" "openra-${MOD_ID}-${TAG}" "${TEMPLATE_DIR}/Contents/Info.plist" + modify_plist "{ADDITIONAL_URL_SCHEMES}" "discord-${DISCORD_APPID}" "${TEMPLATE_DIR}/Contents/Info.plist" } # Deletes from the first argument's mod dirs all the later arguments @@ -98,15 +100,15 @@ make install-core gameinstalldir="/Contents/Resources/" DESTDIR="${BUILTDIR}/Ope make install-dependencies TARGETPLATFORM=osx-x64 gameinstalldir="/Contents/Resources/" DESTDIR="${BUILTDIR}/OpenRA.app" popd > /dev/null || exit 1 -populate_bundle "OpenRA - Red Alert.app" "ra" "Red Alert" +populate_bundle "OpenRA - Red Alert.app" "ra" "Red Alert" "699222659766026240" delete_mods "OpenRA - Red Alert.app" "cnc" "d2k" sign_bundle "OpenRA - Red Alert.app" -populate_bundle "OpenRA - Tiberian Dawn.app" "cnc" "Tiberian Dawn" +populate_bundle "OpenRA - Tiberian Dawn.app" "cnc" "Tiberian Dawn" "699223250181292033" delete_mods "OpenRA - Tiberian Dawn.app" "ra" "d2k" sign_bundle "OpenRA - Tiberian Dawn.app" -populate_bundle "OpenRA - Dune 2000.app" "d2k" "Dune 2000" +populate_bundle "OpenRA - Dune 2000.app" "d2k" "Dune 2000" "712711732770111550" delete_mods "OpenRA - Dune 2000.app" "ra" "cnc" sign_bundle "OpenRA - Dune 2000.app" diff --git a/packaging/windows/OpenRA.nsi b/packaging/windows/OpenRA.nsi index 44a1159765..1511422eb9 100644 --- a/packaging/windows/OpenRA.nsi +++ b/packaging/windows/OpenRA.nsi @@ -62,6 +62,10 @@ Var StartMenuFolder !insertmacro MUI_LANGUAGE "English" +!define RA_DISCORDID 699222659766026240 +!define CNC_DISCORDID 699223250181292033 +!define D2K_DISCORDID 712711732770111550 + ;*************************** ;Section Definitions ;*************************** @@ -76,16 +80,31 @@ Section "-Reg" Reg WriteRegStr HKLM "Software\Classes\openra-ra-${TAG}\DefaultIcon" "" "$INSTDIR\RedAlert.ico,0" WriteRegStr HKLM "Software\Classes\openra-ra-${TAG}\Shell\Open\Command" "" "$INSTDIR\RedAlert.exe Launch.URI=%1" + WriteRegStr HKLM "Software\Classes\discord-${RA_DISCORDID}" "" "URL:Run game ${RA_DISCORDID} protocol" + WriteRegStr HKLM "Software\Classes\discord-${RA_DISCORDID}" "URL Protocol" "" + WriteRegStr HKLM "Software\Classes\discord-${RA_DISCORDID}\DefaultIcon" "" "$INSTDIR\RedAlert.ico,0" + WriteRegStr HKLM "Software\Classes\discord-${RA_DISCORDID}\Shell\Open\Command" "" "$INSTDIR\RedAlert.exe" + WriteRegStr HKLM "Software\Classes\openra-cnc-${TAG}" "" "URL:Join OpenRA server" WriteRegStr HKLM "Software\Classes\openra-cnc-${TAG}" "URL Protocol" "" WriteRegStr HKLM "Software\Classes\openra-cnc-${TAG}\DefaultIcon" "" "$INSTDIR\TiberianDawn.ico,0" WriteRegStr HKLM "Software\Classes\openra-cnc-${TAG}\Shell\Open\Command" "" "$INSTDIR\TiberianDawn.exe Launch.URI=%1" + WriteRegStr HKLM "Software\Classes\discord-${CNC_DISCORDID}" "" "URL:Run game ${CNC_DISCORDID} protocol" + WriteRegStr HKLM "Software\Classes\discord-${CNC_DISCORDID}" "URL Protocol" "" + WriteRegStr HKLM "Software\Classes\discord-${CNC_DISCORDID}\DefaultIcon" "" "$INSTDIR\TiberianDawn.ico,0" + WriteRegStr HKLM "Software\Classes\discord-${CNC_DISCORDID}\Shell\Open\Command" "" "$INSTDIR\TiberianDawn.exe" + WriteRegStr HKLM "Software\Classes\openra-d2k-${TAG}" "" "URL:Join OpenRA server" WriteRegStr HKLM "Software\Classes\openra-d2k-${TAG}" "URL Protocol" "" WriteRegStr HKLM "Software\Classes\openra-d2k-${TAG}\DefaultIcon" "" "$INSTDIR\Dune2000.ico,0" WriteRegStr HKLM "Software\Classes\openra-d2k-${TAG}\Shell\Open\Command" "" "$INSTDIR\Dune2000.exe Launch.URI=%1" + WriteRegStr HKLM "Software\Classes\discord-${D2K_DISCORDID}" "" "URL:Run game ${D2K_DISCORDID} protocol" + WriteRegStr HKLM "Software\Classes\discord-${D2K_DISCORDID}" "URL Protocol" "" + WriteRegStr HKLM "Software\Classes\discord-${D2K_DISCORDID}\DefaultIcon" "" "$INSTDIR\Dune2000.ico,0" + WriteRegStr HKLM "Software\Classes\discord-${D2K_DISCORDID}\Shell\Open\Command" "" "$INSTDIR\Dune2000.exe" + ; Remove obsolete file associations DeleteRegKey HKLM "Software\Classes\.orarep" DeleteRegKey HKLM "Software\Classes\OpenRA_replay" @@ -135,6 +154,8 @@ Section "Game" GAME File "${SRCDIR}\eluant.dll" File "${SRCDIR}\BeaconLib.dll" File "${SRCDIR}\soft_oal.dll" + File "${SRCDIR}\DiscordRPC.dll" + File "${SRCDIR}\Newtonsoft.Json.dll" File "${SRCDIR}\SDL2.dll" File "${SRCDIR}\freetype6.dll" File "${SRCDIR}\lua51.dll" @@ -254,6 +275,8 @@ Function ${UN}Clean Delete $INSTDIR\lua51.dll Delete $INSTDIR\eluant.dll Delete $INSTDIR\freetype6.dll + Delete $INSTDIR\DiscordRPC.dll + Delete $INSTDIR\Newtonsoft.Json.dll Delete $INSTDIR\SDL2-CS.dll Delete $INSTDIR\OpenAL-CS.Core.dll Delete $INSTDIR\BeaconLib.dll @@ -264,6 +287,10 @@ Function ${UN}Clean DeleteRegKey HKLM "Software\Classes\openra-cnc-${TAG}" DeleteRegKey HKLM "Software\Classes\openra-d2k-${TAG}" + DeleteRegKey HKLM "Software\Classes\discord-${RA_DISCORDID}" + DeleteRegKey HKLM "Software\Classes\discord-${CNC_DISCORDID}" + DeleteRegKey HKLM "Software\Classes\discord-${D2K_DISCORDID}" + Delete $INSTDIR\uninstaller.exe RMDir $INSTDIR