mirror of
https://github.com/space-wizards/RobustToolbox.git
synced 2026-02-14 19:29:36 +01:00
* oops
* fixes serialization il
* copytest
* typo & misc fixes
* 139 moment
* boxing
* mesa dum
* stuff
* goodbye bad friend
* last commit before the big (4) rewrite
* adds datanodes
* kills yamlobjserializer in favor of the new system
* adds more serializers, actually implements them & removes most of the last of the old system
* changed yamlfieldattribute namespace
* adds back iselfserialize
* refactors consts&flags
* renames everything to data(field/definition)
* adds afterserialization
* help
* dataclassgen
* fuggen help me mannen
* Fix most errors on content
* Fix engine errors except map loader
* maploader & misc fix
* misc fixes
* thing
* help
* refactors datanodes
* help me mannen
* Separate ITypeSerializer into reader and writer
* Convert all type serializers
* priority
* adds alot
* il fixes
* adds robustgen
* argh
* adds array & enum serialization
* fixes dataclasses
* adds vec2i / misc fixes
* fixes inheritance
* a very notcursed todo
* fixes some custom dataclasses
* push dis
* Remove data classes
* boutta box
* yes
* Add angle and regex serializer tests
* Make TypeSerializerTest abstract
* sets up ioc etc
* remove pushinheritance
* fixes
* Merge fixes, fix yaml hot reloading
* General fixes2
* Make enum serialization ignore case
* Fix the tag not being copied in data nodes
* Fix not properly serializing flag enums
* Fix component serialization on startup
* Implement ValueDataNode ToString
* Serialization IL fixes, fix return and string equality
* Remove async from prototype manager
* Make serializing unsupported node as enum exception more descriptive
* Fix serv3 tryread casting to serializer instead of reader
* Add constructor for invalid node type exception
* Temporary fix for SERV3: Turn populate delegate into regular code
* Fix not copying the data of non primitive types
* Fix not using the data definition found in copying
* Make ISerializationHooks require explicit implementations
* Add test for serialization inheritance
* Improve IsOverridenIn method
* Fix error message when a data definition is null
* Add method to cast a read value in Serv3Manager
* Rename IServ3Manager to ISerializationManager
* Rename usages of serv3manager, add generic copy method
* Fix IL copy method lookup
* Rename old usages of serv3manager
* Add ITypeCopier
* resistance is futile
* we will conquer this codebase
* Add copy method to all serializers
* Make primitive mismatch error message more descriptive
* bing bong im going to freacking heck
* oopsie moment
* hello are you interested in my wares
* does generic serializers under new architecture
* Convert every non generic serializer to the new format, general fixes
* Update usgaes of generic serializers, cleanup
* does some pushinheritance logic
* finishes pushinheritance FRAMEWORK
* shed
* Add box2, color and component registry serializer tests
* Create more deserialized types and store prototypes with their deserialized results
* Fixes and serializer updates
* Add serialization manager extensions
* adds pushinheritance
* Update all prototypes to have a parent and have consistent id/parent properties
* Fix grammar component serialization
* Add generic serializer tests
* thonk
* Add array serializer test
* Replace logger warning calls with exceptions
* fixes
* Move redundant methods to serialization manager extensions, cleanup
* Add array serialization
* fixes context
* more fixes
* argh
* inheritance
* this should do it
* fixes
* adds copiers & fixes some stuff
* copiers use context v1
* finishing copy context
* more context fixes
* Test fixes
* funky maps
* Fix server user interface component serialization
* Fix value tuple serialization
* Add copying for value types and arrays. Fix copy internal for primitives, enums and strings
* fixes
* fixes more stuff
* yes
* Make abstract/interface skips debugs instead of warnings
* Fix typo
* Make some dictionaries readonly
* Add checks for the serialization manager initializing and already being initialized
* Add base type required and usage for MeansDataDefinition and ImplicitDataDefinitionForInheritorsAttribute
* copy by ref
* Fix exception wording
* Update data field required summary with the new forbidden docs
* Use extension in map loader
* wanna erp
* Change serializing to not use il temporarily
* Make writing work with nullable types
* pushing
* check
* cuddling slaps HARD
* Add serialization priority test
* important fix
* a serialization thing
* serializer moment
* Add validation for some type serializers
* adds context
* moar context
* fixes
* Do the thing for appearance
* yoo lmao
* push haha pp
* Temporarily make copy delegate regular c# code
* Create deserialized component registry to handle not inheriting conflicting references
* YAML LINTER BABY
* ayes
* Fix sprite component norot not being default true like in latest master
* Remove redundant todos
* Add summary doc to every ISerializationManager method
* icon fixes
* Add skip hook argument to readers and copiers
* Merge fixes
* Fix ordering of arguments in read and copy reflection call
* Fix user interface components deserialization
* pew pew
* i am going to HECK
* Add MustUseReturnValue to copy-over methods
* Make serialization log calls use the same sawmill
* gamin
* Fix doc errors in ISerializationManager.cs
* goodbye brave soldier
* fixes
* WIP merge fixes and entity serialization
* aaaaaaaaaaaaaaa
* aaaaaaaaaaaaaaa
* adds inheritancebehaviour
* test/datafield fixes
* forgot that one
* adds more verbose validation
* This fixes the YAML hot reloading
* Replace yield break with Enumerable.Empty
* adds copiers
* aaaaaaaaaaaaa
* array fix
priority fix
misc fixes
* fix(?)
* fix.
* funny map serialization (wip)
* funny map serialization (wip)
* Add TODO
* adds proper info the validation
* Make yaml linter 5 times faster (~80% less execution time)
* Improves the error message for missing fields in the linter
* Include component name in unknown component type error node
* adds alwaysrelevant usa
* fixes mapsaving
* moved surpressor to analyzers proj
* warning cleanup & moves surpressor
* removes old msbuild targets
* Revert "Make yaml linter 5 times faster (~80% less execution time)"
This reverts commit 2ee4cc2c26.
* Add serialization to RobustServerSimulation and mock reflection methods
Fixes container tests
* Fix nullability warnings
* Improve yaml linter message feedback
* oops moment
* Add IEquatable, IComparable, ToString and operators to DataPosition
Rename it to NodeMark
Make it a readonly struct
* Remove try catch from enum parsing
* Make dependency management in serialization less bad
* Make dependencies an argument instead of a property on the serialization manager
* Clean up type serializers
* Improve validation messages and resourc epath checking
* Fix sprite error message
* reached perfection
Co-authored-by: Paul <ritter.paul1+git@googlemail.com>
Co-authored-by: DrSmugleaf <DrSmugleaf@users.noreply.github.com>
Co-authored-by: Vera Aguilera Puerto <zddm@outlook.es>
587 lines
19 KiB
C#
587 lines
19 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics.CodeAnalysis;
|
|
using System.Linq;
|
|
using System.Runtime.CompilerServices;
|
|
using Robust.Shared.Exceptions;
|
|
using Robust.Shared.Serialization;
|
|
using Robust.Shared.Utility;
|
|
using DependencyAttribute = Robust.Shared.IoC.DependencyAttribute;
|
|
|
|
namespace Robust.Shared.GameObjects
|
|
{
|
|
/// <inheritdoc />
|
|
public class ComponentManager : IComponentManager
|
|
{
|
|
[Dependency] private readonly IComponentFactory _componentFactory = default!;
|
|
[Dependency] private readonly IEntityManager _entityManager = default!;
|
|
[Dependency] private readonly IComponentDependencyManager _componentDependencyManager = default!;
|
|
|
|
#if EXCEPTION_TOLERANCE
|
|
[Dependency] private readonly IRuntimeLog _runtimeLog = default!;
|
|
#endif
|
|
|
|
private const int TypeCapacity = 32;
|
|
private const int ComponentCollectionCapacity = 1024;
|
|
|
|
private readonly Dictionary<uint, Dictionary<EntityUid, Component>> _entNetIdDict
|
|
= new();
|
|
|
|
private readonly Dictionary<Type, Dictionary<EntityUid, Component>> _entTraitDict
|
|
= new();
|
|
|
|
private readonly HashSet<Component> _deleteSet = new(TypeCapacity);
|
|
|
|
private UniqueIndexHkm<EntityUid, Component> _entCompIndex =
|
|
new(ComponentCollectionCapacity);
|
|
|
|
/// <inheritdoc />
|
|
public event EventHandler<ComponentEventArgs>? ComponentAdded;
|
|
|
|
/// <inheritdoc />
|
|
public event EventHandler<ComponentEventArgs>? ComponentRemoved;
|
|
|
|
/// <inheritdoc />
|
|
public event EventHandler<ComponentEventArgs>? ComponentDeleted;
|
|
|
|
public void Initialize()
|
|
{
|
|
FillComponentDict();
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public void Clear()
|
|
{
|
|
_entNetIdDict.Clear();
|
|
_entTraitDict.Clear();
|
|
_entCompIndex.Clear();
|
|
_deleteSet.Clear();
|
|
FillComponentDict();
|
|
}
|
|
|
|
#region Component Management
|
|
|
|
/// <inheritdoc />
|
|
public T AddComponent<T>(IEntity entity) where T : Component, new()
|
|
{
|
|
if (entity == null) throw new ArgumentNullException(nameof(entity));
|
|
|
|
var newComponent = _componentFactory.GetComponent<T>();
|
|
|
|
newComponent.Owner = entity;
|
|
|
|
AddComponent(entity, newComponent);
|
|
|
|
return newComponent;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public void AddComponent<T>(IEntity entity, T component, bool overwrite = false) where T : Component
|
|
{
|
|
if (entity == null || !entity.IsValid())
|
|
throw new ArgumentException("Entity is not valid.", nameof(entity));
|
|
|
|
if (component == null) throw new ArgumentNullException(nameof(component));
|
|
|
|
if (component.Owner != entity) throw new InvalidOperationException("Component is not owned by entity.");
|
|
|
|
var uid = entity.Uid;
|
|
|
|
// get interface aliases for mapping
|
|
var reg = _componentFactory.GetRegistration(component);
|
|
|
|
// Check that there are no overlapping references.
|
|
foreach (var type in reg.References)
|
|
{
|
|
var dict = _entTraitDict[type];
|
|
if (!dict.TryGetValue(uid, out var duplicate))
|
|
continue;
|
|
|
|
if (!overwrite && !duplicate.Deleted)
|
|
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 ITransformComponent || duplicate is IMetaDataComponent)
|
|
throw new InvalidOperationException("Tried to overwrite a protected component.");
|
|
|
|
RemoveComponentImmediate((Component) duplicate);
|
|
}
|
|
|
|
// add the component to the grid
|
|
foreach (var type in reg.References)
|
|
{
|
|
_entTraitDict[type].Add(uid, component);
|
|
_entCompIndex.Add(uid, component);
|
|
}
|
|
|
|
// add the component to the netId grid
|
|
if (component.NetID != null)
|
|
{
|
|
// the main comp grid keeps this in sync
|
|
|
|
var netId = component.NetID.Value;
|
|
_entNetIdDict[netId].Add(uid, component);
|
|
|
|
// mark the component as dirty for networking
|
|
component.Dirty();
|
|
|
|
ComponentAdded?.Invoke(this, new AddedComponentEventArgs(component));
|
|
}
|
|
|
|
_componentDependencyManager.OnComponentAdd(entity, component);
|
|
|
|
component.OnAdd();
|
|
|
|
if (!entity.Initialized && !entity.Initializing) return;
|
|
|
|
component.Initialize();
|
|
|
|
DebugTools.Assert(component.Initialized, "Component is not initialized after calling Initialize(). "
|
|
+ "Did you forget to call base.Initialize() in an override?");
|
|
|
|
if (entity.Initialized)
|
|
{
|
|
component.Running = true;
|
|
}
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public void RemoveComponent<T>(EntityUid uid)
|
|
{
|
|
RemoveComponent(uid, typeof(T));
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public void RemoveComponent(EntityUid uid, Type type)
|
|
{
|
|
RemoveComponentDeferred((Component) GetComponent(uid, type), uid, false);
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public void RemoveComponent(EntityUid uid, uint netId)
|
|
{
|
|
RemoveComponentDeferred((Component) GetComponent(uid, netId), uid, false);
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public void RemoveComponent(EntityUid uid, IComponent component)
|
|
{
|
|
if (component == null) throw new ArgumentNullException(nameof(component));
|
|
|
|
if (component.Owner == null || component.Owner.Uid != uid)
|
|
throw new InvalidOperationException("Component is not owned by entity.");
|
|
|
|
RemoveComponentDeferred((Component) component, uid, false);
|
|
}
|
|
|
|
private static IEnumerable<Component> InSafeOrder(IEnumerable<Component> comps, bool forCreation = false)
|
|
{
|
|
static int Sequence(IComponent x)
|
|
=> x switch
|
|
{
|
|
ITransformComponent _ => 0,
|
|
IMetaDataComponent _ => 1,
|
|
IPhysicsComponent _ => 2,
|
|
_ => int.MaxValue
|
|
};
|
|
|
|
return forCreation
|
|
? comps.OrderBy(Sequence)
|
|
: comps.OrderByDescending(Sequence);
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public void RemoveComponents(EntityUid uid)
|
|
{
|
|
foreach (var comp in InSafeOrder(_entCompIndex[uid]))
|
|
{
|
|
RemoveComponentDeferred(comp, uid, false);
|
|
}
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public void DisposeComponents(EntityUid uid)
|
|
{
|
|
foreach (var comp in InSafeOrder(_entCompIndex[uid]))
|
|
{
|
|
RemoveComponentDeferred(comp, uid, true);
|
|
}
|
|
|
|
// DisposeComponents means the entity is getting deleted.
|
|
// Safe to wipe the entity out of the index.
|
|
_entCompIndex.Remove(uid);
|
|
}
|
|
|
|
private void RemoveComponentDeferred(Component component, EntityUid uid, bool removeProtected)
|
|
{
|
|
if (component == null) throw new ArgumentNullException(nameof(component));
|
|
|
|
if (component.Deleted) return;
|
|
|
|
#if EXCEPTION_TOLERANCE
|
|
try
|
|
{
|
|
#endif
|
|
// these two components are required on all entities and cannot be removed normally.
|
|
if (!removeProtected && (component is ITransformComponent || component is IMetaDataComponent))
|
|
{
|
|
DebugTools.Assert("Tried to remove a protected component.");
|
|
return;
|
|
}
|
|
|
|
if (!_deleteSet.Add(component))
|
|
{
|
|
// already deferred deletion
|
|
return;
|
|
}
|
|
|
|
component.Running = false;
|
|
component.OnRemove();
|
|
_componentDependencyManager.OnComponentRemove(_entityManager.GetEntity(uid), component);
|
|
ComponentRemoved?.Invoke(this, new RemovedComponentEventArgs(component));
|
|
#if EXCEPTION_TOLERANCE
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
_runtimeLog.LogException(e,
|
|
$"RemoveComponentDeferred, owner={component.Owner}, type={component.GetType()}");
|
|
}
|
|
#endif
|
|
}
|
|
|
|
private void RemoveComponentImmediate(Component component)
|
|
{
|
|
if (component == null) throw new ArgumentNullException(nameof(component));
|
|
|
|
if (!component.Deleted)
|
|
{
|
|
// these two components are required on all entities and cannot be removed.
|
|
if (component is ITransformComponent || component is IMetaDataComponent)
|
|
{
|
|
DebugTools.Assert("Tried to remove a protected component.");
|
|
return;
|
|
}
|
|
|
|
component.Running = false;
|
|
component.OnRemove(); // Sets delete
|
|
ComponentRemoved?.Invoke(this, new RemovedComponentEventArgs(component));
|
|
|
|
}
|
|
|
|
DeleteComponent(component);
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public void CullRemovedComponents()
|
|
{
|
|
foreach (var component in InSafeOrder(_deleteSet))
|
|
{
|
|
DeleteComponent(component);
|
|
}
|
|
|
|
_deleteSet.Clear();
|
|
}
|
|
|
|
private void DeleteComponent(Component component)
|
|
{
|
|
var reg = _componentFactory.GetRegistration(component.GetType());
|
|
|
|
var entityUid = component.Owner.Uid;
|
|
|
|
foreach (var refType in reg.References)
|
|
{
|
|
_entTraitDict[refType].Remove(entityUid);
|
|
}
|
|
|
|
if (component.NetID == null) return;
|
|
|
|
var netId = component.NetID.Value;
|
|
_entNetIdDict[netId].Remove(entityUid);
|
|
_entCompIndex.Remove(entityUid, component);
|
|
|
|
// mark the owning entity as dirty for networking
|
|
component.Owner.Dirty();
|
|
|
|
ComponentDeleted?.Invoke(this, new DeletedComponentEventArgs(component));
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public bool HasComponent<T>(EntityUid uid)
|
|
{
|
|
return HasComponent(uid, typeof(T));
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public bool HasComponent(EntityUid uid, Type type)
|
|
{
|
|
var dict = _entTraitDict[type];
|
|
return dict.TryGetValue(uid, out var comp) && !comp.Deleted;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public bool HasComponent(EntityUid uid, uint netId)
|
|
{
|
|
var dict = _entNetIdDict[netId];
|
|
return dict.TryGetValue(uid, out var comp) && !comp.Deleted;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public T GetComponent<T>(EntityUid uid)
|
|
{
|
|
return (T) GetComponent(uid, typeof(T));
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public IComponent GetComponent(EntityUid uid, Type type)
|
|
{
|
|
// ReSharper disable once InvertIf
|
|
var dict = _entTraitDict[type];
|
|
if (dict.TryGetValue(uid, out var comp))
|
|
{
|
|
if (!comp.Deleted)
|
|
{
|
|
return comp;
|
|
}
|
|
}
|
|
|
|
var ent = _entityManager.GetEntity(uid);
|
|
throw new KeyNotFoundException($"Entity {ent} does not have a component of type {type}");
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public IComponent GetComponent(EntityUid uid, uint netId)
|
|
{
|
|
// ReSharper disable once InvertIf
|
|
var dict = _entNetIdDict[netId];
|
|
if (dict.TryGetValue(uid, out var comp))
|
|
{
|
|
if (!comp.Deleted)
|
|
{
|
|
return comp;
|
|
}
|
|
}
|
|
|
|
var ent = _entityManager.GetEntity(uid);
|
|
throw new KeyNotFoundException($"Entity {ent} does not have a component of NetID {netId}");
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public bool TryGetComponent<T>(EntityUid uid, [NotNullWhen(true)] out T component)
|
|
{
|
|
if (TryGetComponent(uid, typeof(T), out var comp))
|
|
{
|
|
if (!comp.Deleted)
|
|
{
|
|
component = (T) comp;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
component = default!;
|
|
return false;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public bool TryGetComponent(EntityUid uid, Type type, [NotNullWhen(true)] out IComponent? component)
|
|
{
|
|
var dict = _entTraitDict[type];
|
|
if (dict.TryGetValue(uid, out var comp))
|
|
{
|
|
if (!comp.Deleted)
|
|
{
|
|
component = comp;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
component = null;
|
|
return false;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public bool TryGetComponent(EntityUid uid, uint netId, [NotNullWhen(true)] out IComponent? component)
|
|
{
|
|
var dict = _entNetIdDict[netId];
|
|
if (dict.TryGetValue(uid, out var comp))
|
|
{
|
|
if (!comp.Deleted)
|
|
{
|
|
component = comp;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
component = null;
|
|
return false;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public IEnumerable<IComponent> GetComponents(EntityUid uid)
|
|
{
|
|
// ReSharper disable once LoopCanBeConvertedToQuery
|
|
foreach (Component comp in _entCompIndex[uid].ToArray())
|
|
{
|
|
if (comp.Deleted) continue;
|
|
|
|
yield return comp;
|
|
}
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public IEnumerable<T> GetComponents<T>(EntityUid uid)
|
|
{
|
|
var comps = _entCompIndex[uid];
|
|
foreach (var comp in comps)
|
|
{
|
|
if (comp.Deleted || !(comp is T tComp)) continue;
|
|
|
|
yield return tComp;
|
|
}
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public IEnumerable<IComponent> GetNetComponents(EntityUid uid)
|
|
{
|
|
var comps = _entCompIndex[uid];
|
|
foreach (var comp in comps)
|
|
{
|
|
if (comp.Deleted || comp.NetID == null) continue;
|
|
|
|
yield return comp;
|
|
}
|
|
}
|
|
|
|
#region Join Functions
|
|
|
|
/// <inheritdoc />
|
|
public IEnumerable<T> EntityQuery<T>(bool includePaused = false)
|
|
{
|
|
var comps = _entTraitDict[typeof(T)];
|
|
foreach (var comp in comps.Values)
|
|
{
|
|
if (comp.Deleted || !includePaused && comp.Paused) continue;
|
|
|
|
yield return (T) (object) comp;
|
|
}
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public IEnumerable<(TComp1, TComp2)> EntityQuery<TComp1, TComp2>(bool includePaused = false)
|
|
where TComp1 : IComponent
|
|
where TComp2 : IComponent
|
|
{
|
|
// this would prob be faster if trait1 was a list (or an array of structs hue).
|
|
var trait1 = _entTraitDict[typeof(TComp1)];
|
|
var trait2 = _entTraitDict[typeof(TComp2)];
|
|
|
|
// you really want trait1 to be the smaller set of components
|
|
foreach (var kvComp in trait1)
|
|
{
|
|
var uid = kvComp.Key;
|
|
|
|
if (!trait2.TryGetValue(uid, out var t2Comp) || t2Comp.Deleted || !includePaused && kvComp.Value.Paused)
|
|
continue;
|
|
|
|
yield return ((TComp1) (object) kvComp.Value, (TComp2) (object) t2Comp);
|
|
}
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public IEnumerable<(TComp1, TComp2, TComp3)> EntityQuery<TComp1, TComp2, TComp3>(bool includePaused = false)
|
|
where TComp1 : IComponent
|
|
where TComp2 : IComponent
|
|
where TComp3 : IComponent
|
|
{
|
|
var trait1 = _entTraitDict[typeof(TComp1)];
|
|
var trait2 = _entTraitDict[typeof(TComp2)];
|
|
var trait3 = _entTraitDict[typeof(TComp3)];
|
|
|
|
foreach (var kvComp in trait1)
|
|
{
|
|
var uid = kvComp.Key;
|
|
|
|
if (!trait2.TryGetValue(uid, out var t2Comp) || t2Comp.Deleted || !includePaused && kvComp.Value.Paused)
|
|
continue;
|
|
|
|
if (!trait3.TryGetValue(uid, out var t3Comp) || t3Comp.Deleted)
|
|
continue;
|
|
|
|
yield return ((TComp1) (object) kvComp.Value,
|
|
(TComp2) (object) t2Comp,
|
|
(TComp3) (object) t3Comp);
|
|
}
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public IEnumerable<(TComp1, TComp2, TComp3, TComp4)> EntityQuery<TComp1, TComp2, TComp3, TComp4>(bool includePaused = false)
|
|
where TComp1 : IComponent
|
|
where TComp2 : IComponent
|
|
where TComp3 : IComponent
|
|
where TComp4 : IComponent
|
|
{
|
|
var trait1 = _entTraitDict[typeof(TComp1)];
|
|
var trait2 = _entTraitDict[typeof(TComp2)];
|
|
var trait3 = _entTraitDict[typeof(TComp3)];
|
|
var trait4 = _entTraitDict[typeof(TComp4)];
|
|
|
|
foreach (var kvComp in trait1)
|
|
{
|
|
var uid = kvComp.Key;
|
|
|
|
if (!trait2.TryGetValue(uid, out var t2Comp) || t2Comp.Deleted || !includePaused && kvComp.Value.Paused)
|
|
continue;
|
|
|
|
if (!trait3.TryGetValue(uid, out var t3Comp) || t3Comp.Deleted)
|
|
continue;
|
|
|
|
if (!trait4.TryGetValue(uid, out var t4Comp) || t4Comp.Deleted)
|
|
continue;
|
|
|
|
yield return ((TComp1) (object) kvComp.Value,
|
|
(TComp2) (object) t2Comp,
|
|
(TComp3) (object) t3Comp,
|
|
(TComp4) (object) t4Comp);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
/// <inheritdoc />
|
|
public IEnumerable<IComponent> GetAllComponents(Type type, bool includePaused = false)
|
|
{
|
|
var comps = _entTraitDict[type];
|
|
foreach (var comp in comps.Values)
|
|
{
|
|
if (comp.Deleted || !includePaused && comp.Paused) continue;
|
|
|
|
yield return comp;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
private void FillComponentDict()
|
|
{
|
|
foreach (var refType in _componentFactory.GetAllRefTypes())
|
|
{
|
|
_entTraitDict.Add(refType, new Dictionary<EntityUid, Component>());
|
|
}
|
|
|
|
foreach (var netId in _componentFactory.GetAllNetIds())
|
|
{
|
|
_entNetIdDict.Add(netId, new Dictionary<EntityUid, Component>());
|
|
}
|
|
}
|
|
}
|
|
}
|