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 QueueEvent(EntitySystemMessage message)
{
EntityManager.QueueEvent(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);
}
}
}