Move entity init support into base
And other refactorings and fixes
This commit is contained in:
parent
1c6d2bda89
commit
ef075d414a
13 changed files with 166 additions and 51 deletions
|
@ -28,7 +28,7 @@ namespace TechbloxModdingAPI
|
||||||
/// A single (perhaps scaled) block. Properties may return default values if the block is removed and then setting them is ignored.
|
/// A single (perhaps scaled) block. Properties may return default values if the block is removed and then setting them is ignored.
|
||||||
/// For specific block type operations, use the specialised block classes in the TechbloxModdingAPI.Blocks namespace.
|
/// For specific block type operations, use the specialised block classes in the TechbloxModdingAPI.Blocks namespace.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class Block : EcsObjectBase, IHasPhysics, IEquatable<Block>, IEquatable<EGID>
|
public class Block : EcsObjectBase<BlockEntityDescriptor>, IHasPhysics, IEquatable<Block>, IEquatable<EGID>
|
||||||
{
|
{
|
||||||
protected static readonly PlacementEngine PlacementEngine = new();
|
protected static readonly PlacementEngine PlacementEngine = new();
|
||||||
protected static readonly RemovalEngine RemovalEngine = new();
|
protected static readonly RemovalEngine RemovalEngine = new();
|
||||||
|
@ -54,9 +54,7 @@ namespace TechbloxModdingAPI
|
||||||
if (PlacementEngine.IsInGame && GameClient.IsBuildMode)
|
if (PlacementEngine.IsInGame && GameClient.IsBuildMode)
|
||||||
{
|
{
|
||||||
var initializer = PlacementEngine.PlaceBlock(block, position, player, autoWire);
|
var initializer = PlacementEngine.PlaceBlock(block, position, player, autoWire);
|
||||||
var egid = initializer.EGID;
|
var bl = New(initializer);
|
||||||
var bl = New(egid);
|
|
||||||
bl.InitData = initializer;
|
|
||||||
Placed += bl.OnPlacedInit;
|
Placed += bl.OnPlacedInit;
|
||||||
return bl;
|
return bl;
|
||||||
}
|
}
|
||||||
|
@ -124,19 +122,30 @@ namespace TechbloxModdingAPI
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
internal static Block New(EGID egid, bool signaling = false)
|
internal static Block New(EGID egid, bool signaling = false)
|
||||||
{
|
{
|
||||||
if (egid == default) return null;
|
return New(egid, default, signaling);
|
||||||
if (GroupToConstructor.TryGetValue(egid.groupID, out var value))
|
|
||||||
{
|
|
||||||
var (constructor, type) = value;
|
|
||||||
return GetInstance(egid, constructor, type);
|
|
||||||
}
|
|
||||||
|
|
||||||
return signaling
|
|
||||||
? GetInstance(egid, e => new SignalingBlock(e))
|
|
||||||
: GetInstance(egid, e => new Block(e));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Block(EGID id) : base(id, typeof(BlockEntityDescriptor))
|
private static Block New(EcsInitData initData, bool signaling = false)
|
||||||
|
{
|
||||||
|
return New(initData.EGID, initData, signaling);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Block New(EGID egid, EcsInitData initData, bool signaling)
|
||||||
|
{
|
||||||
|
if (egid == default) return null;
|
||||||
|
Func<EGID, Block> constructor;
|
||||||
|
Type type = null;
|
||||||
|
if (GroupToConstructor.TryGetValue(egid.groupID, out var value))
|
||||||
|
(constructor, type) = value;
|
||||||
|
else
|
||||||
|
constructor = signaling ? e => new SignalingBlock(e) : e => new Block(e);
|
||||||
|
|
||||||
|
return initData != default
|
||||||
|
? GetInstanceNew(initData, constructor, type)
|
||||||
|
: GetInstanceExisting(egid, constructor, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Block(EGID id) : base(id)
|
||||||
{
|
{
|
||||||
Type expectedType;
|
Type expectedType;
|
||||||
if (GroupToConstructor.ContainsKey(id.groupID) &&
|
if (GroupToConstructor.ContainsKey(id.groupID) &&
|
||||||
|
@ -375,7 +384,7 @@ namespace TechbloxModdingAPI
|
||||||
var bgec = GetComponent<BlockGroupEntityComponent>();
|
var bgec = GetComponent<BlockGroupEntityComponent>();
|
||||||
return blockGroup = bgec.currentBlockGroup == -1
|
return blockGroup = bgec.currentBlockGroup == -1
|
||||||
? null
|
? null
|
||||||
: GetInstance(new EGID((uint)bgec.currentBlockGroup, BlockGroupExclusiveGroups.BlockGroupEntityGroup),
|
: GetInstanceExisting(new EGID((uint)bgec.currentBlockGroup, BlockGroupExclusiveGroups.BlockGroupEntityGroup),
|
||||||
egid => new BlockGroup((int)egid.entityID, this));
|
egid => new BlockGroup((int)egid.entityID, this));
|
||||||
}
|
}
|
||||||
set
|
set
|
||||||
|
@ -466,7 +475,6 @@ namespace TechbloxModdingAPI
|
||||||
{ //Member method instead of lambda to avoid constantly creating delegates
|
{ //Member method instead of lambda to avoid constantly creating delegates
|
||||||
if (e.ID != Id) return;
|
if (e.ID != Id) return;
|
||||||
Placed -= OnPlacedInit; //And we can reference it
|
Placed -= OnPlacedInit; //And we can reference it
|
||||||
InitData = default; //Remove initializer as it's no longer valid - if the block gets removed it shouldn't be used again
|
|
||||||
if (copiedFrom != default)
|
if (copiedFrom != default)
|
||||||
BlockCloneEngine.CopyBlockStats(copiedFrom, Id);
|
BlockCloneEngine.CopyBlockStats(copiedFrom, Id);
|
||||||
}
|
}
|
||||||
|
|
|
@ -218,7 +218,7 @@ namespace TechbloxModdingAPI.Blocks
|
||||||
/// <returns>A copy of the wire object.</returns>
|
/// <returns>A copy of the wire object.</returns>
|
||||||
public Wire OutputToInputCopy()
|
public Wire OutputToInputCopy()
|
||||||
{
|
{
|
||||||
return GetInstance(wireEGID, egid => new Wire(egid));
|
return GetInstanceExisting(wireEGID, egid => new Wire(egid));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -10,8 +10,25 @@ using TechbloxModdingAPI.Utility;
|
||||||
|
|
||||||
namespace TechbloxModdingAPI.Common;
|
namespace TechbloxModdingAPI.Common;
|
||||||
|
|
||||||
public abstract class EcsObjectBase
|
public abstract class EcsObjectBase<TDescriptor> : EcsObjectBase where TDescriptor : IEntityDescriptor, new()
|
||||||
{
|
{
|
||||||
|
protected EcsObjectBase(EGID id) : base(id, typeof(TDescriptor))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected EcsObjectBase(EntityReference reference) : base(reference, typeof(TDescriptor))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected bool RemoveEntity()
|
||||||
|
{
|
||||||
|
if (!Exists) return false;
|
||||||
|
_engine.Functions.RemoveEntity<TDescriptor>(Id);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract class EcsObjectBase {
|
||||||
public EGID Id => _engine.GetEgid(Reference);
|
public EGID Id => _engine.GetEgid(Reference);
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A reference to a specific entity that persists through group swaps and such.
|
/// A reference to a specific entity that persists through group swaps and such.
|
||||||
|
@ -24,8 +41,11 @@ public abstract class EcsObjectBase
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool Exists => Id != default; // TODO: Might need extra code to support IDs during init
|
public bool Exists => Id != default; // TODO: Might need extra code to support IDs during init
|
||||||
|
|
||||||
|
public readonly Type EntityDescriptorType;
|
||||||
|
public readonly Type[] AllowedEntityComponents;
|
||||||
|
|
||||||
private static readonly Dictionary<Type, WeakDictionary<EntityReference, EcsObjectBase>> _instances = new();
|
private static readonly Dictionary<Type, WeakDictionary<EntityReference, EcsObjectBase>> _instances = new();
|
||||||
private static readonly EcsObjectBaseEngine _engine = new();
|
internal static readonly EcsObjectBaseEngine _engine = new();
|
||||||
|
|
||||||
private static WeakDictionary<EntityReference, EcsObjectBase> GetInstances(Type type)
|
private static WeakDictionary<EntityReference, EcsObjectBase> GetInstances(Type type)
|
||||||
{
|
{
|
||||||
|
@ -34,13 +54,14 @@ public abstract class EcsObjectBase
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns a cached instance if there's an actively used instance of the object already.
|
/// Returns a cached instance if there's an actively used instance of the object already.
|
||||||
/// Objects still get garbage collected and then they will be removed from the cache.
|
/// Objects still get garbage collected and then they will be removed from the cache.<br />
|
||||||
|
/// <b>Only use for existing entities!</b> Use the other overload for newly created entities.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="egid">The EGID of the entity</param>
|
/// <param name="egid">The EGID of the entity</param>
|
||||||
/// <param name="constructor">The constructor to construct the object</param>
|
/// <param name="constructor">The constructor to construct the object</param>
|
||||||
/// <typeparam name="T">The object type</typeparam>
|
/// <typeparam name="T">The object type</typeparam>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
internal static T GetInstance<T>(EGID egid, Func<EGID, T> constructor, Type type = null) where T : EcsObjectBase
|
internal static T GetInstanceExisting<T>(EGID egid, Func<EGID, T> constructor, Type type = null) where T : EcsObjectBase
|
||||||
{
|
{
|
||||||
var instances = GetInstances(type ?? typeof(T));
|
var instances = GetInstances(type ?? typeof(T));
|
||||||
if (instances == null || !instances.TryGetValue(_engine.GetEntityReference(egid), out var instance))
|
if (instances == null || !instances.TryGetValue(_engine.GetEntityReference(egid), out var instance))
|
||||||
|
@ -48,6 +69,33 @@ public abstract class EcsObjectBase
|
||||||
return (T)instance;
|
return (T)instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a cached instance if there's an actively used instance of the object already.
|
||||||
|
/// Objects still get garbage collected and then they will be removed from the cache.<br />
|
||||||
|
/// <b>Only use for newly created entities!</b> Use the other overload for existing entities.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="egid">The EGID of the entity</param>
|
||||||
|
/// <param name="constructor">The constructor to construct the object</param>
|
||||||
|
/// <typeparam name="T">The object type</typeparam>
|
||||||
|
/// <returns></returns>
|
||||||
|
internal static T GetInstanceNew<T>(EcsInitData initData, Func<EGID, T> constructor, Type type = null) where T : EcsObjectBase
|
||||||
|
{
|
||||||
|
var instances = GetInstances(type ?? typeof(T));
|
||||||
|
if (instances == null || !instances.TryGetValue(initData.Reference, out var instance))
|
||||||
|
{
|
||||||
|
var ret = constructor(initData.EGID);
|
||||||
|
ret.InitData = initData;
|
||||||
|
return ret; // It will be added by the constructor
|
||||||
|
}
|
||||||
|
|
||||||
|
return (T)instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static V CreateEntity<U, V>(EGID egid, Func<EGID, V> constructor, Type type = null) where U : IEntityDescriptor, new() where V : EcsObjectBase<U>
|
||||||
|
{
|
||||||
|
return GetInstanceNew(_engine.Factory.BuildEntity<U>(egid), constructor, type);
|
||||||
|
}
|
||||||
|
|
||||||
protected EcsObjectBase(EGID id, Type entityDescriptorType) : this(_engine.GetEntityReference(id), entityDescriptorType)
|
protected EcsObjectBase(EGID id, Type entityDescriptorType) : this(_engine.GetEntityReference(id), entityDescriptorType)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -62,10 +110,12 @@ public abstract class EcsObjectBase
|
||||||
if (!dict.ContainsKey(reference)) // Multiple instances may be created
|
if (!dict.ContainsKey(reference)) // Multiple instances may be created
|
||||||
dict.Add(reference, this);
|
dict.Add(reference, this);
|
||||||
Reference = reference;
|
Reference = reference;
|
||||||
|
EntityDescriptorType = entityDescriptorType;
|
||||||
|
AllowedEntityComponents = EcsUtils.GetValidEntityComponents(entityDescriptorType);
|
||||||
|
// Remove init data once the entity gets submitted so that it won't be used again once the entity is removed
|
||||||
|
if (InitData != default) _engine.TrackNewEntity(this, obj => obj.InitData = default);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
protected internal OptionalRef<T> GetComponentOptional<T>() where T : unmanaged, IEntityComponent
|
protected internal OptionalRef<T> GetComponentOptional<T>() where T : unmanaged, IEntityComponent
|
||||||
{
|
{
|
||||||
return _engine.GetComponentOptional<T>(this);
|
return _engine.GetComponentOptional<T>(this);
|
||||||
|
@ -91,28 +141,22 @@ public abstract class EcsObjectBase
|
||||||
_engine.SetComponent(this, type, name, value);
|
_engine.SetComponent(this, type, name, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected bool RemoveEntity()
|
|
||||||
{
|
|
||||||
// TODO: _entityFunctions.Remove...()
|
|
||||||
}
|
|
||||||
|
|
||||||
#region ECS initializer stuff
|
#region ECS initializer stuff
|
||||||
|
|
||||||
protected internal EcsInitData InitData;
|
internal EcsInitData InitData { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Holds information needed to construct a component initializer.
|
/// Holds information needed to construct a component initializer.
|
||||||
/// Necessary because the initializer is a ref struct which cannot be assigned to a field.
|
/// Necessary because the initializer is a ref struct which cannot be assigned to a field.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected internal struct EcsInitData
|
protected internal readonly record struct EcsInitData(FasterDictionary<RefWrapperType, ITypeSafeDictionary> group, EntityReference Reference, EGID EGID)
|
||||||
{
|
{
|
||||||
private FasterDictionary<RefWrapperType, ITypeSafeDictionary> group;
|
public static implicit operator EcsInitData(EntityInitializer initializer) => new(GetInitGroup(initializer), initializer.reference, initializer.EGID);
|
||||||
private EntityReference reference;
|
|
||||||
|
|
||||||
public static implicit operator EcsInitData(EntityInitializer initializer) => new()
|
private readonly FasterDictionary<RefWrapperType, ITypeSafeDictionary> group = group;
|
||||||
{ group = GetInitGroup(initializer), reference = initializer.reference };
|
public readonly EntityReference Reference = Reference;
|
||||||
|
public readonly EGID EGID = EGID;
|
||||||
public EntityInitializer Initializer(EGID id) => new(id, group, reference);
|
public EntityInitializer Initializer(EGID id = default) => new(id == default ? EGID : id, group, Reference);
|
||||||
public bool Valid => group != null;
|
public bool Valid => group != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,11 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using HarmonyLib;
|
using HarmonyLib;
|
||||||
|
using RobocraftX.Schedulers;
|
||||||
using Svelto.ECS;
|
using Svelto.ECS;
|
||||||
using Svelto.ECS.Hybrid;
|
using Svelto.ECS.Hybrid;
|
||||||
|
using Svelto.Tasks;
|
||||||
|
using Svelto.Tasks.Lean;
|
||||||
using TechbloxModdingAPI.Blocks.Engines;
|
using TechbloxModdingAPI.Blocks.Engines;
|
||||||
using TechbloxModdingAPI.Common.Engines;
|
using TechbloxModdingAPI.Common.Engines;
|
||||||
using TechbloxModdingAPI.Utility;
|
using TechbloxModdingAPI.Utility;
|
||||||
|
@ -9,7 +13,7 @@ using TechbloxModdingAPI.Utility.ECS;
|
||||||
|
|
||||||
namespace TechbloxModdingAPI.Common;
|
namespace TechbloxModdingAPI.Common;
|
||||||
|
|
||||||
public class EcsObjectBaseEngine : IApiEngine
|
public class EcsObjectBaseEngine : IFactoryEngine, IFunEngine
|
||||||
{
|
{
|
||||||
public void Ready()
|
public void Ready()
|
||||||
{
|
{
|
||||||
|
@ -68,4 +72,24 @@ public class EcsObjectBaseEngine : IApiEngine
|
||||||
AccessTools.Field(str.GetType(), name).SetValue(str, value);
|
AccessTools.Field(str.GetType(), name).SetValue(str, value);
|
||||||
prop.SetValue(opt, str);
|
prop.SetValue(opt, str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private readonly Dictionary<EcsObjectBase, Action<EcsObjectBase>> _waitingForSubmission = new();
|
||||||
|
|
||||||
|
public void TrackNewEntity(EcsObjectBase obj, Action<EcsObjectBase> done)
|
||||||
|
{
|
||||||
|
if (_waitingForSubmission.ContainsKey(obj))
|
||||||
|
throw new InvalidOperationException("Something has gone horribly wrong here");
|
||||||
|
_waitingForSubmission.Add(obj, done);
|
||||||
|
WaitUntilEntitySubmission().RunOn(ClientLean.UIScheduler); // TODO: Pick the right scheduler
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerator<TaskContract> WaitUntilEntitySubmission()
|
||||||
|
{
|
||||||
|
// TODO: Get the scheduler instance based on the engine (inject in engine manager)
|
||||||
|
yield return new WaitForSubmissionEnumerator(FullGameFields._mainGameEnginesRoot.scheduler).Continue();
|
||||||
|
foreach (var (obj, done) in _waitingForSubmission) done(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEntityFactory Factory { get; set; }
|
||||||
|
public IEntityFunctions Functions { get; set; }
|
||||||
}
|
}
|
|
@ -17,6 +17,8 @@ public class EngineManager
|
||||||
/// <param name="types">The types to register to</param>
|
/// <param name="types">The types to register to</param>
|
||||||
public static void AddEngine(IApiEngine engine, params ApiEngineType[] types)
|
public static void AddEngine(IApiEngine engine, params ApiEngineType[] types)
|
||||||
{
|
{
|
||||||
|
if (types.Length == 0)
|
||||||
|
Logging.LogWarning($"Engine {engine.GetType().FullName} added without any types! This doesn't do anything.");
|
||||||
foreach (var type in types)
|
foreach (var type in types)
|
||||||
{
|
{
|
||||||
if (!_engines.ContainsKey(type))
|
if (!_engines.ContainsKey(type))
|
||||||
|
|
|
@ -11,7 +11,8 @@ public interface IHasPhysics
|
||||||
|
|
||||||
public static class HasPhysicsExtensions
|
public static class HasPhysicsExtensions
|
||||||
{
|
{
|
||||||
internal static void UpdatePhysicsUECSComponent<T, O>(this O obj, T componentData) where O : EcsObjectBase, IHasPhysics where T : struct, IComponentData
|
internal static void UpdatePhysicsUECSComponent<T, O>(this O obj, T componentData)
|
||||||
|
where O : EcsObjectBase, IHasPhysics where T : struct, IComponentData
|
||||||
{
|
{
|
||||||
var phyStruct = obj.GetComponentOptional<DOTSPhysicsEntityStruct>();
|
var phyStruct = obj.GetComponentOptional<DOTSPhysicsEntityStruct>();
|
||||||
if (phyStruct) //It exists
|
if (phyStruct) //It exists
|
||||||
|
|
23
TechbloxModdingAPI/Common/Utils/EcsUtils.cs
Normal file
23
TechbloxModdingAPI/Common/Utils/EcsUtils.cs
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using HarmonyLib;
|
||||||
|
using Svelto.ECS;
|
||||||
|
|
||||||
|
namespace TechbloxModdingAPI.Common.Utils
|
||||||
|
{
|
||||||
|
public static class EcsUtils
|
||||||
|
{
|
||||||
|
public static Type[] GetValidEntityComponents(Type entityDescriptorType)
|
||||||
|
{
|
||||||
|
// TODO: Cache
|
||||||
|
var templateType = typeof(EntityDescriptorTemplate<>).MakeGenericType(entityDescriptorType);
|
||||||
|
var templateDescriptor = AccessTools.Property(templateType, "descriptor");
|
||||||
|
var getDescriptorExpr = Expression.MakeMemberAccess(null, templateDescriptor ?? throw new InvalidOperationException());
|
||||||
|
var getTemplateDescriptorExpr = Expression.Lambda<Func<IEntityDescriptor>>(getDescriptorExpr);
|
||||||
|
var getTemplateDescriptor = getTemplateDescriptorExpr.Compile();
|
||||||
|
var builders = getTemplateDescriptor().componentsToBuild;
|
||||||
|
return builders.Select(builder => builder.GetEntityComponentType()).ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -8,6 +8,7 @@ using Svelto.Context;
|
||||||
|
|
||||||
using TechbloxModdingAPI.App;
|
using TechbloxModdingAPI.App;
|
||||||
using TechbloxModdingAPI.Blocks;
|
using TechbloxModdingAPI.Blocks;
|
||||||
|
using TechbloxModdingAPI.Common;
|
||||||
using TechbloxModdingAPI.Tasks;
|
using TechbloxModdingAPI.Tasks;
|
||||||
using TechbloxModdingAPI.Utility;
|
using TechbloxModdingAPI.Utility;
|
||||||
|
|
||||||
|
@ -61,6 +62,7 @@ namespace TechbloxModdingAPI
|
||||||
// init input
|
// init input
|
||||||
Input.FakeInput.Init();
|
Input.FakeInput.Init();
|
||||||
// init object-oriented classes
|
// init object-oriented classes
|
||||||
|
EcsObjectBase.Init();
|
||||||
Player.Init();
|
Player.Init();
|
||||||
Block.Init();
|
Block.Init();
|
||||||
BlockGroup.Init();
|
BlockGroup.Init();
|
||||||
|
|
|
@ -84,7 +84,7 @@ namespace TechbloxModdingAPI
|
||||||
|
|
||||||
internal static Player GetInstance(uint id)
|
internal static Player GetInstance(uint id)
|
||||||
{
|
{
|
||||||
return EcsObjectBase.GetInstance(new EGID(id, CharacterExclusiveGroups.OnFootGroup),
|
return EcsObjectBase.GetInstanceExisting(new EGID(id, CharacterExclusiveGroups.OnFootGroup),
|
||||||
e => new Player(e.entityID));
|
e => new Player(e.entityID));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -469,7 +469,7 @@ namespace TechbloxModdingAPI
|
||||||
{
|
{
|
||||||
var egid = playerEngine.GetThingLookedAt(Id, maxDistance);
|
var egid = playerEngine.GetThingLookedAt(Id, maxDistance);
|
||||||
return egid != default && egid.groupID == CommonExclusiveGroups.SIMULATION_BODIES_GROUP
|
return egid != default && egid.groupID == CommonExclusiveGroups.SIMULATION_BODIES_GROUP
|
||||||
? EcsObjectBase.GetInstance(egid, e => new SimBody(e))
|
? EcsObjectBase.GetInstanceExisting(egid, e => new SimBody(e))
|
||||||
: null;
|
: null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -482,7 +482,7 @@ namespace TechbloxModdingAPI
|
||||||
{
|
{
|
||||||
var egid = playerEngine.GetThingLookedAt(Id, maxDistance);
|
var egid = playerEngine.GetThingLookedAt(Id, maxDistance);
|
||||||
return egid != default && egid.groupID == WiresGUIExclusiveGroups.WireGroup
|
return egid != default && egid.groupID == WiresGUIExclusiveGroups.WireGroup
|
||||||
? EcsObjectBase.GetInstance(new EGID(egid.entityID, BuildModeWiresGroups.WiresGroup.Group),
|
? EcsObjectBase.GetInstanceExisting(new EGID(egid.entityID, BuildModeWiresGroups.WiresGroup.Group),
|
||||||
e => new Wire(e))
|
e => new Wire(e))
|
||||||
: null;
|
: null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@ namespace TechbloxModdingAPI
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Cluster Cluster => cluster ??= clusterId == uint.MaxValue // Return cluster or if it's null then set it
|
public Cluster Cluster => cluster ??= clusterId == uint.MaxValue // Return cluster or if it's null then set it
|
||||||
? Block.BlockEngine.GetCluster(Id.entityID) // If we don't have a clusterId set then get it from the game
|
? Block.BlockEngine.GetCluster(Id.entityID) // If we don't have a clusterId set then get it from the game
|
||||||
: GetInstance(new EGID(clusterId, ClustersExclusiveGroups.SIMULATION_CLUSTERS_GROUP),
|
: GetInstanceExisting(new EGID(clusterId, ClustersExclusiveGroups.SIMULATION_CLUSTERS_GROUP),
|
||||||
egid => new Cluster(egid)); // Otherwise get the cluster from the ID
|
egid => new Cluster(egid)); // Otherwise get the cluster from the ID
|
||||||
|
|
||||||
private Cluster cluster;
|
private Cluster cluster;
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
using System.Linq;
|
||||||
using Svelto.ECS;
|
using Svelto.ECS;
|
||||||
using Svelto.ECS.Hybrid;
|
using Svelto.ECS.Hybrid;
|
||||||
using TechbloxModdingAPI.Common;
|
using TechbloxModdingAPI.Common;
|
||||||
|
@ -54,7 +55,10 @@ namespace TechbloxModdingAPI.Utility.ECS
|
||||||
EGID id = group == ExclusiveGroupStruct.Invalid ? obj.Id : new EGID(obj.Id.entityID, group);
|
EGID id = group == ExclusiveGroupStruct.Invalid ? obj.Id : new EGID(obj.Id.entityID, group);
|
||||||
var opt = QueryEntityOptional<T>(entitiesDB, id);
|
var opt = QueryEntityOptional<T>(entitiesDB, id);
|
||||||
if (opt) return ref opt.Get();
|
if (opt) return ref opt.Get();
|
||||||
if (obj.InitData.Valid) return ref obj.InitData.Initializer(id).GetOrAdd<T>();
|
// If initializing the entity, check if the component is allowed by the descriptor, otherwise it could cause
|
||||||
|
// issues in the game with Add() calls running unexpectedly
|
||||||
|
if (obj.InitData.Valid && obj.AllowedEntityComponents.Contains(typeof(T)))
|
||||||
|
return ref obj.InitData.Initializer(id).GetOrAdd<T>();
|
||||||
return ref opt.Get(); //Default value
|
return ref opt.Get(); //Default value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using Svelto.ECS;
|
using Svelto.ECS;
|
||||||
using Svelto.Tasks;
|
using Svelto.Tasks;
|
||||||
using Svelto.Tasks.Lean;
|
using Svelto.Tasks.Lean;
|
||||||
|
@ -58,12 +59,10 @@ namespace TechbloxModdingAPI.Utility.ECS
|
||||||
EGID id = group == ExclusiveGroupStruct.Invalid ? obj.Id : new EGID(obj.Id.entityID, group);
|
EGID id = group == ExclusiveGroupStruct.Invalid ? obj.Id : new EGID(obj.Id.entityID, group);
|
||||||
var opt = QueryEntityOptional<T>(entitiesDB, id);
|
var opt = QueryEntityOptional<T>(entitiesDB, id);
|
||||||
if (opt) return ref opt.Get();
|
if (opt) return ref opt.Get();
|
||||||
if (obj.InitData.Valid) return ref obj.InitData.Initializer(id).GetOrAdd<T>();
|
// If initializing the entity, check if the component is allowed by the descriptor, otherwise it could cause
|
||||||
/*if (!obj.InitData.Valid) return ref opt.Get(); //Default value
|
// issues in the game with Add() calls running unexpectedly
|
||||||
var init = obj.InitData.Initializer(id);
|
if (obj.InitData.Valid && obj.AllowedEntityComponents.Contains(typeof(T)))
|
||||||
// Do not create the component if missing, as that can trigger Add() listeners that, in some cases, may be
|
return ref obj.InitData.Initializer(id).GetOrAdd<T>();
|
||||||
// invalid if (ab)using the classes in an unusual way - TODO: Check entity descriptor or something
|
|
||||||
if (init.Has<T>()) return ref init.Get<T>();*/
|
|
||||||
return ref opt.Get(); //Default value
|
return ref opt.Get(); //Default value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Linq;
|
||||||
using Svelto.DataStructures;
|
using Svelto.DataStructures;
|
||||||
using Svelto.ECS;
|
using Svelto.ECS;
|
||||||
using TechbloxModdingAPI.Common;
|
using TechbloxModdingAPI.Common;
|
||||||
|
@ -14,6 +15,7 @@ namespace TechbloxModdingAPI.Utility
|
||||||
private MB<T> managedArray;
|
private MB<T> managedArray;
|
||||||
private readonly EntityInitializer initializer;
|
private readonly EntityInitializer initializer;
|
||||||
//The possible fields are: (index && (array || managedArray)) || initializer
|
//The possible fields are: (index && (array || managedArray)) || initializer
|
||||||
|
private readonly EcsObjectBase obj;
|
||||||
|
|
||||||
public OptionalRef(NB<T> array, uint index, EGID entityId = default)
|
public OptionalRef(NB<T> array, uint index, EGID entityId = default)
|
||||||
{
|
{
|
||||||
|
@ -23,6 +25,7 @@ namespace TechbloxModdingAPI.Utility
|
||||||
this.entityId = entityId;
|
this.entityId = entityId;
|
||||||
initializer = default;
|
initializer = default;
|
||||||
managedArray = default;
|
managedArray = default;
|
||||||
|
obj = default;
|
||||||
}
|
}
|
||||||
|
|
||||||
public OptionalRef(MB<T> array, uint index, EGID entityId = default)
|
public OptionalRef(MB<T> array, uint index, EGID entityId = default)
|
||||||
|
@ -33,6 +36,7 @@ namespace TechbloxModdingAPI.Utility
|
||||||
this.entityId = entityId;
|
this.entityId = entityId;
|
||||||
initializer = default;
|
initializer = default;
|
||||||
this.array = default;
|
this.array = default;
|
||||||
|
obj = default;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -56,6 +60,7 @@ namespace TechbloxModdingAPI.Utility
|
||||||
array = default;
|
array = default;
|
||||||
index = default;
|
index = default;
|
||||||
managedArray = default;
|
managedArray = default;
|
||||||
|
this.obj = obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -66,7 +71,10 @@ namespace TechbloxModdingAPI.Utility
|
||||||
{
|
{
|
||||||
CompRefCache.Default = default; //The default value can be changed by mods
|
CompRefCache.Default = default; //The default value can be changed by mods
|
||||||
if (state == State.Empty) return ref CompRefCache.Default;
|
if (state == State.Empty) return ref CompRefCache.Default;
|
||||||
if ((state & State.Initializer) != State.Empty) return ref initializer.GetOrAdd<T>();
|
// If initializing the entity, check if the component is allowed by the descriptor, otherwise it could cause
|
||||||
|
// issues in the game with Add() calls running unexpectedly
|
||||||
|
if ((state & State.Initializer) != State.Empty && obj.AllowedEntityComponents.Contains(typeof(T)))
|
||||||
|
return ref initializer.GetOrAdd<T>();
|
||||||
if ((state & State.Native) != State.Empty) return ref array[index];
|
if ((state & State.Native) != State.Empty) return ref array[index];
|
||||||
return ref managedArray[index];
|
return ref managedArray[index];
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue