using System; using System.Security.Cryptography; using System.Text; using GamecraftModdingAPI.App; using GamecraftModdingAPI.Utility; namespace GamecraftRPC { public static class CallbackUtility { private const int SALT_BYTE_LENGTH = 256; private const string STATE_IN_GAME = "In Game"; private const string STATE_IN_MENU = "In Menu"; private const string DEETS_SIM = "Playing "; private const string DEETS_BUILD = "Building "; private const string DEETS_MENU = null; private static RandomNumberGenerator random = RandomNumberGenerator.Create(); private static long lastUserJoinRequest = 0; public static void GameEnter(object sender, GameEventArgs data) { PresenceUtility.LastGameStart = (ulong)(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds; if (PresenceUtility.IsConnecting && PresenceUtility.Lobby.HasValue) { PresenceUtility.IsConnecting = false; ConnectToGamecraftPeer(PresenceUtility.Lobby.Value); } else { Plugin.SetDiscordActivity( state: STATE_IN_GAME, details: DEETS_BUILD + data.GameName, partyMaxSize: 0, partyCurrentSize: 0, start: (long)PresenceUtility.LastGameStart, debug: "GameEnter-API-callback" ); CreateLobby(); } } public static void MenuEnter(object sender, MenuEventArgs data) { if (PresenceUtility.IsConnecting) return; PresenceUtility.LastGameStart = 0; PresenceUtility.Activity.Timestamps.Start = 0; PresenceUtility.Activity.Timestamps.End = 0; PresenceUtility.Activity.Party.Id = null; PresenceUtility.Activity.Party.Size.CurrentSize = 0; PresenceUtility.Activity.Party.Size.MaxSize = 0; PresenceUtility.Activity.Details = DEETS_MENU; PresenceUtility.Activity.State = STATE_IN_MENU; PresenceUtility.Activity.Secrets.Join = null; if (PresenceUtility.Lobby.HasValue && Plugin.DiscordRPC != null) { if (PresenceUtility.IsActivityHost) { Plugin.DiscordRPC.GetLobbyManager().DeleteLobby(PresenceUtility.Lobby.Value.Id, NobodyCares); } else { Plugin.DiscordRPC.GetLobbyManager().DisconnectLobby(PresenceUtility.Lobby.Value.Id, NobodyCares); } PresenceUtility.Lobby = null; } PresenceUtility.IsActivityHost = false; PresenceUtility.IsServerActive = false; Plugin.SetDiscordActivity(PresenceUtility.Activity, debug: "MenuEnter-API-callback"); } public static void SimulationEnter(object sender, GameEventArgs data) { PresenceUtility.Activity.Details = DEETS_SIM + data.GameName; Plugin.SetDiscordActivity(PresenceUtility.Activity, debug: "SimulationEnter-API-callback"); } public static void BuildEnter(object sender, GameEventArgs data) { PresenceUtility.Activity.Details = DEETS_BUILD + data.GameName; Plugin.SetDiscordActivity(PresenceUtility.Activity, debug: "BuildEnter-API-callback"); } private static void CreateLobby() { if (Plugin.DiscordRPC == null) return; Discord.LobbyManager lm = Plugin.DiscordRPC.GetLobbyManager(); Discord.LobbyTransaction lt = lm.GetLobbyCreateTransaction(); lt.SetMetadata("steamid", PresenceUtility.SteamId.ToString()); lt.SetType(Discord.LobbyType.Public); lt.SetCapacity(2); lm.CreateLobby(lt, SyncActivityLobby); PresenceUtility.IsActivityHost = true; } public static void ActivityJoin(string secret) { Discord.LobbyManager lm = Plugin.DiscordRPC.GetLobbyManager(); if (PresenceUtility.Lobby.HasValue) { lm.DeleteLobby(PresenceUtility.Lobby.Value.Id, NobodyCares); PresenceUtility.Lobby = null; } PresenceUtility.IsActivityHost = false; PresenceUtility.IsServerActive = false; lm.ConnectLobbyWithActivitySecret(secret, ConnectToGamecraftServerFromLobby); lastUserJoinRequest = 0; //Logging.MetaLog($"Received activity join"); } public static void ActivityJoinRequest(ref Discord.User user) { lastUserJoinRequest = user.Id; Logging.MetaLog($"Received activity join request from {user.Username}"); } public static void ActivityInvite(Discord.ActivityActionType Type, ref Discord.User user, ref Discord.Activity activity) { if (Type == Discord.ActivityActionType.Join) { Logging.MetaLog($"Received invite to join {activity.Secrets.Join} from {user.Username}"); } } private static void SyncActivityLobby(Discord.Result result, ref Discord.Lobby lobby) { Discord.LobbyManager lm = Plugin.DiscordRPC.GetLobbyManager(); PresenceUtility.Lobby = lobby; int lobbySize = lm.MemberCount(lobby.Id); Logging.MetaLog($"Lobby {lobby.Id} ({lobbySize}/{lobby.Capacity} players)"); // TODO sync lobby info to activity PresenceUtility.Activity.Secrets.Join = lm.GetLobbyActivitySecret(lobby.Id); Logging.MetaLog($"Secret is now {PresenceUtility.Activity.Secrets.Join}"); PresenceUtility.Activity.Party.Id = lobby.Id.ToString(); int currentSize = PresenceUtility.PlayerCount > 0 ? (int)PresenceUtility.PlayerCount : lobbySize; PresenceUtility.Activity.Party.Size.CurrentSize = currentSize; PresenceUtility.Activity.Party.Size.MaxSize = currentSize * 2; Plugin.SetDiscordActivity(PresenceUtility.Activity, debug: "SyncActivityLobby-Discord-callback"); } private static void ConnectToGamecraftServerFromLobby(Discord.Result result, ref Discord.Lobby lobby) { SyncActivityLobby(result, ref lobby); Client client = new Client(); if (client.InMenu) { PresenceUtility.IsConnecting = true; client.MyGames[0].EnterGame(); } else { ConnectToGamecraftPeer(lobby); } } private static void ConnectToGamecraftPeer(Discord.Lobby lobby) { Discord.LobbyManager lm = Plugin.DiscordRPC.GetLobbyManager(); string steamId = lm.GetLobbyMetadataValue(lobby.Id, "steamid"); Logging.MetaLog($"Joined lobby from request, now joining server hosted by {steamId}"); GamecraftModdingAPI.Commands.CommandBuilder.Builder() .Name("ConnectToCreativeServer") .FromExisting() .Invoke(steamId); } public static void DiscordUserJoin(long lobbyId, long userId) { if (PresenceUtility.IsActivityHost) { if (!PresenceUtility.IsServerActive) { Logging.MetaLog("First user connected -- starting server"); GamecraftModdingAPI.Commands.CommandBuilder.Builder() .Name("StartDefaultServer") .FromExisting() .Invoke(); PresenceUtility.IsServerActive = true; } } } public static void NobodyCares(Discord.Result result) { } } }