Unofficial CardLife revival project, pronounced like "celery"
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

189 lignes
7.2KB

  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.Net;
  5. using System.Reflection;
  6. using System.Text;
  7. using CLre_server.API.Engines;
  8. using CLre_server.API.MainServer;
  9. using Game.CommonComponents;
  10. using HarmonyLib;
  11. using Svelto.DataStructures;
  12. using Svelto.ECS;
  13. using User.Server;
  14. namespace CLre_server.WebStatus
  15. {
  16. public static class StatusEndpoints
  17. {
  18. private struct ServerStateCache
  19. {
  20. public List<PlayerData> OnlinePlayers;
  21. public int MaxPlayers;
  22. public RunState State;
  23. public static ServerStateCache Empty()
  24. {
  25. return new ServerStateCache
  26. {
  27. OnlinePlayers = new List<PlayerData>(),
  28. MaxPlayers = -1,
  29. State = RunState.Initialising,
  30. };
  31. }
  32. public string Json()
  33. {
  34. // Unity's built-in JSON serializer does not work with arrays or lists :(
  35. // I miss Newtonsoft...
  36. StringBuilder sb = new StringBuilder($"{{\"PlayersMax\":{MaxPlayers},\"PlayerCount\":{OnlinePlayers.Count},\"Status\":\"{State.ToString()}\",\"OnlinePlayers\":[");
  37. foreach (PlayerData p in OnlinePlayers.ToArray())
  38. {
  39. sb.Append(UnityEngine.JsonUtility.ToJson(p));
  40. sb.Append(",");
  41. }
  42. if (OnlinePlayers.Count > 0) sb.Remove(sb.Length - 1, 1);
  43. sb.Append("]}");
  44. return sb.ToString();
  45. }
  46. }
  47. [Serializable]
  48. private struct PlayerData
  49. {
  50. public string id;
  51. public string name;
  52. public bool isDev;
  53. public float x;
  54. public float y;
  55. public float z;
  56. }
  57. private enum RunState : short
  58. {
  59. Initialising,
  60. Initialised,
  61. Online,
  62. Quitting,
  63. }
  64. private class StatusPollingEngine : ServerEnginePostBuild
  65. {
  66. public override void Ready()
  67. {
  68. API.Utility.Logging.MetaLog("StatusPolling Engine ready");
  69. pollLoop().Run();
  70. }
  71. private delegate void PlayerPositionFunc();
  72. private PlayerPositionFunc _playerPositionFunc = null;
  73. private IEnumerator pollLoop()
  74. {
  75. FieldInfo f = AccessTools.Field(AccessTools.TypeByName("User.Server.AccountExclusiveGroups"), "accountGroup");
  76. ExclusiveGroup accountGroup = (ExclusiveGroup) f.GetValue(null);
  77. while (_clState.State != RunState.Quitting)
  78. {
  79. ReadOnlyCollectionStruct<AccountIdServerNode> accounts =
  80. entitiesDB.QueryEntityViews<AccountIdServerNode>(accountGroup);
  81. int index = 0;
  82. foreach (AccountIdServerNode user in accounts)
  83. {
  84. if (index < _clState.OnlinePlayers.Count)
  85. {
  86. PlayerData p = _clState.OnlinePlayers[index];
  87. p.id = user.accountId.publicId.ToString();
  88. p.name = user.accountId.displayName;
  89. p.isDev = (user.accountId.userFlags & UserFlags.Dev) == UserFlags.Dev;
  90. _clState.OnlinePlayers[index] = p;
  91. }
  92. else
  93. {
  94. PlayerData p = default(PlayerData);
  95. p.id = user.accountId.publicId.ToString();
  96. p.name = user.accountId.displayName;
  97. p.isDev = (user.accountId.userFlags & UserFlags.Dev) == UserFlags.Dev;
  98. _clState.OnlinePlayers.Add(p);
  99. }
  100. index++;
  101. }
  102. if (index != 0) syncPlayerPositions();
  103. if (index < _clState.OnlinePlayers.Count) _clState.OnlinePlayers.RemoveRange(index, _clState.OnlinePlayers.Count - index);
  104. //API.Utility.Logging.MetaLog($"Polled {index} Online Users");
  105. yield return null;
  106. }
  107. }
  108. private void syncPlayerPositions()
  109. {
  110. if (_playerPositionFunc == null)
  111. {
  112. // build non-generic method using reflection
  113. MethodInfo method = AccessTools.Method(typeof(StatusPollingEngine), "getPlayerPositionsGeneric",
  114. generics: new[] {AccessTools.TypeByName("Game.Character.ServerCharacterPositionNode")});
  115. _playerPositionFunc = API.Utility.Reflection.BuildDelegate<PlayerPositionFunc>(method, this);
  116. }
  117. _playerPositionFunc();
  118. }
  119. #pragma warning disable 0618
  120. private void getPlayerPositionsGeneric<T>() where T : EntityView // EntityView is deprecated lol
  121. {
  122. ReadOnlyCollectionStruct<T> scpnCollection = entitiesDB.QueryEntityViews<T>(DEPRECATED_SveltoExtensions.DEPRECATED_GROUP);
  123. //API.Utility.Logging.MetaLog($"Found {scpnCollection.Count} player positions");
  124. int i = 0;
  125. foreach (T scpn in scpnCollection)
  126. {
  127. PlayerData p = _clState.OnlinePlayers[i];
  128. UnityEngine.Vector3 pos = Traverse.Create(scpn).Field<IPositionComponent>("positionComponent")
  129. .Value.position;
  130. p.x = pos.x;
  131. p.y = pos.y;
  132. p.z = pos.z;
  133. _clState.OnlinePlayers[i] = p;
  134. i++;
  135. }
  136. }
  137. #pragma warning restore 0618
  138. }
  139. private static ServerStateCache _clState = ServerStateCache.Empty();
  140. internal static void Init()
  141. {
  142. #if DEBUG
  143. API.Utility.Logging.MetaLog("Status Endpoint initialising");
  144. #endif
  145. new StatusPollingEngine();
  146. // register API event callbacks
  147. Server.Instance.InitStart += (_, __) => _clState.State = RunState.Initialising;
  148. Server.Instance.InitComplete += (_, __) =>
  149. {
  150. _clState.State = RunState.Initialised;
  151. _clState.MaxPlayers = Server.Instance.GameServerSettings.GetMaxPlayers();
  152. };
  153. Server.Instance.FrameworkReady += (_, __) =>
  154. {
  155. _clState.State = RunState.Online;
  156. _clState.MaxPlayers = Server.Instance.GameServerSettings.GetMaxPlayers();
  157. };
  158. Server.Instance.FrameworkExit += (_, __) => _clState.State = RunState.Quitting;
  159. }
  160. [WebEndpoint("/status.json")]
  161. internal static void StatusJson(HttpListenerContext ctx)
  162. {
  163. ctx.Response.Headers.Add("Content-Type", "application/json");
  164. string json = _clState.Json();
  165. #if DEBUG
  166. API.Utility.Logging.MetaLog("JSONified status: " + json);
  167. #endif
  168. byte[] output = Encoding.UTF8.GetBytes(json);
  169. ctx.Response.OutputStream.Write(output, 0, output.Length);
  170. }
  171. }
  172. }