using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.GameObjects.Systems; using Robust.Shared.Interfaces.Network; using Robust.Shared.IoC; using Robust.Shared.Reflection; namespace Robust.Shared.GameObjects.Systems { /// /// A subsystem that acts on all components of a type at once. /// /// /// This class is instantiated by the EntitySystemManager, and any IoC Dependencies will be resolved. /// [Reflect(false)] public abstract class EntitySystem : IEntityEventSubscriber, IEntitySystem { [Dependency] protected readonly IEntityManager EntityManager; [Dependency] protected readonly IEntitySystemManager EntitySystemManager; [Dependency] protected readonly IEntityNetworkManager EntityNetworkManager; protected IEntityQuery EntityQuery; protected IEnumerable RelevantEntities => EntityManager.GetEntities(EntityQuery); private readonly Dictionary)> _awaitingMessages = new Dictionary)>(); protected EntitySystem() { //EntityManager = IoCManager.Resolve(); //EntitySystemManager = IoCManager.Resolve(); //EntityNetworkManager = IoCManager.Resolve(); } public virtual void RegisterMessageTypes() { } public virtual void SubscribeEvents() { } /// public virtual void Initialize() { } /// public virtual void Update(float frameTime) { } /// public virtual void FrameUpdate(float frameTime) { } /// public virtual void Shutdown() { } /// public virtual void HandleNetMessage(INetChannel channel, EntitySystemMessage message) { var type = message.GetType(); if (_awaitingMessages.TryGetValue(type, out var awaiting)) { var (_, tcs) = awaiting; tcs.TrySetResult(message); _awaitingMessages.Remove(type); } } public void RegisterMessageType() where T : EntitySystemMessage { EntitySystemManager.RegisterMessageType(this); } protected void SubscribeEvent(EntityEventHandler evh) where T : EntitySystemMessage { EntityManager.SubscribeEvent(evh, this); } protected void SubscribeEvent(EntityEventHandler evh) where T : EntitySystemMessage { EntityManager.SubscribeEvent(evh, this); } protected void UnsubscribeEvent() where T : EntitySystemMessage { EntityManager.UnsubscribeEvent(this); } protected void RaiseEvent(EntitySystemMessage message) { EntityManager.RaiseEvent(this, message); } protected void RaiseNetworkEvent(EntitySystemMessage message) { EntityNetworkManager.SendSystemNetworkMessage(message); } protected void RaiseNetworkEvent(EntitySystemMessage message, INetChannel channel) { EntityNetworkManager.SendSystemNetworkMessage(message, channel); } protected Task AwaitNetMessage(CancellationToken cancellationToken = default) where T : EntitySystemMessage { var type = typeof(T); if (_awaitingMessages.ContainsKey(type)) { throw new InvalidOperationException("Cannot await the same message type twice at once."); } var tcs = new TaskCompletionSource(); CancellationTokenRegistration reg = default; if (cancellationToken != default) { reg = cancellationToken.Register(() => { _awaitingMessages.Remove(type); tcs.TrySetCanceled(); }); } // Tiny trick so we can return T while the tcs is passed an EntitySystemMessage. async Task DoCast(Task task) { return (T) await task; } _awaitingMessages.Add(type, (reg, tcs)); return DoCast(tcs.Task); } } }