Files
RobustToolbox/Robust.Shared/GameObjects/EntitySystem.cs
T
Vera Aguilera PuertoandGitHub 2b589215aa Improves the Filter API. (#1747)
- Recipients is now of type `IEnumerable<ICommonSession>`.
    - This way, people need to use the Filter API to modify the recipients, instead of being allowed to modify the underlying collection directly.
- Underlying collection is now a HashSet.
    - We want no duplicates at all. This will ensure that while being quite performant.
- Removes `IFilter`.
    - Let's face it, everyone is gonna end up using `Filter` instead as it has a much more convenient API, and nothing else will EVER implement `IFilter`. For this reason, I've just gone ahead and removed it. Every method used `Filter` already, anyway.
- Adds EntitySystem `RaiseNetworkEvent` overload that takes in a `Filter`.
    - This deduplicates a lot of code that enumerated the recipients and raised a network event per each one.
- Made AddPlayersByPvs aware of `net.pvs` and `net.maxupdaterange`, has a range multiplier parameter.
    - Now it will simply add all players to the filter if PVS is disabled, and add all players in range if it's enabled.
    - The range multiplier parameter allows us to make the PVS filter a bit more permissive, and generally better. The range is doubled by default, as it was already before.
- Adds `AddInRange` method to filters.
    - This is useful for the AudioSystem, and the PVS methods use it, too!
- Adds `RemoveByVisibility` method to filters.
    - This will remove all recipients that don't have a visibility flag in their entity's EyeComponent from the filter.
    - (This will be VERY useful for Ghost Pointing, for example)
- Adds `Clone` method to filters.
    - This is useful in cases where methods take in a filter and want to modify it without modifying the original instance. (See AudioSystem)
2021-05-08 22:27:47 +02:00

193 lines
7.1 KiB
C#

using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Threading;
using System.Threading.Tasks;
using JetBrains.Annotations;
using Robust.Shared.IoC;
using Robust.Shared.Network;
using Robust.Shared.Player;
using Robust.Shared.Reflection;
namespace Robust.Shared.GameObjects
{
/// <summary>
/// A subsystem that acts on all components of a type at once.
/// </summary>
/// <remarks>
/// This class is instantiated by the <c>EntitySystemManager</c>, and any IoC Dependencies will be resolved.
/// </remarks>
[Reflect(false), PublicAPI]
public abstract class EntitySystem : IEntitySystem
{
[Dependency] protected readonly IEntityManager EntityManager = default!;
[Dependency] protected readonly IComponentManager ComponentManager = default!;
[Dependency] protected readonly IEntitySystemManager EntitySystemManager = default!;
[Obsolete("You need to create and store the query yourself in a field.")]
protected IEntityQuery? EntityQuery;
[Obsolete("You need to use `EntityManager.GetEntities(EntityQuery)`, or store a query yourself.")]
protected IEnumerable<IEntity> RelevantEntities => EntityQuery != null ? EntityManager.GetEntities(EntityQuery) : EntityManager.GetEntities();
protected internal List<Type> UpdatesAfter { get; } = new();
protected internal List<Type> UpdatesBefore { get; } = new();
IEnumerable<Type> IEntitySystem.UpdatesAfter => UpdatesAfter;
IEnumerable<Type> IEntitySystem.UpdatesBefore => UpdatesBefore;
/// <inheritdoc />
public virtual void Initialize() { }
/// <inheritdoc />
public virtual void Update(float frameTime) { }
/// <inheritdoc />
public virtual void FrameUpdate(float frameTime) { }
/// <inheritdoc />
public virtual void Shutdown() { }
#region Event Proxy
protected void SubscribeNetworkEvent<T>(EntityEventHandler<T> handler)
where T : notnull
{
EntityManager.EventBus.SubscribeEvent(EventSource.Network, this, handler);
}
protected void SubscribeNetworkEvent<T>(EntitySessionEventHandler<T> handler)
where T : notnull
{
EntityManager.EventBus.SubscribeSessionEvent(EventSource.Network, this, handler);
}
protected void SubscribeLocalEvent<T>(EntityEventHandler<T> handler)
where T : notnull
{
EntityManager.EventBus.SubscribeEvent(EventSource.Local, this, handler);
}
protected void SubscribeLocalEvent<T>(EntitySessionEventHandler<T> handler)
where T : notnull
{
EntityManager.EventBus.SubscribeSessionEvent(EventSource.Local, this, handler);
}
protected void UnsubscribeNetworkEvent<T>()
where T : notnull
{
EntityManager.EventBus.UnsubscribeEvent<T>(EventSource.Network, this);
}
protected void UnsubscribeLocalEvent<T>()
where T : notnull
{
EntityManager.EventBus.UnsubscribeEvent<T>(EventSource.Local, this);
}
protected void RaiseLocalEvent<T>(T message) where T : notnull
{
EntityManager.EventBus.RaiseEvent(EventSource.Local, message);
}
protected void RaiseLocalEvent(object message)
{
EntityManager.EventBus.RaiseEvent(EventSource.Local, message);
}
protected void QueueLocalEvent(EntityEventArgs message)
{
EntityManager.EventBus.QueueEvent(EventSource.Local, message);
}
protected void RaiseNetworkEvent(EntityEventArgs message)
{
EntityManager.EntityNetManager?.SendSystemNetworkMessage(message);
}
protected void RaiseNetworkEvent(EntityEventArgs message, INetChannel channel)
{
EntityManager.EntityNetManager?.SendSystemNetworkMessage(message, channel);
}
protected void RaiseNetworkEvent(EntityEventArgs message, Filter filter)
{
foreach (var session in filter.Recipients)
{
EntityManager.EntityNetManager?.SendSystemNetworkMessage(message, session.ConnectedClient);
}
}
protected Task<T> AwaitNetworkEvent<T>(CancellationToken cancellationToken)
where T : EntityEventArgs
{
return EntityManager.EventBus.AwaitEvent<T>(EventSource.Network, cancellationToken);
}
protected void SubscribeLocalEvent<TComp, TEvent>(ComponentEventHandler<TComp, TEvent> handler)
where TComp : IComponent
where TEvent : EntityEventArgs
{
EntityManager.EventBus.SubscribeLocalEvent(handler);
}
[Obsolete("Use the overload without the handler argument.")]
protected void UnsubscribeLocalEvent<TComp, TEvent>(ComponentEventHandler<TComp, TEvent> handler)
where TComp : IComponent
where TEvent : EntityEventArgs
{
EntityManager.EventBus.UnsubscribeLocalEvent<TComp, TEvent>();
}
protected void UnsubscribeLocalEvent<TComp, TEvent>()
where TComp : IComponent
where TEvent : EntityEventArgs
{
EntityManager.EventBus.UnsubscribeLocalEvent<TComp, TEvent>();
}
protected void RaiseLocalEvent<TEvent>(EntityUid uid, TEvent args, bool broadcast = true)
where TEvent : EntityEventArgs
{
EntityManager.EventBus.RaiseLocalEvent(uid, args, broadcast);
}
#endregion
#region Static Helpers
/*
NOTE: Static helpers relating to EntitySystems are here rather than in a
static helper class for conciseness / usability. If we had an "EntitySystems" static class
it would conflict with any imported namespace called "EntitySystems" and require using alias directive, and
if we called it something longer like "EntitySystemUtility", writing out "EntitySystemUtility.Get" seems
pretty tedious for a potentially commonly-used method. Putting it here allows writing "EntitySystem.Get"
which is nice and concise.
*/
/// <summary>
/// Gets the indicated entity system.
/// </summary>
/// <typeparam name="T">entity system to get</typeparam>
/// <returns></returns>
public static T Get<T>() where T : IEntitySystem
{
return IoCManager.Resolve<IEntitySystemManager>().GetEntitySystem<T>();
}
/// <summary>
/// Tries to get an entity system of the specified type.
/// </summary>
/// <typeparam name="T">Type of entity system to find.</typeparam>
/// <param name="entitySystem">instance matching the specified type (if exists).</param>
/// <returns>If an instance of the specified entity system type exists.</returns>
public static bool TryGet<T>([NotNullWhen(true)] out T? entitySystem) where T : IEntitySystem
{
return IoCManager.Resolve<IEntitySystemManager>().TryGetEntitySystem(out entitySystem);
}
#endregion
}
}