Files
RobustToolbox/Robust.Shared/GameObjects/EntityManager.Components.cs
2023-11-27 21:41:01 +11:00

2191 lines
74 KiB
C#

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using JetBrains.Annotations;
using Robust.Shared.GameStates;
using Robust.Shared.Log;
using Robust.Shared.Physics.Components;
using Robust.Shared.Player;
using Robust.Shared.Timing;
using Robust.Shared.Utility;
#if EXCEPTION_TOLERANCE
using Robust.Shared.Exceptions;
#endif
namespace Robust.Shared.GameObjects
{
/// <inheritdoc />
public partial class EntityManager
{
[IoC.Dependency] private readonly IComponentFactory _componentFactory = default!;
#if EXCEPTION_TOLERANCE
[IoC.Dependency] private readonly IRuntimeLog _runtimeLog = default!;
#endif
public IComponentFactory ComponentFactory => _componentFactory;
private const int TypeCapacity = 32;
private const int ComponentCollectionCapacity = 1024;
private const int EntityCapacity = 1024;
private const int NetComponentCapacity = 8;
private static readonly ComponentState DefaultComponentState = new();
private readonly Dictionary<Type, Dictionary<EntityUid, IComponent>> _entTraitDict
= new();
private Dictionary<EntityUid, IComponent>[] _entTraitArray
= Array.Empty<Dictionary<EntityUid, IComponent>>();
private readonly HashSet<IComponent> _deleteSet = new(TypeCapacity);
private UniqueIndexHkm<EntityUid, IComponent> _entCompIndex =
new(ComponentCollectionCapacity);
/// <inheritdoc />
public event Action<AddedComponentEventArgs>? ComponentAdded;
/// <inheritdoc />
public event Action<RemovedComponentEventArgs>? ComponentRemoved;
public void InitializeComponents()
{
if (Initialized)
throw new InvalidOperationException("Already initialized.");
FillComponentDict();
_componentFactory.ComponentAdded += OnComponentAdded;
}
/// <summary>
/// Instantly clears all components from the manager. This will NOT shut them down gracefully.
/// Any entities relying on existing components will be broken.
/// </summary>
public void ClearComponents()
{
_entCompIndex.Clear();
_deleteSet.Clear();
foreach (var dict in _entTraitDict.Values)
{
dict.Clear();
}
}
private void AddComponentRefType(CompIdx type)
{
var dict = new Dictionary<EntityUid, IComponent>();
_entTraitDict.Add(_componentFactory.IdxToType(type), dict);
CompIdx.AssignArray(ref _entTraitArray, type, dict);
}
private void OnComponentAdded(ComponentRegistration obj)
{
AddComponentRefType(obj.Idx);
}
#region Component Management
/// <inheritdoc />
public int Count<T>() where T : IComponent
{
var dict = _entTraitDict[typeof(T)];
return dict.Count;
}
/// <inheritdoc />
public int Count(Type component)
{
var dict = _entTraitDict[component];
return dict.Count;
}
public void InitializeComponents(EntityUid uid, MetaDataComponent? metadata = null)
{
DebugTools.AssertOwner(uid, metadata);
metadata ??= GetComponent<MetaDataComponent>(uid);
DebugTools.Assert(metadata.EntityLifeStage == EntityLifeStage.PreInit);
metadata.EntityLifeStage = EntityLifeStage.Initializing;
// Initialize() can modify the collection of components. Copy them.
FixedArray32<IComponent?> compsFixed = default;
var comps = compsFixed.AsSpan;
CopyComponentsInto(ref comps, uid);
foreach (var comp in comps)
{
if (comp is { LifeStage: ComponentLifeStage.Added })
LifeInitialize(comp, CompIdx.Index(comp.GetType()));
}
#if DEBUG
// Second integrity check in case of.
foreach (var t in _entCompIndex[uid])
{
if (!t.Deleted && !t.Initialized)
{
DebugTools.Assert(
$"Component {t.GetType()} was not initialized at the end of {nameof(InitializeComponents)}.");
}
}
#endif
DebugTools.Assert(metadata.EntityLifeStage == EntityLifeStage.Initializing);
metadata.EntityLifeStage = EntityLifeStage.Initialized;
}
public void StartComponents(EntityUid uid)
{
// Startup() can modify _components
// This code can only handle additions to the list. Is there a better way? Probably not.
FixedArray32<IComponent?> compsFixed = default;
var comps = compsFixed.AsSpan;
CopyComponentsInto(ref comps, uid);
// TODO: please for the love of god remove these initialization order hacks.
// Init transform first, we always have it.
var transform = GetComponent<TransformComponent>(uid);
if (transform.LifeStage == ComponentLifeStage.Initialized)
LifeStartup(transform);
// Init physics second if it exists.
if (TryGetComponent<PhysicsComponent>(uid, out var phys)
&& phys.LifeStage == ComponentLifeStage.Initialized)
{
LifeStartup(phys);
}
// Do rest of components.
foreach (var comp in comps)
{
if (comp is { LifeStage: ComponentLifeStage.Initialized })
LifeStartup(comp);
}
}
public IComponent AddComponent(EntityUid uid, ushort netId, MetaDataComponent? meta = null)
{
var newComponent = _componentFactory.GetComponent(netId);
AddComponent(uid, newComponent, metadata: meta);
return newComponent;
}
public T AddComponent<T>(EntityUid uid) where T : IComponent, new()
{
var newComponent = _componentFactory.GetComponent<T>();
AddComponent(uid, newComponent);
return newComponent;
}
public readonly struct CompInitializeHandle<T> : IDisposable
where T : IComponent
{
private readonly IEntityManager _entMan;
private readonly EntityUid _owner;
public readonly CompIdx CompType;
public readonly T Comp;
public CompInitializeHandle(IEntityManager entityManager, EntityUid owner, T comp, CompIdx compType)
{
_entMan = entityManager;
_owner = owner;
Comp = comp;
CompType = compType;
}
public void Dispose()
{
var metadata = _entMan.GetComponent<MetaDataComponent>(_owner);
if (!metadata.EntityInitialized && !metadata.EntityInitializing)
return;
if (!Comp.Initialized)
((EntityManager) _entMan).LifeInitialize(Comp, CompType);
if (metadata.EntityInitialized && !Comp.Running)
((EntityManager) _entMan).LifeStartup(Comp);
}
public static implicit operator T(CompInitializeHandle<T> handle)
{
return handle.Comp;
}
}
/// <inheritdoc />
[Obsolete]
public CompInitializeHandle<T> AddComponentUninitialized<T>(EntityUid uid) where T : IComponent, new()
{
var reg = _componentFactory.GetRegistration<T>();
var newComponent = (T)_componentFactory.GetComponent(reg);
#pragma warning disable CS0618 // Type or member is obsolete
newComponent.Owner = uid;
#pragma warning restore CS0618 // Type or member is obsolete
if (!uid.IsValid() || !EntityExists(uid))
throw new ArgumentException($"Entity {uid} is not valid.", nameof(uid));
AddComponentInternal(uid, newComponent, false, true);
return new CompInitializeHandle<T>(this, uid, newComponent, reg.Idx);
}
/// <inheritdoc />
public void AddComponent<T>(EntityUid uid, T component, bool overwrite = false, MetaDataComponent? metadata = null) where T : IComponent
{
if (!uid.IsValid() || !EntityExists(uid))
throw new ArgumentException($"Entity {uid} is not valid.", nameof(uid));
if (component == null) throw new ArgumentNullException(nameof(component));
#pragma warning disable CS0618 // Type or member is obsolete
if (component.Owner == default)
{
component.Owner = uid;
}
else if (component.Owner != uid)
{
throw new InvalidOperationException("Component is not owned by entity.");
}
#pragma warning restore CS0618 // Type or member is obsolete
AddComponentInternal(uid, component, overwrite, false, metadata);
}
private void AddComponentInternal<T>(EntityUid uid, T component, bool overwrite, bool skipInit, MetaDataComponent? metadata = null) where T : IComponent
{
// get interface aliases for mapping
var reg = _componentFactory.GetRegistration(component);
AddComponentInternal(uid, component, reg, overwrite, skipInit, metadata);
}
private void AddComponentInternal<T>(EntityUid uid, T component, ComponentRegistration reg, bool overwrite, bool skipInit, MetaDataComponent? metadata = null) where T : IComponent
{
// We can't use typeof(T) here in case T is just Component
DebugTools.Assert(component is MetaDataComponent ||
(metadata ?? MetaQuery.GetComponent(uid)).EntityLifeStage < EntityLifeStage.Terminating,
$"Attempted to add a {component.GetType().Name} component to an entity ({ToPrettyString(uid)}) while it is terminating");
// Check that there is no existing component.
var type = reg.Idx;
var dict = _entTraitArray[type.Value];
DebugTools.Assert(dict != null);
// Code block to restrict access to ref comp.
{
ref var comp = ref CollectionsMarshal.GetValueRefOrAddDefault(dict, uid, out var exists);
if (exists)
{
if (!overwrite && !comp!.Deleted)
{
throw new InvalidOperationException(
$"Component reference type {reg.Name} already occupied by {comp}");
}
// This will invalidate the comp ref as it removes the key from the dictionary.
// This is inefficient, but component overriding rarely ever happens.
RemoveComponentImmediate(comp!, uid, false, metadata);
dict.Add(uid, component);
}
else
{
comp = component;
}
}
// actually ADD the component
_entCompIndex.Add(uid, component);
// add the component to the netId grid
if (reg.NetID != null)
{
// the main comp grid keeps this in sync
var netId = reg.NetID.Value;
metadata ??= MetaQuery.GetComponentInternal(uid);
metadata.NetComponents.Add(netId, component);
}
else
{
component.Networked = false;
}
var eventArgs = new AddedComponentEventArgs(new ComponentEventArgs(component, uid), reg);
ComponentAdded?.Invoke(eventArgs);
_eventBus.OnComponentAdded(eventArgs);
LifeAddToEntity(component, reg.Idx);
if (skipInit)
return;
metadata ??= MetaQuery.GetComponentInternal(uid);
if (!metadata.EntityInitialized && !metadata.EntityInitializing)
return;
if (component.Networked)
DirtyEntity(uid, metadata);
LifeInitialize(component, reg.Idx);
if (metadata.EntityInitialized)
LifeStartup(component);
if (metadata.EntityLifeStage >= EntityLifeStage.MapInitialized)
EventBus.RaiseComponentEvent(component, MapInitEventInstance);
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool RemoveComponent<T>(EntityUid uid, MetaDataComponent? meta = null)
{
return RemoveComponent(uid, typeof(T), meta);
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool RemoveComponent(EntityUid uid, Type type, MetaDataComponent? meta = null)
{
if (!TryGetComponent(uid, type, out var comp))
return false;
RemoveComponentImmediate(comp, uid, false, meta);
return true;
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool RemoveComponent(EntityUid uid, ushort netId, MetaDataComponent? meta = null)
{
if (!MetaQuery.Resolve(uid, ref meta))
return false;
if (!TryGetComponent(uid, netId, out var comp, meta))
return false;
RemoveComponentImmediate(comp, uid, false, meta);
return true;
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void RemoveComponent(EntityUid uid, IComponent component, MetaDataComponent? meta = null)
{
RemoveComponentImmediate(component, uid, false, meta);
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool RemoveComponentDeferred<T>(EntityUid uid)
{
return RemoveComponentDeferred(uid, typeof(T));
}
/// <inheritdoc />
public bool RemoveComponentDeferred(EntityUid uid, Type type)
{
if (!TryGetComponent(uid, type, out var comp))
return false;
RemoveComponentDeferred(comp, uid, false);
return true;
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool RemoveComponentDeferred(EntityUid uid, ushort netId, MetaDataComponent? meta = null)
{
if (!MetaQuery.Resolve(uid, ref meta))
return false;
if (!TryGetComponent(uid, netId, out var comp, meta))
return false;
RemoveComponentDeferred(comp, uid, false);
return true;
}
/// <inheritdoc />
public void RemoveComponentDeferred(EntityUid owner, IComponent component)
{
RemoveComponentDeferred(component, owner, false);
}
/// <inheritdoc />
public void RemoveComponentDeferred(EntityUid owner, Component component)
{
RemoveComponentDeferred(component, owner, false);
}
private static IEnumerable<IComponent> InSafeOrder(IEnumerable<IComponent> comps, bool forCreation = false)
{
static int Sequence(IComponent x)
=> x switch
{
MetaDataComponent _ => 0,
TransformComponent _ => 1,
PhysicsComponent _ => 2,
_ => int.MaxValue
};
return forCreation
? comps.OrderBy(Sequence)
: comps.OrderByDescending(Sequence);
}
/// <inheritdoc />
public void RemoveComponents(EntityUid uid, MetaDataComponent? meta = null)
{
if (!MetaQuery.Resolve(uid, ref meta))
return;
foreach (var comp in InSafeOrder(_entCompIndex[uid]))
{
RemoveComponentImmediate(comp, uid, false, meta);
}
}
/// <inheritdoc />
public void DisposeComponents(EntityUid uid, MetaDataComponent? meta = null)
{
if (!MetaQuery.Resolve(uid, ref meta))
return;
foreach (var comp in InSafeOrder(_entCompIndex[uid]))
{
try
{
RemoveComponentImmediate(comp, uid, true, meta);
}
catch (Exception)
{
_sawmill.Error($"Caught exception while trying to remove component {_componentFactory.GetComponentName(comp.GetType())} from entity '{ToPrettyString(uid)}'");
}
}
_entCompIndex.Remove(uid);
}
private void RemoveComponentDeferred(IComponent component, EntityUid uid, bool terminating)
{
if (component == null) throw new ArgumentNullException(nameof(component));
#pragma warning disable CS0618 // Type or member is obsolete
if (component.Owner != uid)
#pragma warning restore CS0618 // Type or member is obsolete
throw new InvalidOperationException("Component is not owned by entity.");
if (component.Deleted) return;
#if EXCEPTION_TOLERANCE
try
{
#endif
// these two components are required on all entities and cannot be removed normally.
if (!terminating && component is TransformComponent or MetaDataComponent)
{
DebugTools.Assert("Tried to remove a protected component.");
return;
}
if (!_deleteSet.Add(component))
{
// already deferred deletion
return;
}
if (component.LifeStage >= ComponentLifeStage.Initialized && component.LifeStage <= ComponentLifeStage.Running)
LifeShutdown(component);
#if EXCEPTION_TOLERANCE
}
catch (Exception e)
{
_sawmill.Error($"Caught exception while queuing deferred component removal. Entity={ToPrettyString(component.Owner)}, type={component.GetType()}");
_runtimeLog.LogException(e, nameof(RemoveComponentDeferred));
}
#endif
}
private void RemoveComponentImmediate(IComponent component, EntityUid uid, bool terminating,
MetaDataComponent? meta)
{
if (component.Deleted)
{
_sawmill.Warning($"Deleting an already deleted component. Entity: {ToPrettyString(uid)}, Component: {_componentFactory.GetComponentName(component.GetType())}.");
return;
}
#if EXCEPTION_TOLERANCE
try
{
#endif
// these two components are required on all entities and cannot be removed.
if (!terminating && component is TransformComponent or MetaDataComponent)
{
DebugTools.Assert("Tried to remove a protected component.");
return;
}
if (component.Running)
LifeShutdown(component);
if (component.LifeStage != ComponentLifeStage.PreAdd)
LifeRemoveFromEntity(component); // Sets delete
#if EXCEPTION_TOLERANCE
}
catch (Exception e)
{
_sawmill.Error($"Caught exception during immediate component removal. Entity={ToPrettyString(component.Owner)}, type={component.GetType()}");
_runtimeLog.LogException(e, nameof(RemoveComponentImmediate));
}
#endif
DeleteComponent(uid, component, terminating, meta);
}
/// <inheritdoc />
public void CullRemovedComponents()
{
foreach (var component in InSafeOrder(_deleteSet))
{
if (component.Deleted)
continue;
var uid = component.Owner;
#if EXCEPTION_TOLERANCE
try
{
#endif
// The component may have been restarted sometime after removal was deferred.
if (component.Running)
{
// TODO add options to cancel deferred deletion?
_sawmill.Warning($"Found a running component while culling deferred deletions, owner={ToPrettyString(uid)}, type={component.GetType()}");
LifeShutdown(component);
}
if (component.LifeStage != ComponentLifeStage.PreAdd)
LifeRemoveFromEntity(component);
#if EXCEPTION_TOLERANCE
}
catch (Exception e)
{
_sawmill.Error($"Caught exception while processing deferred component removal. Entity={ToPrettyString(component.Owner)}, type={component.GetType()}");
_runtimeLog.LogException(e, nameof(CullRemovedComponents));
}
#endif
DeleteComponent(uid, component, false);
}
_deleteSet.Clear();
}
private void DeleteComponent(EntityUid entityUid, IComponent component, bool terminating, MetaDataComponent? metadata = null)
{
if (!MetaQuery.ResolveInternal(entityUid, ref metadata))
return;
var eventArgs = new RemovedComponentEventArgs(new ComponentEventArgs(component, entityUid), false, metadata);
ComponentRemoved?.Invoke(eventArgs);
_eventBus.OnComponentRemoved(eventArgs);
var reg = _componentFactory.GetRegistration(component);
DebugTools.Assert(component.Networked == (reg.NetID != null));
if (!terminating && reg.NetID != null)
{
if (!metadata.NetComponents.Remove(reg.NetID.Value))
_sawmill.Error($"Entity {ToPrettyString(entityUid, metadata)} did not have {component.GetType().Name} in its networked component dictionary during component deletion.");
if (component.NetSyncEnabled)
{
DirtyEntity(entityUid, metadata);
metadata.LastComponentRemoved = _gameTiming.CurTick;
}
}
_entTraitArray[reg.Idx.Value].Remove(entityUid);
// TODO if terminating the entity, maybe defer this?
// _entCompIndex.Remove(uid) gets called later on anyways.
_entCompIndex.Remove(entityUid, component);
DebugTools.Assert(_netMan.IsClient // Client side prediction can set LastComponentRemoved to some future tick,
|| metadata.EntityLastModifiedTick >= metadata.LastComponentRemoved);
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool HasComponent<T>(EntityUid uid)
{
var dict = _entTraitArray[CompIdx.ArrayIndex<T>()];
DebugTools.Assert(dict != null, $"Unknown component: {typeof(T).Name}");
return dict.TryGetValue(uid, out var comp) && !comp.Deleted;
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool HasComponent<T>(EntityUid? uid)
{
return uid.HasValue && HasComponent<T>(uid.Value);
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool HasComponent(EntityUid uid, Type type)
{
var dict = _entTraitDict[type];
return dict.TryGetValue(uid, out var comp) && !comp.Deleted;
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool HasComponent(EntityUid? uid, Type type)
{
if (!uid.HasValue)
{
return false;
}
var dict = _entTraitDict[type];
return dict.TryGetValue(uid.Value, out var comp) && !comp.Deleted;
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool HasComponent(EntityUid uid, ushort netId, MetaDataComponent? meta = null)
{
if (!MetaQuery.Resolve(uid, ref meta))
return false;
return meta.NetComponents.ContainsKey(netId);
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool HasComponent(EntityUid? uid, ushort netId, MetaDataComponent? meta = null)
{
if (!uid.HasValue)
{
DebugTools.AssertNull(meta);
return false;
}
return HasComponent(uid.Value, netId, meta);
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public T EnsureComponent<T>(EntityUid uid) where T : IComponent, new()
{
if (TryGetComponent<T>(uid, out var component))
{
// Check for deferred component removal.
if (component.LifeStage <= ComponentLifeStage.Running)
return component;
RemoveComponent(uid, component);
}
return AddComponent<T>(uid);
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool EnsureComponent<T>(ref Entity<T?> entity) where T : IComponent, new()
{
if (entity.Comp != null)
{
// Check for deferred component removal.
if (entity.Comp.LifeStage <= ComponentLifeStage.Running)
{
DebugTools.AssertOwner(entity, entity.Comp);
return true;
}
RemoveComponent(entity, entity.Comp);
}
entity.Comp = AddComponent<T>(entity);
return false;
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool EnsureComponent<T>(EntityUid entity, out T component) where T : IComponent, new()
{
if (TryGetComponent<T>(entity, out var comp))
{
// Check for deferred component removal.
if (comp.LifeStage <= ComponentLifeStage.Running)
{
component = comp;
return true;
}
RemoveComponent(entity, comp);
}
component = AddComponent<T>(entity);
return false;
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public T GetComponent<T>(EntityUid uid) where T : IComponent
{
var dict = _entTraitArray[CompIdx.ArrayIndex<T>()];
DebugTools.Assert(dict != null, $"Unknown component: {typeof(T).Name}");
if (dict.TryGetValue(uid, out var comp))
{
if (!comp.Deleted)
{
return (T)comp;
}
}
throw new KeyNotFoundException($"Entity {uid} does not have a component of type {typeof(T)}");
}
public IComponent GetComponent(EntityUid uid, CompIdx type)
{
var dict = _entTraitArray[type.Value];
if (dict.TryGetValue(uid, out var comp))
{
if (!comp.Deleted)
return comp;
}
throw new KeyNotFoundException($"Entity {uid} does not have a component of type {_componentFactory.IdxToType(type)}");
}
/// <inheritdoc />
public IComponent GetComponent(EntityUid uid, Type type)
{
// ReSharper disable once InvertIf
var dict = _entTraitDict[type];
if (dict.TryGetValue(uid, out var comp))
{
if (!comp.Deleted)
{
return comp;
}
}
throw new KeyNotFoundException($"Entity {uid} does not have a component of type {type}");
}
/// <inheritdoc />
public IComponent GetComponent(EntityUid uid, ushort netId, MetaDataComponent? meta = null)
{
return (meta ?? MetaQuery.GetComponentInternal(uid)).NetComponents[netId];
}
/// <inheritdoc />
public IComponent GetComponentInternal(EntityUid uid, CompIdx type)
{
var dict = _entTraitArray[type.Value];
if (dict.TryGetValue(uid, out var comp))
{
return comp;
}
throw new KeyNotFoundException($"Entity {uid} does not have a component of type {type}");
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool TryGetComponent<T>(EntityUid uid, [NotNullWhen(true)] out T? component)
{
var dict = _entTraitArray[CompIdx.ArrayIndex<T>()];
DebugTools.Assert(dict != null, $"Unknown component: {typeof(T).Name}");
if (dict.TryGetValue(uid, out var comp))
{
if (!comp.Deleted)
{
component = (T)comp;
return true;
}
}
component = default;
return false;
}
/// <inheritdoc />
public bool TryGetComponent<T>([NotNullWhen(true)] EntityUid? uid, [NotNullWhen(true)] out T? component)
{
if (!uid.HasValue)
{
component = default!;
return false;
}
if (TryGetComponent(uid.Value, typeof(T), out var comp))
{
if (!comp.Deleted)
{
component = (T)comp;
return true;
}
}
component = default;
return false;
}
/// <inheritdoc />
public bool TryGetComponent(EntityUid uid, Type type, [NotNullWhen(true)] out IComponent? component)
{
var dict = _entTraitDict[type];
if (dict.TryGetValue(uid, out var comp))
{
if (!comp.Deleted)
{
component = comp;
return true;
}
}
component = null;
return false;
}
public bool TryGetComponent(EntityUid uid, CompIdx type, [NotNullWhen(true)] out IComponent? component)
{
var dict = _entTraitArray[type.Value];
if (dict.TryGetValue(uid, out var comp))
{
if (!comp.Deleted)
{
component = comp;
return true;
}
}
component = null;
return false;
}
/// <inheritdoc />
public bool TryGetComponent([NotNullWhen(true)] EntityUid? uid, Type type,
[NotNullWhen(true)] out IComponent? component)
{
if (!uid.HasValue)
{
component = null;
return false;
}
var dict = _entTraitDict[type];
if (dict.TryGetValue(uid.Value, out var comp))
{
if (!comp.Deleted)
{
component = comp;
return true;
}
}
component = null;
return false;
}
/// <inheritdoc />
public bool TryGetComponent(EntityUid uid, ushort netId, [MaybeNullWhen(false)] out IComponent component, MetaDataComponent? meta = null)
{
if (MetaQuery.TryGetComponentInternal(uid, out var metadata)
&& metadata.NetComponents.TryGetValue(netId, out var comp))
{
component = comp;
return true;
}
component = default;
return false;
}
/// <inheritdoc />
public bool TryGetComponent([NotNullWhen(true)] EntityUid? uid, ushort netId,
[MaybeNullWhen(false)] out IComponent component, MetaDataComponent? meta = null)
{
if (!uid.HasValue)
{
DebugTools.AssertNull(meta);
component = default;
return false;
}
return TryGetComponent(uid.Value, netId, out component, meta);
}
public EntityQuery<TComp1> GetEntityQuery<TComp1>() where TComp1 : IComponent
{
var comps = _entTraitArray[CompIdx.ArrayIndex<TComp1>()];
DebugTools.Assert(comps != null, $"Unknown component: {typeof(TComp1).Name}");
return new EntityQuery<TComp1>(comps, _resolveSawmill);
}
public EntityQuery<IComponent> GetEntityQuery(Type type)
{
var comps = _entTraitArray[CompIdx.ArrayIndex(type)];
DebugTools.Assert(comps != null, $"Unknown component: {type.Name}");
return new EntityQuery<IComponent>(comps, _resolveSawmill);
}
/// <inheritdoc />
public IEnumerable<IComponent> GetComponents(EntityUid uid)
{
// ReSharper disable once LoopCanBeConvertedToQuery
foreach (var comp in _entCompIndex[uid].ToArray())
{
if (comp.Deleted) continue;
yield return comp;
}
}
/// <inheritdoc />
public int ComponentCount(EntityUid uid)
{
var comps = _entCompIndex[uid];
return comps.Count;
}
/// <summary>
/// Copy the components for an entity into the given span,
/// or re-allocate the span as an array if there's not enough space.º
/// </summary>
private void CopyComponentsInto(ref Span<IComponent?> comps, EntityUid uid)
{
var set = _entCompIndex[uid];
if (set.Count > comps.Length)
{
comps = new IComponent[set.Count];
}
var i = 0;
foreach (var c in set)
{
comps[i++] = c;
}
}
/// <inheritdoc />
public IEnumerable<T> GetComponents<T>(EntityUid uid)
{
var comps = _entCompIndex[uid].ToArray();
foreach (var comp in comps)
{
if (comp.Deleted || comp is not T tComp) continue;
yield return tComp;
}
}
/// <inheritdoc />
public NetComponentEnumerable GetNetComponents(EntityUid uid, MetaDataComponent? meta = null)
{
meta ??= MetaQuery.GetComponentInternal(uid);
return new NetComponentEnumerable(meta.NetComponents);
}
/// <inheritdoc />
public NetComponentEnumerable? GetNetComponentsOrNull(EntityUid uid, MetaDataComponent? meta = null)
{
return MetaQuery.Resolve(uid, ref meta)
? new NetComponentEnumerable(meta.NetComponents)
: null;
}
#region Join Functions
public (EntityUid Uid, T Component)[] AllComponents<T>() where T : IComponent
{
var query = AllEntityQueryEnumerator<T>();
var comps = new (EntityUid Uid, T Component)[Count<T>()];
var i = 0;
while (query.MoveNext(out var uid, out var comp))
{
comps[i] = (uid, comp);
i++;
}
return comps;
}
public List<(EntityUid Uid, T Component)> AllComponentsList<T>() where T : IComponent
{
var query = AllEntityQueryEnumerator<T>();
var comps = new List<(EntityUid Uid, T Component)>(Count<T>());
while (query.MoveNext(out var uid, out var comp))
{
comps.Add((uid, comp));
}
return comps;
}
public AllEntityQueryEnumerator<TComp1> AllEntityQueryEnumerator<TComp1>()
where TComp1 : IComponent
{
var trait1 = _entTraitArray[CompIdx.ArrayIndex<TComp1>()];
return new AllEntityQueryEnumerator<TComp1>(trait1);
}
public AllEntityQueryEnumerator<TComp1, TComp2> AllEntityQueryEnumerator<TComp1, TComp2>()
where TComp1 : IComponent
where TComp2 : IComponent
{
var trait1 = _entTraitArray[CompIdx.ArrayIndex<TComp1>()];
var trait2 = _entTraitArray[CompIdx.ArrayIndex<TComp2>()];
return new AllEntityQueryEnumerator<TComp1, TComp2>(trait1, trait2);
}
public AllEntityQueryEnumerator<TComp1, TComp2, TComp3> AllEntityQueryEnumerator<TComp1, TComp2, TComp3>()
where TComp1 : IComponent
where TComp2 : IComponent
where TComp3 : IComponent
{
var trait1 = _entTraitArray[CompIdx.ArrayIndex<TComp1>()];
var trait2 = _entTraitArray[CompIdx.ArrayIndex<TComp2>()];
var trait3 = _entTraitArray[CompIdx.ArrayIndex<TComp3>()];
return new AllEntityQueryEnumerator<TComp1, TComp2, TComp3>(trait1, trait2, trait3);
}
public AllEntityQueryEnumerator<TComp1, TComp2, TComp3, TComp4> AllEntityQueryEnumerator<TComp1, TComp2, TComp3, TComp4>()
where TComp1 : IComponent
where TComp2 : IComponent
where TComp3 : IComponent
where TComp4 : IComponent
{
var trait1 = _entTraitArray[CompIdx.ArrayIndex<TComp1>()];
var trait2 = _entTraitArray[CompIdx.ArrayIndex<TComp2>()];
var trait3 = _entTraitArray[CompIdx.ArrayIndex<TComp3>()];
var trait4 = _entTraitArray[CompIdx.ArrayIndex<TComp4>()];
return new AllEntityQueryEnumerator<TComp1, TComp2, TComp3, TComp4>(trait1, trait2, trait3, trait4);
}
public EntityQueryEnumerator<TComp1> EntityQueryEnumerator<TComp1>()
where TComp1 : IComponent
{
var trait1 = _entTraitArray[CompIdx.ArrayIndex<TComp1>()];
return new EntityQueryEnumerator<TComp1>(trait1, MetaQuery);
}
public EntityQueryEnumerator<TComp1, TComp2> EntityQueryEnumerator<TComp1, TComp2>()
where TComp1 : IComponent
where TComp2 : IComponent
{
var trait1 = _entTraitArray[CompIdx.ArrayIndex<TComp1>()];
var trait2 = _entTraitArray[CompIdx.ArrayIndex<TComp2>()];
return new EntityQueryEnumerator<TComp1, TComp2>(trait1, trait2, MetaQuery);
}
public EntityQueryEnumerator<TComp1, TComp2, TComp3> EntityQueryEnumerator<TComp1, TComp2, TComp3>()
where TComp1 : IComponent
where TComp2 : IComponent
where TComp3 : IComponent
{
var trait1 = _entTraitArray[CompIdx.ArrayIndex<TComp1>()];
var trait2 = _entTraitArray[CompIdx.ArrayIndex<TComp2>()];
var trait3 = _entTraitArray[CompIdx.ArrayIndex<TComp3>()];
return new EntityQueryEnumerator<TComp1, TComp2, TComp3>(trait1, trait2, trait3, MetaQuery);
}
public EntityQueryEnumerator<TComp1, TComp2, TComp3, TComp4> EntityQueryEnumerator<TComp1, TComp2, TComp3, TComp4>()
where TComp1 : IComponent
where TComp2 : IComponent
where TComp3 : IComponent
where TComp4 : IComponent
{
var trait1 = _entTraitArray[CompIdx.ArrayIndex<TComp1>()];
var trait2 = _entTraitArray[CompIdx.ArrayIndex<TComp2>()];
var trait3 = _entTraitArray[CompIdx.ArrayIndex<TComp3>()];
var trait4 = _entTraitArray[CompIdx.ArrayIndex<TComp4>()];
return new EntityQueryEnumerator<TComp1, TComp2, TComp3, TComp4>(trait1, trait2, trait3, trait4, MetaQuery);
}
/// <inheritdoc />
public IEnumerable<T> EntityQuery<T>(bool includePaused = false) where T : IComponent
{
var comps = _entTraitArray[CompIdx.ArrayIndex<T>()];
DebugTools.Assert(comps != null, $"Unknown component: {typeof(T).Name}");
if (includePaused)
{
foreach (var t1Comp in comps.Values)
{
if (t1Comp.Deleted) continue;
yield return (T)t1Comp;
}
}
else
{
foreach (var (uid, t1Comp) in comps)
{
if (t1Comp.Deleted || !MetaQuery.TryGetComponentInternal(uid, out var metaComp)) continue;
if (metaComp.EntityPaused) continue;
yield return (T)t1Comp;
}
}
}
/// <inheritdoc />
public IEnumerable<(TComp1, TComp2)> EntityQuery<TComp1, TComp2>(bool includePaused = false)
where TComp1 : IComponent
where TComp2 : IComponent
{
// this would prob be faster if trait1 was a list (or an array of structs hue).
var trait1 = _entTraitArray[CompIdx.ArrayIndex<TComp1>()];
var trait2 = _entTraitArray[CompIdx.ArrayIndex<TComp2>()];
// you really want trait1 to be the smaller set of components
if (includePaused)
{
foreach (var (uid, t1Comp) in trait1)
{
if (!trait2.TryGetValue(uid, out var t2Comp) || t2Comp.Deleted)
continue;
yield return (
(TComp1) t1Comp,
(TComp2) t2Comp);
}
}
else
{
var metaComps = _entTraitArray[CompIdx.ArrayIndex<MetaDataComponent>()];
foreach (var (uid, t1Comp) in trait1)
{
// Check paused last because 90% of the time the component's likely not gonna be paused.
if (!trait2.TryGetValue(uid, out var t2Comp) || t2Comp.Deleted)
continue;
if (t1Comp.Deleted || !metaComps.TryGetValue(uid, out var metaComp)) continue;
var meta = (MetaDataComponent)metaComp;
if (meta.EntityPaused) continue;
yield return (
(TComp1) t1Comp,
(TComp2) t2Comp);
}
}
}
/// <inheritdoc />
public IEnumerable<(TComp1, TComp2, TComp3)> EntityQuery<TComp1, TComp2, TComp3>(bool includePaused = false)
where TComp1 : IComponent
where TComp2 : IComponent
where TComp3 : IComponent
{
var trait1 = _entTraitArray[CompIdx.ArrayIndex<TComp1>()];
var trait2 = _entTraitArray[CompIdx.ArrayIndex<TComp2>()];
var trait3 = _entTraitArray[CompIdx.ArrayIndex<TComp3>()];
if (includePaused)
{
foreach (var (uid, t1Comp) in trait1)
{
if (!trait2.TryGetValue(uid, out var t2Comp) || t2Comp.Deleted)
continue;
if (!trait3.TryGetValue(uid, out var t3Comp) || t3Comp.Deleted)
continue;
yield return (
(TComp1) t1Comp,
(TComp2) t2Comp,
(TComp3) t3Comp);
}
}
else
{
var metaComps = _entTraitArray[CompIdx.ArrayIndex<MetaDataComponent>()];
foreach (var (uid, t1Comp) in trait1)
{
// Check paused last because 90% of the time the component's likely not gonna be paused.
if (!trait2.TryGetValue(uid, out var t2Comp) || t2Comp.Deleted)
continue;
if (!trait3.TryGetValue(uid, out var t3Comp) || t3Comp.Deleted)
continue;
if (t1Comp.Deleted || !metaComps.TryGetValue(uid, out var metaComp)) continue;
var meta = (MetaDataComponent)metaComp;
if (meta.EntityPaused) continue;
yield return (
(TComp1) t1Comp,
(TComp2) t2Comp,
(TComp3) t3Comp);
}
}
}
/// <inheritdoc />
public IEnumerable<(TComp1, TComp2, TComp3, TComp4)> EntityQuery<TComp1, TComp2, TComp3, TComp4>(
bool includePaused = false)
where TComp1 : IComponent
where TComp2 : IComponent
where TComp3 : IComponent
where TComp4 : IComponent
{
var trait1 = _entTraitArray[CompIdx.ArrayIndex<TComp1>()];
var trait2 = _entTraitArray[CompIdx.ArrayIndex<TComp2>()];
var trait3 = _entTraitArray[CompIdx.ArrayIndex<TComp3>()];
var trait4 = _entTraitArray[CompIdx.ArrayIndex<TComp4>()];
if (includePaused)
{
foreach (var (uid, t1Comp) in trait1)
{
if (!trait2.TryGetValue(uid, out var t2Comp) || t2Comp.Deleted)
continue;
if (!trait3.TryGetValue(uid, out var t3Comp) || t3Comp.Deleted)
continue;
if (!trait4.TryGetValue(uid, out var t4Comp) || t4Comp.Deleted)
continue;
yield return (
(TComp1) t1Comp,
(TComp2) t2Comp,
(TComp3) t3Comp,
(TComp4) t4Comp);
}
}
else
{
var metaComps = _entTraitArray[CompIdx.ArrayIndex<MetaDataComponent>()];
foreach (var (uid, t1Comp) in trait1)
{
// Check paused last because 90% of the time the component's likely not gonna be paused.
if (!trait2.TryGetValue(uid, out var t2Comp) || t2Comp.Deleted)
continue;
if (!trait3.TryGetValue(uid, out var t3Comp) || t3Comp.Deleted)
continue;
if (!trait4.TryGetValue(uid, out var t4Comp) || t4Comp.Deleted)
continue;
if (t1Comp.Deleted || !metaComps.TryGetValue(uid, out var metaComp)) continue;
var meta = (MetaDataComponent)metaComp;
if (meta.EntityPaused) continue;
yield return (
(TComp1) t1Comp,
(TComp2) t2Comp,
(TComp3) t3Comp,
(TComp4) t4Comp);
}
}
}
#endregion
/// <inheritdoc />
public IEnumerable<(EntityUid Uid, IComponent Component)> GetAllComponents(Type type, bool includePaused = false)
{
var comps = _entTraitDict[type];
if (includePaused)
{
foreach (var (uid, comp) in comps)
{
if (comp.Deleted) continue;
yield return (uid, comp);
}
}
else
{
foreach (var (uid, comp) in comps)
{
if (comp.Deleted || !MetaQuery.TryGetComponent(uid, out var meta) || meta.EntityPaused) continue;
yield return (uid, comp);
}
}
}
/// <inheritdoc />
public ComponentState GetComponentState(IEventBus eventBus, IComponent component, ICommonSession? session, GameTick fromTick)
{
DebugTools.Assert(component.NetSyncEnabled, $"Attempting to get component state for an un-synced component: {component.GetType()}");
var getState = new ComponentGetState(session, fromTick);
eventBus.RaiseComponentEvent(component, ref getState);
return getState.State ?? DefaultComponentState;
}
public bool CanGetComponentState(IEventBus eventBus, IComponent component, ICommonSession player)
{
var attempt = new ComponentGetStateAttemptEvent(player);
eventBus.RaiseComponentEvent(component, ref attempt);
return !attempt.Cancelled;
}
#endregion
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void FillComponentDict()
{
_entTraitDict.Clear();
Array.Fill(_entTraitArray, null);
foreach (var refType in _componentFactory.GetAllRefTypes())
{
AddComponentRefType(refType);
}
}
}
public readonly struct NetComponentEnumerable
{
private readonly Dictionary<ushort, IComponent> _dictionary;
public NetComponentEnumerable(Dictionary<ushort, IComponent> dictionary) => _dictionary = dictionary;
public NetComponentEnumerator GetEnumerator() => new(_dictionary);
}
public struct NetComponentEnumerator
{
// DO NOT MAKE THIS READONLY
private Dictionary<ushort, IComponent>.Enumerator _dictEnum;
public NetComponentEnumerator(Dictionary<ushort, IComponent> dictionary) =>
_dictEnum = dictionary.GetEnumerator();
public bool MoveNext() => _dictEnum.MoveNext();
public (ushort netId, IComponent component) Current
{
get
{
var val = _dictEnum.Current;
return (val.Key, val.Value);
}
}
}
public readonly struct EntityQuery<TComp1> where TComp1 : IComponent
{
private readonly Dictionary<EntityUid, IComponent> _traitDict;
private readonly ISawmill _sawmill;
public EntityQuery(Dictionary<EntityUid, IComponent> traitDict, ISawmill sawmill)
{
_traitDict = traitDict;
_sawmill = sawmill;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[Pure]
public TComp1 GetComponent(EntityUid uid)
{
if (_traitDict.TryGetValue(uid, out var comp) && !comp.Deleted)
return (TComp1) comp;
throw new KeyNotFoundException($"Entity {uid} does not have a component of type {typeof(TComp1)}");
}
[MethodImpl(MethodImplOptions.AggressiveInlining), Pure]
public Entity<TComp1> Get(EntityUid uid)
{
if (_traitDict.TryGetValue(uid, out var comp) && !comp.Deleted)
return new Entity<TComp1>(uid, (TComp1) comp);
throw new KeyNotFoundException($"Entity {uid} does not have a component of type {typeof(TComp1)}");
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[Pure]
public bool TryGetComponent([NotNullWhen(true)] EntityUid? uid, [NotNullWhen(true)] out TComp1? component)
{
if (uid == null)
{
component = default;
return false;
}
return TryGetComponent(uid.Value, out component);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[Pure]
public bool TryGetComponent(EntityUid uid, [NotNullWhen(true)] out TComp1? component)
{
if (_traitDict.TryGetValue(uid, out var comp) && !comp.Deleted)
{
component = (TComp1) comp;
return true;
}
component = default;
return false;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[Pure]
public bool HasComponent(EntityUid uid)
{
return _traitDict.TryGetValue(uid, out var comp) && !comp.Deleted;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[Pure]
public bool HasComponent(EntityUid? uid)
{
return uid != null && HasComponent(uid.Value);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[Pure]
public bool Resolve(EntityUid uid, [NotNullWhen(true)] ref TComp1? component, bool logMissing = true)
{
if (component != null)
{
DebugTools.AssertOwner(uid, component);
return true;
}
if (_traitDict.TryGetValue(uid, out var comp) && !comp.Deleted)
{
component = (TComp1)comp;
return true;
}
if (logMissing)
_sawmill.Error($"Can't resolve \"{typeof(TComp1)}\" on entity {uid}!\n{new StackTrace(1, true)}");
return false;
}
[MethodImpl(MethodImplOptions.AggressiveInlining), Pure]
public bool Resolve(ref Entity<TComp1?> entity, bool logMissing = true)
{
return Resolve(entity.Owner, ref entity.Comp, logMissing);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[Pure]
public TComp1? CompOrNull(EntityUid uid)
{
if (TryGetComponent(uid, out var comp))
return comp;
return default;
}
#region Internal
/// <summary>
/// Elides the component.Deleted check of <see cref="GetComponent"/>
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[Pure]
internal TComp1 GetComponentInternal(EntityUid uid)
{
if (_traitDict.TryGetValue(uid, out var comp))
return (TComp1) comp;
throw new KeyNotFoundException($"Entity {uid} does not have a component of type {typeof(TComp1)}");
}
/// <summary>
/// Elides the component.Deleted check of <see cref="TryGetComponent(System.Nullable{Robust.Shared.GameObjects.EntityUid},out TComp1?)"/>
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[Pure]
internal bool TryGetComponentInternal([NotNullWhen(true)] EntityUid? uid, [NotNullWhen(true)] out TComp1? component)
{
if (uid == null)
{
component = default;
return false;
}
return TryGetComponentInternal(uid.Value, out component);
}
/// <summary>
/// Elides the component.Deleted check of <see cref="TryGetComponent(System.Nullable{Robust.Shared.GameObjects.EntityUid},out TComp1?)"/>
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[Pure]
internal bool TryGetComponentInternal(EntityUid uid, [NotNullWhen(true)] out TComp1? component)
{
if (_traitDict.TryGetValue(uid, out var comp))
{
component = (TComp1) comp;
return true;
}
component = default;
return false;
}
/// <summary>
/// Elides the component.Deleted check of <see cref="HasComponent(EntityUid)"/>
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[Pure]
internal bool HasComponentInternal(EntityUid uid)
{
return _traitDict.TryGetValue(uid, out var comp) && !comp.Deleted;
}
/// <summary>
/// Elides the component.Deleted check of <see cref="Resolve"/>
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[Pure]
internal bool ResolveInternal(EntityUid uid, [NotNullWhen(true)] ref TComp1? component, bool logMissing = true)
{
if (component != null)
{
DebugTools.AssertOwner(uid, component);
return true;
}
if (_traitDict.TryGetValue(uid, out var comp))
{
component = (TComp1)comp;
return true;
}
if (logMissing)
_sawmill.Error($"Can't resolve \"{typeof(TComp1)}\" on entity {uid}!\n{new StackTrace(1, true)}");
return false;
}
/// <summary>
/// Elides the component.Deleted check of <see cref="CompOrNull"/>
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[Pure]
internal TComp1? CompOrNullInternal(EntityUid uid)
{
if (TryGetComponent(uid, out var comp))
return comp;
return default;
}
#endregion
}
#region Query
/// <summary>
/// Returns all matching unpaused components.
/// </summary>
public struct EntityQueryEnumerator<TComp1> : IDisposable
where TComp1 : IComponent
{
private Dictionary<EntityUid, IComponent>.Enumerator _traitDict;
private readonly EntityQuery<MetaDataComponent> _metaQuery;
public EntityQueryEnumerator(
Dictionary<EntityUid, IComponent> traitDict,
EntityQuery<MetaDataComponent> metaQuery)
{
_traitDict = traitDict.GetEnumerator();
_metaQuery = metaQuery;
}
public bool MoveNext(out EntityUid uid, [NotNullWhen(true)] out TComp1? comp1)
{
while (true)
{
if (!_traitDict.MoveNext())
{
uid = default;
comp1 = default;
return false;
}
var current = _traitDict.Current;
if (current.Value.Deleted)
{
continue;
}
if (!_metaQuery.TryGetComponentInternal(current.Key, out var metaComp) || metaComp.EntityPaused)
{
continue;
}
uid = current.Key;
comp1 = (TComp1)current.Value;
return true;
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool MoveNext([NotNullWhen(true)] out TComp1? comp1)
{
return MoveNext(out _, out comp1);
}
public void Dispose()
{
_traitDict.Dispose();
}
}
/// <summary>
/// Returns all matching unpaused components.
/// </summary>
public struct EntityQueryEnumerator<TComp1, TComp2> : IDisposable
where TComp1 : IComponent
where TComp2 : IComponent
{
private Dictionary<EntityUid, IComponent>.Enumerator _traitDict;
private readonly Dictionary<EntityUid, IComponent> _traitDict2;
private readonly EntityQuery<MetaDataComponent> _metaQuery;
public EntityQueryEnumerator(
Dictionary<EntityUid, IComponent> traitDict,
Dictionary<EntityUid, IComponent> traitDict2,
EntityQuery<MetaDataComponent> metaQuery)
{
_traitDict = traitDict.GetEnumerator();
_traitDict2 = traitDict2;
_metaQuery = metaQuery;
}
public bool MoveNext(out EntityUid uid, [NotNullWhen(true)] out TComp1? comp1, [NotNullWhen(true)] out TComp2? comp2)
{
while (true)
{
if (!_traitDict.MoveNext())
{
uid = default;
comp1 = default;
comp2 = default;
return false;
}
var current = _traitDict.Current;
if (current.Value.Deleted)
{
continue;
}
if (!_metaQuery.TryGetComponentInternal(current.Key, out var metaComp) || metaComp.EntityPaused)
{
continue;
}
if (!_traitDict2.TryGetValue(current.Key, out var comp2Obj) || comp2Obj.Deleted)
{
continue;
}
uid = current.Key;
comp1 = (TComp1)current.Value;
comp2 = (TComp2)comp2Obj;
return true;
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool MoveNext([NotNullWhen(true)] out TComp1? comp1, [NotNullWhen(true)] out TComp2? comp2)
{
return MoveNext(out _, out comp1, out comp2);
}
public void Dispose()
{
_traitDict.Dispose();
}
}
/// <summary>
/// Returns all matching unpaused components.
/// </summary>
public struct EntityQueryEnumerator<TComp1, TComp2, TComp3> : IDisposable
where TComp1 : IComponent
where TComp2 : IComponent
where TComp3 : IComponent
{
private Dictionary<EntityUid, IComponent>.Enumerator _traitDict;
private readonly Dictionary<EntityUid, IComponent> _traitDict2;
private readonly Dictionary<EntityUid, IComponent> _traitDict3;
private readonly EntityQuery<MetaDataComponent> _metaQuery;
public EntityQueryEnumerator(
Dictionary<EntityUid, IComponent> traitDict,
Dictionary<EntityUid, IComponent> traitDict2,
Dictionary<EntityUid, IComponent> traitDict3,
EntityQuery<MetaDataComponent> metaQuery)
{
_traitDict = traitDict.GetEnumerator();
_traitDict2 = traitDict2;
_traitDict3 = traitDict3;
_metaQuery = metaQuery;
}
public bool MoveNext(out EntityUid uid, [NotNullWhen(true)] out TComp1? comp1, [NotNullWhen(true)] out TComp2? comp2, [NotNullWhen(true)] out TComp3? comp3)
{
while (true)
{
if (!_traitDict.MoveNext())
{
uid = default;
comp1 = default;
comp2 = default;
comp3 = default;
return false;
}
var current = _traitDict.Current;
if (current.Value.Deleted)
{
continue;
}
if (!_metaQuery.TryGetComponentInternal(current.Key, out var metaComp) || metaComp.EntityPaused)
{
continue;
}
if (!_traitDict2.TryGetValue(current.Key, out var comp2Obj) || comp2Obj.Deleted)
{
continue;
}
if (!_traitDict3.TryGetValue(current.Key, out var comp3Obj) || comp3Obj.Deleted)
{
continue;
}
uid = current.Key;
comp1 = (TComp1)current.Value;
comp2 = (TComp2)comp2Obj;
comp3 = (TComp3)comp3Obj;
return true;
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool MoveNext(
[NotNullWhen(true)] out TComp1? comp1,
[NotNullWhen(true)] out TComp2? comp2,
[NotNullWhen(true)] out TComp3? comp3)
{
return MoveNext(out _, out comp1, out comp2, out comp3);
}
public void Dispose()
{
_traitDict.Dispose();
}
}
/// <summary>
/// Returns all matching unpaused components.
/// </summary>
public struct EntityQueryEnumerator<TComp1, TComp2, TComp3, TComp4> : IDisposable
where TComp1 : IComponent
where TComp2 : IComponent
where TComp3 : IComponent
where TComp4 : IComponent
{
private Dictionary<EntityUid, IComponent>.Enumerator _traitDict;
private readonly Dictionary<EntityUid, IComponent> _traitDict2;
private readonly Dictionary<EntityUid, IComponent> _traitDict3;
private readonly Dictionary<EntityUid, IComponent> _traitDict4;
private readonly EntityQuery<MetaDataComponent> _metaQuery;
public EntityQueryEnumerator(
Dictionary<EntityUid, IComponent> traitDict,
Dictionary<EntityUid, IComponent> traitDict2,
Dictionary<EntityUid, IComponent> traitDict3,
Dictionary<EntityUid, IComponent> traitDict4,
EntityQuery<MetaDataComponent> metaQuery)
{
_traitDict = traitDict.GetEnumerator();
_traitDict2 = traitDict2;
_traitDict3 = traitDict3;
_traitDict4 = traitDict4;
_metaQuery = metaQuery;
}
public bool MoveNext(out EntityUid uid, [NotNullWhen(true)] out TComp1? comp1, [NotNullWhen(true)] out TComp2? comp2, [NotNullWhen(true)] out TComp3? comp3, [NotNullWhen(true)] out TComp4? comp4)
{
while (true)
{
if (!_traitDict.MoveNext())
{
uid = default;
comp1 = default;
comp2 = default;
comp3 = default;
comp4 = default;
return false;
}
var current = _traitDict.Current;
if (current.Value.Deleted)
{
continue;
}
if (!_metaQuery.TryGetComponentInternal(current.Key, out var metaComp) || metaComp.EntityPaused)
{
continue;
}
if (!_traitDict2.TryGetValue(current.Key, out var comp2Obj) || comp2Obj.Deleted)
{
continue;
}
if (!_traitDict3.TryGetValue(current.Key, out var comp3Obj) || comp3Obj.Deleted)
{
continue;
}
if (!_traitDict4.TryGetValue(current.Key, out var comp4Obj) || comp4Obj.Deleted)
{
continue;
}
uid = current.Key;
comp1 = (TComp1)current.Value;
comp2 = (TComp2)comp2Obj;
comp3 = (TComp3)comp3Obj;
comp4 = (TComp4)comp4Obj;
return true;
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool MoveNext(
[NotNullWhen(true)] out TComp1? comp1,
[NotNullWhen(true)] out TComp2? comp2,
[NotNullWhen(true)] out TComp3? comp3,
[NotNullWhen(true)] out TComp4? comp4)
{
return MoveNext(out _, out comp1, out comp2, out comp3, out comp4);
}
public void Dispose()
{
_traitDict.Dispose();
}
}
#endregion
#region All query
/// <summary>
/// Returns all matching components, paused or not.
/// </summary>
public struct AllEntityQueryEnumerator<TComp1> : IDisposable
where TComp1 : IComponent
{
private Dictionary<EntityUid, IComponent>.Enumerator _traitDict;
public AllEntityQueryEnumerator(
Dictionary<EntityUid, IComponent> traitDict)
{
_traitDict = traitDict.GetEnumerator();
}
public bool MoveNext(out EntityUid uid, [NotNullWhen(true)] out TComp1? comp1)
{
while (true)
{
if (!_traitDict.MoveNext())
{
uid = default;
comp1 = default;
return false;
}
var current = _traitDict.Current;
if (current.Value.Deleted)
{
continue;
}
uid = current.Key;
comp1 = (TComp1)current.Value;
return true;
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool MoveNext([NotNullWhen(true)] out TComp1? comp1)
{
return MoveNext(out _, out comp1);
}
public void Dispose()
{
_traitDict.Dispose();
}
}
/// <summary>
/// Returns all matching components, paused or not.
/// </summary>
public struct AllEntityQueryEnumerator<TComp1, TComp2> : IDisposable
where TComp1 : IComponent
where TComp2 : IComponent
{
private Dictionary<EntityUid, IComponent>.Enumerator _traitDict;
private readonly Dictionary<EntityUid, IComponent> _traitDict2;
public AllEntityQueryEnumerator(
Dictionary<EntityUid, IComponent> traitDict,
Dictionary<EntityUid, IComponent> traitDict2)
{
_traitDict = traitDict.GetEnumerator();
_traitDict2 = traitDict2;
}
public bool MoveNext(out EntityUid uid, [NotNullWhen(true)] out TComp1? comp1, [NotNullWhen(true)] out TComp2? comp2)
{
while (true)
{
if (!_traitDict.MoveNext())
{
uid = default;
comp1 = default;
comp2 = default;
return false;
}
var current = _traitDict.Current;
if (current.Value.Deleted)
{
continue;
}
if (!_traitDict2.TryGetValue(current.Key, out var comp2Obj) || comp2Obj.Deleted)
{
continue;
}
uid = current.Key;
comp1 = (TComp1)current.Value;
comp2 = (TComp2)comp2Obj;
return true;
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool MoveNext([NotNullWhen(true)] out TComp1? comp1, [NotNullWhen(true)] out TComp2? comp2)
{
return MoveNext(out _, out comp1, out comp2);
}
public void Dispose()
{
_traitDict.Dispose();
}
}
/// <summary>
/// Returns all matching components, paused or not.
/// </summary>
public struct AllEntityQueryEnumerator<TComp1, TComp2, TComp3> : IDisposable
where TComp1 : IComponent
where TComp2 : IComponent
where TComp3 : IComponent
{
private Dictionary<EntityUid, IComponent>.Enumerator _traitDict;
private readonly Dictionary<EntityUid, IComponent> _traitDict2;
private readonly Dictionary<EntityUid, IComponent> _traitDict3;
public AllEntityQueryEnumerator(
Dictionary<EntityUid, IComponent> traitDict,
Dictionary<EntityUid, IComponent> traitDict2,
Dictionary<EntityUid, IComponent> traitDict3)
{
_traitDict = traitDict.GetEnumerator();
_traitDict2 = traitDict2;
_traitDict3 = traitDict3;
}
public bool MoveNext(out EntityUid uid, [NotNullWhen(true)] out TComp1? comp1, [NotNullWhen(true)] out TComp2? comp2, [NotNullWhen(true)] out TComp3? comp3)
{
while (true)
{
if (!_traitDict.MoveNext())
{
uid = default;
comp1 = default;
comp2 = default;
comp3 = default;
return false;
}
var current = _traitDict.Current;
if (current.Value.Deleted)
{
continue;
}
if (!_traitDict2.TryGetValue(current.Key, out var comp2Obj) || comp2Obj.Deleted)
{
continue;
}
if (!_traitDict3.TryGetValue(current.Key, out var comp3Obj) || comp3Obj.Deleted)
{
continue;
}
uid = current.Key;
comp1 = (TComp1)current.Value;
comp2 = (TComp2)comp2Obj;
comp3 = (TComp3)comp3Obj;
return true;
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool MoveNext(
[NotNullWhen(true)] out TComp1? comp1,
[NotNullWhen(true)] out TComp2? comp2,
[NotNullWhen(true)] out TComp3? comp3)
{
return MoveNext(out _, out comp1, out comp2, out comp3);
}
public void Dispose()
{
_traitDict.Dispose();
}
}
/// <summary>
/// Returns all matching components, paused or not.
/// </summary>
public struct AllEntityQueryEnumerator<TComp1, TComp2, TComp3, TComp4> : IDisposable
where TComp1 : IComponent
where TComp2 : IComponent
where TComp3 : IComponent
where TComp4 : IComponent
{
private Dictionary<EntityUid, IComponent>.Enumerator _traitDict;
private readonly Dictionary<EntityUid, IComponent> _traitDict2;
private readonly Dictionary<EntityUid, IComponent> _traitDict3;
private readonly Dictionary<EntityUid, IComponent> _traitDict4;
public AllEntityQueryEnumerator(
Dictionary<EntityUid, IComponent> traitDict,
Dictionary<EntityUid, IComponent> traitDict2,
Dictionary<EntityUid, IComponent> traitDict3,
Dictionary<EntityUid, IComponent> traitDict4)
{
_traitDict = traitDict.GetEnumerator();
_traitDict2 = traitDict2;
_traitDict3 = traitDict3;
_traitDict4 = traitDict4;
}
public bool MoveNext(out EntityUid uid, [NotNullWhen(true)] out TComp1? comp1, [NotNullWhen(true)] out TComp2? comp2, [NotNullWhen(true)] out TComp3? comp3, [NotNullWhen(true)] out TComp4? comp4)
{
while (true)
{
if (!_traitDict.MoveNext())
{
uid = default;
comp1 = default;
comp2 = default;
comp3 = default;
comp4 = default;
return false;
}
var current = _traitDict.Current;
if (current.Value.Deleted)
{
continue;
}
if (!_traitDict2.TryGetValue(current.Key, out var comp2Obj) || comp2Obj.Deleted)
{
continue;
}
if (!_traitDict3.TryGetValue(current.Key, out var comp3Obj) || comp3Obj.Deleted)
{
continue;
}
if (!_traitDict4.TryGetValue(current.Key, out var comp4Obj) || comp4Obj.Deleted)
{
continue;
}
uid = current.Key;
comp1 = (TComp1)current.Value;
comp2 = (TComp2)comp2Obj;
comp3 = (TComp3)comp3Obj;
comp4 = (TComp4)comp4Obj;
return true;
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool MoveNext(
[NotNullWhen(true)] out TComp1? comp1,
[NotNullWhen(true)] out TComp2? comp2,
[NotNullWhen(true)] out TComp3? comp3,
[NotNullWhen(true)] out TComp4? comp4)
{
return MoveNext(out _, out comp1, out comp2, out comp3, out comp4);
}
public void Dispose()
{
_traitDict.Dispose();
}
}
#endregion
}