mirror of
https://github.com/space-wizards/RobustToolbox.git
synced 2026-09-15 06:42:25 +02:00
Minor performance improvements (#2860)
This commit is contained in:
@@ -0,0 +1,225 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
using BenchmarkDotNet.Attributes;
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
namespace Robust.Benchmarks.EntityManager;
|
||||
|
||||
public class ComponentIndexBenchmark
|
||||
{
|
||||
// Just a bunch of types to bloat the test lists.
|
||||
|
||||
private readonly CompIndexFetcher _compIndexFetcherDirect;
|
||||
private readonly IFetcher _compIndexFetcher;
|
||||
private readonly DictFetcher _dictFetcherDirect;
|
||||
private readonly IFetcher _dictFetcher;
|
||||
|
||||
|
||||
public ComponentIndexBenchmark()
|
||||
{
|
||||
_compIndexFetcherDirect = new CompIndexFetcher();
|
||||
_compIndexFetcher = _compIndexFetcherDirect;
|
||||
_dictFetcherDirect = new DictFetcher();
|
||||
_dictFetcher = _dictFetcherDirect;
|
||||
}
|
||||
|
||||
[GlobalSetup]
|
||||
public void Setup()
|
||||
{
|
||||
var types = typeof(ComponentIndexBenchmark)
|
||||
.GetNestedTypes(BindingFlags.NonPublic)
|
||||
.Where(t => t.Name.StartsWith("TestType"))
|
||||
.ToArray();
|
||||
|
||||
_compIndexFetcher.Init(types);
|
||||
_dictFetcher.Init(types);
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public int BenchCompIndex() => _compIndexFetcher.Get<TestType50>();
|
||||
|
||||
[Benchmark]
|
||||
public int BenchDict() => _dictFetcher.Get<TestType50>();
|
||||
|
||||
[Benchmark]
|
||||
public int BenchCompIndexDirect() => _compIndexFetcherDirect.Get<TestType50>();
|
||||
|
||||
[Benchmark]
|
||||
public int BenchDictDirect() => _dictFetcherDirect.Get<TestType50>();
|
||||
|
||||
private static CompIdx ArrayIndexFor<T>() => CompArrayIndex<T>.Idx;
|
||||
|
||||
private static int _compIndexMaster = -1;
|
||||
|
||||
private static class CompArrayIndex<T>
|
||||
{
|
||||
// ReSharper disable once StaticMemberInGenericType
|
||||
public static readonly CompIdx Idx = new(Interlocked.Increment(ref _compIndexMaster));
|
||||
}
|
||||
|
||||
private static CompIdx GetCompIdIndex(Type type)
|
||||
{
|
||||
return (CompIdx)typeof(CompArrayIndex<>)
|
||||
.MakeGenericType(type)
|
||||
.GetField(nameof(CompArrayIndex<int>.Idx), BindingFlags.Static | BindingFlags.Public)!
|
||||
.GetValue(null)!;
|
||||
}
|
||||
|
||||
private interface IFetcher
|
||||
{
|
||||
void Init(Type[] types);
|
||||
|
||||
int Get<T>();
|
||||
}
|
||||
|
||||
private sealed class CompIndexFetcher : IFetcher
|
||||
{
|
||||
private int[] _values = Array.Empty<int>();
|
||||
|
||||
public void Init(Type[] types)
|
||||
{
|
||||
var max = types.Max(t => GetCompIdIndex(t).Value);
|
||||
|
||||
_values = new int[max + 1];
|
||||
|
||||
var i = 0;
|
||||
foreach (var type in types)
|
||||
{
|
||||
_values[GetCompIdIndex(type).Value] = i++;
|
||||
}
|
||||
}
|
||||
|
||||
public int Get<T>()
|
||||
{
|
||||
return _values[CompArrayIndex<T>.Idx.Value];
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class DictFetcher : IFetcher
|
||||
{
|
||||
private readonly Dictionary<Type, int> _values = new();
|
||||
|
||||
public void Init(Type[] types)
|
||||
{
|
||||
var i = 0;
|
||||
foreach (var type in types)
|
||||
{
|
||||
_values[type] = i++;
|
||||
}
|
||||
}
|
||||
|
||||
public int Get<T>()
|
||||
{
|
||||
return _values[typeof(T)];
|
||||
}
|
||||
}
|
||||
|
||||
// Just a bunch of types to pad the size of the arrays and such.
|
||||
|
||||
// @formatter:off
|
||||
// ReSharper disable UnusedType.Local
|
||||
private sealed class TestType1{}
|
||||
private sealed class TestType2{}
|
||||
private sealed class TestType3{}
|
||||
private sealed class TestType4{}
|
||||
private sealed class TestType5{}
|
||||
private sealed class TestType6{}
|
||||
private sealed class TestType7{}
|
||||
private sealed class TestType8{}
|
||||
private sealed class TestType9{}
|
||||
private sealed class TestType10{}
|
||||
private sealed class TestType11{}
|
||||
private sealed class TestType12{}
|
||||
private sealed class TestType13{}
|
||||
private sealed class TestType14{}
|
||||
private sealed class TestType15{}
|
||||
private sealed class TestType16{}
|
||||
private sealed class TestType17{}
|
||||
private sealed class TestType18{}
|
||||
private sealed class TestType19{}
|
||||
private sealed class TestType20{}
|
||||
private sealed class TestType21{}
|
||||
private sealed class TestType22{}
|
||||
private sealed class TestType23{}
|
||||
private sealed class TestType24{}
|
||||
private sealed class TestType25{}
|
||||
private sealed class TestType26{}
|
||||
private sealed class TestType27{}
|
||||
private sealed class TestType28{}
|
||||
private sealed class TestType29{}
|
||||
private sealed class TestType30{}
|
||||
private sealed class TestType31{}
|
||||
private sealed class TestType32{}
|
||||
private sealed class TestType33{}
|
||||
private sealed class TestType34{}
|
||||
private sealed class TestType35{}
|
||||
private sealed class TestType36{}
|
||||
private sealed class TestType37{}
|
||||
private sealed class TestType38{}
|
||||
private sealed class TestType39{}
|
||||
private sealed class TestType40{}
|
||||
private sealed class TestType41{}
|
||||
private sealed class TestType42{}
|
||||
private sealed class TestType43{}
|
||||
private sealed class TestType44{}
|
||||
private sealed class TestType45{}
|
||||
private sealed class TestType46{}
|
||||
private sealed class TestType47{}
|
||||
private sealed class TestType48{}
|
||||
private sealed class TestType49{}
|
||||
private sealed class TestType50{}
|
||||
private sealed class TestType51{}
|
||||
private sealed class TestType52{}
|
||||
private sealed class TestType53{}
|
||||
private sealed class TestType54{}
|
||||
private sealed class TestType55{}
|
||||
private sealed class TestType56{}
|
||||
private sealed class TestType57{}
|
||||
private sealed class TestType58{}
|
||||
private sealed class TestType59{}
|
||||
private sealed class TestType60{}
|
||||
private sealed class TestType61{}
|
||||
private sealed class TestType62{}
|
||||
private sealed class TestType63{}
|
||||
private sealed class TestType64{}
|
||||
private sealed class TestType65{}
|
||||
private sealed class TestType66{}
|
||||
private sealed class TestType67{}
|
||||
private sealed class TestType68{}
|
||||
private sealed class TestType69{}
|
||||
private sealed class TestType70{}
|
||||
private sealed class TestType71{}
|
||||
private sealed class TestType72{}
|
||||
private sealed class TestType73{}
|
||||
private sealed class TestType74{}
|
||||
private sealed class TestType75{}
|
||||
private sealed class TestType76{}
|
||||
private sealed class TestType77{}
|
||||
private sealed class TestType78{}
|
||||
private sealed class TestType79{}
|
||||
private sealed class TestType80{}
|
||||
private sealed class TestType81{}
|
||||
private sealed class TestType82{}
|
||||
private sealed class TestType83{}
|
||||
private sealed class TestType84{}
|
||||
private sealed class TestType85{}
|
||||
private sealed class TestType86{}
|
||||
private sealed class TestType87{}
|
||||
private sealed class TestType88{}
|
||||
private sealed class TestType89{}
|
||||
private sealed class TestType90{}
|
||||
private sealed class TestType91{}
|
||||
private sealed class TestType92{}
|
||||
private sealed class TestType93{}
|
||||
private sealed class TestType94{}
|
||||
private sealed class TestType95{}
|
||||
private sealed class TestType96{}
|
||||
private sealed class TestType97{}
|
||||
private sealed class TestType98{}
|
||||
private sealed class TestType99{}
|
||||
// ReSharper restore UnusedType.Local
|
||||
// @formatter:on
|
||||
}
|
||||
@@ -66,7 +66,7 @@ internal sealed class ClientDirtySystem : EntitySystem
|
||||
return _dirty;
|
||||
}
|
||||
|
||||
private void OnEntityDirty(object? sender, EntityUid e)
|
||||
private void OnEntityDirty(EntityUid e)
|
||||
{
|
||||
if (e.IsClientSide()) return;
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ namespace Robust.Server.GameObjects
|
||||
RefreshVisibility(ev.Entity);
|
||||
}
|
||||
|
||||
private void OnEntityInit(object? sender, EntityUid uid)
|
||||
private void OnEntityInit(EntityUid uid)
|
||||
{
|
||||
RefreshVisibility(uid);
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ namespace Robust.Server.GameObjects
|
||||
|
||||
EntityUid IServerEntityManagerInternal.AllocEntity(string? prototypeName, EntityUid uid)
|
||||
{
|
||||
return AllocEntity(prototypeName, uid);
|
||||
return AllocEntity(prototypeName, out _, uid);
|
||||
}
|
||||
|
||||
void IServerEntityManagerInternal.FinishEntityLoad(EntityUid entity, IEntityLoadContext? context)
|
||||
@@ -146,21 +146,21 @@ namespace Robust.Server.GameObjects
|
||||
return _lastProcessedSequencesCmd[session];
|
||||
}
|
||||
|
||||
private void OnEntityRemoved(object? sender, EntityUid e)
|
||||
private void OnEntityRemoved(EntityUid e)
|
||||
{
|
||||
if (_componentDeletionHistory.ContainsKey(e))
|
||||
_componentDeletionHistory.Remove(e);
|
||||
}
|
||||
|
||||
private void OnComponentRemoved(object? sender, ComponentEventArgs e)
|
||||
private void OnComponentRemoved(RemovedComponentEventArgs e)
|
||||
{
|
||||
var reg = ComponentFactory.GetRegistration(e.Component.GetType());
|
||||
var reg = ComponentFactory.GetRegistration(e.BaseArgs.Component.GetType());
|
||||
|
||||
// We only keep track of networked components being removed.
|
||||
if (reg.NetID is not {} netId)
|
||||
return;
|
||||
|
||||
var uid = e.Owner;
|
||||
var uid = e.BaseArgs.Owner;
|
||||
|
||||
if (!_componentDeletionHistory.TryGetValue(uid, out var list))
|
||||
{
|
||||
|
||||
@@ -42,13 +42,13 @@ namespace Robust.Server.GameStates
|
||||
EntityManager.EntityDirtied -= OnEntityDirty;
|
||||
}
|
||||
|
||||
private void OnEntityAdd(object? sender, EntityUid e)
|
||||
private void OnEntityAdd(EntityUid e)
|
||||
{
|
||||
DebugTools.Assert(_currentIndex == _gameTiming.CurTick.Value % DirtyBufferSize);
|
||||
_addEntities[_currentIndex].Add(e);
|
||||
}
|
||||
|
||||
private void OnEntityDirty(object? sender, EntityUid uid)
|
||||
private void OnEntityDirty(EntityUid uid)
|
||||
{
|
||||
if (!_addEntities[_currentIndex].Contains(uid))
|
||||
_dirtyEntities[_currentIndex].Add(uid);
|
||||
|
||||
@@ -216,7 +216,7 @@ internal sealed partial class PVSSystem : EntitySystem
|
||||
|
||||
#region PVSCollection Event Updates
|
||||
|
||||
private void OnEntityDeleted(object? sender, EntityUid e)
|
||||
private void OnEntityDeleted(EntityUid e)
|
||||
{
|
||||
_entityPvsCollection.RemoveIndex(EntityManager.CurrentTick, e);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Robust.Shared.GameObjects;
|
||||
|
||||
public readonly struct CompIdx : IEquatable<CompIdx>
|
||||
{
|
||||
private static readonly ReaderWriterLockSlim SlowStoreLock = new();
|
||||
private static readonly Dictionary<Type, CompIdx> SlowStore = new();
|
||||
|
||||
internal readonly int Value;
|
||||
|
||||
internal static CompIdx Index<T>() => Store<T>.Index;
|
||||
|
||||
internal static CompIdx Index(Type t)
|
||||
{
|
||||
using (SlowStoreLock.ReadGuard())
|
||||
{
|
||||
if (SlowStore.TryGetValue(t, out var idx))
|
||||
return idx;
|
||||
}
|
||||
|
||||
// Doesn't exist in the store, get a write lock and add it.
|
||||
using (SlowStoreLock.WriteGuard())
|
||||
{
|
||||
var idx = (CompIdx)typeof(Store<>)
|
||||
.MakeGenericType(t)
|
||||
.GetField(nameof(Store<int>.Index), BindingFlags.Static | BindingFlags.Public)!
|
||||
.GetValue(null)!;
|
||||
|
||||
SlowStore[t] = idx;
|
||||
return idx;
|
||||
}
|
||||
}
|
||||
|
||||
internal static int ArrayIndex<T>() => Index<T>().Value;
|
||||
internal static int ArrayIndex(Type type) => Index(type).Value;
|
||||
|
||||
internal static void AssignArray<T>(ref T[] array, CompIdx idx, T value)
|
||||
{
|
||||
RefArray(ref array, idx) = value;
|
||||
}
|
||||
|
||||
internal static ref T RefArray<T>(ref T[] array, CompIdx idx)
|
||||
{
|
||||
var curLength = array.Length;
|
||||
if (curLength <= idx.Value)
|
||||
{
|
||||
var newLength = MathHelper.NextPowerOfTwo(Math.Max(8, idx.Value));
|
||||
Array.Resize(ref array, newLength);
|
||||
}
|
||||
|
||||
return ref array[idx.Value];
|
||||
}
|
||||
|
||||
private static int _CompIdxMaster = -1;
|
||||
|
||||
private static class Store<T>
|
||||
{
|
||||
// ReSharper disable once StaticMemberInGenericType
|
||||
public static readonly CompIdx Index = new(Interlocked.Increment(ref _CompIdxMaster));
|
||||
}
|
||||
|
||||
internal CompIdx(int value)
|
||||
{
|
||||
Value = value;
|
||||
}
|
||||
|
||||
public bool Equals(CompIdx other)
|
||||
{
|
||||
return Value == other.Value;
|
||||
}
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return obj is CompIdx other && Equals(other);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return Value;
|
||||
}
|
||||
|
||||
public static bool operator ==(CompIdx left, CompIdx right)
|
||||
{
|
||||
return left.Equals(right);
|
||||
}
|
||||
|
||||
public static bool operator !=(CompIdx left, CompIdx right)
|
||||
{
|
||||
return !left.Equals(right);
|
||||
}
|
||||
}
|
||||
@@ -210,8 +210,9 @@ namespace Robust.Shared.GameObjects
|
||||
/// <inheritdoc />
|
||||
public virtual ComponentState GetComponentState()
|
||||
{
|
||||
if (!(Attribute.GetCustomAttribute(GetType(), typeof(NetworkedComponentAttribute)) is NetworkedComponentAttribute))
|
||||
throw new InvalidOperationException($"Calling base {nameof(GetComponentState)} without being networked.");
|
||||
DebugTools.Assert(
|
||||
Attribute.GetCustomAttribute(GetType(), typeof(NetworkedComponentAttribute)) != null,
|
||||
$"Calling base {nameof(GetComponentState)} without being networked.");
|
||||
|
||||
return DefaultComponentState;
|
||||
}
|
||||
|
||||
@@ -1,19 +1,15 @@
|
||||
#nullable enable
|
||||
using System;
|
||||
|
||||
namespace Robust.Shared.GameObjects
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Arguments for an event related to a component.
|
||||
/// </summary>
|
||||
public abstract class ComponentEventArgs : EventArgs
|
||||
public readonly struct ComponentEventArgs
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Component that this event relates to.
|
||||
/// </summary>
|
||||
public IComponent Component { get; }
|
||||
public Component Component { get; }
|
||||
|
||||
/// <summary>
|
||||
/// EntityUid of the entity this component belongs to.
|
||||
@@ -24,50 +20,41 @@ namespace Robust.Shared.GameObjects
|
||||
/// Constructs a new instance of <see cref="ComponentEventArgs"/>.
|
||||
/// </summary>
|
||||
/// <param name="component">The relevant component</param>
|
||||
/// <param name="Owner">EntityUid of the entity this component belongs to.</param>
|
||||
protected ComponentEventArgs(IComponent component, EntityUid owner)
|
||||
/// <param name="owner">EntityUid of the entity this component belongs to.</param>
|
||||
public ComponentEventArgs(Component component, EntityUid owner)
|
||||
{
|
||||
Component = component;
|
||||
Owner = owner;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Arguments for an event related to a component being added.
|
||||
/// </summary>
|
||||
public sealed class AddedComponentEventArgs : ComponentEventArgs
|
||||
public readonly struct AddedComponentEventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// Constructs a new instance of <see cref="AddedComponentEventArgs"/>.
|
||||
/// </summary>
|
||||
/// <param name="component">The relevant component</param>
|
||||
/// <param name="uid">EntityUid of the entity this component belongs to.</param>
|
||||
public AddedComponentEventArgs(IComponent component, EntityUid uid) : base(component, uid) { }
|
||||
public readonly ComponentEventArgs BaseArgs;
|
||||
|
||||
public AddedComponentEventArgs(ComponentEventArgs baseArgs)
|
||||
{
|
||||
BaseArgs = baseArgs;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Arguments for an event related to a component being removed.
|
||||
/// </summary>
|
||||
public sealed class RemovedComponentEventArgs : ComponentEventArgs
|
||||
public readonly struct RemovedComponentEventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// Constructs a new instance of <see cref="RemovedComponentEventArgs"/>.
|
||||
/// </summary>
|
||||
/// <param name="component">The relevant component</param>
|
||||
/// <param name="uid">EntityUid of the entity this component belongs to.</param>
|
||||
public RemovedComponentEventArgs(IComponent component, EntityUid uid) : base(component, uid) { }
|
||||
public readonly ComponentEventArgs BaseArgs;
|
||||
|
||||
public RemovedComponentEventArgs(ComponentEventArgs baseArgs)
|
||||
{
|
||||
BaseArgs = baseArgs;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Arguments for an event related to a component being deleted.
|
||||
/// </summary>
|
||||
public sealed class DeletedComponentEventArgs : ComponentEventArgs
|
||||
public readonly struct DeletedComponentEventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// Constructs a new instance of <see cref="DeletedComponentEventArgs"/>.
|
||||
/// </summary>
|
||||
/// <param name="component">The relevant component</param>
|
||||
/// <param name="uid">EntityUid of the entity this component belongs to.</param>
|
||||
public DeletedComponentEventArgs(IComponent component, EntityUid uid) : base(component, uid) { }
|
||||
public readonly ComponentEventArgs BaseArgs;
|
||||
|
||||
public DeletedComponentEventArgs(ComponentEventArgs baseArgs)
|
||||
{
|
||||
BaseArgs = baseArgs;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,28 +20,6 @@ namespace Robust.Shared.GameObjects
|
||||
private readonly IDynamicTypeFactoryInternal _typeFactory;
|
||||
private readonly IReflectionManager _reflectionManager;
|
||||
|
||||
private sealed class ComponentRegistration : IComponentRegistration
|
||||
{
|
||||
public string Name { get; }
|
||||
public ushort? NetID { get; set; }
|
||||
public Type Type { get; }
|
||||
internal readonly List<Type> References = new();
|
||||
IReadOnlyList<Type> IComponentRegistration.References => References;
|
||||
|
||||
public ComponentRegistration(string name, Type type)
|
||||
{
|
||||
Name = name;
|
||||
NetID = null;
|
||||
Type = type;
|
||||
References.Add(type);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"ComponentRegistration({Name}: {Type})";
|
||||
}
|
||||
}
|
||||
|
||||
// Bunch of dictionaries to allow lookups in all directions.
|
||||
/// <summary>
|
||||
/// Mapping of component name to type.
|
||||
@@ -56,23 +34,27 @@ namespace Robust.Shared.GameObjects
|
||||
/// <summary>
|
||||
/// Mapping of network ID to type.
|
||||
/// </summary>
|
||||
private List<IComponentRegistration>? _networkedComponents;
|
||||
private List<ComponentRegistration>? _networkedComponents;
|
||||
|
||||
/// <summary>
|
||||
/// Mapping of concrete component types to their registration.
|
||||
/// </summary>
|
||||
private readonly Dictionary<Type, ComponentRegistration> types = new();
|
||||
|
||||
private ComponentRegistration[] _array = Array.Empty<ComponentRegistration>();
|
||||
|
||||
/// <summary>
|
||||
/// Set of components that should be ignored. Probably just the list of components unique to the other project.
|
||||
/// </summary>
|
||||
private readonly HashSet<string> IgnoredComponentNames = new();
|
||||
|
||||
/// <inheritdoc />
|
||||
public event Action<IComponentRegistration>? ComponentAdded;
|
||||
private readonly Dictionary<CompIdx, Type> _idxToType = new();
|
||||
|
||||
/// <inheritdoc />
|
||||
public event Action<(IComponentRegistration, Type)>? ComponentReferenceAdded;
|
||||
public event Action<ComponentRegistration>? ComponentAdded;
|
||||
|
||||
/// <inheritdoc />
|
||||
public event Action<ComponentRegistration, CompIdx>? ComponentReferenceAdded;
|
||||
|
||||
/// <inheritdoc />
|
||||
public event Action<string>? ComponentIgnoreAdded;
|
||||
@@ -81,7 +63,7 @@ namespace Robust.Shared.GameObjects
|
||||
public IEnumerable<Type> AllRegisteredTypes => types.Keys;
|
||||
|
||||
/// <inheritdoc />
|
||||
public IReadOnlyList<IComponentRegistration>? NetworkedComponents => _networkedComponents;
|
||||
public IReadOnlyList<ComponentRegistration>? NetworkedComponents => _networkedComponents;
|
||||
|
||||
private IEnumerable<ComponentRegistration> AllRegistrations => types.Values;
|
||||
|
||||
@@ -155,10 +137,15 @@ namespace Robust.Shared.GameObjects
|
||||
}
|
||||
}
|
||||
|
||||
var registration = new ComponentRegistration(name, type);
|
||||
var idx = CompIdx.Index(type);
|
||||
_idxToType[idx] = type;
|
||||
|
||||
var registration = new ComponentRegistration(name, type, idx);
|
||||
|
||||
names[name] = registration;
|
||||
_lowerCaseNames[lowerCaseName] = name;
|
||||
types[type] = registration;
|
||||
CompIdx.AssignArray(ref _array, idx, registration);
|
||||
|
||||
ComponentAdded?.Invoke(registration);
|
||||
|
||||
@@ -216,13 +203,19 @@ namespace Robust.Shared.GameObjects
|
||||
throw new InvalidOperationException($"Unregistered type: {target}");
|
||||
}
|
||||
|
||||
if (@interface == typeof(MetaDataComponent) || @interface == typeof(TransformComponent))
|
||||
throw new InvalidOperationException("Cannot make Transform or Metadata a reference type!");
|
||||
|
||||
var idx = CompIdx.Index(@interface);
|
||||
_idxToType[idx] = @interface;
|
||||
|
||||
var registration = types[target];
|
||||
if (registration.References.Contains(@interface))
|
||||
if (registration.References.Contains(idx))
|
||||
{
|
||||
throw new InvalidOperationException($"Attempted to register a reference twice: {@interface}");
|
||||
}
|
||||
registration.References.Add(@interface);
|
||||
ComponentReferenceAdded?.Invoke((registration, @interface));
|
||||
registration.References.Add(idx);
|
||||
ComponentReferenceAdded?.Invoke(registration, idx);
|
||||
}
|
||||
|
||||
public void IgnoreMissingComponents()
|
||||
@@ -292,6 +285,11 @@ namespace Robust.Shared.GameObjects
|
||||
return _typeFactory.CreateInstanceUnchecked<IComponent>(types[componentType].Type);
|
||||
}
|
||||
|
||||
public IComponent GetComponent(CompIdx componentType)
|
||||
{
|
||||
return _typeFactory.CreateInstanceUnchecked<IComponent>(_array[componentType.Value].Type);
|
||||
}
|
||||
|
||||
public T GetComponent<T>() where T : IComponent, new()
|
||||
{
|
||||
if (!types.ContainsKey(typeof(T)))
|
||||
@@ -316,7 +314,7 @@ namespace Robust.Shared.GameObjects
|
||||
return _typeFactory.CreateInstanceUnchecked<IComponent>(GetRegistration(netId).Type);
|
||||
}
|
||||
|
||||
public IComponentRegistration GetRegistration(string componentName, bool ignoreCase = false)
|
||||
public ComponentRegistration GetRegistration(string componentName, bool ignoreCase = false)
|
||||
{
|
||||
if (ignoreCase && _lowerCaseNames.TryGetValue(componentName, out var lowerCaseName))
|
||||
{
|
||||
@@ -338,7 +336,7 @@ namespace Robust.Shared.GameObjects
|
||||
return GetRegistration(componentType).Name;
|
||||
}
|
||||
|
||||
public IComponentRegistration GetRegistration(ushort netID)
|
||||
public ComponentRegistration GetRegistration(ushort netID)
|
||||
{
|
||||
if (_networkedComponents is null)
|
||||
throw new ComponentRegistrationLockException();
|
||||
@@ -353,7 +351,7 @@ namespace Robust.Shared.GameObjects
|
||||
}
|
||||
}
|
||||
|
||||
public IComponentRegistration GetRegistration(Type reference)
|
||||
public ComponentRegistration GetRegistration(Type reference)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -365,17 +363,19 @@ namespace Robust.Shared.GameObjects
|
||||
}
|
||||
}
|
||||
|
||||
public IComponentRegistration GetRegistration<T>() where T : IComponent, new()
|
||||
public ComponentRegistration GetRegistration<T>() where T : IComponent, new()
|
||||
{
|
||||
return GetRegistration(typeof(T));
|
||||
}
|
||||
|
||||
public IComponentRegistration GetRegistration(IComponent component)
|
||||
public ComponentRegistration GetRegistration(IComponent component)
|
||||
{
|
||||
return GetRegistration(component.GetType());
|
||||
}
|
||||
|
||||
public bool TryGetRegistration(string componentName, [NotNullWhen(true)] out IComponentRegistration? registration, bool ignoreCase = false)
|
||||
public ComponentRegistration GetRegistration(CompIdx idx) => _array[idx.Value];
|
||||
|
||||
public bool TryGetRegistration(string componentName, [NotNullWhen(true)] out ComponentRegistration? registration, bool ignoreCase = false)
|
||||
{
|
||||
if (ignoreCase && _lowerCaseNames.TryGetValue(componentName, out var lowerCaseName))
|
||||
{
|
||||
@@ -392,7 +392,7 @@ namespace Robust.Shared.GameObjects
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool TryGetRegistration(Type reference, [NotNullWhen(true)] out IComponentRegistration? registration)
|
||||
public bool TryGetRegistration(Type reference, [NotNullWhen(true)] out ComponentRegistration? registration)
|
||||
{
|
||||
if (types.TryGetValue(reference, out var tempRegistration))
|
||||
{
|
||||
@@ -404,12 +404,12 @@ namespace Robust.Shared.GameObjects
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool TryGetRegistration<T>([NotNullWhen(true)] out IComponentRegistration? registration) where T : IComponent, new()
|
||||
public bool TryGetRegistration<T>([NotNullWhen(true)] out ComponentRegistration? registration) where T : IComponent, new()
|
||||
{
|
||||
return TryGetRegistration(typeof(T), out registration);
|
||||
}
|
||||
|
||||
public bool TryGetRegistration(ushort netID, [NotNullWhen(true)] out IComponentRegistration? registration)
|
||||
public bool TryGetRegistration(ushort netID, [NotNullWhen(true)] out ComponentRegistration? registration)
|
||||
{
|
||||
if (_networkedComponents is not null && _networkedComponents.TryGetValue(netID, out var tempRegistration))
|
||||
{
|
||||
@@ -421,7 +421,7 @@ namespace Robust.Shared.GameObjects
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool TryGetRegistration(IComponent component, [NotNullWhen(true)] out IComponentRegistration? registration)
|
||||
public bool TryGetRegistration(IComponent component, [NotNullWhen(true)] out ComponentRegistration? registration)
|
||||
{
|
||||
return TryGetRegistration(component.GetType(), out registration);
|
||||
}
|
||||
@@ -467,7 +467,7 @@ namespace Robust.Shared.GameObjects
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<Type> GetAllRefTypes()
|
||||
public IEnumerable<CompIdx> GetAllRefTypes()
|
||||
{
|
||||
return AllRegistrations.SelectMany(r => r.References).Distinct();
|
||||
}
|
||||
@@ -480,7 +480,7 @@ namespace Robust.Shared.GameObjects
|
||||
// component names are 1:1 with component concrete types
|
||||
|
||||
// a subset of component names are networked
|
||||
var networkedRegs = new List<IComponentRegistration>(names.Count);
|
||||
var networkedRegs = new List<ComponentRegistration>(names.Count);
|
||||
|
||||
foreach (var kvRegistration in names)
|
||||
{
|
||||
@@ -497,12 +497,14 @@ namespace Robust.Shared.GameObjects
|
||||
|
||||
for (ushort i = 0; i < networkedRegs.Count; i++)
|
||||
{
|
||||
var registration = (ComponentRegistration) networkedRegs[i];
|
||||
var registration = networkedRegs[i];
|
||||
registration.NetID = i;
|
||||
}
|
||||
|
||||
_networkedComponents = networkedRegs;
|
||||
}
|
||||
|
||||
public Type IdxToType(CompIdx idx) => _idxToType[idx];
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Utility.Collections;
|
||||
|
||||
namespace Robust.Shared.GameObjects;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a component registered into a <see cref="IComponentFactory" />.
|
||||
/// </summary>
|
||||
/// <seealso cref="IComponentFactory" />
|
||||
/// <seealso cref="IComponent" />
|
||||
public sealed class ComponentRegistration
|
||||
{
|
||||
/// <summary>
|
||||
/// The name of the component.
|
||||
/// This is used as the <c>type</c> field in the component declarations if entity prototypes.
|
||||
/// </summary>
|
||||
/// <seealso cref="IComponent.Name" />
|
||||
public string Name { get; }
|
||||
|
||||
public CompIdx Idx { get; }
|
||||
|
||||
/// <summary>
|
||||
/// ID used to reference the component type across the network.
|
||||
/// If null, no network synchronization will be available for this component.
|
||||
/// </summary>
|
||||
/// <seealso cref="NetworkedComponentAttribute" />
|
||||
public ushort? NetID { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// The type that will be instantiated if this component is created.
|
||||
/// </summary>
|
||||
public Type Type { get; }
|
||||
|
||||
public ValueList<CompIdx> References;
|
||||
|
||||
public ComponentRegistration(string name, Type type, CompIdx idx)
|
||||
{
|
||||
Name = name;
|
||||
Type = type;
|
||||
Idx = idx;
|
||||
References.Add(idx);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"ComponentRegistration({Name}: {Type})";
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Robust.Shared.Utility;
|
||||
using Robust.Shared.Utility.Collections;
|
||||
|
||||
namespace Robust.Shared.GameObjects
|
||||
{
|
||||
@@ -75,6 +76,8 @@ namespace Robust.Shared.GameObjects
|
||||
/// <param name="args">Event arguments for the event.</param>
|
||||
internal void RaiseComponentEvent<TEvent>(IComponent component, ref TEvent args)
|
||||
where TEvent : notnull;
|
||||
|
||||
public void OnlyCallOnRobustUnitTestISwearToGodPleaseSomebodyKillThisNightmare();
|
||||
}
|
||||
|
||||
internal partial class EntityEventBus : IDirectedEventBus, IEventBus, IDisposable
|
||||
@@ -113,6 +116,11 @@ namespace Robust.Shared.GameObjects
|
||||
_eventTables.DispatchComponent<TEvent>(component.Owner, component, ref unitRef, true);
|
||||
}
|
||||
|
||||
public void OnlyCallOnRobustUnitTestISwearToGodPleaseSomebodyKillThisNightmare()
|
||||
{
|
||||
_eventTables.IgnoreUnregisteredComponents = true;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void RaiseLocalEvent<TEvent>(EntityUid uid, TEvent args, bool broadcast = true)
|
||||
where TEvent : notnull
|
||||
@@ -172,7 +180,13 @@ namespace Robust.Shared.GameObjects
|
||||
void EventHandler(EntityUid uid, IComponent comp, ref TEvent args)
|
||||
=> handler(uid, (TComp)comp, args);
|
||||
|
||||
_eventTables.Subscribe<TEvent>(typeof(TComp), typeof(TEvent), EventHandler, null, false);
|
||||
_eventTables.Subscribe<TEvent>(
|
||||
CompIdx.Index<TComp>(),
|
||||
typeof(TComp),
|
||||
typeof(TEvent),
|
||||
EventHandler,
|
||||
null,
|
||||
false);
|
||||
}
|
||||
|
||||
public void SubscribeLocalEvent<TComp, TEvent>(
|
||||
@@ -188,7 +202,13 @@ namespace Robust.Shared.GameObjects
|
||||
|
||||
var orderData = new OrderingData(orderType, before, after);
|
||||
|
||||
_eventTables.Subscribe<TEvent>(typeof(TComp), typeof(TEvent), EventHandler, orderData, false);
|
||||
_eventTables.Subscribe<TEvent>(
|
||||
CompIdx.Index<TComp>(),
|
||||
typeof(TComp),
|
||||
typeof(TEvent),
|
||||
EventHandler,
|
||||
orderData,
|
||||
false);
|
||||
HandleOrderRegistration(typeof(TEvent), orderData);
|
||||
}
|
||||
|
||||
@@ -198,7 +218,13 @@ namespace Robust.Shared.GameObjects
|
||||
void EventHandler(EntityUid uid, IComponent comp, ref TEvent args)
|
||||
=> handler(uid, (TComp)comp, ref args);
|
||||
|
||||
_eventTables.Subscribe<TEvent>(typeof(TComp), typeof(TEvent), EventHandler, null, true);
|
||||
_eventTables.Subscribe<TEvent>(
|
||||
CompIdx.Index<TComp>(),
|
||||
typeof(TComp),
|
||||
typeof(TEvent),
|
||||
EventHandler,
|
||||
null,
|
||||
true);
|
||||
}
|
||||
|
||||
public void SubscribeLocalEvent<TComp, TEvent>(ComponentEventRefHandler<TComp, TEvent> handler, Type orderType,
|
||||
@@ -210,7 +236,14 @@ namespace Robust.Shared.GameObjects
|
||||
|
||||
var orderData = new OrderingData(orderType, before, after);
|
||||
|
||||
_eventTables.Subscribe<TEvent>(typeof(TComp), typeof(TEvent), EventHandler, orderData, true);
|
||||
_eventTables.Subscribe<TEvent>(
|
||||
CompIdx.Index<TComp>(),
|
||||
typeof(TComp),
|
||||
typeof(TEvent),
|
||||
EventHandler,
|
||||
orderData,
|
||||
true);
|
||||
|
||||
HandleOrderRegistration(typeof(TEvent), orderData);
|
||||
}
|
||||
|
||||
@@ -219,7 +252,7 @@ namespace Robust.Shared.GameObjects
|
||||
where TComp : IComponent
|
||||
where TEvent : notnull
|
||||
{
|
||||
_eventTables.Unsubscribe(typeof(TComp), typeof(TEvent));
|
||||
_eventTables.Unsubscribe(CompIdx.Index<TComp>(), typeof(TEvent));
|
||||
}
|
||||
|
||||
private sealed class EventTables : IDisposable
|
||||
@@ -231,10 +264,10 @@ namespace Robust.Shared.GameObjects
|
||||
private IComponentFactory _comFac;
|
||||
|
||||
// eUid -> EventType -> { CompType1, ... CompTypeN }
|
||||
private Dictionary<EntityUid, Dictionary<Type, HashSet<Type>>> _eventTables;
|
||||
private Dictionary<EntityUid, Dictionary<Type, HashSet<CompIdx>>> _eventTables;
|
||||
|
||||
// EventType -> CompType -> Handler
|
||||
private Dictionary<Type, Dictionary<Type, DirectedRegistration>> _subscriptions;
|
||||
// CompType -> EventType -> Handler
|
||||
private Dictionary<Type, DirectedRegistration>?[] _subscriptions;
|
||||
|
||||
// prevents shitcode, get your subscriptions figured out before you start spawning entities
|
||||
private bool _subscriptionLock;
|
||||
@@ -250,34 +283,60 @@ namespace Robust.Shared.GameObjects
|
||||
_entMan.ComponentAdded += OnComponentAdded;
|
||||
_entMan.ComponentRemoved += OnComponentRemoved;
|
||||
|
||||
// Dynamic handling of components is only for RobustUnitTest compatibility spaghetti.
|
||||
_comFac.ComponentAdded += ComFacOnComponentAdded;
|
||||
_comFac.ComponentReferenceAdded += ComFacOnComponentReferenceAdded;
|
||||
|
||||
_eventTables = new();
|
||||
_subscriptions = new();
|
||||
_subscriptions = Array.Empty<Dictionary<Type, DirectedRegistration>>();
|
||||
_subscriptionLock = false;
|
||||
|
||||
InitSubscriptionsArray();
|
||||
}
|
||||
|
||||
private void OnEntityAdded(object? sender, EntityUid e)
|
||||
public bool IgnoreUnregisteredComponents;
|
||||
|
||||
private void InitSubscriptionsArray()
|
||||
{
|
||||
foreach (var refType in _comFac.GetAllRefTypes())
|
||||
{
|
||||
CompIdx.AssignArray(ref _subscriptions, refType, new Dictionary<Type, DirectedRegistration>());
|
||||
}
|
||||
}
|
||||
|
||||
private void ComFacOnComponentReferenceAdded(ComponentRegistration arg1, CompIdx arg2)
|
||||
{
|
||||
CompIdx.RefArray(ref _subscriptions, arg2) ??= new Dictionary<Type, DirectedRegistration>();
|
||||
}
|
||||
|
||||
private void ComFacOnComponentAdded(ComponentRegistration obj)
|
||||
{
|
||||
CompIdx.RefArray(ref _subscriptions, obj.Idx) ??= new Dictionary<Type, DirectedRegistration>();
|
||||
}
|
||||
|
||||
private void OnEntityAdded(EntityUid e)
|
||||
{
|
||||
AddEntity(e);
|
||||
}
|
||||
|
||||
private void OnEntityDeleted(object? sender, EntityUid e)
|
||||
private void OnEntityDeleted(EntityUid e)
|
||||
{
|
||||
RemoveEntity(e);
|
||||
}
|
||||
|
||||
private void OnComponentAdded(object? sender, ComponentEventArgs e)
|
||||
private void OnComponentAdded(AddedComponentEventArgs e)
|
||||
{
|
||||
_subscriptionLock = true;
|
||||
|
||||
AddComponent(e.Owner, e.Component.GetType());
|
||||
AddComponent(e.BaseArgs.Owner, CompIdx.Index(e.BaseArgs.Component.GetType()));
|
||||
}
|
||||
|
||||
private void OnComponentRemoved(object? sender, ComponentEventArgs e)
|
||||
private void OnComponentRemoved(RemovedComponentEventArgs e)
|
||||
{
|
||||
RemoveComponent(e.Owner, e.Component.GetType());
|
||||
RemoveComponent(e.BaseArgs.Owner, CompIdx.Index(e.BaseArgs.Component.GetType()));
|
||||
}
|
||||
|
||||
private void AddSubscription(Type compType, Type eventType, DirectedRegistration registration)
|
||||
private void AddSubscription(CompIdx compType, Type compTypeObj, Type eventType, DirectedRegistration registration)
|
||||
{
|
||||
if (_subscriptionLock)
|
||||
throw new InvalidOperationException("Subscription locked.");
|
||||
@@ -286,26 +345,32 @@ namespace Robust.Shared.GameObjects
|
||||
|
||||
if (referenceEvent != registration.ReferenceEvent)
|
||||
throw new InvalidOperationException(
|
||||
$"Attempted to subscribe by-ref and by-value to the same directed event! comp={compType.Name}, event={eventType.Name} eventIsByRef={referenceEvent} subscriptionIsByRef={registration.ReferenceEvent}");
|
||||
$"Attempted to subscribe by-ref and by-value to the same directed event! comp={compTypeObj.Name}, event={eventType.Name} eventIsByRef={referenceEvent} subscriptionIsByRef={registration.ReferenceEvent}");
|
||||
|
||||
if (!_subscriptions.TryGetValue(compType, out var compSubs))
|
||||
if (compType.Value >= _subscriptions.Length || _subscriptions[compType.Value] is not { } compSubs)
|
||||
{
|
||||
compSubs = new Dictionary<Type, DirectedRegistration>();
|
||||
_subscriptions.Add(compType, compSubs);
|
||||
if (IgnoreUnregisteredComponents)
|
||||
return;
|
||||
|
||||
throw new InvalidOperationException($"Component is not a valid reference type: {compTypeObj.Name}");
|
||||
}
|
||||
|
||||
if (compSubs.ContainsKey(eventType))
|
||||
throw new InvalidOperationException(
|
||||
$"Duplicate Subscriptions for comp={compType.Name}, event={eventType.Name}");
|
||||
$"Duplicate Subscriptions for comp={compTypeObj}, event={eventType.Name}");
|
||||
|
||||
compSubs.Add(eventType, registration);
|
||||
}
|
||||
|
||||
public void Subscribe<TEvent>(Type compType, Type eventType, DirectedEventHandler<TEvent> handler,
|
||||
public void Subscribe<TEvent>(
|
||||
CompIdx compType,
|
||||
Type compTypeObj,
|
||||
Type eventType,
|
||||
DirectedEventHandler<TEvent> handler,
|
||||
OrderingData? order, bool byReference)
|
||||
where TEvent : notnull
|
||||
{
|
||||
AddSubscription(compType, eventType, new DirectedRegistration(handler, order,
|
||||
AddSubscription(compType, compTypeObj, eventType, new DirectedRegistration(handler, order,
|
||||
(EntityUid uid, IComponent comp, ref Unit ev) =>
|
||||
{
|
||||
ref var tev = ref Unsafe.As<Unit, TEvent>(ref ev);
|
||||
@@ -313,13 +378,18 @@ namespace Robust.Shared.GameObjects
|
||||
}, byReference));
|
||||
}
|
||||
|
||||
public void Unsubscribe(Type compType, Type eventType)
|
||||
public void Unsubscribe(CompIdx compType, Type eventType)
|
||||
{
|
||||
if (_subscriptionLock)
|
||||
throw new InvalidOperationException("Subscription locked.");
|
||||
|
||||
if (!_subscriptions.TryGetValue(compType, out var compSubs))
|
||||
return;
|
||||
if (compType.Value >= _subscriptions.Length || _subscriptions[compType.Value] is not { } compSubs)
|
||||
{
|
||||
if (IgnoreUnregisteredComponents)
|
||||
return;
|
||||
|
||||
throw new InvalidOperationException("Trying to unsubscribe from unregistered component!");
|
||||
}
|
||||
|
||||
compSubs.Remove(eventType);
|
||||
}
|
||||
@@ -328,7 +398,7 @@ namespace Robust.Shared.GameObjects
|
||||
{
|
||||
// odds are at least 1 component will subscribe to an event on the entity, so just
|
||||
// preallocate the table now. Dispatch does not need to check this later.
|
||||
_eventTables.Add(euid, new Dictionary<Type, HashSet<Type>>());
|
||||
_eventTables.Add(euid, new Dictionary<Type, HashSet<CompIdx>>());
|
||||
}
|
||||
|
||||
private void RemoveEntity(EntityUid euid)
|
||||
@@ -336,21 +406,20 @@ namespace Robust.Shared.GameObjects
|
||||
_eventTables.Remove(euid);
|
||||
}
|
||||
|
||||
private void AddComponent(EntityUid euid, Type compType)
|
||||
private void AddComponent(EntityUid euid, CompIdx compType)
|
||||
{
|
||||
var eventTable = _eventTables[euid];
|
||||
|
||||
var enumerator = GetReferences(compType);
|
||||
while (enumerator.MoveNext(out var type))
|
||||
{
|
||||
if (!_subscriptions.TryGetValue(type, out var compSubs))
|
||||
continue;
|
||||
var compSubs = _subscriptions[type.Value]!;
|
||||
|
||||
foreach (var kvSub in compSubs)
|
||||
{
|
||||
if (!eventTable.TryGetValue(kvSub.Key, out var subscribedComps))
|
||||
{
|
||||
subscribedComps = new HashSet<Type>();
|
||||
subscribedComps = new HashSet<CompIdx>();
|
||||
eventTable.Add(kvSub.Key, subscribedComps);
|
||||
}
|
||||
|
||||
@@ -359,15 +428,14 @@ namespace Robust.Shared.GameObjects
|
||||
}
|
||||
}
|
||||
|
||||
private void RemoveComponent(EntityUid euid, Type compType)
|
||||
private void RemoveComponent(EntityUid euid, CompIdx compType)
|
||||
{
|
||||
var eventTable = _eventTables[euid];
|
||||
|
||||
var enumerator = GetReferences(compType);
|
||||
while (enumerator.MoveNext(out var type))
|
||||
{
|
||||
if (!_subscriptions.TryGetValue(type, out var compSubs))
|
||||
continue;
|
||||
var compSubs = _subscriptions[type.Value]!;
|
||||
|
||||
foreach (var kvSub in compSubs)
|
||||
{
|
||||
@@ -407,8 +475,7 @@ namespace Robust.Shared.GameObjects
|
||||
|
||||
foreach (var compType in subscribedComps)
|
||||
{
|
||||
if (!_subscriptions.TryGetValue(compType, out var compSubs))
|
||||
return;
|
||||
var compSubs = _subscriptions[compType.Value]!;
|
||||
|
||||
if (!compSubs.TryGetValue(eventType, out var reg))
|
||||
return;
|
||||
@@ -425,11 +492,10 @@ namespace Robust.Shared.GameObjects
|
||||
public void DispatchComponent<TEvent>(EntityUid euid, IComponent component, ref Unit args, bool dispatchByReference)
|
||||
where TEvent : notnull
|
||||
{
|
||||
var enumerator = GetReferences(component.GetType());
|
||||
var enumerator = GetReferences(CompIdx.Index(component.GetType()));
|
||||
while (enumerator.MoveNext(out var type))
|
||||
{
|
||||
if (!_subscriptions.TryGetValue(type, out var compSubs))
|
||||
continue;
|
||||
var compSubs = _subscriptions[type.Value]!;
|
||||
|
||||
if (!compSubs.TryGetValue(typeof(TEvent), out var reg))
|
||||
continue;
|
||||
@@ -450,7 +516,11 @@ namespace Robust.Shared.GameObjects
|
||||
public void Clear()
|
||||
{
|
||||
ClearEntities();
|
||||
_subscriptions = new();
|
||||
|
||||
foreach (var sub in _subscriptions)
|
||||
{
|
||||
sub?.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
@@ -461,6 +531,9 @@ namespace Robust.Shared.GameObjects
|
||||
_entMan.ComponentAdded -= OnComponentAdded;
|
||||
_entMan.ComponentRemoved -= OnComponentRemoved;
|
||||
|
||||
_comFac.ComponentAdded -= ComFacOnComponentAdded;
|
||||
_comFac.ComponentReferenceAdded -= ComFacOnComponentReferenceAdded;
|
||||
|
||||
// punishment for use-after-free
|
||||
_entMan = null!;
|
||||
_eventTables = null!;
|
||||
@@ -470,7 +543,7 @@ namespace Robust.Shared.GameObjects
|
||||
/// <summary>
|
||||
/// Enumerates the type's component references, returning the type itself last.
|
||||
/// </summary>
|
||||
private ReferencesEnumerator GetReferences(Type type)
|
||||
private ReferencesEnumerator GetReferences(CompIdx type)
|
||||
{
|
||||
return new(type, _comFac.GetRegistration(type).References);
|
||||
}
|
||||
@@ -499,12 +572,12 @@ namespace Robust.Shared.GameObjects
|
||||
|
||||
private struct ReferencesEnumerator
|
||||
{
|
||||
private readonly Type _baseType;
|
||||
private readonly IReadOnlyList<Type> _list;
|
||||
private readonly CompIdx _baseType;
|
||||
private readonly ValueList<CompIdx> _list;
|
||||
private readonly int _totalLength;
|
||||
private int _idx;
|
||||
|
||||
public ReferencesEnumerator(Type baseType, IReadOnlyList<Type> list)
|
||||
public ReferencesEnumerator(CompIdx baseType, ValueList<CompIdx> list)
|
||||
{
|
||||
_baseType = baseType;
|
||||
_list = list;
|
||||
@@ -512,7 +585,7 @@ namespace Robust.Shared.GameObjects
|
||||
_idx = 0;
|
||||
}
|
||||
|
||||
public bool MoveNext([NotNullWhen(true)] out Type? type)
|
||||
public bool MoveNext([NotNullWhen(true)] out CompIdx type)
|
||||
{
|
||||
if (_idx >= _totalLength)
|
||||
{
|
||||
@@ -522,7 +595,7 @@ namespace Robust.Shared.GameObjects
|
||||
return true;
|
||||
}
|
||||
|
||||
type = null;
|
||||
type = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -537,13 +610,16 @@ namespace Robust.Shared.GameObjects
|
||||
private struct SubscriptionsEnumerator : IDisposable
|
||||
{
|
||||
private readonly Type _eventType;
|
||||
private HashSet<Type>.Enumerator _enumerator;
|
||||
private readonly IReadOnlyDictionary<Type, Dictionary<Type, DirectedRegistration>> _subscriptions;
|
||||
private HashSet<CompIdx>.Enumerator _enumerator;
|
||||
private readonly Dictionary<Type, DirectedRegistration>?[] _subscriptions;
|
||||
private readonly EntityUid _uid;
|
||||
private readonly IEntityManager _entityManager;
|
||||
|
||||
public SubscriptionsEnumerator(Type eventType, HashSet<Type>.Enumerator enumerator,
|
||||
IReadOnlyDictionary<Type, Dictionary<Type, DirectedRegistration>> subscriptions, EntityUid uid,
|
||||
public SubscriptionsEnumerator(
|
||||
Type eventType,
|
||||
HashSet<CompIdx>.Enumerator enumerator,
|
||||
Dictionary<Type, DirectedRegistration>?[] subscriptions,
|
||||
EntityUid uid,
|
||||
IEntityManager entityManager)
|
||||
{
|
||||
_eventType = eventType;
|
||||
@@ -556,22 +632,15 @@ namespace Robust.Shared.GameObjects
|
||||
public bool MoveNext(
|
||||
[NotNullWhen(true)] out (IComponent Component, DirectedRegistration Registration)? tuple)
|
||||
{
|
||||
_enumerator.MoveNext();
|
||||
|
||||
// ReSharper disable once ConditionIsAlwaysTrueOrFalse
|
||||
if (_enumerator.Current == null)
|
||||
if (!_enumerator.MoveNext())
|
||||
{
|
||||
tuple = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
var compType = _enumerator.Current;
|
||||
|
||||
if (!_subscriptions.TryGetValue(compType, out var compSubs))
|
||||
{
|
||||
tuple = null;
|
||||
return false;
|
||||
}
|
||||
var compSubs = _subscriptions[compType.Value]!;
|
||||
|
||||
if (!compSubs.TryGetValue(_eventType, out var registration))
|
||||
{
|
||||
|
||||
@@ -1,17 +1,12 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using System.Reflection;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Physics;
|
||||
using Robust.Shared.Players;
|
||||
using Robust.Shared.Utility;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Log;
|
||||
using System.Diagnostics;
|
||||
#if EXCEPTION_TOLERANCE
|
||||
@@ -51,13 +46,13 @@ namespace Robust.Shared.GameObjects
|
||||
new(ComponentCollectionCapacity);
|
||||
|
||||
/// <inheritdoc />
|
||||
public event EventHandler<ComponentEventArgs>? ComponentAdded;
|
||||
public event Action<AddedComponentEventArgs>? ComponentAdded;
|
||||
|
||||
/// <inheritdoc />
|
||||
public event EventHandler<ComponentEventArgs>? ComponentRemoved;
|
||||
public event Action<RemovedComponentEventArgs>? ComponentRemoved;
|
||||
|
||||
/// <inheritdoc />
|
||||
public event EventHandler<ComponentEventArgs>? ComponentDeleted;
|
||||
public event Action<DeletedComponentEventArgs>? ComponentDeleted;
|
||||
|
||||
public void InitializeComponents()
|
||||
{
|
||||
@@ -83,41 +78,21 @@ namespace Robust.Shared.GameObjects
|
||||
FillComponentDict();
|
||||
}
|
||||
|
||||
private void AddComponentRefType(Type type)
|
||||
private void AddComponentRefType(CompIdx type)
|
||||
{
|
||||
var dict = new Dictionary<EntityUid, Component>();
|
||||
_entTraitDict.Add(type, dict);
|
||||
var index = GetCompIdIndex(type);
|
||||
EnsureEntTraitIndexCapacity(index);
|
||||
_entTraitArray[index] = dict;
|
||||
_entTraitDict.Add(_componentFactory.IdxToType(type), dict);
|
||||
CompIdx.AssignArray(ref _entTraitArray, type, dict);
|
||||
}
|
||||
|
||||
private void OnComponentAdded(IComponentRegistration obj)
|
||||
private void OnComponentAdded(ComponentRegistration obj)
|
||||
{
|
||||
AddComponentRefType(obj.Type);
|
||||
AddComponentRefType(obj.Idx);
|
||||
}
|
||||
|
||||
private void OnComponentReferenceAdded((IComponentRegistration, Type type) obj)
|
||||
private void OnComponentReferenceAdded(ComponentRegistration reg, CompIdx type)
|
||||
{
|
||||
AddComponentRefType(obj.Item2);
|
||||
}
|
||||
|
||||
private static int GetCompIdIndex(Type type)
|
||||
{
|
||||
return (int)typeof(CompArrayIndex<>)
|
||||
.MakeGenericType(type)
|
||||
.GetField(nameof(CompArrayIndex<int>.Index), BindingFlags.Static | BindingFlags.Public)!
|
||||
.GetValue(null)!;
|
||||
}
|
||||
|
||||
private void EnsureEntTraitIndexCapacity(int index)
|
||||
{
|
||||
var curLength = _entTraitArray.Length;
|
||||
if (curLength > index)
|
||||
return;
|
||||
|
||||
var newLength = MathHelper.NextPowerOfTwo(Math.Max(8, index));
|
||||
Array.Resize(ref _entTraitArray, newLength);
|
||||
AddComponentRefType(type);
|
||||
}
|
||||
|
||||
#region Component Management
|
||||
@@ -128,22 +103,31 @@ namespace Robust.Shared.GameObjects
|
||||
DebugTools.Assert(metadata.EntityLifeStage == EntityLifeStage.PreInit);
|
||||
metadata.EntityLifeStage = EntityLifeStage.Initializing;
|
||||
|
||||
// Initialize() can modify the collection of components.
|
||||
var components = GetComponents(uid)
|
||||
.OrderBy(x => x switch
|
||||
{
|
||||
TransformComponent _ => 0,
|
||||
IPhysBody _ => 1,
|
||||
_ => int.MaxValue
|
||||
});
|
||||
// Initialize() can modify the collection of components. Copy them.
|
||||
FixedArray32<Component?> compsFixed = default;
|
||||
|
||||
foreach (var component in components)
|
||||
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)
|
||||
transform.LifeInitialize(this);
|
||||
|
||||
// Init physics second if it exists.
|
||||
if (TryGetComponent<PhysicsComponent>(uid, out var phys)
|
||||
&& phys.LifeStage < ComponentLifeStage.Initialized)
|
||||
{
|
||||
var comp = (Component)component;
|
||||
if (comp.Initialized)
|
||||
continue;
|
||||
phys.LifeInitialize(this);
|
||||
}
|
||||
|
||||
comp.LifeInitialize(this);
|
||||
// Do rest of components.
|
||||
foreach (var comp in comps)
|
||||
{
|
||||
if (comp is { LifeStage: < ComponentLifeStage.Initialized })
|
||||
comp.LifeInitialize(this);
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
@@ -165,24 +149,32 @@ namespace Robust.Shared.GameObjects
|
||||
|
||||
public void StartComponents(EntityUid uid)
|
||||
{
|
||||
// TODO: Move this to EntityManager.
|
||||
// Startup() can modify _components
|
||||
// This code can only handle additions to the list. Is there a better way? Probably not.
|
||||
var comps = GetComponents(uid)
|
||||
.OrderBy(x => x switch
|
||||
{
|
||||
TransformComponent _ => 0,
|
||||
IPhysBody _ => 1,
|
||||
_ => int.MaxValue
|
||||
});
|
||||
FixedArray32<Component?> compsFixed = default;
|
||||
|
||||
foreach (var component in comps)
|
||||
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)
|
||||
transform.LifeStartup(this);
|
||||
|
||||
// Init physics second if it exists.
|
||||
if (TryGetComponent<PhysicsComponent>(uid, out var phys)
|
||||
&& phys.LifeStage == ComponentLifeStage.Initialized)
|
||||
{
|
||||
var comp = (Component)component;
|
||||
if (comp.LifeStage == ComponentLifeStage.Initialized)
|
||||
{
|
||||
phys.LifeStartup(this);
|
||||
}
|
||||
|
||||
// Do rest of components.
|
||||
foreach (var comp in comps)
|
||||
{
|
||||
if (comp is { LifeStage: ComponentLifeStage.Initialized })
|
||||
comp.LifeStartup(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -265,7 +257,7 @@ namespace Robust.Shared.GameObjects
|
||||
// Check that there are no overlapping references.
|
||||
foreach (var type in reg.References)
|
||||
{
|
||||
var dict = _entTraitDict[type];
|
||||
var dict = _entTraitArray[type.Value];
|
||||
if (!dict.TryGetValue(uid, out var duplicate))
|
||||
continue;
|
||||
|
||||
@@ -273,17 +265,13 @@ namespace Robust.Shared.GameObjects
|
||||
throw new InvalidOperationException(
|
||||
$"Component reference type {type} already occupied by {duplicate}");
|
||||
|
||||
// these two components are required on all entities and cannot be overwritten.
|
||||
if (duplicate is TransformComponent || duplicate is MetaDataComponent)
|
||||
throw new InvalidOperationException("Tried to overwrite a protected component.");
|
||||
|
||||
RemoveComponentImmediate(duplicate, uid, false);
|
||||
}
|
||||
|
||||
// add the component to the grid
|
||||
foreach (var type in reg.References)
|
||||
{
|
||||
_entTraitDict[type].Add(uid, component);
|
||||
_entTraitArray[type.Value].Add(uid, component);
|
||||
_entCompIndex.Add(uid, component);
|
||||
}
|
||||
|
||||
@@ -305,7 +293,7 @@ namespace Robust.Shared.GameObjects
|
||||
Dirty(component);
|
||||
}
|
||||
|
||||
ComponentAdded?.Invoke(this, new AddedComponentEventArgs(component, uid));
|
||||
ComponentAdded?.Invoke(new AddedComponentEventArgs(new ComponentEventArgs(component, uid)));
|
||||
|
||||
component.LifeAddToEntity(this);
|
||||
|
||||
@@ -437,7 +425,7 @@ namespace Robust.Shared.GameObjects
|
||||
|
||||
if (component.LifeStage != ComponentLifeStage.PreAdd)
|
||||
component.LifeRemoveFromEntity(this);
|
||||
ComponentRemoved?.Invoke(this, new RemovedComponentEventArgs(component, uid));
|
||||
ComponentRemoved?.Invoke(new RemovedComponentEventArgs(new ComponentEventArgs(component, uid)));
|
||||
#if EXCEPTION_TOLERANCE
|
||||
}
|
||||
catch (Exception e)
|
||||
@@ -471,7 +459,7 @@ namespace Robust.Shared.GameObjects
|
||||
if (component.LifeStage != ComponentLifeStage.PreAdd)
|
||||
component.LifeRemoveFromEntity(this); // Sets delete
|
||||
|
||||
ComponentRemoved?.Invoke(this, new RemovedComponentEventArgs(component, uid));
|
||||
ComponentRemoved?.Invoke(new RemovedComponentEventArgs(new ComponentEventArgs(component, uid)));
|
||||
}
|
||||
#if EXCEPTION_TOLERANCE
|
||||
}
|
||||
@@ -516,18 +504,18 @@ namespace Robust.Shared.GameObjects
|
||||
|
||||
foreach (var refType in reg.References)
|
||||
{
|
||||
_entTraitDict[refType].Remove(entityUid);
|
||||
_entTraitArray[refType.Value].Remove(entityUid);
|
||||
}
|
||||
|
||||
_entCompIndex.Remove(entityUid, component);
|
||||
ComponentDeleted?.Invoke(this, new DeletedComponentEventArgs(component, entityUid));
|
||||
ComponentDeleted?.Invoke(new DeletedComponentEventArgs(new ComponentEventArgs(component, entityUid)));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool HasComponent<T>(EntityUid uid)
|
||||
{
|
||||
return _entTraitArray[ArrayIndexFor<T>()].TryGetValue(uid, out var comp) && !comp.Deleted;
|
||||
return _entTraitArray[CompIdx.ArrayIndex<T>()].TryGetValue(uid, out var comp) && !comp.Deleted;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -607,7 +595,7 @@ namespace Robust.Shared.GameObjects
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public T GetComponent<T>(EntityUid uid)
|
||||
{
|
||||
var dict = _entTraitArray[ArrayIndexFor<T>()];
|
||||
var dict = _entTraitArray[CompIdx.ArrayIndex<T>()];
|
||||
if (dict.TryGetValue(uid, out var comp))
|
||||
{
|
||||
if (!comp.Deleted)
|
||||
@@ -619,6 +607,18 @@ namespace Robust.Shared.GameObjects
|
||||
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)
|
||||
{
|
||||
@@ -644,7 +644,7 @@ namespace Robust.Shared.GameObjects
|
||||
/// <inheritdoc />
|
||||
public bool TryGetComponent<T>(EntityUid uid, [NotNullWhen(true)] out T component)
|
||||
{
|
||||
var dict = _entTraitArray[ArrayIndexFor<T>()];
|
||||
var dict = _entTraitArray[CompIdx.ArrayIndex<T>()];
|
||||
if (dict.TryGetValue(uid, out var comp))
|
||||
{
|
||||
if (!comp.Deleted)
|
||||
@@ -758,7 +758,7 @@ namespace Robust.Shared.GameObjects
|
||||
|
||||
public EntityQuery<TComp1> GetEntityQuery<TComp1>() where TComp1 : Component
|
||||
{
|
||||
return new EntityQuery<TComp1>(_entTraitArray[ArrayIndexFor<TComp1>()]);
|
||||
return new EntityQuery<TComp1>(_entTraitArray[CompIdx.ArrayIndex<TComp1>()]);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -773,6 +773,25 @@ namespace Robust.Shared.GameObjects
|
||||
}
|
||||
}
|
||||
|
||||
/// <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<Component?> comps, EntityUid uid)
|
||||
{
|
||||
var set = _entCompIndex[uid];
|
||||
if (set.Count > comps.Length)
|
||||
{
|
||||
comps = new Component[set.Count];
|
||||
}
|
||||
|
||||
var i = 0;
|
||||
foreach (var c in set)
|
||||
{
|
||||
comps[i++] = c;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<T> GetComponents<T>(EntityUid uid)
|
||||
{
|
||||
@@ -796,7 +815,7 @@ namespace Robust.Shared.GameObjects
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<T> EntityQuery<T>(bool includePaused = false) where T : IComponent
|
||||
{
|
||||
var comps = _entTraitArray[ArrayIndexFor<T>()];
|
||||
var comps = _entTraitArray[CompIdx.ArrayIndex<T>()];
|
||||
|
||||
if (includePaused)
|
||||
{
|
||||
@@ -809,7 +828,7 @@ namespace Robust.Shared.GameObjects
|
||||
}
|
||||
else
|
||||
{
|
||||
var metaComps = _entTraitArray[ArrayIndexFor<MetaDataComponent>()];
|
||||
var metaComps = _entTraitArray[CompIdx.ArrayIndex<MetaDataComponent>()];
|
||||
|
||||
foreach (var t1Comp in comps.Values)
|
||||
{
|
||||
@@ -830,8 +849,8 @@ namespace Robust.Shared.GameObjects
|
||||
where TComp2 : IComponent
|
||||
{
|
||||
// this would prob be faster if trait1 was a list (or an array of structs hue).
|
||||
var trait1 = _entTraitArray[ArrayIndexFor<TComp1>()];
|
||||
var trait2 = _entTraitArray[ArrayIndexFor<TComp2>()];
|
||||
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)
|
||||
@@ -848,7 +867,7 @@ namespace Robust.Shared.GameObjects
|
||||
}
|
||||
else
|
||||
{
|
||||
var metaComps = _entTraitArray[ArrayIndexFor<MetaDataComponent>()];
|
||||
var metaComps = _entTraitArray[CompIdx.ArrayIndex<MetaDataComponent>()];
|
||||
|
||||
foreach (var (uid, t1Comp) in trait1)
|
||||
{
|
||||
@@ -875,9 +894,9 @@ namespace Robust.Shared.GameObjects
|
||||
where TComp2 : IComponent
|
||||
where TComp3 : IComponent
|
||||
{
|
||||
var trait1 = _entTraitArray[ArrayIndexFor<TComp1>()];
|
||||
var trait2 = _entTraitArray[ArrayIndexFor<TComp2>()];
|
||||
var trait3 = _entTraitArray[ArrayIndexFor<TComp3>()];
|
||||
var trait1 = _entTraitArray[CompIdx.ArrayIndex<TComp1>()];
|
||||
var trait2 = _entTraitArray[CompIdx.ArrayIndex<TComp2>()];
|
||||
var trait3 = _entTraitArray[CompIdx.ArrayIndex<TComp3>()];
|
||||
|
||||
if (includePaused)
|
||||
{
|
||||
@@ -897,7 +916,7 @@ namespace Robust.Shared.GameObjects
|
||||
}
|
||||
else
|
||||
{
|
||||
var metaComps = _entTraitArray[ArrayIndexFor<MetaDataComponent>()];
|
||||
var metaComps = _entTraitArray[CompIdx.ArrayIndex<MetaDataComponent>()];
|
||||
|
||||
foreach (var (uid, t1Comp) in trait1)
|
||||
{
|
||||
@@ -930,10 +949,10 @@ namespace Robust.Shared.GameObjects
|
||||
where TComp3 : IComponent
|
||||
where TComp4 : IComponent
|
||||
{
|
||||
var trait1 = _entTraitArray[ArrayIndexFor<TComp1>()];
|
||||
var trait2 = _entTraitArray[ArrayIndexFor<TComp2>()];
|
||||
var trait3 = _entTraitArray[ArrayIndexFor<TComp3>()];
|
||||
var trait4 = _entTraitArray[ArrayIndexFor<TComp4>()];
|
||||
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)
|
||||
{
|
||||
@@ -957,7 +976,7 @@ namespace Robust.Shared.GameObjects
|
||||
}
|
||||
else
|
||||
{
|
||||
var metaComps = _entTraitArray[ArrayIndexFor<MetaDataComponent>()];
|
||||
var metaComps = _entTraitArray[CompIdx.ArrayIndex<MetaDataComponent>()];
|
||||
|
||||
foreach (var (uid, t1Comp) in trait1)
|
||||
{
|
||||
@@ -1044,16 +1063,6 @@ namespace Robust.Shared.GameObjects
|
||||
AddComponentRefType(refType);
|
||||
}
|
||||
}
|
||||
|
||||
private static int ArrayIndexFor<T>() => CompArrayIndex<T>.Index;
|
||||
|
||||
private static int _compIndexMaster = -1;
|
||||
|
||||
private static class CompArrayIndex<T>
|
||||
{
|
||||
// ReSharper disable once StaticMemberInGenericType
|
||||
public static readonly int Index = Interlocked.Increment(ref _compIndexMaster);
|
||||
}
|
||||
}
|
||||
|
||||
public readonly struct NetComponentEnumerable
|
||||
|
||||
@@ -57,11 +57,11 @@ namespace Robust.Shared.GameObjects
|
||||
/// <inheritdoc />
|
||||
public IEventBus EventBus => _eventBus;
|
||||
|
||||
public event EventHandler<EntityUid>? EntityAdded;
|
||||
public event EventHandler<EntityUid>? EntityInitialized;
|
||||
public event EventHandler<EntityUid>? EntityStarted;
|
||||
public event EventHandler<EntityUid>? EntityDeleted;
|
||||
public event EventHandler<EntityUid>? EntityDirtied; // only raised after initialization
|
||||
public event Action<EntityUid>? EntityAdded;
|
||||
public event Action<EntityUid>? EntityInitialized;
|
||||
public event Action<EntityUid>? EntityStarted;
|
||||
public event Action<EntityUid>? EntityDeleted;
|
||||
public event Action<EntityUid>? EntityDirtied; // only raised after initialization
|
||||
|
||||
public bool Started { get; protected set; }
|
||||
public bool Initialized { get; protected set; }
|
||||
@@ -233,7 +233,7 @@ namespace Robust.Shared.GameObjects
|
||||
var currentTick = CurrentTick;
|
||||
|
||||
// We want to retrieve MetaDataComponent even if its Deleted flag is set.
|
||||
if (!_entTraitArray[ArrayIndexFor<MetaDataComponent>()].TryGetValue(uid, out var component))
|
||||
if (!_entTraitArray[CompIdx.ArrayIndex<MetaDataComponent>()].TryGetValue(uid, out var component))
|
||||
throw new KeyNotFoundException($"Entity {uid} does not exist, cannot dirty it.");
|
||||
|
||||
var metadata = (MetaDataComponent)component;
|
||||
@@ -244,7 +244,7 @@ namespace Robust.Shared.GameObjects
|
||||
|
||||
if (metadata.EntityLifeStage > EntityLifeStage.Initializing)
|
||||
{
|
||||
EntityDirtied?.Invoke(this, uid);
|
||||
EntityDirtied?.Invoke(uid);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -273,7 +273,7 @@ namespace Robust.Shared.GameObjects
|
||||
// Networking blindly spams entities at this function, they can already be
|
||||
// deleted from being a child of a previously deleted entity
|
||||
// TODO: Why does networking need to send deletes for child entities?
|
||||
if (!_entTraitArray[ArrayIndexFor<MetaDataComponent>()].TryGetValue(e, out var comp)
|
||||
if (!_entTraitArray[CompIdx.ArrayIndex<MetaDataComponent>()].TryGetValue(e, out var comp)
|
||||
|| comp is not MetaDataComponent meta || meta.EntityDeleted)
|
||||
return;
|
||||
|
||||
@@ -322,7 +322,7 @@ namespace Robust.Shared.GameObjects
|
||||
DisposeComponents(uid);
|
||||
|
||||
metadata.EntityLifeStage = EntityLifeStage.Deleted;
|
||||
EntityDeleted?.Invoke(this, uid);
|
||||
EntityDeleted?.Invoke(uid);
|
||||
EventBus.RaiseEvent(EventSource.Local, new EntityDeletedMessage(uid));
|
||||
Entities.Remove(uid);
|
||||
}
|
||||
@@ -337,7 +337,7 @@ namespace Robust.Shared.GameObjects
|
||||
|
||||
public bool EntityExists(EntityUid uid)
|
||||
{
|
||||
return _entTraitArray[ArrayIndexFor<MetaDataComponent>()].ContainsKey(uid);
|
||||
return _entTraitArray[CompIdx.ArrayIndex<MetaDataComponent>()].ContainsKey(uid);
|
||||
}
|
||||
|
||||
public bool EntityExists(EntityUid? uid)
|
||||
@@ -347,12 +347,12 @@ namespace Robust.Shared.GameObjects
|
||||
|
||||
public bool Deleted(EntityUid uid)
|
||||
{
|
||||
return !_entTraitArray[ArrayIndexFor<MetaDataComponent>()].TryGetValue(uid, out var comp) || ((MetaDataComponent) comp).EntityDeleted;
|
||||
return !_entTraitArray[CompIdx.ArrayIndex<MetaDataComponent>()].TryGetValue(uid, out var comp) || ((MetaDataComponent) comp).EntityDeleted;
|
||||
}
|
||||
|
||||
public bool Deleted(EntityUid? uid)
|
||||
{
|
||||
return !uid.HasValue || !_entTraitArray[ArrayIndexFor<MetaDataComponent>()].TryGetValue(uid.Value, out var comp) || ((MetaDataComponent) comp).EntityDeleted;
|
||||
return !uid.HasValue || !_entTraitArray[CompIdx.ArrayIndex<MetaDataComponent>()].TryGetValue(uid.Value, out var comp) || ((MetaDataComponent) comp).EntityDeleted;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -369,7 +369,10 @@ namespace Robust.Shared.GameObjects
|
||||
/// <summary>
|
||||
/// Allocates an entity and stores it but does not load components or do initialization.
|
||||
/// </summary>
|
||||
private protected EntityUid AllocEntity(string? prototypeName, EntityUid uid = default)
|
||||
private protected EntityUid AllocEntity(
|
||||
string? prototypeName,
|
||||
out MetaDataComponent metadata,
|
||||
EntityUid uid = default)
|
||||
{
|
||||
EntityPrototype? prototype = null;
|
||||
if (!string.IsNullOrWhiteSpace(prototypeName))
|
||||
@@ -378,9 +381,10 @@ namespace Robust.Shared.GameObjects
|
||||
prototype = PrototypeManager.Index<EntityPrototype>(prototypeName);
|
||||
}
|
||||
|
||||
var entity = AllocEntity(uid);
|
||||
var entity = AllocEntity(out metadata, uid);
|
||||
|
||||
GetComponent<MetaDataComponent>(entity).EntityPrototype = prototype;
|
||||
metadata._entityPrototype = prototype;
|
||||
Dirty(metadata);
|
||||
|
||||
return entity;
|
||||
}
|
||||
@@ -388,7 +392,7 @@ namespace Robust.Shared.GameObjects
|
||||
/// <summary>
|
||||
/// Allocates an entity and stores it but does not load components or do initialization.
|
||||
/// </summary>
|
||||
private protected EntityUid AllocEntity(EntityUid uid = default)
|
||||
private protected EntityUid AllocEntity(out MetaDataComponent metadata, EntityUid uid = default)
|
||||
{
|
||||
if (uid == default)
|
||||
{
|
||||
@@ -401,9 +405,9 @@ namespace Robust.Shared.GameObjects
|
||||
}
|
||||
|
||||
// we want this called before adding components
|
||||
EntityAdded?.Invoke(this, uid);
|
||||
EntityAdded?.Invoke(uid);
|
||||
|
||||
var metadata = new MetaDataComponent { Owner = uid };
|
||||
metadata = new MetaDataComponent { Owner = uid };
|
||||
|
||||
Entities.Add(uid);
|
||||
// add the required MetaDataComponent directly.
|
||||
@@ -421,12 +425,12 @@ namespace Robust.Shared.GameObjects
|
||||
private protected virtual EntityUid CreateEntity(string? prototypeName, EntityUid uid = default)
|
||||
{
|
||||
if (prototypeName == null)
|
||||
return AllocEntity(uid);
|
||||
return AllocEntity(out _, uid);
|
||||
|
||||
var entity = AllocEntity(prototypeName, uid);
|
||||
var entity = AllocEntity(prototypeName, out var metadata, uid);
|
||||
try
|
||||
{
|
||||
EntityPrototype.LoadEntity(GetComponent<MetaDataComponent>(entity).EntityPrototype, entity, ComponentFactory, PrototypeManager, this, _serManager, null);
|
||||
EntityPrototype.LoadEntity(metadata.EntityPrototype, entity, ComponentFactory, PrototypeManager, this, _serManager, null);
|
||||
return entity;
|
||||
}
|
||||
catch (Exception e)
|
||||
@@ -465,17 +469,17 @@ namespace Robust.Shared.GameObjects
|
||||
protected void InitializeEntity(EntityUid entity, MetaDataComponent? meta = null)
|
||||
{
|
||||
InitializeComponents(entity, meta);
|
||||
EntityInitialized?.Invoke(this, entity);
|
||||
EntityInitialized?.Invoke(entity);
|
||||
}
|
||||
|
||||
protected void StartEntity(EntityUid entity)
|
||||
{
|
||||
StartComponents(entity);
|
||||
EntityStarted?.Invoke(this, entity);
|
||||
EntityStarted?.Invoke(entity);
|
||||
}
|
||||
|
||||
public void RunMapInit(EntityUid entity, MetaDataComponent meta)
|
||||
{
|
||||
{
|
||||
if (meta.EntityLifeStage == EntityLifeStage.MapInitialized)
|
||||
return; // Already map initialized, do nothing.
|
||||
|
||||
@@ -489,7 +493,7 @@ namespace Robust.Shared.GameObjects
|
||||
public virtual EntityStringRepresentation ToPrettyString(EntityUid uid)
|
||||
{
|
||||
// We want to retrieve the MetaData component even if it is deleted.
|
||||
if (!_entTraitArray[ArrayIndexFor<MetaDataComponent>()].TryGetValue(uid, out var component))
|
||||
if (!_entTraitArray[CompIdx.ArrayIndex<MetaDataComponent>()].TryGetValue(uid, out var component))
|
||||
return new EntityStringRepresentation(uid, true);
|
||||
|
||||
var metadata = (MetaDataComponent) component;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
namespace Robust.Shared.GameObjects
|
||||
{
|
||||
public sealed class EntityInitializedMessage : EntityEventArgs
|
||||
public readonly struct EntityInitializedMessage
|
||||
{
|
||||
public EntityUid Entity { get; }
|
||||
|
||||
|
||||
public EntityInitializedMessage(EntityUid entity)
|
||||
{
|
||||
Entity = entity;
|
||||
|
||||
@@ -50,8 +50,8 @@ namespace Robust.Shared.GameObjects
|
||||
/// <seealso cref="IComponent" />
|
||||
public interface IComponentFactory
|
||||
{
|
||||
event Action<IComponentRegistration> ComponentAdded;
|
||||
event Action<(IComponentRegistration, Type)> ComponentReferenceAdded;
|
||||
event Action<ComponentRegistration> ComponentAdded;
|
||||
event Action<ComponentRegistration, CompIdx> ComponentReferenceAdded;
|
||||
event Action<string> ComponentIgnoreAdded;
|
||||
|
||||
/// <summary>
|
||||
@@ -67,7 +67,7 @@ namespace Robust.Shared.GameObjects
|
||||
/// This will be null if the network Ids have not been generated yet.
|
||||
/// </remarks>
|
||||
/// <seealso cref="GenerateNetIds"/>
|
||||
IReadOnlyList<IComponentRegistration>? NetworkedComponents { get; }
|
||||
IReadOnlyList<ComponentRegistration>? NetworkedComponents { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Get whether a component is available right now.
|
||||
@@ -105,6 +105,8 @@ namespace Robust.Shared.GameObjects
|
||||
/// </exception>
|
||||
IComponent GetComponent(Type componentType);
|
||||
|
||||
IComponent GetComponent(CompIdx componentType);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a new component instantiated of the specified type.
|
||||
/// </summary>
|
||||
@@ -154,7 +156,7 @@ namespace Robust.Shared.GameObjects
|
||||
/// <exception cref="UnknownComponentException">
|
||||
/// Thrown if no component exists with the given name <see cref="componentName"/>.
|
||||
/// </exception>
|
||||
IComponentRegistration GetRegistration(string componentName, bool ignoreCase = false);
|
||||
ComponentRegistration GetRegistration(string componentName, bool ignoreCase = false);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the registration belonging to a component, throwing an exception if it does not exist.
|
||||
@@ -163,7 +165,7 @@ namespace Robust.Shared.GameObjects
|
||||
/// <exception cref="UnknownComponentException">
|
||||
/// Thrown if no component exists of type <see cref="reference"/>.
|
||||
/// </exception>
|
||||
IComponentRegistration GetRegistration(Type reference);
|
||||
ComponentRegistration GetRegistration(Type reference);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the registration belonging to a component, throwing an exception if it does not exist.
|
||||
@@ -172,7 +174,7 @@ namespace Robust.Shared.GameObjects
|
||||
/// <exception cref="UnknownComponentException">
|
||||
/// Thrown if no component of type <see cref="T"/> exists.
|
||||
/// </exception>
|
||||
IComponentRegistration GetRegistration<T>() where T : IComponent, new();
|
||||
ComponentRegistration GetRegistration<T>() where T : IComponent, new();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the registration belonging to a component, throwing an
|
||||
@@ -183,7 +185,7 @@ namespace Robust.Shared.GameObjects
|
||||
/// <exception cref="UnknownComponentException">
|
||||
/// Thrown if no component with id <see cref="netID"/> exists.
|
||||
/// </exception>
|
||||
IComponentRegistration GetRegistration(ushort netID);
|
||||
ComponentRegistration GetRegistration(ushort netID);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the registration of a component, throwing an exception if
|
||||
@@ -194,7 +196,9 @@ namespace Robust.Shared.GameObjects
|
||||
/// <exception cref="UnknownComponentException">
|
||||
/// Thrown if no registration exists for component <see cref="component"/>.
|
||||
/// </exception>
|
||||
IComponentRegistration GetRegistration(IComponent component);
|
||||
ComponentRegistration GetRegistration(IComponent component);
|
||||
|
||||
ComponentRegistration GetRegistration(CompIdx idx);
|
||||
|
||||
/// <summary>
|
||||
/// Tries to get the registration belonging to a component.
|
||||
@@ -203,7 +207,7 @@ namespace Robust.Shared.GameObjects
|
||||
/// <param name="registration">The registration if found, null otherwise.</param>
|
||||
/// <param name="ignoreCase">Whether or not to ignore casing on <see cref="componentName"/></param>
|
||||
/// <returns>true it found, false otherwise.</returns>
|
||||
bool TryGetRegistration(string componentName, [NotNullWhen(true)] out IComponentRegistration? registration, bool ignoreCase = false);
|
||||
bool TryGetRegistration(string componentName, [NotNullWhen(true)] out ComponentRegistration? registration, bool ignoreCase = false);
|
||||
|
||||
/// <summary>
|
||||
/// Tries to get the registration belonging to a component.
|
||||
@@ -211,7 +215,7 @@ namespace Robust.Shared.GameObjects
|
||||
/// <param name="reference">A reference corresponding to the component to look up.</param>
|
||||
/// <param name="registration">The registration if found, null otherwise.</param>
|
||||
/// <returns>true it found, false otherwise.</returns>
|
||||
bool TryGetRegistration(Type reference, [NotNullWhen(true)] out IComponentRegistration? registration);
|
||||
bool TryGetRegistration(Type reference, [NotNullWhen(true)] out ComponentRegistration? registration);
|
||||
|
||||
/// <summary>
|
||||
/// Tries to get the registration belonging to a component.
|
||||
@@ -219,7 +223,7 @@ namespace Robust.Shared.GameObjects
|
||||
/// <typeparam name="T">A type referencing the component.</typeparam>
|
||||
/// <param name="registration">The registration if found, null otherwise.</param>
|
||||
/// <returns>true it found, false otherwise.</returns>
|
||||
bool TryGetRegistration<T>([NotNullWhen(true)] out IComponentRegistration? registration) where T : IComponent, new();
|
||||
bool TryGetRegistration<T>([NotNullWhen(true)] out ComponentRegistration? registration) where T : IComponent, new();
|
||||
|
||||
/// <summary>
|
||||
/// Tries to get the registration belonging to a component.
|
||||
@@ -227,7 +231,7 @@ namespace Robust.Shared.GameObjects
|
||||
/// <param name="netID">The network ID corresponding to the component.</param>
|
||||
/// <param name="registration">The registration if found, null otherwise.</param>
|
||||
/// <returns>true it found, false otherwise.</returns>
|
||||
bool TryGetRegistration(ushort netID, [NotNullWhen(true)] out IComponentRegistration? registration);
|
||||
bool TryGetRegistration(ushort netID, [NotNullWhen(true)] out ComponentRegistration? registration);
|
||||
|
||||
/// <summary>
|
||||
/// Tries to get the registration of a component.
|
||||
@@ -235,48 +239,16 @@ namespace Robust.Shared.GameObjects
|
||||
/// <param name="component">An instance of the component.</param>
|
||||
/// <param name="registration">The registration if found, null otherwise.</param>
|
||||
/// <returns>true it found, false otherwise.</returns>
|
||||
bool TryGetRegistration(IComponent component, [NotNullWhen(true)] out IComponentRegistration? registration);
|
||||
bool TryGetRegistration(IComponent component, [NotNullWhen(true)] out ComponentRegistration? registration);
|
||||
|
||||
/// <summary>
|
||||
/// Automatically create registrations for all components with a <see cref="RegisterComponentAttribute" />
|
||||
/// </summary>
|
||||
void DoAutoRegistrations();
|
||||
|
||||
IEnumerable<Type> GetAllRefTypes();
|
||||
IEnumerable<CompIdx> GetAllRefTypes();
|
||||
void GenerateNetIds();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents a component registered into a <see cref="IComponentFactory" />.
|
||||
/// </summary>
|
||||
/// <seealso cref="IComponentFactory" />
|
||||
/// <seealso cref="IComponent" />
|
||||
public interface IComponentRegistration
|
||||
{
|
||||
/// <summary>
|
||||
/// The name of the component.
|
||||
/// This is used as the <c>type</c> field in the component declarations if entity prototypes.
|
||||
/// </summary>
|
||||
/// <seealso cref="IComponent.Name" />
|
||||
string Name { get; }
|
||||
|
||||
/// <summary>
|
||||
/// ID used to reference the component type across the network.
|
||||
/// If null, no network synchronization will be available for this component.
|
||||
/// </summary>
|
||||
/// <seealso cref="NetworkedComponentAttribute" />
|
||||
ushort? NetID { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The type that will be instantiated if this component is created.
|
||||
/// </summary>
|
||||
Type Type { get; }
|
||||
|
||||
/// <summary>
|
||||
/// A list of type references that can be used to get a reference to an instance of this component,
|
||||
/// for methods like GetComponent.
|
||||
/// These are not unique and can overlap with other components.
|
||||
/// </summary>
|
||||
IReadOnlyList<Type> References { get; }
|
||||
Type IdxToType(CompIdx idx);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,18 +10,18 @@ namespace Robust.Shared.GameObjects
|
||||
/// <summary>
|
||||
/// A component was added to the manager.
|
||||
/// </summary>
|
||||
event EventHandler<ComponentEventArgs>? ComponentAdded;
|
||||
event Action<AddedComponentEventArgs>? ComponentAdded;
|
||||
|
||||
/// <summary>
|
||||
/// A component was removed from the manager.
|
||||
/// </summary>
|
||||
event EventHandler<ComponentEventArgs>? ComponentRemoved;
|
||||
event Action<RemovedComponentEventArgs>? ComponentRemoved;
|
||||
|
||||
/// <summary>
|
||||
/// A component was deleted. This is usually deferred until some time after it was removed.
|
||||
/// Usually you will want to subscribe to <see cref="ComponentRemoved"/>.
|
||||
/// </summary>
|
||||
event EventHandler<ComponentEventArgs>? ComponentDeleted;
|
||||
event Action<DeletedComponentEventArgs>? ComponentDeleted;
|
||||
|
||||
/// <summary>
|
||||
/// Calls Initialize() on all registered components of the entity.
|
||||
@@ -46,7 +46,7 @@ namespace Robust.Shared.GameObjects
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This function returns a disposable initialize handle that you can use in a <see langword="using" /> statement, to set up a component
|
||||
/// before initialization is ran on it.
|
||||
/// before initialization is ran on it.
|
||||
/// </remarks>
|
||||
/// <typeparam name="T">Concrete component type to add.</typeparam>
|
||||
/// <param name="uid">Entity being modified.</param>
|
||||
@@ -189,6 +189,14 @@ namespace Robust.Shared.GameObjects
|
||||
/// <returns>The component of Type from the Entity.</returns>
|
||||
T GetComponent<T>(EntityUid uid);
|
||||
|
||||
/// <summary>
|
||||
/// Returns the component of a specific type.
|
||||
/// </summary>
|
||||
/// <param name="uid">Entity UID to look on.</param>
|
||||
/// <param name="type">A trait or component type to check for.</param>
|
||||
/// <returns>The component of Type from the Entity.</returns>
|
||||
IComponent GetComponent(EntityUid uid, CompIdx type);
|
||||
|
||||
/// <summary>
|
||||
/// Returns the component of a specific type.
|
||||
/// </summary>
|
||||
|
||||
@@ -45,11 +45,11 @@ namespace Robust.Shared.GameObjects
|
||||
|
||||
#region Entity Management
|
||||
|
||||
event EventHandler<EntityUid>? EntityAdded;
|
||||
event EventHandler<EntityUid>? EntityInitialized;
|
||||
event EventHandler<EntityUid>? EntityStarted;
|
||||
event EventHandler<EntityUid>? EntityDeleted;
|
||||
event EventHandler<EntityUid>? EntityDirtied; // only raised after initialization
|
||||
event Action<EntityUid>? EntityAdded;
|
||||
event Action<EntityUid>? EntityInitialized;
|
||||
event Action<EntityUid>? EntityStarted;
|
||||
event Action<EntityUid>? EntityDeleted;
|
||||
event Action<EntityUid>? EntityDirtied; // only raised after initialization
|
||||
|
||||
EntityUid CreateEntityUninitialized(string? prototypeName, EntityUid euid);
|
||||
|
||||
|
||||
@@ -204,7 +204,7 @@ namespace Robust.Shared.GameObjects
|
||||
RemoveFromEntityTree(args.Owner, false);
|
||||
}
|
||||
|
||||
private void OnEntityInit(object? sender, EntityUid uid)
|
||||
private void OnEntityInit(EntityUid uid)
|
||||
{
|
||||
if (_container.IsEntityInContainer(uid)) return;
|
||||
|
||||
|
||||
+4
-4
@@ -63,7 +63,7 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations
|
||||
components[compType] = read;
|
||||
}
|
||||
|
||||
var referenceTypes = new List<Type>();
|
||||
var referenceTypes = new List<CompIdx>();
|
||||
// Assert that there are no conflicting component references.
|
||||
foreach (var componentName in components.Keys)
|
||||
{
|
||||
@@ -125,7 +125,7 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations
|
||||
list.Add(serializationManager.ValidateNode(type, copy, context));
|
||||
}
|
||||
|
||||
var referenceTypes = new List<Type>();
|
||||
var referenceTypes = new List<CompIdx>();
|
||||
|
||||
// Assert that there are no conflicting component references.
|
||||
foreach (var componentName in components.Keys)
|
||||
@@ -204,9 +204,9 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations
|
||||
return newCompReg;
|
||||
}
|
||||
|
||||
private Dictionary<IComponentRegistration, int> ToTypeIndexedDictionary(SequenceDataNode node, IComponentFactory componentFactory)
|
||||
private Dictionary<ComponentRegistration, int> ToTypeIndexedDictionary(SequenceDataNode node, IComponentFactory componentFactory)
|
||||
{
|
||||
var dict = new Dictionary<IComponentRegistration, int>();
|
||||
var dict = new Dictionary<ComponentRegistration, int>();
|
||||
for (var i = 0; i < node.Count; i++)
|
||||
{
|
||||
var mapping = (MappingDataNode)node[i];
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#nullable enable
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
@@ -18,7 +17,7 @@ namespace Robust.Shared.Utility
|
||||
/// <typeparam name="TKey">The type of key.</typeparam>
|
||||
/// <typeparam name="TValue">The type of value.</typeparam>
|
||||
/// <seealso cref="UniqueIndexExtensions"/>
|
||||
internal interface IUniqueIndex<TKey, TValue> : IEnumerable<KeyValuePair<TKey, ISet<TValue>>> where TKey : notnull
|
||||
internal interface IUniqueIndex<TKey, TValue> : IEnumerable<KeyValuePair<TKey, HashSet<TValue>>> where TKey : notnull
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
@@ -88,13 +87,6 @@ namespace Robust.Shared.Utility
|
||||
[CollectionAccess(CollectionAccessType.UpdatedContent)]
|
||||
void Touch(TKey key);
|
||||
|
||||
/// <summary>
|
||||
/// Makes a given key's set immutable.
|
||||
/// </summary>
|
||||
/// <param name="key">A given key.</param>
|
||||
[CollectionAccess(CollectionAccessType.UpdatedContent)]
|
||||
bool Freeze(TKey key);
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the index from a collection of keys.
|
||||
/// </summary>
|
||||
@@ -109,7 +101,7 @@ namespace Robust.Shared.Utility
|
||||
/// <param name="index">An equivalent collection.</param>
|
||||
/// <exception cref="InvalidOperationException">Already initialized.</exception>
|
||||
[CollectionAccess(CollectionAccessType.UpdatedContent)]
|
||||
void Initialize(IEnumerable<KeyValuePair<TKey, ISet<TValue>>> index);
|
||||
void Initialize(IEnumerable<KeyValuePair<TKey, HashSet<TValue>>> index);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#nullable enable
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
@@ -28,7 +27,7 @@ namespace Robust.Shared.Utility
|
||||
public struct UniqueIndex<TKey, TValue> : IUniqueIndex<TKey, TValue> where TKey : notnull
|
||||
{
|
||||
|
||||
private ImmutableDictionary<TKey, ISet<TValue>>? _index;
|
||||
private ImmutableDictionary<TKey, HashSet<TValue>>? _index;
|
||||
|
||||
/// <inheritdoc />
|
||||
public int KeyCount => _index?.Count ?? 0;
|
||||
@@ -36,12 +35,12 @@ namespace Robust.Shared.Utility
|
||||
/// <inheritdoc />
|
||||
public bool Add(TKey key, TValue value)
|
||||
{
|
||||
ISet<TValue>? set;
|
||||
HashSet<TValue>? set;
|
||||
|
||||
if (_index is null)
|
||||
{
|
||||
set = new HashSet<TValue> {value};
|
||||
_index = ImmutableDictionary.CreateRange(new[] {new KeyValuePair<TKey, ISet<TValue>>(key, set)});
|
||||
_index = ImmutableDictionary.CreateRange(new[] {new KeyValuePair<TKey, HashSet<TValue>>(key, set)});
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -57,12 +56,12 @@ namespace Robust.Shared.Utility
|
||||
/// <inheritdoc />
|
||||
public int AddRange(TKey key, IEnumerable<TValue> values)
|
||||
{
|
||||
ISet<TValue>? set;
|
||||
HashSet<TValue>? set;
|
||||
|
||||
if (_index is null)
|
||||
{
|
||||
set = new HashSet<TValue>(values);
|
||||
_index = ImmutableDictionary.CreateRange(new[] {new KeyValuePair<TKey, ISet<TValue>>(key, set)});
|
||||
_index = ImmutableDictionary.CreateRange(new[] {new KeyValuePair<TKey, HashSet<TValue>>(key, set)});
|
||||
return set.Count;
|
||||
}
|
||||
|
||||
@@ -152,37 +151,19 @@ namespace Robust.Shared.Utility
|
||||
/// <inheritdoc />
|
||||
public void Touch(TKey key)
|
||||
{
|
||||
_index ??= ImmutableDictionary<TKey, ISet<TValue>>.Empty;
|
||||
_index ??= ImmutableDictionary<TKey, HashSet<TValue>>.Empty;
|
||||
|
||||
if (_index.ContainsKey(key)) return;
|
||||
|
||||
_index = _index.Add(key, new HashSet<TValue>());
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Freeze(TKey key)
|
||||
{
|
||||
if (_index is null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!_index.TryGetValue(key, out var set)
|
||||
|| set is ImmutableHashSet<TValue>)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
_index = _index.SetItem(key, ImmutableHashSet.CreateRange(set));
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Initialize(IEnumerable<TKey> keys)
|
||||
=> Initialize(keys.Select(k => new KeyValuePair<TKey, ISet<TValue>>(k, new HashSet<TValue>())));
|
||||
=> Initialize(keys.Select(k => new KeyValuePair<TKey, HashSet<TValue>>(k, new HashSet<TValue>())));
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Initialize(IEnumerable<KeyValuePair<TKey, ISet<TValue>>> index)
|
||||
public void Initialize(IEnumerable<KeyValuePair<TKey, HashSet<TValue>>> index)
|
||||
{
|
||||
if (_index != null) throw new InvalidOperationException("Already initialized.");
|
||||
|
||||
@@ -193,11 +174,11 @@ namespace Robust.Shared.Utility
|
||||
{
|
||||
get
|
||||
{
|
||||
ISet<TValue>? set;
|
||||
HashSet<TValue>? set;
|
||||
|
||||
if (_index is null)
|
||||
{
|
||||
_index = ImmutableDictionary<TKey, ISet<TValue>>.Empty;
|
||||
_index = ImmutableDictionary<TKey, HashSet<TValue>>.Empty;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -215,14 +196,14 @@ namespace Robust.Shared.Utility
|
||||
|
||||
/// <inheritdoc cref="IEnumerable{T}"/>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public IEnumerator<KeyValuePair<TKey, ISet<TValue>>> GetEnumerator()
|
||||
public IEnumerator<KeyValuePair<TKey, HashSet<TValue>>> GetEnumerator()
|
||||
{
|
||||
if (_index != null)
|
||||
{
|
||||
return _index.GetEnumerator();
|
||||
}
|
||||
|
||||
return Enumerable.Empty<KeyValuePair<TKey, ISet<TValue>>>().GetEnumerator();
|
||||
return Enumerable.Empty<KeyValuePair<TKey, HashSet<TValue>>>().GetEnumerator();
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
#nullable enable
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using JetBrains.Annotations;
|
||||
@@ -29,10 +27,10 @@ namespace Robust.Shared.Utility
|
||||
{
|
||||
|
||||
[NotNull]
|
||||
private readonly Dictionary<TKey, ISet<TValue>> _index;
|
||||
private readonly Dictionary<TKey, HashSet<TValue>> _index;
|
||||
|
||||
public UniqueIndexHkm(int capacity)
|
||||
=> _index = new Dictionary<TKey, ISet<TValue>>(capacity);
|
||||
=> _index = new Dictionary<TKey, HashSet<TValue>>(capacity);
|
||||
|
||||
/// <inheritdoc />
|
||||
public int KeyCount => _index.Count;
|
||||
@@ -142,27 +140,12 @@ namespace Robust.Shared.Utility
|
||||
_index.Add(key, new HashSet<TValue>());
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Freeze(TKey key)
|
||||
{
|
||||
InitializedCheck();
|
||||
|
||||
if (!_index.TryGetValue(key, out var set)
|
||||
|| set is ImmutableHashSet<TValue>)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
_index[key] = ImmutableHashSet.CreateRange(set);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Initialize(IEnumerable<TKey> keys)
|
||||
=> Initialize(keys.Select(k => new KeyValuePair<TKey, ISet<TValue>>(k, new HashSet<TValue>())));
|
||||
=> Initialize(keys.Select(k => new KeyValuePair<TKey, HashSet<TValue>>(k, new HashSet<TValue>())));
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Initialize(IEnumerable<KeyValuePair<TKey, ISet<TValue>>> index)
|
||||
public void Initialize(IEnumerable<KeyValuePair<TKey, HashSet<TValue>>> index)
|
||||
{
|
||||
InitializedCheck();
|
||||
|
||||
@@ -175,7 +158,7 @@ namespace Robust.Shared.Utility
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ISet<TValue> this[TKey key]
|
||||
public HashSet<TValue> this[TKey key]
|
||||
{
|
||||
get
|
||||
{
|
||||
@@ -191,7 +174,7 @@ namespace Robust.Shared.Utility
|
||||
|
||||
/// <inheritdoc cref="IEnumerable{T}"/>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public IEnumerator<KeyValuePair<TKey, ISet<TValue>>> GetEnumerator()
|
||||
public IEnumerator<KeyValuePair<TKey, HashSet<TValue>>> GetEnumerator()
|
||||
{
|
||||
InitializedCheck();
|
||||
|
||||
|
||||
@@ -84,18 +84,6 @@ namespace Robust.UnitTesting
|
||||
var entMan = IoCManager.Resolve<IEntityManager>();
|
||||
var mapMan = IoCManager.Resolve<IMapManager>();
|
||||
|
||||
// So by default EntityManager does its own EntitySystemManager initialize during Startup.
|
||||
// We want to bypass this and load our own systems hence we will manually initialize it here.
|
||||
entMan.Initialize();
|
||||
mapMan.Initialize();
|
||||
systems.Initialize();
|
||||
|
||||
IoCManager.Resolve<IReflectionManager>().LoadAssemblies(assemblies);
|
||||
|
||||
var modLoader = IoCManager.Resolve<TestingModLoader>();
|
||||
modLoader.Assemblies = contentAssemblies;
|
||||
modLoader.TryLoadModulesFrom(ResourcePath.Root, "");
|
||||
|
||||
// Required components for the engine to work
|
||||
var compFactory = IoCManager.Resolve<IComponentFactory>();
|
||||
|
||||
@@ -124,6 +112,26 @@ namespace Robust.UnitTesting
|
||||
compFactory.RegisterClass<FixturesComponent>();
|
||||
}
|
||||
|
||||
if (!compFactory.AllRegisteredTypes.Contains(typeof(EntityLookupComponent)))
|
||||
{
|
||||
compFactory.RegisterClass<EntityLookupComponent>();
|
||||
}
|
||||
|
||||
// So by default EntityManager does its own EntitySystemManager initialize during Startup.
|
||||
// We want to bypass this and load our own systems hence we will manually initialize it here.
|
||||
entMan.Initialize();
|
||||
// RobustUnitTest is complete hot garbage.
|
||||
// This makes EventTables ignore *all* the screwed up component abuse it causes.
|
||||
entMan.EventBus.OnlyCallOnRobustUnitTestISwearToGodPleaseSomebodyKillThisNightmare();
|
||||
mapMan.Initialize();
|
||||
systems.Initialize();
|
||||
|
||||
IoCManager.Resolve<IReflectionManager>().LoadAssemblies(assemblies);
|
||||
|
||||
var modLoader = IoCManager.Resolve<TestingModLoader>();
|
||||
modLoader.Assemblies = contentAssemblies;
|
||||
modLoader.TryLoadModulesFrom(ResourcePath.Root, "");
|
||||
|
||||
entMan.Startup();
|
||||
mapMan.Startup();
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Robust.Shared.GameObjects;
|
||||
@@ -19,14 +20,17 @@ namespace Robust.UnitTesting.Shared.GameObjects
|
||||
var entUid = new EntityUid(7);
|
||||
var compInstance = new MetaDataComponent();
|
||||
|
||||
var compRegistration = new Mock<IComponentRegistration>();
|
||||
var compRegistration = new ComponentRegistration(
|
||||
"MetaData",
|
||||
typeof(MetaDataComponent),
|
||||
CompIdx.Index<MetaDataComponent>());
|
||||
|
||||
var entManMock = new Mock<IEntityManager>();
|
||||
|
||||
var compFacMock = new Mock<IComponentFactory>();
|
||||
|
||||
compRegistration.Setup(m => m.References).Returns(new List<Type> {typeof(MetaDataComponent)});
|
||||
compFacMock.Setup(m => m.GetRegistration(typeof(MetaDataComponent))).Returns(compRegistration.Object);
|
||||
compFacMock.Setup(m => m.GetRegistration(CompIdx.Index<MetaDataComponent>())).Returns(compRegistration);
|
||||
compFacMock.Setup(m => m.GetAllRefTypes()).Returns(new[] { CompIdx.Index<MetaDataComponent>() });
|
||||
entManMock.Setup(m => m.ComponentFactory).Returns(compFacMock.Object);
|
||||
|
||||
IComponent? outIComponent = compInstance;
|
||||
@@ -36,15 +40,19 @@ namespace Robust.UnitTesting.Shared.GameObjects
|
||||
entManMock.Setup(m => m.GetComponent(entUid, typeof(MetaDataComponent)))
|
||||
.Returns(compInstance);
|
||||
|
||||
entManMock.Setup(m => m.GetComponent(entUid, CompIdx.Index<MetaDataComponent>()))
|
||||
.Returns(compInstance);
|
||||
|
||||
var bus = new EntityEventBus(entManMock.Object);
|
||||
bus.OnlyCallOnRobustUnitTestISwearToGodPleaseSomebodyKillThisNightmare();
|
||||
|
||||
// Subscribe
|
||||
int calledCount = 0;
|
||||
bus.SubscribeLocalEvent<MetaDataComponent, TestEvent>(HandleTestEvent);
|
||||
|
||||
// add a component to the system
|
||||
entManMock.Raise(m=>m.EntityAdded += null, entManMock.Object, entUid);
|
||||
entManMock.Raise(m => m.ComponentAdded += null, new AddedComponentEventArgs(compInstance, entUid));
|
||||
entManMock.Raise(m => m.EntityAdded += null, entUid);
|
||||
entManMock.Raise(m => m.ComponentAdded += null, new AddedComponentEventArgs(new ComponentEventArgs(compInstance, entUid)));
|
||||
|
||||
// Raise
|
||||
var evntArgs = new TestEvent(5);
|
||||
@@ -71,12 +79,15 @@ namespace Robust.UnitTesting.Shared.GameObjects
|
||||
|
||||
var entManMock = new Mock<IEntityManager>();
|
||||
|
||||
var compRegistration = new Mock<IComponentRegistration>();
|
||||
var compRegistration = new ComponentRegistration(
|
||||
"MetaData",
|
||||
typeof(MetaDataComponent),
|
||||
CompIdx.Index<MetaDataComponent>());
|
||||
|
||||
var compFacMock = new Mock<IComponentFactory>();
|
||||
|
||||
compRegistration.Setup(m => m.References).Returns(new List<Type> {typeof(MetaDataComponent)});
|
||||
compFacMock.Setup(m => m.GetRegistration(typeof(MetaDataComponent))).Returns(compRegistration.Object);
|
||||
compFacMock.Setup(m => m.GetRegistration(CompIdx.Index<MetaDataComponent>())).Returns(compRegistration);
|
||||
compFacMock.Setup(m => m.GetAllRefTypes()).Returns(new[] { CompIdx.Index<MetaDataComponent>() });
|
||||
entManMock.Setup(m => m.ComponentFactory).Returns(compFacMock.Object);
|
||||
|
||||
IComponent? outIComponent = compInstance;
|
||||
@@ -87,6 +98,7 @@ namespace Robust.UnitTesting.Shared.GameObjects
|
||||
.Returns(compInstance);
|
||||
|
||||
var bus = new EntityEventBus(entManMock.Object);
|
||||
bus.OnlyCallOnRobustUnitTestISwearToGodPleaseSomebodyKillThisNightmare();
|
||||
|
||||
// Subscribe
|
||||
int calledCount = 0;
|
||||
@@ -94,8 +106,8 @@ namespace Robust.UnitTesting.Shared.GameObjects
|
||||
bus.UnsubscribeLocalEvent<MetaDataComponent, TestEvent>();
|
||||
|
||||
// add a component to the system
|
||||
entManMock.Raise(m => m.EntityAdded += null, entManMock.Object, entUid);
|
||||
entManMock.Raise(m => m.ComponentAdded += null, new AddedComponentEventArgs(compInstance, entUid));
|
||||
entManMock.Raise(m => m.EntityAdded += null, entUid);
|
||||
entManMock.Raise(m => m.ComponentAdded += null, new AddedComponentEventArgs(new ComponentEventArgs(compInstance, entUid)));
|
||||
|
||||
// Raise
|
||||
var evntArgs = new TestEvent(5);
|
||||
@@ -121,12 +133,15 @@ namespace Robust.UnitTesting.Shared.GameObjects
|
||||
|
||||
compInstance.Owner = entUid;
|
||||
|
||||
var compRegistration = new Mock<IComponentRegistration>();
|
||||
var compRegistration = new ComponentRegistration(
|
||||
"MetaData",
|
||||
typeof(MetaDataComponent),
|
||||
CompIdx.Index<MetaDataComponent>());
|
||||
|
||||
var compFacMock = new Mock<IComponentFactory>();
|
||||
|
||||
compRegistration.Setup(m => m.References).Returns(new List<Type> {typeof(MetaDataComponent)});
|
||||
compFacMock.Setup(m => m.GetRegistration(typeof(MetaDataComponent))).Returns(compRegistration.Object);
|
||||
compFacMock.Setup(m => m.GetRegistration(CompIdx.Index<MetaDataComponent>())).Returns(compRegistration);
|
||||
compFacMock.Setup(m => m.GetAllRefTypes()).Returns(new[] { CompIdx.Index<MetaDataComponent>() });
|
||||
entManMock.Setup(m => m.ComponentFactory).Returns(compFacMock.Object);
|
||||
|
||||
IComponent? outIComponent = compInstance;
|
||||
@@ -137,14 +152,15 @@ namespace Robust.UnitTesting.Shared.GameObjects
|
||||
.Returns(compInstance);
|
||||
|
||||
var bus = new EntityEventBus(entManMock.Object);
|
||||
bus.OnlyCallOnRobustUnitTestISwearToGodPleaseSomebodyKillThisNightmare();
|
||||
|
||||
// Subscribe
|
||||
int calledCount = 0;
|
||||
bus.SubscribeLocalEvent<MetaDataComponent, ComponentInit>(HandleTestEvent);
|
||||
|
||||
// add a component to the system
|
||||
entManMock.Raise(m=>m.EntityAdded += null, entManMock.Object, entUid);
|
||||
entManMock.Raise(m => m.ComponentAdded += null, new AddedComponentEventArgs(compInstance, entUid));
|
||||
entManMock.Raise(m => m.EntityAdded += null, entUid);
|
||||
entManMock.Raise(m => m.ComponentAdded += null, new AddedComponentEventArgs(new ComponentEventArgs(compInstance, entUid)));
|
||||
|
||||
// Raise
|
||||
((IEventBus)bus).RaiseComponentEvent(compInstance, new ComponentInit());
|
||||
@@ -168,23 +184,30 @@ namespace Robust.UnitTesting.Shared.GameObjects
|
||||
var entManMock = new Mock<IEntityManager>();
|
||||
var compFacMock = new Mock<IComponentFactory>();
|
||||
|
||||
List<CompIdx> allRefTypes = new();
|
||||
void Setup<T>(out T instance) where T : IComponent, new()
|
||||
{
|
||||
IComponent? inst = instance = new T();
|
||||
var reg = new Mock<IComponentRegistration>();
|
||||
reg.Setup(m => m.References).Returns(new Type[] {typeof(T)});
|
||||
var reg = new ComponentRegistration(
|
||||
typeof(T).Name,
|
||||
typeof(T),
|
||||
CompIdx.Index<T>());
|
||||
|
||||
compFacMock.Setup(m => m.GetRegistration(typeof(T))).Returns(reg.Object);
|
||||
compFacMock.Setup(m => m.GetRegistration(CompIdx.Index<T>())).Returns(reg);
|
||||
entManMock.Setup(m => m.TryGetComponent(entUid, typeof(T), out inst)).Returns(true);
|
||||
entManMock.Setup(m => m.GetComponent(entUid, typeof(T))).Returns(inst);
|
||||
allRefTypes.Add(CompIdx.Index<T>());
|
||||
}
|
||||
|
||||
Setup<OrderAComponent>(out var instA);
|
||||
Setup<OrderBComponent>(out var instB);
|
||||
Setup<OrderCComponent>(out var instC);
|
||||
|
||||
compFacMock.Setup(m => m.GetAllRefTypes()).Returns(allRefTypes.ToArray());
|
||||
|
||||
entManMock.Setup(m => m.ComponentFactory).Returns(compFacMock.Object);
|
||||
var bus = new EntityEventBus(entManMock.Object);
|
||||
bus.OnlyCallOnRobustUnitTestISwearToGodPleaseSomebodyKillThisNightmare();
|
||||
|
||||
// Subscribe
|
||||
var a = false;
|
||||
@@ -212,10 +235,10 @@ namespace Robust.UnitTesting.Shared.GameObjects
|
||||
bus.SubscribeLocalEvent<OrderCComponent, TestEvent>(HandlerC, typeof(OrderCComponent));
|
||||
|
||||
// add a component to the system
|
||||
entManMock.Raise(m=>m.EntityAdded += null, entManMock.Object, entUid);
|
||||
entManMock.Raise(m => m.ComponentAdded += null, new AddedComponentEventArgs(instA, entUid));
|
||||
entManMock.Raise(m => m.ComponentAdded += null, new AddedComponentEventArgs(instB, entUid));
|
||||
entManMock.Raise(m => m.ComponentAdded += null, new AddedComponentEventArgs(instC, entUid));
|
||||
entManMock.Raise(m => m.EntityAdded += null, entUid);
|
||||
entManMock.Raise(m => m.ComponentAdded += null, new AddedComponentEventArgs(new ComponentEventArgs(instA, entUid)));
|
||||
entManMock.Raise(m => m.ComponentAdded += null, new AddedComponentEventArgs(new ComponentEventArgs(instB, entUid)));
|
||||
entManMock.Raise(m => m.ComponentAdded += null, new AddedComponentEventArgs(new ComponentEventArgs(instC, entUid)));
|
||||
|
||||
// Raise
|
||||
var evntArgs = new TestEvent(5);
|
||||
|
||||
@@ -11,7 +11,9 @@ namespace Robust.UnitTesting.Shared.GameObjects
|
||||
{
|
||||
private static EntityEventBus BusFactory()
|
||||
{
|
||||
var compFacMock = new Mock<IComponentFactory>();
|
||||
var entManMock = new Mock<IEntityManager>();
|
||||
entManMock.SetupGet(e => e.ComponentFactory).Returns(compFacMock.Object);
|
||||
var bus = new EntityEventBus(entManMock.Object);
|
||||
return bus;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user