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.

199 lines
6.7KB

  1. using System;
  2. using System.Security.Cryptography;
  3. using System.Text;
  4. using GamecraftModdingAPI.App;
  5. using GamecraftModdingAPI.Utility;
  6. namespace GamecraftRPC
  7. {
  8. public static class CallbackUtility
  9. {
  10. private const int SALT_BYTE_LENGTH = 256;
  11. private const string STATE_IN_GAME = "In Game";
  12. private const string STATE_IN_MENU = "In Menu";
  13. private const string DEETS_SIM = "Playing ";
  14. private const string DEETS_BUILD = "Building ";
  15. private const string DEETS_MENU = null;
  16. private static RandomNumberGenerator random = RandomNumberGenerator.Create();
  17. private static long lastUserJoinRequest = 0;
  18. public static void GameEnter(object sender, GameEventArgs data)
  19. {
  20. PresenceUtility.LastGameStart = (ulong)(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds;
  21. if (PresenceUtility.IsConnecting && PresenceUtility.Lobby.HasValue)
  22. {
  23. PresenceUtility.IsConnecting = false;
  24. ConnectToGamecraftPeer(PresenceUtility.Lobby.Value);
  25. }
  26. else
  27. {
  28. Plugin.SetDiscordActivity(
  29. state: STATE_IN_GAME,
  30. details: DEETS_BUILD + data.GameName,
  31. partyMaxSize: 0,
  32. partyCurrentSize: 0,
  33. start: (long)PresenceUtility.LastGameStart,
  34. debug: "GameEnter-API-callback"
  35. );
  36. CreateLobby();
  37. }
  38. }
  39. public static void MenuEnter(object sender, MenuEventArgs data)
  40. {
  41. if (PresenceUtility.IsConnecting) return;
  42. PresenceUtility.LastGameStart = 0;
  43. PresenceUtility.Activity.Timestamps.Start = 0;
  44. PresenceUtility.Activity.Timestamps.End = 0;
  45. PresenceUtility.Activity.Party.Id = null;
  46. PresenceUtility.Activity.Party.Size.CurrentSize = 0;
  47. PresenceUtility.Activity.Party.Size.MaxSize = 0;
  48. PresenceUtility.Activity.Details = DEETS_MENU;
  49. PresenceUtility.Activity.State = STATE_IN_MENU;
  50. PresenceUtility.Activity.Secrets.Join = null;
  51. if (PresenceUtility.Lobby.HasValue && Plugin.DiscordRPC != null)
  52. {
  53. if (PresenceUtility.IsActivityHost)
  54. {
  55. Plugin.DiscordRPC.GetLobbyManager().DeleteLobby(PresenceUtility.Lobby.Value.Id, NobodyCares);
  56. }
  57. else
  58. {
  59. Plugin.DiscordRPC.GetLobbyManager().DisconnectLobby(PresenceUtility.Lobby.Value.Id, NobodyCares);
  60. }
  61. PresenceUtility.Lobby = null;
  62. }
  63. PresenceUtility.IsActivityHost = false;
  64. PresenceUtility.IsServerActive = false;
  65. PresenceUtility.IsVoiceConnected = false;
  66. Plugin.SetDiscordActivity(PresenceUtility.Activity, debug: "MenuEnter-API-callback");
  67. }
  68. public static void SimulationEnter(object sender, GameEventArgs data)
  69. {
  70. PresenceUtility.Activity.Details = DEETS_SIM + data.GameName;
  71. Plugin.SetDiscordActivity(PresenceUtility.Activity, debug: "SimulationEnter-API-callback");
  72. }
  73. public static void BuildEnter(object sender, GameEventArgs data)
  74. {
  75. PresenceUtility.Activity.Details = DEETS_BUILD + data.GameName;
  76. Plugin.SetDiscordActivity(PresenceUtility.Activity, debug: "BuildEnter-API-callback");
  77. }
  78. private static void CreateLobby()
  79. {
  80. if (Plugin.DiscordRPC == null) return;
  81. Discord.LobbyManager lm = Plugin.DiscordRPC.GetLobbyManager();
  82. Discord.LobbyTransaction lt = lm.GetLobbyCreateTransaction();
  83. lt.SetMetadata("steamid", PresenceUtility.SteamId.ToString());
  84. lt.SetType(Discord.LobbyType.Public);
  85. lt.SetCapacity(2);
  86. lm.CreateLobby(lt, SyncActivityLobby);
  87. PresenceUtility.IsActivityHost = true;
  88. }
  89. public static void ActivityJoin(string secret)
  90. {
  91. Discord.LobbyManager lm = Plugin.DiscordRPC.GetLobbyManager();
  92. if (PresenceUtility.Lobby.HasValue)
  93. {
  94. lm.DeleteLobby(PresenceUtility.Lobby.Value.Id, NobodyCares);
  95. PresenceUtility.Lobby = null;
  96. }
  97. PresenceUtility.IsActivityHost = false;
  98. PresenceUtility.IsServerActive = false;
  99. lm.ConnectLobbyWithActivitySecret(secret, ConnectToGamecraftServerFromLobby);
  100. lastUserJoinRequest = 0;
  101. //Logging.MetaLog($"Received activity join");
  102. }
  103. public static void ActivityJoinRequest(ref Discord.User user)
  104. {
  105. lastUserJoinRequest = user.Id;
  106. Logging.MetaLog($"Received activity join request from {user.Username}");
  107. }
  108. public static void ActivityInvite(Discord.ActivityActionType Type, ref Discord.User user, ref Discord.Activity activity)
  109. {
  110. if (Type == Discord.ActivityActionType.Join)
  111. {
  112. Logging.MetaLog($"Received invite to join {activity.Secrets.Join} from {user.Username}");
  113. }
  114. }
  115. private static void SyncActivityLobby(Discord.Result result, ref Discord.Lobby lobby)
  116. {
  117. Discord.LobbyManager lm = Plugin.DiscordRPC.GetLobbyManager();
  118. PresenceUtility.Lobby = lobby;
  119. int lobbySize = lm.MemberCount(lobby.Id);
  120. Logging.MetaLog($"Lobby {lobby.Id} ({lobbySize}/{lobby.Capacity} players)");
  121. // TODO sync lobby info to activity
  122. PresenceUtility.Activity.Secrets.Join = lm.GetLobbyActivitySecret(lobby.Id);
  123. Logging.MetaLog($"Secret is now {PresenceUtility.Activity.Secrets.Join}");
  124. PresenceUtility.Activity.Party.Id = lobby.Id.ToString();
  125. int currentSize = PresenceUtility.PlayerCount > 0 ? (int)PresenceUtility.PlayerCount : lobbySize;
  126. PresenceUtility.Activity.Party.Size.CurrentSize = currentSize;
  127. PresenceUtility.Activity.Party.Size.MaxSize = currentSize * 2;
  128. Plugin.SetDiscordActivity(PresenceUtility.Activity, debug: "SyncActivityLobby-Discord-callback");
  129. }
  130. private static void ConnectToGamecraftServerFromLobby(Discord.Result result, ref Discord.Lobby lobby)
  131. {
  132. SyncActivityLobby(result, ref lobby);
  133. Client client = new Client();
  134. if (client.InMenu)
  135. {
  136. PresenceUtility.IsConnecting = true;
  137. client.MyGames[0].EnterGame();
  138. }
  139. else
  140. {
  141. ConnectToGamecraftPeer(lobby);
  142. }
  143. }
  144. private static void ConnectToGamecraftPeer(Discord.Lobby lobby)
  145. {
  146. Discord.LobbyManager lm = Plugin.DiscordRPC.GetLobbyManager();
  147. string steamId = lm.GetLobbyMetadataValue(lobby.Id, "steamid");
  148. Logging.MetaLog($"Joined lobby from request, now joining server hosted by {steamId}");
  149. GamecraftModdingAPI.Commands.CommandBuilder.Builder()
  150. .Name("ConnectToCreativeServer")
  151. .FromExisting<string>()
  152. .Invoke(steamId);
  153. }
  154. public static void DiscordUserJoin(long lobbyId, long userId)
  155. {
  156. if (PresenceUtility.IsActivityHost)
  157. {
  158. if (!PresenceUtility.IsServerActive)
  159. {
  160. Logging.MetaLog("First user connected -- starting server");
  161. GamecraftModdingAPI.Commands.CommandBuilder.Builder()
  162. .Name("StartDefaultServer")
  163. .FromExisting()
  164. .Invoke();
  165. PresenceUtility.IsServerActive = true;
  166. }
  167. }
  168. }
  169. public static void NobodyCares(Discord.Result result)
  170. {
  171. }
  172. }
  173. }