diff --git a/TechbloxModdingAPI/Blocks/Engines/RemovalEngine.cs b/TechbloxModdingAPI/Blocks/Engines/RemovalEngine.cs index 0610a18..e4e899b 100644 --- a/TechbloxModdingAPI/Blocks/Engines/RemovalEngine.cs +++ b/TechbloxModdingAPI/Blocks/Engines/RemovalEngine.cs @@ -22,7 +22,7 @@ namespace TechbloxModdingAPI.Blocks.Engines { private static IEntityFunctions _entityFunctions; private static MachineGraphConnectionEntityFactory _connectionFactory; - private NativeHashSet removedConnections = new(2000, Allocator.Persistent); + private NativeHashSet removedConnections; public bool RemoveBlock(EGID target) { @@ -44,6 +44,7 @@ namespace TechbloxModdingAPI.Blocks.Engines public void Ready() { + removedConnections = new(2000, Allocator.Persistent); } public EntitiesDB entitiesDB { get; set; } @@ -77,7 +78,8 @@ namespace TechbloxModdingAPI.Blocks.Engines public JobHandle DeterministicStep(in float deltaTime, JobHandle inputDeps) { - removedConnections.Clear(); + if (removedConnections.IsCreated) + removedConnections.Clear(); return default; } } diff --git a/TechbloxModdingAPI/Blocks/Engines/SignalEngine.cs b/TechbloxModdingAPI/Blocks/Engines/SignalEngine.cs index ffd2b07..a30f638 100644 --- a/TechbloxModdingAPI/Blocks/Engines/SignalEngine.cs +++ b/TechbloxModdingAPI/Blocks/Engines/SignalEngine.cs @@ -226,27 +226,27 @@ namespace TechbloxModdingAPI.Blocks.Engines uint entityID = (output ? ports.firstOutputID : ports.firstInputID) + i; if (!mapper.TryGetArrayAndEntityIndex(entityID, out var index, out var array) || array[index].usage != portUsage) continue; - return new OptionalRef(array, index); + return new OptionalRef(array, index, new EGID(entityID, group)); } return default; } - public ref WireEntityStruct MatchPortToWire(PortEntityStruct port, EGID blockID, out bool exists) + public OptionalRef MatchPortToWire(PortEntityStruct port, EGID blockID, out EGID wireID) { - var (wires, count) = entitiesDB.QueryEntities(NamedExclusiveGroup.Group); + var (wires, ids, count) = entitiesDB.QueryEntities(NamedExclusiveGroup.Group); for (uint i = 0; i < count; i++) { if ((wires[i].destinationPortUsage == port.usage && wires[i].destinationBlockEGID == blockID) || (wires[i].sourcePortUsage == port.usage && wires[i].sourceBlockEGID == blockID)) { - exists = true; - return ref wires[i]; + wireID = new EGID(ids[i], BuildModeWiresGroups.WiresGroup.Group); + return new OptionalRef(wires, i); } } - exists = false; - WireEntityStruct[] defRef = new WireEntityStruct[1]; - return ref defRef[0]; + + wireID = default; + return default; } public EGID MatchBlocksToWire(EGID startBlock, EGID endBlock, byte startPort = byte.MaxValue, byte endPort = byte.MaxValue) @@ -275,19 +275,23 @@ namespace TechbloxModdingAPI.Blocks.Engines endPorts = new EGID[] {new EGID(ports.firstInputID + endPort, NamedExclusiveGroup.Group) }; } - var (wires, count) = entitiesDB.QueryEntities(NamedExclusiveGroup.Group); for (int endIndex = 0; endIndex < endPorts.Length; endIndex++) { PortEntityStruct endPES = entitiesDB.QueryEntity(endPorts[endIndex]); for (int startIndex = 0; startIndex < startPorts.Length; startIndex++) { PortEntityStruct startPES = entitiesDB.QueryEntity(startPorts[startIndex]); + foreach (var wire in entitiesDB.QueryEntitiesOptional( + NamedExclusiveGroup.Group)) + { + + } for (int w = 0; w < count; w++) { if ((wires[w].destinationPortUsage == endPES.usage && wires[w].destinationBlockEGID == endBlock) && (wires[w].sourcePortUsage == startPES.usage && wires[w].sourceBlockEGID == startBlock)) { - return wires[w].ID; + return new EGID(ids[w], NamedExclusiveGroup.Group); } } } @@ -308,12 +312,12 @@ namespace TechbloxModdingAPI.Blocks.Engines public EGID[] GetElectricBlocks() { var res = new FasterList(); - foreach (var ((coll, count), _) in entitiesDB.QueryEntities()) + foreach (var ((coll, ids, count), _) in entitiesDB.QueryEntities()) { for (int i = 0; i < count; i++) { ref BlockPortsStruct s = ref coll[i]; - //res.Add(s.ID); - TODO + //res.Add(s.ID); - TODO: Would need to search for the groups for each block } } diff --git a/TechbloxModdingAPI/Blocks/SignalingBlock.cs b/TechbloxModdingAPI/Blocks/SignalingBlock.cs index 7ae6e6a..bf679c4 100644 --- a/TechbloxModdingAPI/Blocks/SignalingBlock.cs +++ b/TechbloxModdingAPI/Blocks/SignalingBlock.cs @@ -46,9 +46,9 @@ namespace TechbloxModdingAPI.Blocks /// The connected wire. /// Port identifier. /// Whether the port has a wire connected to it. - protected ref WireEntityStruct GetConnectedWire(PortEntityStruct port, out bool connected) + protected OptionalRef GetConnectedWire(PortEntityStruct port, out EGID egid) { - return ref SignalEngine.MatchPortToWire(port, Id, out connected); + return SignalEngine.MatchPortToWire(port, Id, out egid); } /// diff --git a/TechbloxModdingAPI/Blocks/Wire.cs b/TechbloxModdingAPI/Blocks/Wire.cs index e59312d..41a8791 100644 --- a/TechbloxModdingAPI/Blocks/Wire.cs +++ b/TechbloxModdingAPI/Blocks/Wire.cs @@ -5,6 +5,7 @@ using Svelto.ECS; using Svelto.ECS.Experimental; using TechbloxModdingAPI.Blocks.Engines; +using TechbloxModdingAPI.Utility; namespace TechbloxModdingAPI.Blocks { @@ -45,9 +46,9 @@ namespace TechbloxModdingAPI.Blocks { var port = signalEngine.MatchBlockIOToPort(end, endPort, false); if (!port) return null; - WireEntityStruct wire = signalEngine.MatchPortToWire(port, end.Id, out var exists); - return exists - ? new Wire(wire.sourceBlockEGID, end.Id, wire.sourcePortUsage, endPort, wire.ID, false) + var wire = signalEngine.MatchPortToWire(port, end.Id, out var egid); + return wire + ? new Wire(wire.Get().sourceBlockEGID, end.Id, wire.Get().sourcePortUsage, endPort, egid, false) : null; } @@ -62,9 +63,9 @@ namespace TechbloxModdingAPI.Blocks { var port = signalEngine.MatchBlockIOToPort(start, startPort, true); if (!port) return null; - WireEntityStruct wire = signalEngine.MatchPortToWire(port, start.Id, out var exists); - return exists - ? new Wire(start.Id, wire.destinationBlockEGID, startPort, wire.destinationPortUsage, wire.ID, false) + var wire = signalEngine.MatchPortToWire(port, start.Id, out var egid); + return wire + ? new Wire(start.Id, wire.Get().destinationBlockEGID, startPort, wire.Get().destinationPortUsage, egid, false) : null; } diff --git a/TechbloxModdingAPI/Utility/ManagedApiExtensions.cs b/TechbloxModdingAPI/Utility/ManagedApiExtensions.cs index b67705f..fb8d758 100644 --- a/TechbloxModdingAPI/Utility/ManagedApiExtensions.cs +++ b/TechbloxModdingAPI/Utility/ManagedApiExtensions.cs @@ -1,3 +1,5 @@ +using System.Collections; +using System.Collections.Generic; using Svelto.ECS; using Svelto.ECS.Hybrid; @@ -18,7 +20,7 @@ namespace TechbloxModdingAPI.Utility { return entitiesDB.TryQueryEntitiesAndIndex(egid, out uint index, out var array) ? new OptionalRef(array, index) - : new OptionalRef(); + : new OptionalRef(); } /// @@ -29,7 +31,8 @@ namespace TechbloxModdingAPI.Utility /// The group of the entity if the object can have multiple /// The component to query /// A reference to the component or a dummy value - public static OptionalRef QueryEntityOptional(this EntitiesDB entitiesDB, EcsObjectBase obj, ExclusiveGroupStruct group = default) + public static OptionalRef QueryEntityOptional(this EntitiesDB entitiesDB, EcsObjectBase obj, + ExclusiveGroupStruct group = default) where T : struct, IEntityViewComponent { EGID id = group == ExclusiveGroupStruct.Invalid ? obj.Id : new EGID(obj.Id.entityID, group); @@ -45,7 +48,8 @@ namespace TechbloxModdingAPI.Utility /// The group of the entity if the object can have multiple /// The component to query /// A reference to the component or a dummy value - public static ref T QueryEntityOrDefault(this EntitiesDB entitiesDB, EcsObjectBase obj, ExclusiveGroupStruct group = default) + public static ref T QueryEntityOrDefault(this EntitiesDB entitiesDB, EcsObjectBase obj, + ExclusiveGroupStruct group = default) where T : struct, IEntityViewComponent { EGID id = group == ExclusiveGroupStruct.Invalid ? obj.Id : new EGID(obj.Id.entityID, group); @@ -54,5 +58,19 @@ namespace TechbloxModdingAPI.Utility if (obj.InitData.Valid) return ref obj.InitData.Initializer(id).GetOrAdd(); return ref opt.Get(); //Default value } + + /// + /// Query entities as OptionalRefs. The elements always exist, it's just a nice way to encapsulate the data. + /// + /// + /// + /// + /// + /// + /// + public static RefCollection QueryEntitiesOptional(this EntitiesDB entitiesDB, ExclusiveGroupStruct group) where T : struct, IBaseEntityComponent + { + return entitiesDB.QueryEntities(group); + } } } \ No newline at end of file diff --git a/TechbloxModdingAPI/Utility/NativeApiExtensions.cs b/TechbloxModdingAPI/Utility/NativeApiExtensions.cs index dec1eb0..a673bc4 100644 --- a/TechbloxModdingAPI/Utility/NativeApiExtensions.cs +++ b/TechbloxModdingAPI/Utility/NativeApiExtensions.cs @@ -22,7 +22,7 @@ namespace TechbloxModdingAPI.Utility { return entitiesDB.TryQueryEntitiesAndIndex(egid, out uint index, out var array) ? new OptionalRef(array, index) - : new OptionalRef(); + : new OptionalRef(); } /// @@ -33,7 +33,8 @@ namespace TechbloxModdingAPI.Utility /// The group of the entity if the object can have multiple /// The component to query /// A reference to the component or a dummy value - public static OptionalRef QueryEntityOptional(this EntitiesDB entitiesDB, EcsObjectBase obj, ExclusiveGroupStruct group = default) + public static OptionalRef QueryEntityOptional(this EntitiesDB entitiesDB, EcsObjectBase obj, + ExclusiveGroupStruct group = default) where T : unmanaged, IEntityComponent { EGID id = group == ExclusiveGroupStruct.Invalid ? obj.Id : new EGID(obj.Id.entityID, group); @@ -49,7 +50,8 @@ namespace TechbloxModdingAPI.Utility /// The group of the entity if the object can have multiple /// The component to query /// A reference to the component or a dummy value - public static ref T QueryEntityOrDefault(this EntitiesDB entitiesDB, EcsObjectBase obj, ExclusiveGroupStruct group = default) + public static ref T QueryEntityOrDefault(this EntitiesDB entitiesDB, EcsObjectBase obj, + ExclusiveGroupStruct group = default) where T : unmanaged, IEntityComponent { EGID id = group == ExclusiveGroupStruct.Invalid ? obj.Id : new EGID(obj.Id.entityID, group); @@ -76,8 +78,9 @@ namespace TechbloxModdingAPI.Utility /// The component that changed public static void PublishEntityChangeDelayed(this EntitiesDB entitiesDB, EGID id, int limit = 80) where T : unmanaged, IEntityComponent - { //TODO: Doesn't seem to help - if(!ChangesToPublish.ContainsKey(typeof(T))) + { + //TODO: Doesn't seem to help + if (!ChangesToPublish.ContainsKey(typeof(T))) ChangesToPublish.Add(typeof(T), (0, new HashSet())); var changes = ChangesToPublish[typeof(T)].Changes; if (changes.Contains(id)) return; @@ -98,5 +101,15 @@ namespace TechbloxModdingAPI.Utility yield return Yield.It; ChangesToPublish[typeof(T)] = (0, changes); } + + public static IEnumerable QueryEntities(this EntitiesDB entitiesDB, ExclusiveGroupStruct group, + ManagedApiExtensions.EntityEnumeratorSelect select) where T : unmanaged, IEntityComponent + { + var (coll, ids, count) = entitiesDB.QueryEntities(group); + for (uint i = 0; i < count; i++) + { + yield return select(ref coll[i], new EGID(ids[i], group)); + } + } } } \ No newline at end of file diff --git a/TechbloxModdingAPI/Utility/OptionalRef.cs b/TechbloxModdingAPI/Utility/OptionalRef.cs index a5e26b6..e1dfb4b 100644 --- a/TechbloxModdingAPI/Utility/OptionalRef.cs +++ b/TechbloxModdingAPI/Utility/OptionalRef.cs @@ -4,8 +4,9 @@ using Svelto.ECS; namespace TechbloxModdingAPI.Utility { - public ref struct OptionalRef where T : struct, IEntityComponent + public ref struct OptionalRef where T : struct, IBaseEntityComponent { + private readonly EGID entityId; private readonly State state; private readonly uint index; private NB array; @@ -13,19 +14,21 @@ namespace TechbloxModdingAPI.Utility private readonly EntityInitializer initializer; //The possible fields are: (index && (array || managedArray)) || initializer - public OptionalRef(NB array, uint index) + public OptionalRef(NB array, uint index, EGID entityId = default) { state = State.Native; this.array = array; this.index = index; + this.entityId = entityId; initializer = default; } - public OptionalRef(MB array, uint index) + public OptionalRef(MB array, uint index, EGID entityId = default) { state = State.Managed; managedArray = array; this.index = index; + this.entityId = entityId; initializer = default; this.array = default; } @@ -35,8 +38,9 @@ namespace TechbloxModdingAPI.Utility /// /// The object with the initializer /// Whether the struct is unmanaged - public OptionalRef(EcsObjectBase obj, bool unmanaged) + public OptionalRef(EcsObjectBase obj, bool unmanaged, EGID entityId = default) { + this.entityId = entityId; if (obj.InitData.Valid) { initializer = obj.InitData.Initializer(obj.Id); @@ -80,6 +84,8 @@ namespace TechbloxModdingAPI.Utility public static implicit operator bool(OptionalRef opt) => opt.state != State.Empty; + public static implicit operator EGID(OptionalRef opt) => opt.entityId; + /// /// Creates an instance of a struct T that can be referenced. /// diff --git a/TechbloxModdingAPI/Utility/RefCollection.cs b/TechbloxModdingAPI/Utility/RefCollection.cs new file mode 100644 index 0000000..13a91d2 --- /dev/null +++ b/TechbloxModdingAPI/Utility/RefCollection.cs @@ -0,0 +1,88 @@ +using System; +using Svelto.DataStructures; +using Svelto.ECS; +using Svelto.ECS.Hybrid; +using Svelto.ECS.Internal; + +namespace TechbloxModdingAPI.Utility +{ + public ref struct RefCollection where T : struct, IBaseEntityComponent + { + private readonly bool managed; + private int count; + private NB nativeArray; + private MB managedArray; + private NativeEntityIDs nativeIDs; + private ManagedEntityIDs managedIDs; + + private RefCollection(EntityCollection coll, T inst = default) + { + if (inst is IEntityComponent) + { + DeconstructCollection(coll); + } + if (typeof(T).IsAssignableFrom(typeof(IEntityViewComponent))) + { + (managedArray, managedIDs, count) = coll2; + } + } + + private void DeconstructCollection(EntityCollection coll) where TM : struct, IEntityViewComponent + where TN : unmanaged, IEntityComponent + { + switch (coll) + { + case EntityCollection cm: + { + MB ma; + (ma, managedIDs, count) = cm; + if (ma is MB mb) + managedArray = mb; + else + throw new InvalidCastException("Expected managed buffer in managed entity collection! Wut"); + break; + } + case EntityCollection cn: + { + NB na; + (na, nativeIDs, count) = cn; + if (na is NB nb) + nativeArray = nb; + else + throw new InvalidCastException("Expected native buffer in native entity collection! Wut"); + break; + } + } + } + + public static implicit operator RefCollection(EntityCollection coll) + { + return new RefCollection(coll); + } + + public Enumerator GetEnumerator() => new(this); + + public ref struct Enumerator + { + private RefCollection collection; + private uint index; + public Enumerator(RefCollection collection) + { + index = default; + this.collection = collection; + } + + public OptionalRef Current => collection.coll.[index]; + + public bool MoveNext() + { + return true; + } + } + + private static void Test(EntityCollection coll) where TN : unmanaged, IEntityComponent + { + + } + } +} \ No newline at end of file