ExtensionCableSystem.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362
  1. using System.Diagnostics.CodeAnalysis;
  2. using Content.Server.Power.Components;
  3. using Robust.Shared.Map.Components;
  4. using Robust.Shared.Physics;
  5. using Robust.Shared.Physics.Components;
  6. namespace Content.Server.Power.EntitySystems
  7. {
  8. public sealed class ExtensionCableSystem : EntitySystem
  9. {
  10. public override void Initialize()
  11. {
  12. base.Initialize();
  13. //Lifecycle events
  14. SubscribeLocalEvent<ExtensionCableProviderComponent, ComponentStartup>(OnProviderStarted);
  15. SubscribeLocalEvent<ExtensionCableProviderComponent, ComponentShutdown>(OnProviderShutdown);
  16. SubscribeLocalEvent<ExtensionCableReceiverComponent, ComponentStartup>(OnReceiverStarted);
  17. SubscribeLocalEvent<ExtensionCableReceiverComponent, ComponentShutdown>(OnReceiverShutdown);
  18. //Anchoring
  19. SubscribeLocalEvent<ExtensionCableReceiverComponent, AnchorStateChangedEvent>(OnReceiverAnchorStateChanged);
  20. SubscribeLocalEvent<ExtensionCableReceiverComponent, ReAnchorEvent>(OnReceiverReAnchor);
  21. SubscribeLocalEvent<ExtensionCableProviderComponent, AnchorStateChangedEvent>(OnProviderAnchorStateChanged);
  22. SubscribeLocalEvent<ExtensionCableProviderComponent, ReAnchorEvent>(OnProviderReAnchor);
  23. }
  24. #region Provider
  25. public void SetProviderTransferRange(EntityUid uid, int range, ExtensionCableProviderComponent? provider = null)
  26. {
  27. if (!Resolve(uid, ref provider))
  28. return;
  29. provider.TransferRange = range;
  30. ResetReceivers(provider);
  31. }
  32. private void OnProviderStarted(EntityUid uid, ExtensionCableProviderComponent provider, ComponentStartup args)
  33. {
  34. Connect(uid, provider);
  35. }
  36. private void OnProviderShutdown(EntityUid uid, ExtensionCableProviderComponent provider, ComponentShutdown args)
  37. {
  38. var xform = Transform(uid);
  39. // If grid deleting no need to update power.
  40. if (HasComp<MapGridComponent>(xform.GridUid) &&
  41. MetaData(xform.GridUid.Value).EntityLifeStage > EntityLifeStage.MapInitialized)
  42. {
  43. return;
  44. }
  45. Disconnect(uid, provider);
  46. }
  47. private void OnProviderAnchorStateChanged(EntityUid uid, ExtensionCableProviderComponent provider, ref AnchorStateChangedEvent args)
  48. {
  49. if (args.Anchored)
  50. Connect(uid, provider);
  51. else
  52. Disconnect(uid, provider);
  53. }
  54. private void Connect(EntityUid uid, ExtensionCableProviderComponent provider)
  55. {
  56. provider.Connectable = true;
  57. foreach (var receiver in FindAvailableReceivers(uid, provider.TransferRange))
  58. {
  59. receiver.Comp.Provider?.LinkedReceivers.Remove(receiver);
  60. receiver.Comp.Provider = provider;
  61. provider.LinkedReceivers.Add(receiver);
  62. RaiseLocalEvent(receiver, new ProviderConnectedEvent(provider), broadcast: false);
  63. RaiseLocalEvent(uid, new ReceiverConnectedEvent(receiver), broadcast: false);
  64. }
  65. }
  66. private void Disconnect(EntityUid uid, ExtensionCableProviderComponent provider)
  67. {
  68. // same as OnProviderShutdown
  69. provider.Connectable = false;
  70. ResetReceivers(provider);
  71. }
  72. private void OnProviderReAnchor(EntityUid uid, ExtensionCableProviderComponent component, ref ReAnchorEvent args)
  73. {
  74. Disconnect(uid, component);
  75. Connect(uid, component);
  76. }
  77. private void ResetReceivers(ExtensionCableProviderComponent provider)
  78. {
  79. var providerId = provider.Owner;
  80. var receivers = provider.LinkedReceivers.ToArray();
  81. provider.LinkedReceivers.Clear();
  82. foreach (var receiver in receivers)
  83. {
  84. var receiverId = receiver.Owner;
  85. receiver.Provider = null;
  86. RaiseLocalEvent(receiverId, new ProviderDisconnectedEvent(provider), broadcast: false);
  87. RaiseLocalEvent(providerId, new ReceiverDisconnectedEvent((receiverId, receiver)), broadcast: false);
  88. }
  89. foreach (var receiver in receivers)
  90. {
  91. // No point resetting what the receiver is doing if it's deleting, plus significant perf savings
  92. // in not doing needless lookups
  93. var receiverId = receiver.Owner;
  94. if (!EntityManager.IsQueuedForDeletion(receiverId)
  95. && MetaData(receiverId).EntityLifeStage <= EntityLifeStage.MapInitialized)
  96. {
  97. TryFindAndSetProvider(receiver);
  98. }
  99. }
  100. }
  101. private IEnumerable<Entity<ExtensionCableReceiverComponent>> FindAvailableReceivers(EntityUid owner, float range)
  102. {
  103. var xform = Transform(owner);
  104. var coordinates = xform.Coordinates;
  105. if (!TryComp(xform.GridUid, out MapGridComponent? grid))
  106. yield break;
  107. var nearbyEntities = grid.GetCellsInSquareArea(coordinates, (int) Math.Ceiling(range / grid.TileSize));
  108. foreach (var entity in nearbyEntities)
  109. {
  110. if (entity == owner)
  111. continue;
  112. if (EntityManager.IsQueuedForDeletion(entity) || MetaData(entity).EntityLifeStage > EntityLifeStage.MapInitialized)
  113. continue;
  114. if (!TryComp(entity, out ExtensionCableReceiverComponent? receiver))
  115. continue;
  116. if (!receiver.Connectable || receiver.Provider != null)
  117. continue;
  118. if ((Transform(entity).LocalPosition - xform.LocalPosition).Length() <= Math.Min(range, receiver.ReceptionRange))
  119. yield return (entity, receiver);
  120. }
  121. }
  122. #endregion
  123. #region Receiver
  124. public void SetReceiverReceptionRange(EntityUid uid, int range, ExtensionCableReceiverComponent? receiver = null)
  125. {
  126. if (!Resolve(uid, ref receiver))
  127. return;
  128. var provider = receiver.Provider;
  129. receiver.Provider = null;
  130. RaiseLocalEvent(uid, new ProviderDisconnectedEvent(provider), broadcast: false);
  131. if (provider != null)
  132. {
  133. RaiseLocalEvent(provider.Owner, new ReceiverDisconnectedEvent((uid, receiver)), broadcast: false);
  134. provider.LinkedReceivers.Remove(receiver);
  135. }
  136. receiver.ReceptionRange = range;
  137. TryFindAndSetProvider(receiver);
  138. }
  139. private void OnReceiverStarted(EntityUid uid, ExtensionCableReceiverComponent receiver, ComponentStartup args)
  140. {
  141. if (EntityManager.TryGetComponent(receiver.Owner, out PhysicsComponent? physicsComponent))
  142. {
  143. receiver.Connectable = physicsComponent.BodyType == BodyType.Static;
  144. }
  145. if (receiver.Provider == null)
  146. {
  147. TryFindAndSetProvider(receiver);
  148. }
  149. }
  150. private void OnReceiverShutdown(EntityUid uid, ExtensionCableReceiverComponent receiver, ComponentShutdown args)
  151. {
  152. Disconnect(uid, receiver);
  153. }
  154. private void OnReceiverAnchorStateChanged(EntityUid uid, ExtensionCableReceiverComponent receiver, ref AnchorStateChangedEvent args)
  155. {
  156. if (args.Anchored)
  157. {
  158. Connect(uid, receiver);
  159. }
  160. else
  161. {
  162. Disconnect(uid, receiver);
  163. }
  164. }
  165. private void OnReceiverReAnchor(EntityUid uid, ExtensionCableReceiverComponent receiver, ref ReAnchorEvent args)
  166. {
  167. Disconnect(uid, receiver);
  168. Connect(uid, receiver);
  169. }
  170. private void Connect(EntityUid uid, ExtensionCableReceiverComponent receiver)
  171. {
  172. receiver.Connectable = true;
  173. if (receiver.Provider == null)
  174. {
  175. TryFindAndSetProvider(receiver);
  176. }
  177. }
  178. private void Disconnect(EntityUid uid, ExtensionCableReceiverComponent receiver)
  179. {
  180. receiver.Connectable = false;
  181. RaiseLocalEvent(uid, new ProviderDisconnectedEvent(receiver.Provider), broadcast: false);
  182. if (receiver.Provider != null)
  183. {
  184. RaiseLocalEvent(receiver.Provider.Owner, new ReceiverDisconnectedEvent((uid, receiver)), broadcast: false);
  185. receiver.Provider.LinkedReceivers.Remove(receiver);
  186. }
  187. receiver.Provider = null;
  188. }
  189. private void TryFindAndSetProvider(ExtensionCableReceiverComponent receiver, TransformComponent? xform = null)
  190. {
  191. var uid = receiver.Owner;
  192. if (!receiver.Connectable)
  193. return;
  194. if (!TryFindAvailableProvider(uid, receiver.ReceptionRange, out var provider, xform))
  195. return;
  196. receiver.Provider = provider;
  197. provider.LinkedReceivers.Add(receiver);
  198. RaiseLocalEvent(uid, new ProviderConnectedEvent(provider), broadcast: false);
  199. RaiseLocalEvent(provider.Owner, new ReceiverConnectedEvent((uid, receiver)), broadcast: false);
  200. }
  201. private bool TryFindAvailableProvider(EntityUid owner, float range, [NotNullWhen(true)] out ExtensionCableProviderComponent? foundProvider, TransformComponent? xform = null)
  202. {
  203. if (!Resolve(owner, ref xform) || !TryComp(xform.GridUid, out MapGridComponent? grid))
  204. {
  205. foundProvider = null;
  206. return false;
  207. }
  208. var coordinates = xform.Coordinates;
  209. var nearbyEntities = grid.GetCellsInSquareArea(coordinates, (int) Math.Ceiling(range / grid.TileSize));
  210. var cableQuery = GetEntityQuery<ExtensionCableProviderComponent>();
  211. var metaQuery = GetEntityQuery<MetaDataComponent>();
  212. var xformQuery = GetEntityQuery<TransformComponent>();
  213. ExtensionCableProviderComponent? closestCandidate = null;
  214. var closestDistanceFound = float.MaxValue;
  215. foreach (var entity in nearbyEntities)
  216. {
  217. if (entity == owner || !cableQuery.TryGetComponent(entity, out var provider) || !provider.Connectable)
  218. continue;
  219. if (EntityManager.IsQueuedForDeletion(entity))
  220. continue;
  221. if (!metaQuery.TryGetComponent(entity, out var meta) || meta.EntityLifeStage > EntityLifeStage.MapInitialized)
  222. continue;
  223. // Find the closest provider
  224. if (!xformQuery.TryGetComponent(entity, out var entityXform))
  225. continue;
  226. var distance = (entityXform.LocalPosition - xform.LocalPosition).Length();
  227. if (distance >= closestDistanceFound)
  228. continue;
  229. closestCandidate = provider;
  230. closestDistanceFound = distance;
  231. }
  232. // Make sure the provider is in range before claiming success
  233. if (closestCandidate != null && closestDistanceFound <= Math.Min(range, closestCandidate.TransferRange))
  234. {
  235. foundProvider = closestCandidate;
  236. return true;
  237. }
  238. foundProvider = null;
  239. return false;
  240. }
  241. #endregion
  242. #region Events
  243. /// <summary>
  244. /// Sent when a <see cref="ExtensionCableProviderComponent"/> connects to a <see cref="ExtensionCableReceiverComponent"/>
  245. /// </summary>
  246. public sealed class ProviderConnectedEvent : EntityEventArgs
  247. {
  248. /// <summary>
  249. /// The <see cref="ExtensionCableProviderComponent"/> that connected.
  250. /// </summary>
  251. public ExtensionCableProviderComponent Provider;
  252. public ProviderConnectedEvent(ExtensionCableProviderComponent provider)
  253. {
  254. Provider = provider;
  255. }
  256. }
  257. /// <summary>
  258. /// Sent when a <see cref="ExtensionCableProviderComponent"/> disconnects from a <see cref="ExtensionCableReceiverComponent"/>
  259. /// </summary>
  260. public sealed class ProviderDisconnectedEvent : EntityEventArgs
  261. {
  262. /// <summary>
  263. /// The <see cref="ExtensionCableProviderComponent"/> that disconnected.
  264. /// </summary>
  265. public ExtensionCableProviderComponent? Provider;
  266. public ProviderDisconnectedEvent(ExtensionCableProviderComponent? provider)
  267. {
  268. Provider = provider;
  269. }
  270. }
  271. /// <summary>
  272. /// Sent when a <see cref="ExtensionCableReceiverComponent"/> connects to a <see cref="ExtensionCableProviderComponent"/>
  273. /// </summary>
  274. public sealed class ReceiverConnectedEvent : EntityEventArgs
  275. {
  276. /// <summary>
  277. /// The <see cref="ExtensionCableReceiverComponent"/> that connected.
  278. /// </summary>
  279. public Entity<ExtensionCableReceiverComponent> Receiver;
  280. public ReceiverConnectedEvent(Entity<ExtensionCableReceiverComponent> receiver)
  281. {
  282. Receiver = receiver;
  283. }
  284. }
  285. /// <summary>
  286. /// Sent when a <see cref="ExtensionCableReceiverComponent"/> disconnects from a <see cref="ExtensionCableProviderComponent"/>
  287. /// </summary>
  288. public sealed class ReceiverDisconnectedEvent : EntityEventArgs
  289. {
  290. /// <summary>
  291. /// The <see cref="ExtensionCableReceiverComponent"/> that disconnected.
  292. /// </summary>
  293. public Entity<ExtensionCableReceiverComponent> Receiver;
  294. public ReceiverDisconnectedEvent(Entity<ExtensionCableReceiverComponent> receiver)
  295. {
  296. Receiver = receiver;
  297. }
  298. }
  299. #endregion
  300. }
  301. }