Discord integration for Gamecraft
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

222 lines
8.3KB

  1. using System;
  2. using System.Reflection;
  3. //using Microsoft.Win32;
  4. using IllusionPlugin;
  5. using GamecraftModdingAPI.App;
  6. using GamecraftModdingAPI.Commands;
  7. using Discord;
  8. namespace GamecraftRPC
  9. {
  10. public class Plugin : IPlugin // the Illusion Plugin Architecture (IPA) will ignore classes that don't implement IPlugin'
  11. {
  12. public string Name { get; } = Assembly.GetExecutingAssembly().GetName().Name;
  13. public string Version { get; } =
  14. #if DEBUG
  15. Assembly.GetExecutingAssembly().GetName().Version.ToString() + "alpha";
  16. #else
  17. Assembly.GetExecutingAssembly().GetName().Version.ToString();
  18. #endif
  19. private const long CLIENT_ID =
  20. #if DEBUG
  21. 692733325902872619;
  22. #else
  23. 696732441012076605;
  24. #endif
  25. private const LogLevel LOG_LEVEL =
  26. #if DEBUG
  27. LogLevel.Debug;
  28. #else
  29. LogLevel.Warn;
  30. #endif
  31. internal static Discord.Discord DiscordRPC;
  32. // called when Gamecraft shuts down
  33. public void OnApplicationQuit()
  34. {
  35. // Shutdown this mod
  36. if (DiscordRPC != null)
  37. {
  38. DiscordRPC.GetActivityManager().ClearActivity((result) => { GamecraftModdingAPI.Utility.Logging.LogDebug($"Cleared status: {result}"); DiscordRPC.Dispose(); });
  39. }
  40. GamecraftModdingAPI.Utility.Logging.LogDebug($"{Name} has shutdown");
  41. // Shutdown the Gamecraft modding API last
  42. GamecraftModdingAPI.Main.Shutdown();
  43. }
  44. // called when Gamecraft starts up
  45. public void OnApplicationStart()
  46. {
  47. // Initialize the Gamecraft modding API first
  48. GamecraftModdingAPI.Main.Init();
  49. // detect Wine (maybe?)
  50. bool isWineDetected = false;
  51. foreach (var key in Microsoft.Win32.Registry.CurrentUser.OpenSubKey("Software").GetSubKeyNames())
  52. {
  53. if (key == "Wine")
  54. {
  55. isWineDetected = true;
  56. break;
  57. }
  58. }
  59. if (isWineDetected)
  60. {
  61. // info for getting this to work through Wine/Proton
  62. GamecraftModdingAPI.Utility.Logging.MetaLog("\n--------------------------------\n\nIt looks like you may be using Wine/Proton, cool!\nPlease install https://github.com/0e4ef622/wine-discord-ipc-bridge to get this to work.\n\n--------------------------------");
  63. }
  64. // Initialize this mod
  65. DiscordRPC = new Discord.Discord(CLIENT_ID, (UInt64)Discord.CreateFlags.NoRequireDiscord);
  66. DiscordRPC.SetLogHook(LOG_LEVEL, (_, msg) => { GamecraftModdingAPI.Utility.Logging.MetaLog(msg); });
  67. //DiscordRPC.GetActivityManager().RegisterSteam(1078000);
  68. ActivityManager am = DiscordRPC.GetActivityManager();
  69. am.OnActivityJoinRequest += CallbackUtility.ActivityJoinRequest;
  70. am.OnActivityJoin += CallbackUtility.ActivityJoin;
  71. am.OnActivityInvite += CallbackUtility.ActivityInvite;
  72. LobbyManager lm = DiscordRPC.GetLobbyManager();
  73. lm.OnMemberConnect += CallbackUtility.DiscordUserJoin;
  74. SetDiscordActivity(state: $"{UnityEngine.Application.version} ({Version})", details: $"Initializing...", start: (int)(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds);
  75. Game.Edit += CallbackUtility.BuildEnter;
  76. Game.Enter += CallbackUtility.GameEnter;
  77. Game.Simulate += CallbackUtility.SimulationEnter;
  78. Client.EnterMenu += CallbackUtility.MenuEnter;
  79. GamecraftModdingAPI.Utility.GameEngineManager.AddGameEngine(new Engines.PlayerCountEngine());
  80. CommandBuilder.Builder()
  81. .Name("JoinDiscord")
  82. .Description("Join the Exmods server for help or more information")
  83. .Action(() =>
  84. {
  85. if (DiscordRPC != null)
  86. {
  87. DiscordRPC.GetOverlayManager().OpenGuildInvite("2CtWzZT", CallbackUtility.NobodyCares);
  88. }
  89. else
  90. {
  91. GamecraftModdingAPI.Utility.Logging.CommandLogError("Discord GameSDK functionality is unavailable. Please make sure Discord is open when launching Gamecraft.");
  92. }
  93. })
  94. .Build();
  95. CommandBuilder.Builder()
  96. .Name("InviteDiscordUser")
  97. .Description("Invite a Discord user (by id) to your game")
  98. .Action<long>((userId) =>
  99. {
  100. if (DiscordRPC != null)
  101. {
  102. Game game = Game.CurrentGame();
  103. DiscordRPC.GetActivityManager().SendInvite(userId, Discord.ActivityActionType.Join, $"Let's play Gamecraft together! (requires the GamecraftRPC mod)", CallbackUtility.NobodyCares);
  104. }
  105. else
  106. {
  107. GamecraftModdingAPI.Utility.Logging.CommandLogError("Discord GameSDK functionality is unavailable. Please make sure Discord is open when launching Gamecraft.");
  108. }
  109. })
  110. .Build();
  111. CommandBuilder.Builder()
  112. .Name(Name + "Info")
  113. .Description("Build information for the GamecraftRPC mod.")
  114. .Action(() =>
  115. {
  116. if (DiscordRPC != null)
  117. {
  118. Game game = Game.CurrentGame();
  119. Client client = new Client();
  120. GamecraftModdingAPI.Utility.Logging.CommandLog($"Gamecraft {client.Version}\nUnity {client.UnityVersion}\n{Name} {Version}\nSDK {DiscordRPC.ToString()}\nGame {game.Name}");
  121. }
  122. else
  123. {
  124. GamecraftModdingAPI.Utility.Logging.CommandLogError("Discord GameSDK functionality is unavailable. Please make sure Discord is open when launching Gamecraft.");
  125. }
  126. })
  127. .Build();
  128. GamecraftModdingAPI.Utility.Logging.LogDebug($"{Name} has started up");
  129. }
  130. public void OnFixedUpdate() { } // called once per physics update
  131. public void OnLevelWasInitialized(int level) { } // called after a level is initialized
  132. public void OnLevelWasLoaded(int level) { } // called after a level is loaded
  133. public void OnUpdate() // called once per rendered frame (frame update)
  134. {
  135. if (DiscordRPC != null ) DiscordRPC.RunCallbacks();
  136. }
  137. public static void SetDiscordActivity(string state = null, string details = null, long start = 0, long end = 0, string largeImg = "gamecraft-logo-g", string largeTxt = "Gamecraft", string smallImg = "exmods-logo-xm2", string smallTxt = "Exmods", string partyId = null, int partyCurrentSize = 0, int partyMaxSize = 0, string matchSecret = null, string joinSecret = null, string spectateSecret = null, bool instance = true, string debug = "")
  138. {
  139. if (DiscordRPC == null) return;
  140. ref Activity activity = ref PresenceUtility.Activity;
  141. activity.Instance = instance;
  142. if (state != null) activity.State = state;
  143. if (details != null) activity.Details = details;
  144. if (start != 0) activity.Timestamps.Start = start;
  145. if (end != 0) activity.Timestamps.End = end;
  146. if (!string.IsNullOrEmpty(largeImg))
  147. {
  148. activity.Assets.LargeImage = largeImg;
  149. activity.Assets.LargeText = largeTxt;
  150. }
  151. if (!string.IsNullOrEmpty(smallImg))
  152. {
  153. activity.Assets.SmallImage = smallImg;
  154. activity.Assets.SmallText = smallTxt;
  155. }
  156. if (!string.IsNullOrEmpty(partyId))
  157. {
  158. activity.Party.Id = partyId;
  159. activity.Party.Size.CurrentSize = partyCurrentSize;
  160. activity.Party.Size.MaxSize = partyMaxSize;
  161. }
  162. if (!string.IsNullOrEmpty(matchSecret) || !string.IsNullOrEmpty(joinSecret) || !string.IsNullOrEmpty(spectateSecret))
  163. {
  164. activity.Secrets.Match = matchSecret;
  165. activity.Secrets.Join = joinSecret;
  166. activity.Secrets.Spectate = spectateSecret;
  167. }
  168. DiscordRPC.GetActivityManager().UpdateActivity(activity, result =>
  169. {
  170. GamecraftModdingAPI.Utility.Logging.MetaLog($"Update Activity Result: {result} {debug}");
  171. });
  172. }
  173. public static void SetDiscordActivity(Discord.Activity activity, string debug = "")
  174. {
  175. if (DiscordRPC == null) return;
  176. PresenceUtility.Activity = activity;
  177. DiscordRPC.GetActivityManager().UpdateActivity(PresenceUtility.Activity, result =>
  178. {
  179. GamecraftModdingAPI.Utility.Logging.MetaLog($"Update Activity Result: {result} {debug}");
  180. });
  181. }
  182. public static void SetDiscordActivity(string debug = "")
  183. {
  184. if (DiscordRPC == null) return;
  185. DiscordRPC.GetActivityManager().UpdateActivity(PresenceUtility.Activity, result =>
  186. {
  187. GamecraftModdingAPI.Utility.Logging.MetaLog($"Update Activity Result: {result} {debug}");
  188. });
  189. }
  190. }
  191. }