fix changes

This commit is contained in:
Mikhail 2023-04-06 23:40:47 +08:00
parent b565510a69
commit b2958cd0de
10 changed files with 303 additions and 201 deletions

View File

@ -5,6 +5,8 @@ using delayedOp = System.Int32;
namespace DCFApixels.DragonECS
{
[StructLayout(LayoutKind.Sequential, Pack = 0, Size = 8)]
public readonly ref struct EcsReadonlyGroup
{
@ -242,7 +244,7 @@ namespace DCFApixels.DragonECS
private readonly EcsGroup _source;
private readonly int[] _dense;
private readonly int _count;
private int _pointer;
private int _index;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Enumerator(EcsGroup group)
@ -250,26 +252,22 @@ namespace DCFApixels.DragonECS
_source = group;
_dense = group._dense;
_count = group.Count;
_pointer = 0;
_index = 0;
}
public ent Current
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _source.World.GetEntity(_dense[_pointer]);
get => _source.World.GetEntity(_dense[_index]);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool MoveNext()
{
return ++_pointer <= _count && _count < _dense.Length; //_count < _dense.Length дает среде понять что проверки на выход за границы не нужны
// <= потму что отсчет начинается с индекса 1
return ++_index <= _count && _count < _dense.Length; //_count < _dense.Length дает среде понять что проверки на выход за границы не нужны
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Dispose()
{
_source.Unlock();
}
public void Dispose() => _source.Unlock();
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Reset() { }

View File

@ -1,60 +1,51 @@
using System;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Unity.Profiling;
namespace DCFApixels.DragonECS
{
public interface IEcsPool
{
public int EntitiesCount { get; }
public int Capacity { get; }
public Type ComponentType { get; }
public int ComponentID { get; }
public IEcsWorld World { get; }
public Type DataType { get; }
public int ID { get; }
public int Count { get; }
public int Capacity { get; }
public bool Has(int entityID);
public void Write(int entityID);
public void Del(int entityID);
internal void OnWorldResize(int newSize);
}
public interface IEcsPool<T> : IEcsPool
where T : struct
public interface IEcsPool<T> : IEcsPool where T : struct
{
public ref readonly T Read(int entity);
public new ref T Write(int entity);
}
public class EcsNullPool : IEcsPool
public struct NullComponent { }
public sealed class EcsNullPool : IEcsPool<NullComponent>
{
public static EcsNullPool instance => new EcsNullPool(null);
private readonly IEcsWorld _source;
public EcsNullPool(IEcsWorld source)
{
_source = source;
}
private EcsNullPool(IEcsWorld source) => _source = source;
private NullComponent fakeComponent;
public Type ComponentType => typeof(NullComponent);
public int ComponentID => -1;
public IEcsWorld World => _source;
public Type DataType => typeof(void);
public int ID => -1;
public int EntitiesCount => 0;
public int Count => 0;
public int Capacity => 1;
public void Del(int index) { }
public bool Has(int index) => false;
public void Write(int index) { }
void IEcsPool.Write(int entityID) { }
public ref readonly NullComponent Read(int entity) => ref fakeComponent;
public ref NullComponent Write(int entity) => ref fakeComponent;
void IEcsPool.OnWorldResize(int newSize) { }
}
public class EcsPool<T> : IEcsPool<T>
public sealed class EcsPool<T> : IEcsPool<T>
where T : struct
{
private readonly int _id;
private readonly int _componentID;
private readonly IEcsWorld _source;
private int[] _mapping;// index = entity / value = itemIndex;/ value = 0 = no entity
@ -68,19 +59,18 @@ namespace DCFApixels.DragonECS
private PoolRunnres _poolRunnres;
#region Properites
public int EntitiesCount => _itemsCount;
public int Count => _itemsCount;
public int Capacity => _items.Length;
public IEcsWorld World => _source;
public Type DataType => typeof(T);
public int ID => _id;
public Type ComponentType => typeof(T);
public int ComponentID => _componentID;
#endregion
#region Constructors
internal EcsPool(IEcsWorld source, int id, int capacity, PoolRunnres poolRunnres)
{
_source = source;
_id = id;
_componentID = id;
_mapping = new int[source.EntitesCapacity];
_recycledItems = new int[128];
@ -94,7 +84,6 @@ namespace DCFApixels.DragonECS
#endregion
#region Write/Read/Has/Del
private ProfilerMarker _writeMark = new ProfilerMarker("EcsPoo.Write");
private ProfilerMarker _readMark = new ProfilerMarker("EcsPoo.Read");
private ProfilerMarker _hasMark = new ProfilerMarker("EcsPoo.Has");
@ -119,7 +108,7 @@ namespace DCFApixels.DragonECS
}
_mapping[entityID] = itemIndex;
_componentResetHandler.Reset(ref _items[itemIndex]);
_source.OnEntityComponentAdded(entityID, _id);
_source.OnEntityComponentAdded(entityID, _componentID);
_poolRunnres.add.OnComponentAdd<T>(entityID);
}
@ -148,7 +137,7 @@ namespace DCFApixels.DragonECS
_recycledItems[_recycledItemsCount++] = _mapping[entityID];
_mapping[entityID] = 0;
_itemsCount--;
_source.OnEntityComponentRemoved(entityID, _id);
_source.OnEntityComponentRemoved(entityID, _componentID);
_poolRunnres.del.OnComponentDel<T>(entityID);
// }
}
@ -161,17 +150,16 @@ namespace DCFApixels.DragonECS
}
#endregion
#region Equals/GetHashCode
public override bool Equals(object obj)
{
return base.Equals(obj);
}
public override int GetHashCode() => _source.GetHashCode() + ID;
#region Object
public override bool Equals(object obj) => base.Equals(obj);
public override int GetHashCode() => _source.GetHashCode() + ~ComponentID;
#endregion
#region Internal
void IEcsPool.OnWorldResize(int newSize)
{
Array.Resize(ref _mapping, newSize);
}
#endregion
}
}

View File

@ -1,46 +1,51 @@
using DCFApixels.DragonECS;
using DCFApixels.DragonECS.Internal;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEditorInternal;
namespace DCFApixels.Assets.DragonECS.src
namespace DCFApixels.DragonECS
{
public class EcsRelationTable
/* public interface IEcsRealationTable : IEcsReadonlyTable
{
public EcsFilter Relations<TComponent>() where TComponent : struct;
}
public sealed class EcsRelationTable<TArchetype> : IEcsRealationTable
where TArchetype : EcsRelationTableArchetypeBase
{
public readonly IEcsWorld leftWorld;
public readonly IEcsWorld rightWorld;
private int[] _relationEntities; //dense
private int[] _relations; //dense
private int[] _leftMapping;
private int[] _rgihtMapping;
private int _relationsCount;
private IEcsPool[] _pools;
private EcsNullPool _nullPool;
#region Properties
public int RelationsCount
{
get => _relationsCount;
}
public Type ArchetypeType => typeof(TArchetype);
public int EntitesCount => _relationsCount;
public int EntitesCapacity => _relations.Length;
#endregion
#region Constructors
internal EcsRelationTable(IEcsWorld leftWorld, IEcsWorld rightWorld)
{
this.leftWorld = leftWorld;
this.rightWorld = rightWorld;
_relationEntities = new int[512];
_relations = new int[512];
_leftMapping = new int[512];
_rgihtMapping = new int[512];
_relationsCount = 0;
}
#endregion
#region RealtionControls
public void AddRelation(int leftEnttiyID, int rightEntityID)
{
@ -53,5 +58,80 @@ namespace DCFApixels.Assets.DragonECS.src
{
}
}
#endregion
public ReadOnlySpan<IEcsPool> GetAllPools()
{
throw new NotImplementedException();
}
public int GetComponentID<T>()
{
throw new NotImplementedException();
}
public EcsPool<T> GetPool<T>() where T : struct
{
throw new NotImplementedException();
}
public EcsPool<T> UncheckedGetPool<T>() where T : struct
{
throw new NotImplementedException();
}
public EcsFilter Entities<TComponent>() where TComponent : struct
{
throw new NotImplementedException();
}
public EcsFilter Filter<TInc>() where TInc : struct, IInc
{
throw new NotImplementedException();
}
public EcsFilter Filter<TInc, TExc>()
where TInc : struct, IInc
where TExc : struct, IExc
{
throw new NotImplementedException();
}
public bool IsMaskCompatible<TInc>(int entity) where TInc : struct, IInc
{
throw new NotImplementedException();
}
public bool IsMaskCompatible<TInc, TExc>(int entity)
where TInc : struct, IInc
where TExc : struct, IExc
{
throw new NotImplementedException();
}
public bool IsMaskCompatible(EcsMask mask, int entity)
{
throw new NotImplementedException();
}
public bool IsMaskCompatibleWithout(EcsMask mask, int entity, int otherPoolID)
{
throw new NotImplementedException();
}
void IEcsReadonlyTable.OnEntityComponentAdded(int entityID, int changedPoolID)
{
throw new NotImplementedException();
}
void IEcsReadonlyTable.OnEntityComponentRemoved(int entityID, int changedPoolID)
{
throw new NotImplementedException();
}
void IEcsReadonlyTable.RegisterGroup(EcsGroup group)
{
throw new NotImplementedException();
}
}*/
}

View File

@ -1,52 +1,29 @@
using System;
using DCFApixels.DragonECS.Internal;
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace DCFApixels.DragonECS
{
public interface IEcsWorld
public interface IEcsWorld : IEcsReadonlyTable
{
#region Properties
//private float _timeScale;//TODO реализовать собсвенныйтайм склей для разных миров
public bool IsEmpty { get; }
public Type ArchetypeType { get; }
public int ID { get; }
public EcsPipeline Pipeline { get; }
public int EntitesCount { get; }
public int EntitesCapacity { get; }
#endregion
#region GetterMethods
public ReadOnlySpan<IEcsPool> GetAllPools();
#endregion
#region Methods
public EcsPool<T> GetPool<T>() where T : struct;
public EcsPool<T> UncheckedGetPool<T>() where T : struct;
#region Entities
public EcsFilter Entities<TComponent>() where TComponent : struct;
public EcsFilter Filter<TInc>() where TInc : struct, IInc;
public EcsFilter Filter<TInc, TExc>() where TInc : struct, IInc where TExc : struct, IExc;
public ent NewEntity();
public void DelEntity(ent entity);
public bool EntityIsAlive(int entityID, short gen);
public ent GetEntity(int entityID);
public void Destroy();
public bool IsMaskCompatible<TInc>(int entity) where TInc : struct, IInc;
public bool IsMaskCompatible<TInc, TExc>(int entity) where TInc : struct, IInc where TExc : struct, IExc;
public bool IsMaskCompatible(EcsMask mask, int entity);
public bool IsMaskCompatibleWithout(EcsMask mask, int entity, int otherPoolID);
internal void OnEntityComponentAdded(int entityID, int changedPoolID);
internal void OnEntityComponentRemoved(int entityID, int changedPoolID);
public int GetComponentID<T>();
internal void RegisterGroup(EcsGroup group);
#endregion
}
@ -57,12 +34,19 @@ namespace DCFApixels.DragonECS
public readonly short id;
public EcsWorld()
protected EcsWorld(bool isIndexed)
{
id = (short)_worldIdDispenser.GetFree();
if(id >= Worlds.Length)
Array.Resize(ref Worlds, Worlds.Length << 1);
Worlds[id] = (IEcsWorld)this;
if(isIndexed == true)
{
id = (short)_worldIdDispenser.GetFree();
if (id >= Worlds.Length)
Array.Resize(ref Worlds, Worlds.Length << 1);
Worlds[id] = (IEcsWorld)this;
}
else
{
id = -1;
}
}
protected void Realeze()
@ -106,8 +90,12 @@ namespace DCFApixels.DragonECS
#endregion
#region Internal Properties
int IEcsReadonlyTable.Count => _entitiesCount;
int IEcsReadonlyTable.Capacity => _denseEntities.Length;
#endregion
#region Properties
public bool IsEmpty => _entitiesCount < 0;
public Type ArchetypeType => typeof(TArchetype);
public int ID => id;
public EcsPipeline Pipeline => _pipeline;
@ -117,12 +105,12 @@ namespace DCFApixels.DragonECS
#endregion
#region Constructors
public EcsWorld(EcsPipeline pipline = null)
public EcsWorld(EcsPipeline pipline = null) : base(true)
{
_pipeline = pipline ?? EcsPipeline.Empty;
if (!_pipeline.IsInit) pipline.Init();
_entityDispenser = new IntDispenser(1);
_nullPool = new EcsNullPool(this);
_nullPool = EcsNullPool.instance;
_pools = new IEcsPool[512];
FillArray(_pools, _nullPool);
@ -154,7 +142,6 @@ namespace DCFApixels.DragonECS
int oldCapacity = _pools.Length;
Array.Resize(ref _pools, ComponentType.Capacity);
FillArray(_pools, _nullPool, oldCapacity, oldCapacity - _pools.Length);
//Array.Fill(_pools, _nullPool, oldCapacity, oldCapacity - _pools.Length); //TODO Fix it
Array.Resize(ref _filtersByIncludedComponents, ComponentType.Capacity);
Array.Resize(ref _filtersByExcludedComponents, ComponentType.Capacity);
@ -285,7 +272,7 @@ namespace DCFApixels.DragonECS
#region EntityChangedReact
void IEcsWorld.OnEntityComponentAdded(int entityID, int componentID)
void IEcsReadonlyTable.OnEntityComponentAdded(int entityID, int componentID)
{
var includeList = _filtersByIncludedComponents[componentID];
var excludeList = _filtersByExcludedComponents[componentID];
@ -316,7 +303,7 @@ namespace DCFApixels.DragonECS
// if (excludeList != null) foreach (var filter in excludeList) filter.entities.Remove(entityID);
}
void IEcsWorld.OnEntityComponentRemoved(int entityID, int componentID)
void IEcsReadonlyTable.OnEntityComponentRemoved(int entityID, int componentID)
{
var includeList = _filtersByIncludedComponents[componentID];
var excludeList = _filtersByExcludedComponents[componentID];
@ -458,7 +445,7 @@ namespace DCFApixels.DragonECS
#endregion
#region Other
void IEcsWorld.RegisterGroup(EcsGroup group)
void IEcsReadonlyTable.RegisterGroup(EcsGroup group)
{
_groups.Add(group);
}

View File

@ -6,45 +6,46 @@ using System.Threading.Tasks;
namespace DCFApixels.DragonECS
{
public interface IEcsEntityComponentTable
public interface IEcsReadonlyTable
{
#region Properties
public bool IsEmpty { get; }
/// <summary>Table Archetype</summary>
public Type ArchetypeType { get; }
//public int ID { get; }
public int EntitesCount { get; }
public int EntitesCapacity { get; }
#endregion
#region GetterMethods
public ReadOnlySpan<IEcsPool> GetAllPools();
#endregion
#region Methods
public ReadOnlySpan<IEcsPool> GetAllPools();
public int GetComponentID<T>();
public EcsPool<T> GetPool<T>() where T : struct;
public EcsPool<T> UncheckedGetPool<T>() where T : struct;
public EcsFilter Entities<TComponent>() where TComponent : struct;
public EcsFilter Filter<TInc>() where TInc : struct, IInc;
public EcsFilter Filter<TInc, TExc>() where TInc : struct, IInc where TExc : struct, IExc;
public ent NewEntity();
public void DelEntity(ent entity);
public bool EntityIsAlive(int entityID, short gen);
public ent GetEntity(int entityID);
public void Destroy();
public bool IsMaskCompatible<TInc>(int entity) where TInc : struct, IInc;
public bool IsMaskCompatible<TInc, TExc>(int entity) where TInc : struct, IInc where TExc : struct, IExc;
public bool IsMaskCompatible(EcsMask mask, int entity);
public bool IsMaskCompatibleWithout(EcsMask mask, int entity, int otherPoolID);
#endregion
#region Properties
internal int Count { get; }
internal int Capacity { get; }
#endregion
#region Internal Methods
internal void OnEntityComponentAdded(int entityID, int changedPoolID);
internal void OnEntityComponentRemoved(int entityID, int changedPoolID);
public int GetComponentID<T>();
internal void RegisterGroup(EcsGroup group);
#endregion
}
public static class IEcsReadonlyEntityComponentTableExtensions
{
public static bool IsNullOrEmpty(this IEcsReadonlyTable self)
{
return self == null || self.Count <= 0;
}
}
}

View File

@ -0,0 +1,7 @@
namespace DCFApixels.DragonECS
{
public interface INullDummy
{
public bool IsDummy { get; }
}
}

View File

@ -0,0 +1,16 @@
using System;
namespace DCFApixels.DragonECS.Internal
{
public abstract class EcsRelationTableArchetypeBase
{
public EcsRelationTableArchetypeBase()
{
throw new TypeAccessException("Сreating instances of EcsRelationTableArchetype class is not available.");
}
}
public sealed class EcsRelationTableArchetype<TLeftWorld, TRightWorld> : EcsRelationTableArchetypeBase
where TLeftWorld : EcsWorld<TLeftWorld>
where TRightWorld : EcsWorld<TRightWorld>
{ }
}

View File

@ -0,0 +1,8 @@
namespace DCFApixels.DragonECS
{
public interface ITabelRecord
{
//TODO rename to index; Так ent по определению станет идентификатором
public int Id { get; }
}
}

View File

@ -5,16 +5,26 @@ using System.Runtime.InteropServices;
namespace DCFApixels.DragonECS
{
public interface IEntityRecord : ITabelRecord
{
public bool IsSpecific { get; }
internal long Full { get; }
public short Gen { get; }
public short World { get; }
}
// id - 32 bits
// gen - 16 bits
// world - 16 bits
[StructLayout(LayoutKind.Explicit, Pack = 2, Size = 8)]
public readonly struct ent : IEquatable<long>, IEquatable<ent>
public readonly partial struct ent :
IEquatable<long>,
IEquatable<ent>,
IEntityRecord
{
public static readonly ent NULL = default;
[FieldOffset(0)]
private readonly long _full;
internal readonly long full; //Union
[FieldOffset(3)]
public readonly int id;
[FieldOffset(1)]
@ -22,44 +32,41 @@ namespace DCFApixels.DragonECS
[FieldOffset(0)]
public readonly short world;
#region IEntityRecord
bool IEntityRecord.IsSpecific => false;
long IEntityRecord.Full => full;
int ITabelRecord.Id => id;
short IEntityRecord.Gen => gen;
short IEntityRecord.World => world;
#endregion
#region Constructors
[EditorBrowsable(EditorBrowsableState.Never)]
public ent(int id, short gen, short world): this()
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ent(int id, short gen, short world) : this()
{
this.id = id;
this.gen = gen;
this.world = world;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal ent(long full) : this()
{
_full = full;
this.full = full;
}
#endregion
#region GetHashCode
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override int GetHashCode()
{
return unchecked((int)(_full)) ^ (int)(_full >> 32);
}
public override int GetHashCode() => unchecked((int)(full)) ^ (int)(full >> 32);
#endregion
#region Equals
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override bool Equals(object obj)
{
return obj is ent other && _full == other._full;
}
public override bool Equals(object obj) => obj is ent other && full == other.full;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(ent other)
{
return _full == other._full;
}
public bool Equals(ent other) => full == other.full;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(long other)
{
return _full == other;
}
public bool Equals(long other) => full == other;
#endregion
#region ToString
@ -69,31 +76,72 @@ namespace DCFApixels.DragonECS
#region operators
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(in ent a, in ent b) => a._full == b._full;
public static bool operator ==(in ent a, in ent b) => a.full == b.full;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(in ent a, in ent b) => a._full != b._full;
public static bool operator !=(in ent a, in ent b) => a.full != b.full;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static explicit operator long(in ent a) => a._full;
public static explicit operator long(in ent a) => a.full;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static explicit operator int(in ent a) => a.id;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static explicit operator ent(in long a) => new ent(a);
#endregion
}
public static partial class entExtensions
public readonly partial struct ent
{
private static EcsProfilerMarker _IsAliveMarker = new EcsProfilerMarker("ent.IsAlive");
private static EcsProfilerMarker _IsNullMarker = new EcsProfilerMarker("ent.IsNull");
private static EcsProfilerMarker _ReadMarker = new EcsProfilerMarker("ent.Read");
private static EcsProfilerMarker _WriteMarker = new EcsProfilerMarker("ent.Write");
private static EcsProfilerMarker _HasMarker = new EcsProfilerMarker("ent.Has");
private static EcsProfilerMarker _DelMarker = new EcsProfilerMarker("ent.Del");
public bool IsNull
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
//using (_IsNullMarker.Auto())
return this == NULL;
}
}
public ref readonly T Read<T>()
where T : struct
{
//using (_ReadMarker.Auto())
return ref EcsWorld.Worlds[world].GetPool<T>().Read(id);
}
public ref T Write<T>()
where T : struct
{
//using (_WriteMarker.Auto())
return ref EcsWorld.Worlds[world].GetPool<T>().Write(id);
}
public bool Has<T>()
where T : struct
{
//using (_HasMarker.Auto())
return EcsWorld.Worlds[world].GetPool<T>().Has(id);
}
public bool NotHas<T>()
where T : struct
{
//using (_HasMarker.Auto())
return EcsWorld.Worlds[world].GetPool<T>().Has(id);
}
public void Del<T>()
where T : struct
{
//using (_DelMarker.Auto())
EcsWorld.Worlds[world].GetPool<T>().Del(id);
}
}
public static partial class entExtensions
{
private static EcsProfilerMarker _IsAliveMarker = new EcsProfilerMarker("ent.IsAlive");
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsAlive(this ref ent self)
{
@ -104,43 +152,5 @@ namespace DCFApixels.DragonECS
return result;
//}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsNull(this in ent self)
{
//using (_IsNullMarker.Auto())
return self == ent.NULL;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ref readonly T Read<T>(this in ent self)
where T : struct
{
//using (_ReadMarker.Auto())
return ref EcsWorld.Worlds[self.world].GetPool<T>().Read(self.id);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ref T Write<T>(this in ent self)
where T : struct
{
//using (_WriteMarker.Auto())
return ref EcsWorld.Worlds[self.world].GetPool<T>().Write(self.id);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool Has<T>(this in ent self)
where T : struct
{
//using (_HasMarker.Auto())
return EcsWorld.Worlds[self.world].GetPool<T>().Has(self.id);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool NotHas<T>(this in ent self) where T : struct => !Has<T>(in self);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Del<T>(this in ent self)
where T : struct
{
//using (_DelMarker.Auto())
EcsWorld.Worlds[self.world].GetPool<T>().Del(self.id);
}
}
}

View File

@ -16,14 +16,21 @@ namespace DCFApixels.DragonECS.TODO
// left entity id - 32 bits
// right entity id - 32 bits
[StructLayout(LayoutKind.Explicit, Pack = 4, Size = 8)]
public struct rel
[StructLayout(LayoutKind.Sequential, Pack = 0, Size = 8)]
public readonly ref partial struct rel
{
[FieldOffset(0)]
public int l;
[FieldOffset(1)]
public int r;
public readonly int id;
public readonly short leftWorld;
public readonly short rightWorld;
#region Constructors
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public rel(int id, short leftWorld, short rightWorld)
{
this.id = id;
this.leftWorld = leftWorld;
this.rightWorld = rightWorld;
}
#endregion
}
}