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.

CallbackUtility.cs 6.6KB

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