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.

198 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. Plugin.SetDiscordActivity(PresenceUtility.Activity, debug: "MenuEnter-API-callback");
  66. }
  67. public static void SimulationEnter(object sender, GameEventArgs data)
  68. {
  69. PresenceUtility.Activity.Details = DEETS_SIM + data.GameName;
  70. Plugin.SetDiscordActivity(PresenceUtility.Activity, debug: "SimulationEnter-API-callback");
  71. }
  72. public static void BuildEnter(object sender, GameEventArgs data)
  73. {
  74. PresenceUtility.Activity.Details = DEETS_BUILD + data.GameName;
  75. Plugin.SetDiscordActivity(PresenceUtility.Activity, debug: "BuildEnter-API-callback");
  76. }
  77. private static void CreateLobby()
  78. {
  79. if (Plugin.DiscordRPC == null) return;
  80. Discord.LobbyManager lm = Plugin.DiscordRPC.GetLobbyManager();
  81. Discord.LobbyTransaction lt = lm.GetLobbyCreateTransaction();
  82. lt.SetMetadata("steamid", PresenceUtility.SteamId.ToString());
  83. lt.SetType(Discord.LobbyType.Public);
  84. lt.SetCapacity(2);
  85. lm.CreateLobby(lt, SyncActivityLobby);
  86. PresenceUtility.IsActivityHost = true;
  87. }
  88. public static void ActivityJoin(string secret)
  89. {
  90. Discord.LobbyManager lm = Plugin.DiscordRPC.GetLobbyManager();
  91. if (PresenceUtility.Lobby.HasValue)
  92. {
  93. lm.DeleteLobby(PresenceUtility.Lobby.Value.Id, NobodyCares);
  94. PresenceUtility.Lobby = null;
  95. }
  96. PresenceUtility.IsActivityHost = false;
  97. PresenceUtility.IsServerActive = false;
  98. lm.ConnectLobbyWithActivitySecret(secret, ConnectToGamecraftServerFromLobby);
  99. lastUserJoinRequest = 0;
  100. //Logging.MetaLog($"Received activity join");
  101. }
  102. public static void ActivityJoinRequest(ref Discord.User user)
  103. {
  104. lastUserJoinRequest = user.Id;
  105. Logging.MetaLog($"Received activity join request from {user.Username}");
  106. }
  107. public static void ActivityInvite(Discord.ActivityActionType Type, ref Discord.User user, ref Discord.Activity activity)
  108. {
  109. if (Type == Discord.ActivityActionType.Join)
  110. {
  111. Logging.MetaLog($"Received invite to join {activity.Secrets.Join} from {user.Username}");
  112. }
  113. }
  114. private static void SyncActivityLobby(Discord.Result result, ref Discord.Lobby lobby)
  115. {
  116. Discord.LobbyManager lm = Plugin.DiscordRPC.GetLobbyManager();
  117. PresenceUtility.Lobby = lobby;
  118. int lobbySize = lm.MemberCount(lobby.Id);
  119. Logging.MetaLog($"Lobby {lobby.Id} ({lobbySize}/{lobby.Capacity} players)");
  120. // TODO sync lobby info to activity
  121. PresenceUtility.Activity.Secrets.Join = lm.GetLobbyActivitySecret(lobby.Id);
  122. Logging.MetaLog($"Secret is now {PresenceUtility.Activity.Secrets.Join}");
  123. PresenceUtility.Activity.Party.Id = lobby.Id.ToString();
  124. int currentSize = PresenceUtility.PlayerCount > 0 ? (int)PresenceUtility.PlayerCount : lobbySize;
  125. PresenceUtility.Activity.Party.Size.CurrentSize = currentSize;
  126. PresenceUtility.Activity.Party.Size.MaxSize = currentSize * 2;
  127. Plugin.SetDiscordActivity(PresenceUtility.Activity, debug: "SyncActivityLobby-Discord-callback");
  128. }
  129. private static void ConnectToGamecraftServerFromLobby(Discord.Result result, ref Discord.Lobby lobby)
  130. {
  131. SyncActivityLobby(result, ref lobby);
  132. Client client = new Client();
  133. if (client.InMenu)
  134. {
  135. PresenceUtility.IsConnecting = true;
  136. client.MyGames[0].EnterGame();
  137. }
  138. else
  139. {
  140. ConnectToGamecraftPeer(lobby);
  141. }
  142. }
  143. private static void ConnectToGamecraftPeer(Discord.Lobby lobby)
  144. {
  145. Discord.LobbyManager lm = Plugin.DiscordRPC.GetLobbyManager();
  146. string steamId = lm.GetLobbyMetadataValue(lobby.Id, "steamid");
  147. Logging.MetaLog($"Joined lobby from request, now joining server hosted by {steamId}");
  148. GamecraftModdingAPI.Commands.CommandBuilder.Builder()
  149. .Name("ConnectToCreativeServer")
  150. .FromExisting<string>()
  151. .Invoke(steamId);
  152. }
  153. public static void DiscordUserJoin(long lobbyId, long userId)
  154. {
  155. if (PresenceUtility.IsActivityHost)
  156. {
  157. if (!PresenceUtility.IsServerActive)
  158. {
  159. Logging.MetaLog("First user connected -- starting server");
  160. GamecraftModdingAPI.Commands.CommandBuilder.Builder()
  161. .Name("StartDefaultServer")
  162. .FromExisting()
  163. .Invoke();
  164. PresenceUtility.IsServerActive = true;
  165. }
  166. }
  167. }
  168. public static void NobodyCares(Discord.Result result)
  169. {
  170. }
  171. }
  172. }