diff --git a/GamecraftRPC/Engines/PlayerCountEngine.cs b/GamecraftRPC/Engines/PlayerCountEngine.cs new file mode 100644 index 0000000..d0fb14a --- /dev/null +++ b/GamecraftRPC/Engines/PlayerCountEngine.cs @@ -0,0 +1,66 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +using GamecraftModdingAPI.Tasks; +using GamecraftModdingAPI.Utility; +using Svelto.ECS; + +using RobocraftX.Character; +using RobocraftX.Physics; + +namespace GamecraftRPC.Engines +{ + class PlayerCountEngine : IApiEngine + { + public string Name => "GamecraftRPCPlayerCountGameEngine"; + + public EntitiesDB entitiesDB { set; private get; } + + private Discord.Discord discordRPC = null; + + private bool Ok = false; + + public void Dispose() + { + Ok = false; + PresenceUtility.PlayerCount = 0; + PresenceUtility.Activity.Party.Size.CurrentSize = 0; + PresenceUtility.Activity.Party.Size.MaxSize = 0; + PresenceUtility.Activity.Party.Id = ""; + } + + public void Ready() + { + Ok = true; + Scheduler.Schedule(new Repeatable(updatePlayerCount, () => { return Ok; }, delay: 2f)); + PresenceUtility.Activity.Party.Size.CurrentSize = 1; + PresenceUtility.Activity.Party.Size.MaxSize = PresenceUtility.LobbySize; + PresenceUtility.Activity.Party.Id = "";//PresenceUtility.PartyId.ToString(); + } + + private void updatePlayerCount() + { + if (entitiesDB == null) return; + uint count = 0; + for (uint i = 0; i < CharacterExclusiveGroups.AllCharacters.Length; i++) + { + count += entitiesDB.Count(CharacterExclusiveGroups.AllCharacters[i]); + } + GamecraftModdingAPI.Utility.Logging.MetaLog($"Player Count: {count}"); + if ((int)count != PresenceUtility.PlayerCount && count > 0) + { + PresenceUtility.PlayerCount = (int)count; + PresenceUtility.Activity.Party.Size.CurrentSize = (int)count; + Plugin.SetDiscordActivity(discordRPC, debug: "PlayerCountEngine-updatePlayerCount"); + } + } + + public PlayerCountEngine(Discord.Discord discordRPC) + { + this.discordRPC = discordRPC; + } + } +} diff --git a/GamecraftRPC/Events/EditPresenceHandler.cs b/GamecraftRPC/Events/EditPresenceHandler.cs index 3bbf120..d07e2d0 100644 --- a/GamecraftRPC/Events/EditPresenceHandler.cs +++ b/GamecraftRPC/Events/EditPresenceHandler.cs @@ -18,7 +18,7 @@ namespace GamecraftRPC.Events public static void OnAdd(Discord.Discord discordRPC) { - Plugin.SetDiscordActivity(discordRPC, state: "In-Game", details: $"Editing {GameMode.SaveGameDetails.Name}", start: GamePresenceHandler.GameStart); + Plugin.SetDiscordActivity(discordRPC, state: "In-Game", details: $"Editing {GameMode.SaveGameDetails.Name}", start: PresenceUtility.LastGameStart, matchSecret: PresenceUtility.GameSecret, joinSecret: PresenceUtility.GameSecret); } public EditPresenceHandler(Discord.Discord _discordRPC) : base((db) => { OnAdd(_discordRPC); }, (db) => { }, EventType.BuildSwitchedTo, HandlerName) diff --git a/GamecraftRPC/Events/GamePresenceHandler.cs b/GamecraftRPC/Events/GamePresenceHandler.cs index e6df147..b9622da 100644 --- a/GamecraftRPC/Events/GamePresenceHandler.cs +++ b/GamecraftRPC/Events/GamePresenceHandler.cs @@ -8,6 +8,8 @@ using GamecraftModdingAPI.Events; using Svelto.ECS; using RobocraftX.Common; +using Discord; + namespace GamecraftRPC.Events { class GamePresenceHandler : SimpleEventHandlerEngine @@ -16,12 +18,28 @@ namespace GamecraftRPC.Events //private Discord.Discord discordRPC = null; - public static int GameStart = 0; - public static void OnAdd(Discord.Discord discordRPC) { - GameStart = (int)(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds; - Plugin.SetDiscordActivity(discordRPC, state: "In-Game", details: $"Editing {GameMode.SaveGameDetails.Name}", start: GameStart); + PresenceUtility.LastGameStart = (int)(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds; + + LobbyTransaction ltxn = discordRPC.GetLobbyManager().GetLobbyCreateTransaction(); + UserManager um = discordRPC.GetUserManager(); + um.OnCurrentUserUpdate += () => + { + ltxn.SetOwner(um.GetCurrentUser().Id); + ltxn.SetCapacity((uint)PresenceUtility.LobbySize); + ltxn.SetType(LobbyType.Private); + ltxn.SetMetadata("ownerSteamId", Steamworks.SteamClient.SteamId.AccountId.ToString()); + discordRPC.GetLobbyManager().CreateLobby(ltxn, + (Result result, ref Lobby lobby) => + { + GamecraftModdingAPI.Utility.Logging.LogDebug($"Lobby status: {result}"); + PresenceUtility.LobbyId = lobby.Id; + PresenceUtility.GameSecret = lobby.Secret; + + }); + }; + Plugin.SetDiscordActivity(discordRPC, state: "In-Game", details: $"Editing {GameMode.SaveGameDetails.Name}", start: PresenceUtility.LastGameStart, partyId: PresenceUtility.PartyId.ToString(), partyCurrentSize: 1, partyMaxSize: PresenceUtility.LobbySize, debug: "GamePresence-OnAdd"); } public GamePresenceHandler(Discord.Discord _discordRPC) : base((db) => { OnAdd(_discordRPC); }, (db) => { }, EventType.GameSwitchedTo, HandlerName) diff --git a/GamecraftRPC/Events/SimulatePresenceHandler.cs b/GamecraftRPC/Events/SimulatePresenceHandler.cs index e0dc77b..900cc0c 100644 --- a/GamecraftRPC/Events/SimulatePresenceHandler.cs +++ b/GamecraftRPC/Events/SimulatePresenceHandler.cs @@ -18,7 +18,7 @@ namespace GamecraftRPC.Events public static void OnAdd(Discord.Discord discordRPC) { - Plugin.SetDiscordActivity(discordRPC, state: "In-Game", details: $"Playing {GameMode.SaveGameDetails.Name}", start: GamePresenceHandler.GameStart); + Plugin.SetDiscordActivity(discordRPC, state: "In-Game", details: $"Playing {GameMode.SaveGameDetails.Name}", start: PresenceUtility.LastGameStart, matchSecret: PresenceUtility.GameSecret, joinSecret: PresenceUtility.GameSecret); } public SimulatePresenceHandler(Discord.Discord _discordRPC) : base((db) => { OnAdd(_discordRPC); }, (db) => { }, EventType.SimulationSwitchedTo, HandlerName) diff --git a/GamecraftRPC/Plugin.cs b/GamecraftRPC/Plugin.cs index 472b06b..6793826 100644 --- a/GamecraftRPC/Plugin.cs +++ b/GamecraftRPC/Plugin.cs @@ -14,7 +14,12 @@ namespace GamecraftRPC public string Version { get; } = Assembly.GetExecutingAssembly().GetName().Version.ToString(); - private static readonly long CLIENT_ID = 692733325902872619; + private static readonly long CLIENT_ID = +#if DEBUG + 692733325902872619; +#else + 696732441012076605; +#endif private Discord.Discord discordRPC; @@ -22,6 +27,11 @@ namespace GamecraftRPC 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 @@ -36,6 +46,18 @@ namespace GamecraftRPC // 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); @@ -50,8 +72,34 @@ namespace GamecraftRPC "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(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"); } @@ -69,14 +117,12 @@ namespace GamecraftRPC 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", bool instance = true) + 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; - Activity activity = new Activity - { - Instance = instance, - }; + ref Activity activity = ref PresenceUtility.Activity; + activity.Instance = instance; if (state != null) activity.State = state; if (details != null) activity.Details = details; @@ -92,10 +138,39 @@ namespace GamecraftRPC 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}"); + 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}"); }); } } diff --git a/GamecraftRPC/PresenceUtility.cs b/GamecraftRPC/PresenceUtility.cs new file mode 100644 index 0000000..0db79e6 --- /dev/null +++ b/GamecraftRPC/PresenceUtility.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Security.Cryptography; + +using RobocraftX.Common; + +using Discord; + +namespace GamecraftRPC +{ + public static class PresenceUtility + { + public static int LastGameStart = 0; + + public static string GameSecret { + get + { + return _gameSecret == null? Steamworks.SteamClient.SteamId.AccountId.ToString() : _gameSecret; + } + set + { + _gameSecret = value; + } + } + + private static string _gameSecret = null; + + public static int PlayerCount = 1; + + public static Activity Activity; + + public static uint PartyId { get => Steamworks.SteamClient.SteamId.AccountId; } + + public static long LobbyId; + + public static int LobbySize = 10; + + public static Relationship[] Users; + } +}