Start updating to Techblox 2022.08.11.09.42 and start work on RefCollection

What have I got myself into
This commit is contained in:
Norbi Peti 2022-09-29 00:29:12 +02:00
parent 55344d1352
commit f70b65e796
No known key found for this signature in database
GPG key ID: DBA4C4549A927E56
8 changed files with 166 additions and 34 deletions

View file

@ -22,7 +22,7 @@ namespace TechbloxModdingAPI.Blocks.Engines
{ {
private static IEntityFunctions _entityFunctions; private static IEntityFunctions _entityFunctions;
private static MachineGraphConnectionEntityFactory _connectionFactory; private static MachineGraphConnectionEntityFactory _connectionFactory;
private NativeHashSet<ulong> removedConnections = new(2000, Allocator.Persistent); private NativeHashSet<ulong> removedConnections;
public bool RemoveBlock(EGID target) public bool RemoveBlock(EGID target)
{ {
@ -44,6 +44,7 @@ namespace TechbloxModdingAPI.Blocks.Engines
public void Ready() public void Ready()
{ {
removedConnections = new(2000, Allocator.Persistent);
} }
public EntitiesDB entitiesDB { get; set; } public EntitiesDB entitiesDB { get; set; }
@ -77,6 +78,7 @@ namespace TechbloxModdingAPI.Blocks.Engines
public JobHandle DeterministicStep(in float deltaTime, JobHandle inputDeps) public JobHandle DeterministicStep(in float deltaTime, JobHandle inputDeps)
{ {
if (removedConnections.IsCreated)
removedConnections.Clear(); removedConnections.Clear();
return default; return default;
} }

View file

@ -226,27 +226,27 @@ namespace TechbloxModdingAPI.Blocks.Engines
uint entityID = (output ? ports.firstOutputID : ports.firstInputID) + i; uint entityID = (output ? ports.firstOutputID : ports.firstInputID) + i;
if (!mapper.TryGetArrayAndEntityIndex(entityID, out var index, out var array) || if (!mapper.TryGetArrayAndEntityIndex(entityID, out var index, out var array) ||
array[index].usage != portUsage) continue; array[index].usage != portUsage) continue;
return new OptionalRef<PortEntityStruct>(array, index); return new OptionalRef<PortEntityStruct>(array, index, new EGID(entityID, group));
} }
return default; return default;
} }
public ref WireEntityStruct MatchPortToWire(PortEntityStruct port, EGID blockID, out bool exists) public OptionalRef<WireEntityStruct> MatchPortToWire(PortEntityStruct port, EGID blockID, out EGID wireID)
{ {
var (wires, count) = entitiesDB.QueryEntities<WireEntityStruct>(NamedExclusiveGroup<BuildModeWiresGroups.WiresGroup>.Group); var (wires, ids, count) = entitiesDB.QueryEntities<WireEntityStruct>(NamedExclusiveGroup<BuildModeWiresGroups.WiresGroup>.Group);
for (uint i = 0; i < count; i++) for (uint i = 0; i < count; i++)
{ {
if ((wires[i].destinationPortUsage == port.usage && wires[i].destinationBlockEGID == blockID) if ((wires[i].destinationPortUsage == port.usage && wires[i].destinationBlockEGID == blockID)
|| (wires[i].sourcePortUsage == port.usage && wires[i].sourceBlockEGID == blockID)) || (wires[i].sourcePortUsage == port.usage && wires[i].sourceBlockEGID == blockID))
{ {
exists = true; wireID = new EGID(ids[i], BuildModeWiresGroups.WiresGroup.Group);
return ref wires[i]; return new OptionalRef<WireEntityStruct>(wires, i);
} }
} }
exists = false;
WireEntityStruct[] defRef = new WireEntityStruct[1]; wireID = default;
return ref defRef[0]; return default;
} }
public EGID MatchBlocksToWire(EGID startBlock, EGID endBlock, byte startPort = byte.MaxValue, byte endPort = byte.MaxValue) 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<BuildModeWiresGroups.InputPortsGroup>.Group) }; endPorts = new EGID[] {new EGID(ports.firstInputID + endPort, NamedExclusiveGroup<BuildModeWiresGroups.InputPortsGroup>.Group) };
} }
var (wires, count) = entitiesDB.QueryEntities<WireEntityStruct>(NamedExclusiveGroup<BuildModeWiresGroups.WiresGroup>.Group);
for (int endIndex = 0; endIndex < endPorts.Length; endIndex++) for (int endIndex = 0; endIndex < endPorts.Length; endIndex++)
{ {
PortEntityStruct endPES = entitiesDB.QueryEntity<PortEntityStruct>(endPorts[endIndex]); PortEntityStruct endPES = entitiesDB.QueryEntity<PortEntityStruct>(endPorts[endIndex]);
for (int startIndex = 0; startIndex < startPorts.Length; startIndex++) for (int startIndex = 0; startIndex < startPorts.Length; startIndex++)
{ {
PortEntityStruct startPES = entitiesDB.QueryEntity<PortEntityStruct>(startPorts[startIndex]); PortEntityStruct startPES = entitiesDB.QueryEntity<PortEntityStruct>(startPorts[startIndex]);
foreach (var wire in entitiesDB.QueryEntitiesOptional<WireEntityStruct>(
NamedExclusiveGroup<BuildModeWiresGroups.WiresGroup>.Group))
{
}
for (int w = 0; w < count; w++) for (int w = 0; w < count; w++)
{ {
if ((wires[w].destinationPortUsage == endPES.usage && wires[w].destinationBlockEGID == endBlock) if ((wires[w].destinationPortUsage == endPES.usage && wires[w].destinationBlockEGID == endBlock)
&& (wires[w].sourcePortUsage == startPES.usage && wires[w].sourceBlockEGID == startBlock)) && (wires[w].sourcePortUsage == startPES.usage && wires[w].sourceBlockEGID == startBlock))
{ {
return wires[w].ID; return new EGID(ids[w], NamedExclusiveGroup<BuildModeWiresGroups.WiresGroup>.Group);
} }
} }
} }
@ -308,12 +312,12 @@ namespace TechbloxModdingAPI.Blocks.Engines
public EGID[] GetElectricBlocks() public EGID[] GetElectricBlocks()
{ {
var res = new FasterList<EGID>(); var res = new FasterList<EGID>();
foreach (var ((coll, count), _) in entitiesDB.QueryEntities<BlockPortsStruct>()) foreach (var ((coll, ids, count), _) in entitiesDB.QueryEntities<BlockPortsStruct>())
{ {
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
{ {
ref BlockPortsStruct s = ref coll[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
} }
} }

View file

@ -46,9 +46,9 @@ namespace TechbloxModdingAPI.Blocks
/// <returns>The connected wire.</returns> /// <returns>The connected wire.</returns>
/// <param name="portId">Port identifier.</param> /// <param name="portId">Port identifier.</param>
/// <param name="connected">Whether the port has a wire connected to it.</param> /// <param name="connected">Whether the port has a wire connected to it.</param>
protected ref WireEntityStruct GetConnectedWire(PortEntityStruct port, out bool connected) protected OptionalRef<WireEntityStruct> GetConnectedWire(PortEntityStruct port, out EGID egid)
{ {
return ref SignalEngine.MatchPortToWire(port, Id, out connected); return SignalEngine.MatchPortToWire(port, Id, out egid);
} }
/// <summary> /// <summary>

View file

@ -5,6 +5,7 @@ using Svelto.ECS;
using Svelto.ECS.Experimental; using Svelto.ECS.Experimental;
using TechbloxModdingAPI.Blocks.Engines; using TechbloxModdingAPI.Blocks.Engines;
using TechbloxModdingAPI.Utility;
namespace TechbloxModdingAPI.Blocks namespace TechbloxModdingAPI.Blocks
{ {
@ -45,9 +46,9 @@ namespace TechbloxModdingAPI.Blocks
{ {
var port = signalEngine.MatchBlockIOToPort(end, endPort, false); var port = signalEngine.MatchBlockIOToPort(end, endPort, false);
if (!port) return null; if (!port) return null;
WireEntityStruct wire = signalEngine.MatchPortToWire(port, end.Id, out var exists); var wire = signalEngine.MatchPortToWire(port, end.Id, out var egid);
return exists return wire
? new Wire(wire.sourceBlockEGID, end.Id, wire.sourcePortUsage, endPort, wire.ID, false) ? new Wire(wire.Get().sourceBlockEGID, end.Id, wire.Get().sourcePortUsage, endPort, egid, false)
: null; : null;
} }
@ -62,9 +63,9 @@ namespace TechbloxModdingAPI.Blocks
{ {
var port = signalEngine.MatchBlockIOToPort(start, startPort, true); var port = signalEngine.MatchBlockIOToPort(start, startPort, true);
if (!port) return null; if (!port) return null;
WireEntityStruct wire = signalEngine.MatchPortToWire(port, start.Id, out var exists); var wire = signalEngine.MatchPortToWire(port, start.Id, out var egid);
return exists return wire
? new Wire(start.Id, wire.destinationBlockEGID, startPort, wire.destinationPortUsage, wire.ID, false) ? new Wire(start.Id, wire.Get().destinationBlockEGID, startPort, wire.Get().destinationPortUsage, egid, false)
: null; : null;
} }

View file

@ -1,3 +1,5 @@
using System.Collections;
using System.Collections.Generic;
using Svelto.ECS; using Svelto.ECS;
using Svelto.ECS.Hybrid; using Svelto.ECS.Hybrid;
@ -29,7 +31,8 @@ namespace TechbloxModdingAPI.Utility
/// <param name="group">The group of the entity if the object can have multiple</param> /// <param name="group">The group of the entity if the object can have multiple</param>
/// <typeparam name="T">The component to query</typeparam> /// <typeparam name="T">The component to query</typeparam>
/// <returns>A reference to the component or a dummy value</returns> /// <returns>A reference to the component or a dummy value</returns>
public static OptionalRef<T> QueryEntityOptional<T>(this EntitiesDB entitiesDB, EcsObjectBase obj, ExclusiveGroupStruct group = default) public static OptionalRef<T> QueryEntityOptional<T>(this EntitiesDB entitiesDB, EcsObjectBase obj,
ExclusiveGroupStruct group = default)
where T : struct, IEntityViewComponent where T : struct, IEntityViewComponent
{ {
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);
@ -45,7 +48,8 @@ namespace TechbloxModdingAPI.Utility
/// <param name="group">The group of the entity if the object can have multiple</param> /// <param name="group">The group of the entity if the object can have multiple</param>
/// <typeparam name="T">The component to query</typeparam> /// <typeparam name="T">The component to query</typeparam>
/// <returns>A reference to the component or a dummy value</returns> /// <returns>A reference to the component or a dummy value</returns>
public static ref T QueryEntityOrDefault<T>(this EntitiesDB entitiesDB, EcsObjectBase obj, ExclusiveGroupStruct group = default) public static ref T QueryEntityOrDefault<T>(this EntitiesDB entitiesDB, EcsObjectBase obj,
ExclusiveGroupStruct group = default)
where T : struct, IEntityViewComponent where T : struct, IEntityViewComponent
{ {
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);
@ -54,5 +58,19 @@ namespace TechbloxModdingAPI.Utility
if (obj.InitData.Valid) return ref obj.InitData.Initializer(id).GetOrAdd<T>(); if (obj.InitData.Valid) return ref obj.InitData.Initializer(id).GetOrAdd<T>();
return ref opt.Get(); //Default value return ref opt.Get(); //Default value
} }
/// <summary>
/// Query entities as OptionalRefs. The elements always exist, it's just a nice way to encapsulate the data.
/// </summary>
/// <param name="entitiesDB"></param>
/// <param name="group"></param>
/// <param name="select"></param>
/// <typeparam name="T"></typeparam>
/// <typeparam name="TR"></typeparam>
/// <returns></returns>
public static RefCollection<T> QueryEntitiesOptional<T>(this EntitiesDB entitiesDB, ExclusiveGroupStruct group) where T : struct, IBaseEntityComponent
{
return entitiesDB.QueryEntities<T>(group);
}
} }
} }

View file

@ -33,7 +33,8 @@ namespace TechbloxModdingAPI.Utility
/// <param name="group">The group of the entity if the object can have multiple</param> /// <param name="group">The group of the entity if the object can have multiple</param>
/// <typeparam name="T">The component to query</typeparam> /// <typeparam name="T">The component to query</typeparam>
/// <returns>A reference to the component or a dummy value</returns> /// <returns>A reference to the component or a dummy value</returns>
public static OptionalRef<T> QueryEntityOptional<T>(this EntitiesDB entitiesDB, EcsObjectBase obj, ExclusiveGroupStruct group = default) public static OptionalRef<T> QueryEntityOptional<T>(this EntitiesDB entitiesDB, EcsObjectBase obj,
ExclusiveGroupStruct group = default)
where T : unmanaged, IEntityComponent where T : unmanaged, IEntityComponent
{ {
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);
@ -49,7 +50,8 @@ namespace TechbloxModdingAPI.Utility
/// <param name="group">The group of the entity if the object can have multiple</param> /// <param name="group">The group of the entity if the object can have multiple</param>
/// <typeparam name="T">The component to query</typeparam> /// <typeparam name="T">The component to query</typeparam>
/// <returns>A reference to the component or a dummy value</returns> /// <returns>A reference to the component or a dummy value</returns>
public static ref T QueryEntityOrDefault<T>(this EntitiesDB entitiesDB, EcsObjectBase obj, ExclusiveGroupStruct group = default) public static ref T QueryEntityOrDefault<T>(this EntitiesDB entitiesDB, EcsObjectBase obj,
ExclusiveGroupStruct group = default)
where T : unmanaged, IEntityComponent where T : unmanaged, IEntityComponent
{ {
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);
@ -76,7 +78,8 @@ namespace TechbloxModdingAPI.Utility
/// <typeparam name="T">The component that changed</typeparam> /// <typeparam name="T">The component that changed</typeparam>
public static void PublishEntityChangeDelayed<T>(this EntitiesDB entitiesDB, EGID id, int limit = 80) public static void PublishEntityChangeDelayed<T>(this EntitiesDB entitiesDB, EGID id, int limit = 80)
where T : unmanaged, IEntityComponent where T : unmanaged, IEntityComponent
{ //TODO: Doesn't seem to help {
//TODO: Doesn't seem to help
if (!ChangesToPublish.ContainsKey(typeof(T))) if (!ChangesToPublish.ContainsKey(typeof(T)))
ChangesToPublish.Add(typeof(T), (0, new HashSet<EGID>())); ChangesToPublish.Add(typeof(T), (0, new HashSet<EGID>()));
var changes = ChangesToPublish[typeof(T)].Changes; var changes = ChangesToPublish[typeof(T)].Changes;
@ -98,5 +101,15 @@ namespace TechbloxModdingAPI.Utility
yield return Yield.It; yield return Yield.It;
ChangesToPublish[typeof(T)] = (0, changes); ChangesToPublish[typeof(T)] = (0, changes);
} }
public static IEnumerable<TR> QueryEntities<T, TR>(this EntitiesDB entitiesDB, ExclusiveGroupStruct group,
ManagedApiExtensions.EntityEnumeratorSelect<T, TR> select) where T : unmanaged, IEntityComponent
{
var (coll, ids, count) = entitiesDB.QueryEntities<T>(group);
for (uint i = 0; i < count; i++)
{
yield return select(ref coll[i], new EGID(ids[i], group));
}
}
} }
} }

View file

@ -4,8 +4,9 @@ using Svelto.ECS;
namespace TechbloxModdingAPI.Utility namespace TechbloxModdingAPI.Utility
{ {
public ref struct OptionalRef<T> where T : struct, IEntityComponent public ref struct OptionalRef<T> where T : struct, IBaseEntityComponent
{ {
private readonly EGID entityId;
private readonly State state; private readonly State state;
private readonly uint index; private readonly uint index;
private NB<T> array; private NB<T> array;
@ -13,19 +14,21 @@ namespace TechbloxModdingAPI.Utility
private readonly EntityInitializer initializer; private readonly EntityInitializer initializer;
//The possible fields are: (index && (array || managedArray)) || initializer //The possible fields are: (index && (array || managedArray)) || initializer
public OptionalRef(NB<T> array, uint index) public OptionalRef(NB<T> array, uint index, EGID entityId = default)
{ {
state = State.Native; state = State.Native;
this.array = array; this.array = array;
this.index = index; this.index = index;
this.entityId = entityId;
initializer = default; initializer = default;
} }
public OptionalRef(MB<T> array, uint index) public OptionalRef(MB<T> array, uint index, EGID entityId = default)
{ {
state = State.Managed; state = State.Managed;
managedArray = array; managedArray = array;
this.index = index; this.index = index;
this.entityId = entityId;
initializer = default; initializer = default;
this.array = default; this.array = default;
} }
@ -35,8 +38,9 @@ namespace TechbloxModdingAPI.Utility
/// </summary> /// </summary>
/// <param name="obj">The object with the initializer</param> /// <param name="obj">The object with the initializer</param>
/// <param name="unmanaged">Whether the struct is unmanaged</param> /// <param name="unmanaged">Whether the struct is unmanaged</param>
public OptionalRef(EcsObjectBase obj, bool unmanaged) public OptionalRef(EcsObjectBase obj, bool unmanaged, EGID entityId = default)
{ {
this.entityId = entityId;
if (obj.InitData.Valid) if (obj.InitData.Valid)
{ {
initializer = obj.InitData.Initializer(obj.Id); initializer = obj.InitData.Initializer(obj.Id);
@ -80,6 +84,8 @@ namespace TechbloxModdingAPI.Utility
public static implicit operator bool(OptionalRef<T> opt) => opt.state != State.Empty; public static implicit operator bool(OptionalRef<T> opt) => opt.state != State.Empty;
public static implicit operator EGID(OptionalRef<T> opt) => opt.entityId;
/// <summary> /// <summary>
/// Creates an instance of a struct T that can be referenced. /// Creates an instance of a struct T that can be referenced.
/// </summary> /// </summary>

View file

@ -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<T> where T : struct, IBaseEntityComponent
{
private readonly bool managed;
private int count;
private NB<T> nativeArray;
private MB<T> managedArray;
private NativeEntityIDs nativeIDs;
private ManagedEntityIDs managedIDs;
private RefCollection(EntityCollection<T> coll, T inst = default)
{
if (inst is IEntityComponent)
{
DeconstructCollection<T, T>(coll);
}
if (typeof(T).IsAssignableFrom(typeof(IEntityViewComponent)))
{
(managedArray, managedIDs, count) = coll2;
}
}
private void DeconstructCollection<TM, TN>(EntityCollection<T> coll) where TM : struct, IEntityViewComponent
where TN : unmanaged, IEntityComponent
{
switch (coll)
{
case EntityCollection<TM> cm:
{
MB<TM> ma;
(ma, managedIDs, count) = cm;
if (ma is MB<T> mb)
managedArray = mb;
else
throw new InvalidCastException("Expected managed buffer in managed entity collection! Wut");
break;
}
case EntityCollection<TN> cn:
{
NB<TN> na;
(na, nativeIDs, count) = cn;
if (na is NB<T> nb)
nativeArray = nb;
else
throw new InvalidCastException("Expected native buffer in native entity collection! Wut");
break;
}
}
}
public static implicit operator RefCollection<T>(EntityCollection<T> coll)
{
return new RefCollection<T>(coll);
}
public Enumerator GetEnumerator() => new(this);
public ref struct Enumerator
{
private RefCollection<T> collection;
private uint index;
public Enumerator(RefCollection<T> collection)
{
index = default;
this.collection = collection;
}
public OptionalRef<T> Current => collection.coll.[index];
public bool MoveNext()
{
return true;
}
}
private static void Test<TN>(EntityCollection<TN> coll) where TN : unmanaged, IEntityComponent
{
}
}
}