using System; using System.Reflection; //using Microsoft.Win32; using IllusionPlugin; using GamecraftModdingAPI.Events; using GamecraftModdingAPI.Commands; using Discord; namespace GamecraftRPC { public class Plugin : IPlugin // the Illusion Plugin Architecture (IPA) will ignore classes that don't implement IPlugin' { public string Name { get; } = Assembly.GetExecutingAssembly().GetName().Name; public string Version { get; } = Assembly.GetExecutingAssembly().GetName().Version.ToString(); private static readonly long CLIENT_ID = #if DEBUG 692733325902872619; #else 696732441012076605; #endif private Discord.Discord discordRPC; // called when Gamecraft shuts down public void OnApplicationQuit() { // Shutdown this mod if (discordRPC != null) { discordRPC.GetActivityManager().ClearActivity((result) => { GamecraftModdingAPI.Utility.Logging.LogDebug($"Cleared status: {result}"); }); discordRPC.Dispose(); } GamecraftModdingAPI.Utility.Logging.LogDebug($"{Name} has shutdown"); // Shutdown the Gamecraft modding API last GamecraftModdingAPI.Main.Shutdown(); } // called when Gamecraft starts up public void OnApplicationStart() { // Initialize the Gamecraft modding API first GamecraftModdingAPI.Main.Init(); // detect Wine (maybe?) bool isWineDetected = false; foreach (var key in Microsoft.Win32.Registry.CurrentUser.OpenSubKey("Software").GetSubKeyNames()) { if (key == "Wine") { isWineDetected = true; break; } } if (isWineDetected) { // check for or install fake Discord 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--------------------------------"); } // Initialize this mod discordRPC = new Discord.Discord(CLIENT_ID, (UInt64)Discord.CreateFlags.Default); discordRPC.SetLogHook(LogLevel.Debug, (_, msg) => { GamecraftModdingAPI.Utility.Logging.MetaLog(msg); }); discordRPC.GetRelationshipManager().OnRefresh += () => { discordRPC.GetRelationshipManager().Filter((ref Relationship r) => { return r.Presence.Status == Status.Online && r.Type == RelationshipType.Friend; }); PresenceUtility.Users = new Relationship[discordRPC.GetRelationshipManager().Count()]; for (uint i = 0; i < discordRPC.GetRelationshipManager().Count(); i++) { PresenceUtility.Users[i] = discordRPC.GetRelationshipManager().GetAt(i); } }; SetDiscordActivity(discordRPC, state: "Loading...", details: "Initializing Gamecraft", start: (int)(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds); EventManager.AddEventHandler(new Events.GamePresenceHandler(discordRPC)); EventManager.AddEventHandler(new Events.MenuPresenceHandler(discordRPC)); EventManager.AddEventHandler(new Events.EditPresenceHandler(discordRPC)); EventManager.AddEventHandler(new Events.SimulatePresenceHandler(discordRPC)); SimpleCustomCommandEngine rpcCommand = new SimpleCustomCommandEngine( (s) => { SetDiscordActivity(discordRPC, state: s); }, // TODO: command action "SetRichPresence", // command name (used to invoke it in the console) "Set Discord status (experimental)" // command description (displayed when help command is executed) ); // this command can also be executed using the Command Computer SimpleCustomCommandEngine inviteNGniusCommand = new SimpleCustomCommandEngine(() => discordRPC.GetActivityManager().SendInvite(106537989684887552, ActivityActionType.Join, "Join the Borg", (res) => { GamecraftModdingAPI.Utility.Logging.LogDebug($"Send invite {res}"); }), "InviteNGnius", "Send a Discord lobby invite to NGnius"); SimpleCustomCommandEngine inviteDiscordCommand = new SimpleCustomCommandEngine((id) => discordRPC.GetActivityManager().SendInvite(id, ActivityActionType.Join, "Join the Borg", (res) => { GamecraftModdingAPI.Utility.Logging.LogDebug($"Send invite {res}"); }), "InviteDiscord", "Send a game invite to a Discord user"); SimpleCustomCommandEngine listDiscordUsersCommand = new SimpleCustomCommandEngine( () => { string result = "Online Friends\n"; for (int i = 0; i < PresenceUtility.Users.Length; i++) { result += $"{PresenceUtility.Users[i].User.Username} ({PresenceUtility.Users[i].User.Id})\n"; } GamecraftModdingAPI.Utility.Logging.CommandLog(result); }, "ListDiscordUsers", "List online Discord friends"); // register the command so the modding API knows about it CommandManager.AddCommand(rpcCommand); CommandManager.AddCommand(inviteNGniusCommand); CommandManager.AddCommand(inviteDiscordCommand); CommandManager.AddCommand(listDiscordUsersCommand); GamecraftModdingAPI.Utility.GameEngineManager.AddGameEngine(new Engines.PlayerCountEngine(discordRPC)); GamecraftModdingAPI.Utility.Logging.LogDebug($"{Name} has started up"); } // unused methods public void OnFixedUpdate() { } // called once per physics update public void OnLevelWasInitialized(int level) { } // called after a level is initialized public void OnLevelWasLoaded(int level) { } // called after a level is loaded public void OnUpdate() // called once per rendered frame (frame update) { if (discordRPC != null ) discordRPC.RunCallbacks(); } public static void SetDiscordActivity(Discord.Discord discordRPC, string state = null, string details = null, int start = 0, int 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 = "") { if (discordRPC == null) return; ref Activity activity = ref PresenceUtility.Activity; activity.Instance = instance; if (state != null) activity.State = state; if (details != null) activity.Details = details; if (start != 0) activity.Timestamps.Start = start; if (end != 0) activity.Timestamps.End = end; if (!string.IsNullOrEmpty(largeImg)) { activity.Assets.LargeImage = largeImg; activity.Assets.LargeText = largeTxt; } if (!string.IsNullOrEmpty(smallImg)) { activity.Assets.SmallImage = smallImg; activity.Assets.SmallText = smallTxt; } if (!string.IsNullOrEmpty(partyId)) { activity.Party.Id = partyId; activity.Party.Size.CurrentSize = partyCurrentSize; activity.Party.Size.MaxSize = partyMaxSize; } if (!string.IsNullOrEmpty(matchSecret) || !string.IsNullOrEmpty(joinSecret) || !string.IsNullOrEmpty(spectateSecret)) { activity.Secrets.Match = matchSecret; activity.Secrets.Join = joinSecret; activity.Secrets.Spectate = spectateSecret; } discordRPC.GetActivityManager().UpdateActivity(activity, result => { GamecraftModdingAPI.Utility.Logging.MetaLog($"Update Activity Result: {result} {debug}"); }); } public static void SetDiscordActivity(Discord.Discord discordRPC, Discord.Activity activity, string debug = "") { PresenceUtility.Activity = activity; discordRPC.GetActivityManager().UpdateActivity(PresenceUtility.Activity, result => { GamecraftModdingAPI.Utility.Logging.MetaLog($"Update Activity Result: {result} {debug}"); }); } public static void SetDiscordActivity(Discord.Discord discordRPC, string debug = "") { discordRPC.GetActivityManager().UpdateActivity(PresenceUtility.Activity, result => { GamecraftModdingAPI.Utility.Logging.MetaLog($"Update Activity Result: {result} {debug}"); }); } } }