mirror of
https://github.com/DCFApixels/DragonECS.git
synced 2025-11-13 00:55:55 +08:00
ReworkWorld
This commit is contained in:
parent
d64d4407c9
commit
b73652cb37
454
src/EcsFilter.cs
454
src/EcsFilter.cs
@ -6,196 +6,37 @@ namespace DCFApixels.DragonECS
|
|||||||
#region Incs/Excs base
|
#region Incs/Excs base
|
||||||
public interface ICondition
|
public interface ICondition
|
||||||
{
|
{
|
||||||
public int[] GetComponentsIDs();
|
public int[] GetComponentsIDs<TWorldArchetype>() where TWorldArchetype : IWorldArchetype;
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Incs
|
#region Incs
|
||||||
public interface IInc : ICondition { }
|
public interface IInc : ICondition { }
|
||||||
|
|
||||||
|
public struct Inc : IInc
|
||||||
|
{
|
||||||
|
public int[] GetComponentsIDs<TWorldArchetype>() where TWorldArchetype : IWorldArchetype => Array.Empty<int>();
|
||||||
|
}
|
||||||
public struct Inc<T0> : IInc
|
public struct Inc<T0> : IInc
|
||||||
{
|
{
|
||||||
public int[] GetComponentsIDs()
|
public int[] GetComponentsIDs<TWorldArchetype>()
|
||||||
|
where TWorldArchetype : IWorldArchetype
|
||||||
{
|
{
|
||||||
return new int[]
|
return new int[]
|
||||||
{
|
{
|
||||||
ComponentType<T0>.globalID
|
EcsWorld<TWorldArchetype>.ComponentType<T0>.uniqueID
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public struct Inc<T0, T1> : IInc
|
public struct Inc<T0, T1> : IInc
|
||||||
{
|
{
|
||||||
public int[] GetComponentsIDs()
|
public int[] GetComponentsIDs<TWorldArchetype>()
|
||||||
|
where TWorldArchetype : IWorldArchetype
|
||||||
{
|
{
|
||||||
return new int[]
|
return new int[]
|
||||||
{
|
{
|
||||||
ComponentType<T0>.globalID,
|
EcsWorld<TWorldArchetype>.ComponentType<T0>.uniqueID,
|
||||||
ComponentType<T1>.globalID
|
EcsWorld<TWorldArchetype>.ComponentType<T1>.uniqueID
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public struct Inc<T0, T1, T2> : IInc
|
|
||||||
{
|
|
||||||
public int[] GetComponentsIDs()
|
|
||||||
{
|
|
||||||
return new int[]
|
|
||||||
{
|
|
||||||
ComponentType<T0>.globalID,
|
|
||||||
ComponentType<T1>.globalID,
|
|
||||||
ComponentType<T2>.globalID
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public struct Inc<T0, T1, T2, T3> : IInc
|
|
||||||
{
|
|
||||||
public int[] GetComponentsIDs()
|
|
||||||
{
|
|
||||||
return new int[]
|
|
||||||
{
|
|
||||||
ComponentType<T0>.globalID,
|
|
||||||
ComponentType<T1>.globalID,
|
|
||||||
ComponentType<T2>.globalID,
|
|
||||||
ComponentType<T3>.globalID
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public struct Inc<T0, T1, T2, T3, T4> : IInc
|
|
||||||
{
|
|
||||||
public int[] GetComponentsIDs()
|
|
||||||
{
|
|
||||||
return new int[]
|
|
||||||
{
|
|
||||||
ComponentType<T0>.globalID,
|
|
||||||
ComponentType<T1>.globalID,
|
|
||||||
ComponentType<T2>.globalID,
|
|
||||||
ComponentType<T3>.globalID,
|
|
||||||
ComponentType<T4>.globalID
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public struct Inc<T0, T1, T2, T3, T4, T5> : IInc
|
|
||||||
{
|
|
||||||
public int[] GetComponentsIDs()
|
|
||||||
{
|
|
||||||
return new int[]
|
|
||||||
{
|
|
||||||
ComponentType<T0>.globalID,
|
|
||||||
ComponentType<T1>.globalID,
|
|
||||||
ComponentType<T2>.globalID,
|
|
||||||
ComponentType<T3>.globalID,
|
|
||||||
ComponentType<T4>.globalID,
|
|
||||||
ComponentType<T5>.globalID
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public struct Inc<T0, T1, T2, T3, T4, T5, T6> : IInc
|
|
||||||
{
|
|
||||||
public int[] GetComponentsIDs()
|
|
||||||
{
|
|
||||||
return new int[]
|
|
||||||
{
|
|
||||||
ComponentType<T0>.globalID,
|
|
||||||
ComponentType<T1>.globalID,
|
|
||||||
ComponentType<T2>.globalID,
|
|
||||||
ComponentType<T3>.globalID,
|
|
||||||
ComponentType<T4>.globalID,
|
|
||||||
ComponentType<T5>.globalID,
|
|
||||||
ComponentType<T6>.globalID
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public struct Inc<T0, T1, T2, T3, T4, T5, T6, T7> : IInc
|
|
||||||
{
|
|
||||||
public int[] GetComponentsIDs()
|
|
||||||
{
|
|
||||||
return new int[]
|
|
||||||
{
|
|
||||||
ComponentType<T0>.globalID,
|
|
||||||
ComponentType<T1>.globalID,
|
|
||||||
ComponentType<T2>.globalID,
|
|
||||||
ComponentType<T3>.globalID,
|
|
||||||
ComponentType<T4>.globalID,
|
|
||||||
ComponentType<T5>.globalID,
|
|
||||||
ComponentType<T6>.globalID,
|
|
||||||
ComponentType<T7>.globalID
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public struct Inc<T0, T1, T2, T3, T4, T5, T6, T7, T8> : IInc
|
|
||||||
{
|
|
||||||
public int[] GetComponentsIDs()
|
|
||||||
{
|
|
||||||
return new int[]
|
|
||||||
{
|
|
||||||
ComponentType<T0>.globalID,
|
|
||||||
ComponentType<T1>.globalID,
|
|
||||||
ComponentType<T2>.globalID,
|
|
||||||
ComponentType<T3>.globalID,
|
|
||||||
ComponentType<T4>.globalID,
|
|
||||||
ComponentType<T5>.globalID,
|
|
||||||
ComponentType<T6>.globalID,
|
|
||||||
ComponentType<T7>.globalID,
|
|
||||||
ComponentType<T8>.globalID
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public struct Inc<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9> : IInc
|
|
||||||
{
|
|
||||||
public int[] GetComponentsIDs()
|
|
||||||
{
|
|
||||||
return new int[]
|
|
||||||
{
|
|
||||||
ComponentType<T0>.globalID,
|
|
||||||
ComponentType<T1>.globalID,
|
|
||||||
ComponentType<T2>.globalID,
|
|
||||||
ComponentType<T3>.globalID,
|
|
||||||
ComponentType<T4>.globalID,
|
|
||||||
ComponentType<T5>.globalID,
|
|
||||||
ComponentType<T6>.globalID,
|
|
||||||
ComponentType<T7>.globalID,
|
|
||||||
ComponentType<T8>.globalID,
|
|
||||||
ComponentType<T9>.globalID
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public struct Inc<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> : IInc
|
|
||||||
{
|
|
||||||
public int[] GetComponentsIDs()
|
|
||||||
{
|
|
||||||
return new int[]
|
|
||||||
{
|
|
||||||
ComponentType<T0>.globalID,
|
|
||||||
ComponentType<T1>.globalID,
|
|
||||||
ComponentType<T2>.globalID,
|
|
||||||
ComponentType<T3>.globalID,
|
|
||||||
ComponentType<T4>.globalID,
|
|
||||||
ComponentType<T5>.globalID,
|
|
||||||
ComponentType<T6>.globalID,
|
|
||||||
ComponentType<T7>.globalID,
|
|
||||||
ComponentType<T8>.globalID,
|
|
||||||
ComponentType<T9>.globalID,
|
|
||||||
ComponentType<T10>.globalID
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public struct Inc<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11> : IInc
|
|
||||||
{
|
|
||||||
public int[] GetComponentsIDs()
|
|
||||||
{
|
|
||||||
return new int[]
|
|
||||||
{
|
|
||||||
ComponentType<T0>.globalID,
|
|
||||||
ComponentType<T1>.globalID,
|
|
||||||
ComponentType<T2>.globalID,
|
|
||||||
ComponentType<T3>.globalID,
|
|
||||||
ComponentType<T4>.globalID,
|
|
||||||
ComponentType<T5>.globalID,
|
|
||||||
ComponentType<T6>.globalID,
|
|
||||||
ComponentType<T7>.globalID,
|
|
||||||
ComponentType<T8>.globalID,
|
|
||||||
ComponentType<T9>.globalID,
|
|
||||||
ComponentType<T10>.globalID,
|
|
||||||
ComponentType<T11>.globalID
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -204,112 +45,114 @@ namespace DCFApixels.DragonECS
|
|||||||
#region Excs
|
#region Excs
|
||||||
public interface IExc : ICondition { }
|
public interface IExc : ICondition { }
|
||||||
|
|
||||||
|
public struct Exc : IExc
|
||||||
|
{
|
||||||
|
public int[] GetComponentsIDs<TWorldArchetype>() where TWorldArchetype : IWorldArchetype => Array.Empty<int>();
|
||||||
|
}
|
||||||
public struct Exc<T0> : IExc
|
public struct Exc<T0> : IExc
|
||||||
{
|
{
|
||||||
public int[] GetComponentsIDs()
|
public int[] GetComponentsIDs<TWorldArchetype>()
|
||||||
|
where TWorldArchetype : IWorldArchetype
|
||||||
{
|
{
|
||||||
return new int[]
|
return new int[]
|
||||||
{
|
{
|
||||||
ComponentType<T0>.globalID
|
EcsWorld<TWorldArchetype>.ComponentType<T0>.uniqueID,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public struct Exc<T0, T1> : IExc
|
public struct Exc<T0, T1> : IExc
|
||||||
{
|
{
|
||||||
public int[] GetComponentsIDs()
|
public int[] GetComponentsIDs<TWorldArchetype>()
|
||||||
|
where TWorldArchetype : IWorldArchetype
|
||||||
{
|
{
|
||||||
return new int[]
|
return new int[]
|
||||||
{
|
{
|
||||||
ComponentType<T0>.globalID,
|
EcsWorld<TWorldArchetype>.ComponentType<T0>.uniqueID,
|
||||||
ComponentType<T1>.globalID
|
EcsWorld<TWorldArchetype>.ComponentType<T1>.uniqueID
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public struct Exc<T0, T1, T2> : IExc
|
#endregion
|
||||||
|
|
||||||
|
#region BakedMask
|
||||||
|
public abstract class BakedMask
|
||||||
{
|
{
|
||||||
public int[] GetComponentsIDs()
|
internal readonly int[] Inc;
|
||||||
|
internal readonly int[] Exc;
|
||||||
|
internal readonly Mask Mask;
|
||||||
|
|
||||||
|
internal int IncCount
|
||||||
{
|
{
|
||||||
return new int[]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
{
|
get => Inc.Length;
|
||||||
ComponentType<T0>.globalID,
|
}
|
||||||
ComponentType<T1>.globalID,
|
internal int ExcCount
|
||||||
ComponentType<T2>.globalID
|
{
|
||||||
};
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
get => Exc.Length;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Уникальный айди в рамках одного архиетипа мира
|
||||||
|
internal abstract int UniqueID { get; }
|
||||||
|
internal abstract Type WorldArchetypeType { get; }
|
||||||
|
|
||||||
|
protected BakedMask(int[] inc, int[] exc, Mask mask)
|
||||||
|
{
|
||||||
|
Inc = inc;
|
||||||
|
Exc = exc;
|
||||||
|
Mask = mask;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public struct Exc<T0, T1, T2, T3> : IExc
|
|
||||||
|
public abstract class BakedMask<TWorldArchetype> : BakedMask
|
||||||
{
|
{
|
||||||
public int[] GetComponentsIDs()
|
internal static int increment = 1;
|
||||||
{
|
internal static int capacity = 512;
|
||||||
return new int[]
|
|
||||||
{
|
protected BakedMask(int[] inc, int[] exc, Mask mask) : base(inc, exc, mask) { }
|
||||||
ComponentType<T0>.globalID,
|
|
||||||
ComponentType<T1>.globalID,
|
|
||||||
ComponentType<T2>.globalID,
|
|
||||||
ComponentType<T3>.globalID
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
public struct Exc<T0, T1, T2, T3, T4> : IExc
|
|
||||||
|
public sealed class BakedMask<TWorldArchetype, TMask> : BakedMask<TWorldArchetype>
|
||||||
|
where TWorldArchetype : IWorldArchetype
|
||||||
|
where TMask : MaskSingleton<TMask>
|
||||||
{
|
{
|
||||||
public int[] GetComponentsIDs()
|
public static readonly int uniqueID;
|
||||||
|
|
||||||
|
static BakedMask()
|
||||||
{
|
{
|
||||||
return new int[]
|
uniqueID = increment++;
|
||||||
{
|
#if DEBUG || DCFAECS_NO_SANITIZE_CHECKS
|
||||||
ComponentType<T0>.globalID,
|
if (uniqueID >= ushort.MaxValue)
|
||||||
ComponentType<T1>.globalID,
|
throw new EcsFrameworkException($"No more room for new BakedMask for this {typeof(TWorldArchetype).FullName} IWorldArchetype");
|
||||||
ComponentType<T2>.globalID,
|
#endif
|
||||||
ComponentType<T3>.globalID,
|
if (increment > capacity)
|
||||||
ComponentType<T4>.globalID
|
capacity <<= 1;
|
||||||
};
|
_instance = new BakedMask<TWorldArchetype, TMask>();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
public struct Exc<T0, T1, T2, T3, T4, T5> : IExc
|
private BakedMask() : base(
|
||||||
{
|
MaskSingleton<TMask>.Instance.MakeInc<IWorldArchetype>(),
|
||||||
public int[] GetComponentsIDs()
|
MaskSingleton<TMask>.Instance.MakeExc<IWorldArchetype>(),
|
||||||
|
MaskSingleton<TMask>.Instance)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
private static readonly BakedMask<TWorldArchetype, TMask> _instance = new BakedMask<TWorldArchetype, TMask>();
|
||||||
|
public static BakedMask<TWorldArchetype, TMask> Instance
|
||||||
{
|
{
|
||||||
return new int[]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
{
|
get => _instance;
|
||||||
ComponentType<T0>.globalID,
|
|
||||||
ComponentType<T1>.globalID,
|
|
||||||
ComponentType<T2>.globalID,
|
|
||||||
ComponentType<T3>.globalID,
|
|
||||||
ComponentType<T4>.globalID,
|
|
||||||
ComponentType<T5>.globalID
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
public struct Exc<T0, T1, T2, T3, T4, T5, T6> : IExc
|
internal override int UniqueID
|
||||||
{
|
|
||||||
public int[] GetComponentsIDs()
|
|
||||||
{
|
{
|
||||||
return new int[]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
{
|
get => uniqueID;
|
||||||
ComponentType<T0>.globalID,
|
|
||||||
ComponentType<T1>.globalID,
|
|
||||||
ComponentType<T2>.globalID,
|
|
||||||
ComponentType<T3>.globalID,
|
|
||||||
ComponentType<T4>.globalID,
|
|
||||||
ComponentType<T5>.globalID,
|
|
||||||
ComponentType<T6>.globalID
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
public struct Exc<T0, T1, T2, T3, T4, T5, T6, T7> : IExc
|
internal override Type WorldArchetypeType
|
||||||
{
|
|
||||||
public int[] GetComponentsIDs()
|
|
||||||
{
|
{
|
||||||
return new int[]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
{
|
get => typeof(IWorldArchetype);
|
||||||
ComponentType<T0>.globalID,
|
|
||||||
ComponentType<T1>.globalID,
|
|
||||||
ComponentType<T2>.globalID,
|
|
||||||
ComponentType<T3>.globalID,
|
|
||||||
ComponentType<T4>.globalID,
|
|
||||||
ComponentType<T5>.globalID,
|
|
||||||
ComponentType<T6>.globalID,
|
|
||||||
ComponentType<T7>.globalID
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
@ -317,111 +160,76 @@ namespace DCFApixels.DragonECS
|
|||||||
#region Masks
|
#region Masks
|
||||||
public abstract class Mask
|
public abstract class Mask
|
||||||
{
|
{
|
||||||
protected internal static int _typeIDIncrement = 0;
|
internal abstract int[] MakeInc<TWorldArchetype>() where TWorldArchetype : IWorldArchetype;
|
||||||
|
internal abstract int[] MakeExc<TWorldArchetype>() where TWorldArchetype : IWorldArchetype;
|
||||||
internal abstract int[] Include { get; }
|
public abstract BakedMask GetBaked<TWorldArchetype>() where TWorldArchetype : IWorldArchetype;
|
||||||
internal abstract int[] Exclude { get; }
|
|
||||||
|
|
||||||
public abstract int ID { get; }
|
|
||||||
|
|
||||||
public int IncCount
|
|
||||||
{
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
get => Include.Length;
|
|
||||||
}
|
|
||||||
public int ExcCount
|
|
||||||
{
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
get => Exclude.Length;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
public sealed class Mask<TInc> : Mask
|
public abstract class MaskSingleton<TSelf> : Mask
|
||||||
where TInc : struct, IInc
|
where TSelf : Mask
|
||||||
{
|
{
|
||||||
internal static readonly int[] include = new TInc().GetComponentsIDs();
|
protected static TSelf _instance;
|
||||||
internal static readonly int[] exclude = Array.Empty<int>();
|
internal static TSelf Instance
|
||||||
public static readonly int id = _typeIDIncrement++;
|
|
||||||
private static Mask<TInc> _instance = new Mask<TInc>();
|
|
||||||
|
|
||||||
private Mask() { }
|
|
||||||
|
|
||||||
public static Mask<TInc> Instance
|
|
||||||
{
|
{
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
get => _instance;
|
get => _instance;
|
||||||
}
|
}
|
||||||
public override int ID
|
|
||||||
{
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
get => id;
|
|
||||||
}
|
|
||||||
internal override int[] Include
|
|
||||||
{
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
get => include;
|
|
||||||
}
|
|
||||||
internal override int[] Exclude
|
|
||||||
{
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
get => exclude;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
public sealed class Mask<TInc, TExc> : Mask
|
|
||||||
|
public class Mask<TInc> : MaskSingleton<Mask<TInc>>
|
||||||
|
where TInc : struct, IInc
|
||||||
|
{
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
internal override int[] MakeInc<TWorldArchetype>() => new TInc().GetComponentsIDs<TWorldArchetype>();
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
internal override int[] MakeExc<TWorldArchetype>() => Array.Empty<int>();
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public override BakedMask GetBaked<TWorldArchetype>()
|
||||||
|
{
|
||||||
|
return BakedMask<TWorldArchetype, Mask<TInc>>.Instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Mask() { _instance = new Mask<TInc>(); }
|
||||||
|
}
|
||||||
|
public class Mask<TInc, TExc> : MaskSingleton<Mask<TInc, TExc>>
|
||||||
where TInc : struct, IInc
|
where TInc : struct, IInc
|
||||||
where TExc : struct, IExc
|
where TExc : struct, IExc
|
||||||
{
|
{
|
||||||
internal static readonly int[] include = new TInc().GetComponentsIDs();
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
internal static readonly int[] exclude = new TExc().GetComponentsIDs();
|
internal override int[] MakeInc<TWorldArchetype>() => new TInc().GetComponentsIDs<TWorldArchetype>();
|
||||||
public static readonly int id = _typeIDIncrement++;
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private static Mask<TInc, TExc> _instance = new Mask<TInc, TExc>();
|
internal override int[] MakeExc<TWorldArchetype>() => new TExc().GetComponentsIDs<TWorldArchetype>();
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public override BakedMask GetBaked<TWorldArchetype>()
|
||||||
|
{
|
||||||
|
return BakedMask<TWorldArchetype, Mask<TInc, TExc>>.Instance;
|
||||||
|
}
|
||||||
|
|
||||||
private Mask() { }
|
static Mask() { _instance = new Mask<TInc, TExc>(); }
|
||||||
|
|
||||||
public static Mask<TInc, TExc> Instance
|
|
||||||
{
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
get => _instance;
|
|
||||||
}
|
|
||||||
public override int ID
|
|
||||||
{
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
get => id;
|
|
||||||
}
|
|
||||||
internal override int[] Include
|
|
||||||
{
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
get => include;
|
|
||||||
}
|
|
||||||
internal override int[] Exclude
|
|
||||||
{
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
get => exclude;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Filter
|
#region Filter
|
||||||
public interface IEcsFilter
|
public interface IEcsFilter
|
||||||
{
|
{
|
||||||
public EcsWorld World { get; }
|
public IEcsWorld World { get; }
|
||||||
public Mask Mask { get; }
|
public BakedMask Mask { get; }
|
||||||
public IEcsReadonlyGroup Entities { get; }
|
public IEcsReadonlyGroup Entities { get; }
|
||||||
public int EntitiesCount { get; }
|
public int EntitiesCount { get; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class EcsFilter : IEcsFilter
|
public class EcsFilter : IEcsFilter
|
||||||
{
|
{
|
||||||
private readonly EcsWorld _source;
|
private readonly IEcsWorld _source;
|
||||||
private readonly EcsGroup _entities;
|
private readonly EcsGroup _entities;
|
||||||
private readonly Mask _mask;
|
private readonly BakedMask _mask;
|
||||||
|
|
||||||
#region Properties
|
#region Properties
|
||||||
public EcsWorld World
|
public IEcsWorld World
|
||||||
{
|
{
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
get => _source;
|
get => _source;
|
||||||
}
|
}
|
||||||
public Mask Mask
|
public BakedMask Mask
|
||||||
{
|
{
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
get => _mask;
|
get => _mask;
|
||||||
@ -439,7 +247,7 @@ namespace DCFApixels.DragonECS
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Constrcutors
|
#region Constrcutors
|
||||||
internal EcsFilter(EcsWorld source, Mask mask, int capasity)
|
internal EcsFilter(IEcsWorld source, BakedMask mask, int capasity)
|
||||||
{
|
{
|
||||||
_source = source;
|
_source = source;
|
||||||
_mask = mask;
|
_mask = mask;
|
||||||
|
|||||||
@ -5,7 +5,7 @@ namespace DCFApixels.DragonECS
|
|||||||
{
|
{
|
||||||
public interface IEcsReadonlyGroup
|
public interface IEcsReadonlyGroup
|
||||||
{
|
{
|
||||||
public EcsWorld World { get; }
|
public IEcsWorld World { get; }
|
||||||
public int Count { get; }
|
public int Count { get; }
|
||||||
public EcsGroup.Enumerator GetEnumerator();
|
public EcsGroup.Enumerator GetEnumerator();
|
||||||
}
|
}
|
||||||
@ -17,7 +17,7 @@ namespace DCFApixels.DragonECS
|
|||||||
|
|
||||||
public class EcsGroup : IEcsGroup
|
public class EcsGroup : IEcsGroup
|
||||||
{
|
{
|
||||||
private EcsWorld _source;
|
private IEcsWorld _source;
|
||||||
private SparseSet _entities;
|
private SparseSet _entities;
|
||||||
|
|
||||||
private DelayedOp[] _delayedOps;
|
private DelayedOp[] _delayedOps;
|
||||||
@ -26,12 +26,12 @@ namespace DCFApixels.DragonECS
|
|||||||
private int _lockCount;
|
private int _lockCount;
|
||||||
|
|
||||||
#region Properties
|
#region Properties
|
||||||
public EcsWorld World => _source;
|
public IEcsWorld World => _source;
|
||||||
public int Count => _entities.Count;
|
public int Count => _entities.Count;
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Constrcutors
|
#region Constrcutors
|
||||||
public EcsGroup(EcsWorld world, int entitiesCapacity, int delayedOpsCapacity = 128)
|
public EcsGroup(IEcsWorld world, int entitiesCapacity, int delayedOpsCapacity = 128)
|
||||||
{
|
{
|
||||||
_source = world;
|
_source = world;
|
||||||
_entities = new SparseSet(entitiesCapacity);
|
_entities = new SparseSet(entitiesCapacity);
|
||||||
|
|||||||
@ -10,28 +10,34 @@ namespace DCFApixels.DragonECS
|
|||||||
{
|
{
|
||||||
public interface IEcsPool
|
public interface IEcsPool
|
||||||
{
|
{
|
||||||
public EcsWorld World { get; }
|
public IEcsWorld World { get; }
|
||||||
public int ID { get; }
|
public int ID { get; }
|
||||||
public bool Has(int index);
|
public bool Has(int index);
|
||||||
public void Write(int index);
|
public void Write(int index);
|
||||||
public void Del(int index);
|
public void Del(int index);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class EcsPool<T> : IEcsPool
|
public interface IEcsPool<T> : IEcsPool
|
||||||
|
where T : struct
|
||||||
|
{
|
||||||
|
public ref readonly T Read(int entity);
|
||||||
|
public new ref T Write(int entity);
|
||||||
|
}
|
||||||
|
public class EcsPool<T> : IEcsPool<T>
|
||||||
where T : struct
|
where T : struct
|
||||||
{
|
{
|
||||||
private readonly int _id;
|
private readonly int _id;
|
||||||
private readonly EcsWorld _source;
|
private readonly IEcsWorld _source;
|
||||||
private readonly SparseSet _sparseSet;
|
private readonly SparseSet _sparseSet;
|
||||||
private T[] _denseItems;
|
private T[] _denseItems;
|
||||||
|
|
||||||
#region Properites
|
#region Properites
|
||||||
public EcsWorld World => _source;
|
public IEcsWorld World => _source;
|
||||||
public int ID => _id;
|
public int ID => _id;
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Constructors
|
#region Constructors
|
||||||
public EcsPool(EcsWorld source, int capacity)
|
public EcsPool(IEcsWorld source, int capacity)
|
||||||
{
|
{
|
||||||
_source = source;
|
_source = source;
|
||||||
_sparseSet = new SparseSet(capacity);
|
_sparseSet = new SparseSet(capacity);
|
||||||
@ -42,34 +48,36 @@ namespace DCFApixels.DragonECS
|
|||||||
|
|
||||||
#region Read/Write/Has/Del
|
#region Read/Write/Has/Del
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public ref readonly T Read(int index)
|
public ref readonly T Read(int entity)
|
||||||
{
|
{
|
||||||
return ref _denseItems[_sparseSet[index]];
|
return ref _denseItems[_sparseSet[entity]];
|
||||||
}
|
}
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public ref T Write(int index)
|
public ref T Write(int entity)
|
||||||
{
|
{
|
||||||
if (_sparseSet.Contains(index))
|
if (_sparseSet.Contains(entity))
|
||||||
{
|
{
|
||||||
return ref _denseItems[_sparseSet[index]];
|
return ref _denseItems[_sparseSet[entity]];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_sparseSet.Add(index);
|
_sparseSet.Add(entity);
|
||||||
_sparseSet.Normalize(ref _denseItems);
|
_sparseSet.Normalize(ref _denseItems);
|
||||||
return ref _denseItems[_sparseSet.IndexOf(index)];
|
_source.OnEntityComponentAdded(entity, _id);
|
||||||
|
return ref _denseItems[_sparseSet.IndexOf(entity)];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public bool Has(int index)
|
public bool Has(int entity)
|
||||||
{
|
{
|
||||||
return _sparseSet.IndexOf(index) > 0;
|
return _sparseSet.IndexOf(entity) > 0;
|
||||||
}
|
}
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public void Del(int index)
|
public void Del(int entity)
|
||||||
{
|
{
|
||||||
_sparseSet.RemoveAt(index);
|
_sparseSet.RemoveAt(entity);
|
||||||
|
_source.OnEntityComponentRemoved(entity, _id);
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|||||||
@ -19,8 +19,8 @@ namespace DCFApixels.DragonECS
|
|||||||
private bool _isDestoryed = false;
|
private bool _isDestoryed = false;
|
||||||
|
|
||||||
private int _worldIdIncrement;
|
private int _worldIdIncrement;
|
||||||
private Dictionary<string, EcsWorld> _worldsDict = new Dictionary<string, EcsWorld>();
|
private Dictionary<string, IEcsWorld> _worldsDict = new Dictionary<string, IEcsWorld>();
|
||||||
private List<EcsWorld> _worlds = new List<EcsWorld>();
|
private List<IEcsWorld> _worlds = new List<IEcsWorld>();
|
||||||
|
|
||||||
private Dictionary<Type, IEcsProcessorsRunner> _runners;
|
private Dictionary<Type, IEcsProcessorsRunner> _runners;
|
||||||
private Dictionary<Type, IEcsProcessorsMessenger> _messengers;
|
private Dictionary<Type, IEcsProcessorsMessenger> _messengers;
|
||||||
@ -89,11 +89,12 @@ namespace DCFApixels.DragonECS
|
|||||||
_allProcessors.Add(system);
|
_allProcessors.Add(system);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
public EcsSession AddWorld(string name)
|
public EcsSession AddWorld<TArchetype>(EcsWorld<TArchetype> world, string name = "")
|
||||||
|
where TArchetype : IWorldArchetype
|
||||||
{
|
{
|
||||||
CheckInitForMethod(nameof(AddWorld));
|
CheckInitForMethod(nameof(AddWorld));
|
||||||
|
|
||||||
//_worlds.Add(new EcsWorld(_worldIdIncrement++));
|
_worlds.Add(new EcsWorld(_worldIdIncrement++));
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,20 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace DCFApixels.DragonECS
|
|
||||||
{
|
|
||||||
public abstract class EcsTable
|
|
||||||
{
|
|
||||||
internal EcsFilter _filter;
|
|
||||||
|
|
||||||
public EcsTable(ref TableBuilder builder) { }
|
|
||||||
|
|
||||||
public EcsFilter Filter
|
|
||||||
{
|
|
||||||
get => _filter;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@ -1,11 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: ce8e0e17f18931e4284946bddba80e02
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
215
src/EcsWorld.cs
215
src/EcsWorld.cs
@ -1,215 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace DCFApixels.DragonECS
|
|
||||||
{
|
|
||||||
|
|
||||||
public class EcsWorldMap
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
public class EcsWorld
|
|
||||||
{
|
|
||||||
public const int MAX_WORLDS = byte.MaxValue; //Номер последнего мира 254
|
|
||||||
public const int DEAD_WORLD_ID = byte.MaxValue; //Зарезервированный номер мира для мертвых сущьностей
|
|
||||||
|
|
||||||
private byte _id = DEAD_WORLD_ID;
|
|
||||||
|
|
||||||
//private float _timeScale;//TODO реализовать собсвенныйтайм склей для разных миров
|
|
||||||
|
|
||||||
private IEcsPool[] _pools;
|
|
||||||
private SparseSet _componentIDToPoolID;
|
|
||||||
|
|
||||||
private SparseSet _entities = new SparseSet();
|
|
||||||
private short[] _gens;
|
|
||||||
|
|
||||||
private List<EcsFilter>[] _filtersByIncludedComponents;
|
|
||||||
private List<EcsFilter>[] _filtersByExcludedComponents;
|
|
||||||
|
|
||||||
private EcsFilter[] _filters;
|
|
||||||
private SparseSet _maskIDToFilterID;
|
|
||||||
|
|
||||||
#region Properties
|
|
||||||
public int ID => _id;
|
|
||||||
public bool IsAlive => _id != DEAD_WORLD_ID;
|
|
||||||
public bool IsEmpty => _entities.Count < 0;
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Constructors
|
|
||||||
public EcsWorld()
|
|
||||||
{
|
|
||||||
_pools = new IEcsPool[512];
|
|
||||||
_entities = new SparseSet(512);
|
|
||||||
_componentIDToPoolID = new SparseSet(512);
|
|
||||||
_maskIDToFilterID = new SparseSet(512);
|
|
||||||
_filters = new EcsFilter[512];
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Pools
|
|
||||||
public EcsPool<T> GetPool<T>()
|
|
||||||
where T : struct
|
|
||||||
{
|
|
||||||
int uniqueID = ComponentType<T>.globalID;
|
|
||||||
int poolIndex = _componentIDToPoolID.IndexOf(uniqueID);
|
|
||||||
if (poolIndex >= 0)
|
|
||||||
{
|
|
||||||
return (EcsPool<T>)_pools[poolIndex];
|
|
||||||
}
|
|
||||||
#if DEBUG
|
|
||||||
if (_componentIDToPoolID.Count >= ushort.MaxValue)
|
|
||||||
{
|
|
||||||
throw new EcsFrameworkException("No more room for new component into this world.");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
var pool = new EcsPool<T>(this, 512);
|
|
||||||
_componentIDToPoolID.Add(uniqueID);
|
|
||||||
_componentIDToPoolID.Normalize(ref _pools);
|
|
||||||
_componentIDToPoolID.Normalize(ref _filtersByIncludedComponents);
|
|
||||||
_componentIDToPoolID.Normalize(ref _filtersByExcludedComponents);
|
|
||||||
|
|
||||||
_pools[_componentIDToPoolID.IndexOf(poolIndex)] = pool;
|
|
||||||
return pool;
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Filters
|
|
||||||
public EcsFilter GetFilter<TMask>(TMask mask) where TMask : Mask
|
|
||||||
{
|
|
||||||
if (_maskIDToFilterID.TryAdd(mask.ID, ref _filters))
|
|
||||||
{
|
|
||||||
EcsFilter filter = new EcsFilter(this, mask, 512);
|
|
||||||
_filters[_maskIDToFilterID.IndexOf(mask.ID)] = filter;
|
|
||||||
return filter;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return _filters[_maskIDToFilterID.IndexOf(mask.ID)];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region NewEntity
|
|
||||||
public ent NewEntity()
|
|
||||||
{
|
|
||||||
int entityID = _entities.GetFree();
|
|
||||||
_entities.Normalize(ref _gens);
|
|
||||||
_gens[entityID]++;
|
|
||||||
|
|
||||||
|
|
||||||
return new ent(entityID, _gens[entityID], _id);
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Destroy
|
|
||||||
public void Destroy()
|
|
||||||
{
|
|
||||||
_id = DEAD_WORLD_ID;
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region IsMaskCompatible/IsMaskCompatibleWithout
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public bool IsMaskCompatible(Mask mask, int entity)
|
|
||||||
{
|
|
||||||
for (int i = 0, iMax = mask.IncCount; i < iMax; i++)
|
|
||||||
{
|
|
||||||
if (!_pools[_componentIDToPoolID[mask.Include[i]]].Has(entity))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (int i = 0, iMax = mask.ExcCount; i < iMax; i++)
|
|
||||||
{
|
|
||||||
if (_pools[_componentIDToPoolID[mask.Exclude[i]]].Has(entity))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public bool IsMaskCompatibleWithout(Mask mask, int entity, int otherPoolID)
|
|
||||||
{
|
|
||||||
for (int i = 0, iMax = mask.IncCount; i < iMax; i++)
|
|
||||||
{
|
|
||||||
int poolID = _componentIDToPoolID[mask.Include[i]];
|
|
||||||
if (poolID == otherPoolID || !_pools[poolID].Has(entity))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (int i = 0, iMax = mask.ExcCount; i < iMax; i++)
|
|
||||||
{
|
|
||||||
int poolID = _componentIDToPoolID[mask.Exclude[i]];
|
|
||||||
if (poolID != otherPoolID && _pools[poolID].Has(entity))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region EntityChangedReact
|
|
||||||
internal void OnEntityComponentAdded(int entityID, int changedPoolID)
|
|
||||||
{
|
|
||||||
var includeList = _filtersByIncludedComponents[changedPoolID];
|
|
||||||
var excludeList = _filtersByExcludedComponents[changedPoolID];
|
|
||||||
|
|
||||||
if (includeList != null)
|
|
||||||
{
|
|
||||||
foreach (var filter in includeList)
|
|
||||||
{
|
|
||||||
if (IsMaskCompatible(filter.Mask, entityID))
|
|
||||||
{
|
|
||||||
filter.Add(entityID);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (excludeList != null)
|
|
||||||
{
|
|
||||||
foreach (var filter in excludeList)
|
|
||||||
{
|
|
||||||
if (IsMaskCompatibleWithout(filter.Mask, entityID, changedPoolID))
|
|
||||||
{
|
|
||||||
filter.Remove(entityID);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void OnEntityComponentRemoved(int entityID, int changedPoolID)
|
|
||||||
{
|
|
||||||
var includeList = _filtersByIncludedComponents[changedPoolID];
|
|
||||||
var excludeList = _filtersByExcludedComponents[changedPoolID];
|
|
||||||
|
|
||||||
if (includeList != null)
|
|
||||||
{
|
|
||||||
foreach (var filter in includeList)
|
|
||||||
{
|
|
||||||
if (IsMaskCompatible(filter.Mask, entityID))
|
|
||||||
{
|
|
||||||
filter.Remove(entityID);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (excludeList != null)
|
|
||||||
{
|
|
||||||
foreach (var filter in excludeList)
|
|
||||||
{
|
|
||||||
if (IsMaskCompatibleWithout(filter.Mask, entityID, changedPoolID))
|
|
||||||
{
|
|
||||||
filter.Add(entityID);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
}
|
|
||||||
260
src/IEcsWorld.cs
Normal file
260
src/IEcsWorld.cs
Normal file
@ -0,0 +1,260 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace DCFApixels.DragonECS
|
||||||
|
{
|
||||||
|
public interface IWorldArchetype { }
|
||||||
|
public struct DefaultArchetype : IWorldArchetype { }
|
||||||
|
|
||||||
|
public interface IEcsWorld
|
||||||
|
{
|
||||||
|
public const int MAX_WORLDS = byte.MaxValue; //Номер последнего мира 254
|
||||||
|
public const int DEAD_WORLD_ID = byte.MaxValue; //Зарезервированный номер мира для мертвых сущьностей
|
||||||
|
|
||||||
|
//private float _timeScale;//TODO реализовать собсвенныйтайм склей для разных миров
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
public ushort ID { get; internal set; }
|
||||||
|
public bool IsAlive { get; }
|
||||||
|
public bool IsEmpty { get; }
|
||||||
|
public Type ArchetypeType { get; }
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
public EcsPool<T> GetPool<T>() where T : struct;
|
||||||
|
public EcsFilter GetFilter<TMask>() where TMask : MaskSingleton<TMask>;
|
||||||
|
public ent NewEntity();
|
||||||
|
public void Destroy();
|
||||||
|
|
||||||
|
public bool IsMaskCompatible(Mask mask, int entity);
|
||||||
|
public bool IsMaskCompatibleWithout(Mask mask, int entity, int otherPoolID);
|
||||||
|
|
||||||
|
internal void OnEntityComponentAdded(int entityID, int changedPoolID);
|
||||||
|
internal void OnEntityComponentRemoved(int entityID, int changedPoolID);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class EcsWorld<TArchetype> : IEcsWorld
|
||||||
|
where TArchetype : IWorldArchetype
|
||||||
|
{
|
||||||
|
private ushort _id = IEcsWorld.DEAD_WORLD_ID;
|
||||||
|
|
||||||
|
private SparseSet _componentIDToPoolID;
|
||||||
|
|
||||||
|
private SparseSet _entities = new SparseSet();
|
||||||
|
private short[] _gens;
|
||||||
|
|
||||||
|
private IEcsPool[] _pools;
|
||||||
|
|
||||||
|
private List<EcsFilter>[] _filtersByIncludedComponents;
|
||||||
|
private List<EcsFilter>[] _filtersByExcludedComponents;
|
||||||
|
|
||||||
|
private EcsFilter[] _filters;
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
public ushort ID => _id;
|
||||||
|
ushort IEcsWorld.ID { get => _id; set => _id = value; }
|
||||||
|
|
||||||
|
public bool IsAlive => _id != IEcsWorld.DEAD_WORLD_ID;
|
||||||
|
public bool IsEmpty => _entities.Count < 0;
|
||||||
|
public Type ArchetypeType => typeof(TArchetype);
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
public EcsWorld()
|
||||||
|
{
|
||||||
|
_pools = new IEcsPool[512];
|
||||||
|
_entities = new SparseSet(512);
|
||||||
|
_componentIDToPoolID = new SparseSet(512);
|
||||||
|
_filters = new EcsFilter[512];
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region GetPool
|
||||||
|
public EcsPool<T> GetPool<T>() where T : struct
|
||||||
|
{
|
||||||
|
int uniqueID = ComponentType<T>.uniqueID;
|
||||||
|
|
||||||
|
if (uniqueID >= _pools.Length)
|
||||||
|
{
|
||||||
|
Array.Resize(ref _pools, ComponentType.capacity);
|
||||||
|
Array.Resize(ref _filtersByIncludedComponents, ComponentType.capacity);
|
||||||
|
Array.Resize(ref _filtersByExcludedComponents, ComponentType.capacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_pools[uniqueID] == null)
|
||||||
|
{
|
||||||
|
_pools[uniqueID] = new EcsPool<T>(this, 512);
|
||||||
|
}
|
||||||
|
return (EcsPool<T>)_pools[uniqueID];
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region GetFilter
|
||||||
|
public EcsFilter GetFilter<TMask>() where TMask : MaskSingleton<TMask>
|
||||||
|
{
|
||||||
|
var bakedmask = BakedMask<TArchetype, TMask>.Instance;
|
||||||
|
|
||||||
|
if (_filters.Length >= BakedMask<TArchetype>.capacity)
|
||||||
|
{
|
||||||
|
Array.Resize(ref _filters, BakedMask<TArchetype>.capacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_filters[bakedmask.UniqueID] == null)
|
||||||
|
{
|
||||||
|
_filters[bakedmask.UniqueID] = new EcsFilter(this, bakedmask, 512);
|
||||||
|
}
|
||||||
|
return _filters[bakedmask.UniqueID];
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region IsMaskCompatible/IsMaskCompatibleWithout
|
||||||
|
public bool IsMaskCompatible(Mask mask, int entity)
|
||||||
|
{
|
||||||
|
BakedMask bakedMask = mask.GetBaked<TArchetype>();
|
||||||
|
for (int i = 0, iMax = bakedMask.IncCount; i < iMax; i++)
|
||||||
|
{
|
||||||
|
if (!_pools[_componentIDToPoolID[bakedMask.Inc[i]]].Has(entity))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int i = 0, iMax = bakedMask.ExcCount; i < iMax; i++)
|
||||||
|
{
|
||||||
|
if (_pools[_componentIDToPoolID[bakedMask.Exc[i]]].Has(entity))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsMaskCompatibleWithout(Mask mask, int entity, int otherPoolID)
|
||||||
|
{
|
||||||
|
BakedMask bakedMask = mask.GetBaked<TArchetype>();
|
||||||
|
for (int i = 0, iMax = bakedMask.IncCount; i < iMax; i++)
|
||||||
|
{
|
||||||
|
int poolID = _componentIDToPoolID[bakedMask.Inc[i]];
|
||||||
|
if (poolID == otherPoolID || !_pools[poolID].Has(entity))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int i = 0, iMax = bakedMask.ExcCount; i < iMax; i++)
|
||||||
|
{
|
||||||
|
int poolID = _componentIDToPoolID[bakedMask.Exc[i]];
|
||||||
|
if (poolID != otherPoolID && _pools[poolID].Has(entity))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region EntityChangedReact
|
||||||
|
void IEcsWorld.OnEntityComponentAdded(int entityID, int changedPoolID)
|
||||||
|
{
|
||||||
|
var includeList = _filtersByIncludedComponents[changedPoolID];
|
||||||
|
var excludeList = _filtersByExcludedComponents[changedPoolID];
|
||||||
|
|
||||||
|
if (includeList != null)
|
||||||
|
{
|
||||||
|
foreach (var filter in includeList)
|
||||||
|
{
|
||||||
|
if (IsMaskCompatible(filter.Mask.Mask, entityID))
|
||||||
|
{
|
||||||
|
filter.Add(entityID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (excludeList != null)
|
||||||
|
{
|
||||||
|
foreach (var filter in excludeList)
|
||||||
|
{
|
||||||
|
if (IsMaskCompatibleWithout(filter.Mask.Mask, entityID, changedPoolID))
|
||||||
|
{
|
||||||
|
filter.Remove(entityID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void IEcsWorld.OnEntityComponentRemoved(int entityID, int changedPoolID)
|
||||||
|
{
|
||||||
|
var includeList = _filtersByIncludedComponents[changedPoolID];
|
||||||
|
var excludeList = _filtersByExcludedComponents[changedPoolID];
|
||||||
|
|
||||||
|
if (includeList != null)
|
||||||
|
{
|
||||||
|
foreach (var filter in includeList)
|
||||||
|
{
|
||||||
|
if (IsMaskCompatible(filter.Mask.Mask, entityID))
|
||||||
|
{
|
||||||
|
filter.Remove(entityID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (excludeList != null)
|
||||||
|
{
|
||||||
|
foreach (var filter in excludeList)
|
||||||
|
{
|
||||||
|
if (IsMaskCompatibleWithout(filter.Mask.Mask, entityID, changedPoolID))
|
||||||
|
{
|
||||||
|
filter.Add(entityID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region NewEntity
|
||||||
|
public Entity NewEntity()
|
||||||
|
{
|
||||||
|
int entityID = _entities.GetFree();
|
||||||
|
_entities.Normalize(ref _gens);
|
||||||
|
_gens[entityID]++;
|
||||||
|
|
||||||
|
return new Entity(this, entityID);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Destroy
|
||||||
|
public void Destroy()
|
||||||
|
{
|
||||||
|
_id = IEcsWorld.DEAD_WORLD_ID;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Utils
|
||||||
|
internal abstract class ComponentType
|
||||||
|
{
|
||||||
|
internal static int increment = 1;
|
||||||
|
internal static int capacity = 512;
|
||||||
|
}
|
||||||
|
internal sealed class ComponentType<T> : ComponentType
|
||||||
|
{
|
||||||
|
internal static int uniqueID;
|
||||||
|
|
||||||
|
static ComponentType()
|
||||||
|
{
|
||||||
|
uniqueID = increment++;
|
||||||
|
#if DEBUG || DCFAECS_NO_SANITIZE_CHECKS
|
||||||
|
if (increment + 1 > ushort.MaxValue)
|
||||||
|
{
|
||||||
|
throw new EcsFrameworkException($"No more room for new component for this {typeof(TArchetype).FullName} IWorldArchetype");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (increment > capacity)
|
||||||
|
{
|
||||||
|
capacity <<= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -8,7 +8,7 @@ namespace DCFApixels.DragonECS
|
|||||||
[StructLayout(LayoutKind.Sequential, Pack = 0, Size = 8)]
|
[StructLayout(LayoutKind.Sequential, Pack = 0, Size = 8)]
|
||||||
public readonly struct ent : IEquatable<long>, IEquatable<ent>
|
public readonly struct ent : IEquatable<long>, IEquatable<ent>
|
||||||
{
|
{
|
||||||
public static readonly long NULL = 0;
|
public static readonly ent NULL = default;
|
||||||
|
|
||||||
// id - 32 bits
|
// id - 32 bits
|
||||||
// gen - 16 bits
|
// gen - 16 bits
|
||||||
@ -23,25 +23,25 @@ namespace DCFApixels.DragonECS
|
|||||||
get => (int)(_full >> 32);
|
get => (int)(_full >> 32);
|
||||||
}
|
}
|
||||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||||
public short gen
|
public ushort gen
|
||||||
{
|
{
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
get => (short)((_full << 32) >> 48);
|
get => (ushort)((_full << 32) >> 48);
|
||||||
|
|
||||||
}
|
}
|
||||||
// но чтобы значене default было NULL сульностью, мир хранится в виде ID + 1
|
// но чтобы значене default было NULL сульностью, мир хранится в виде ID + 1
|
||||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||||
public short world
|
public ushort world
|
||||||
{
|
{
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
get => (short)(((_full << 48) >> 48) - 1);
|
get => (ushort)(((_full << 48) >> 48) - 1);
|
||||||
|
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Constructors
|
#region Constructors
|
||||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||||
public ent(int id, short gen, short world)
|
public ent(int id, short gen, ushort world)
|
||||||
{
|
{
|
||||||
_full = ((long)id) << 32;
|
_full = ((long)id) << 32;
|
||||||
_full += ((long)gen) << 16;
|
_full += ((long)gen) << 16;
|
||||||
@ -112,11 +112,11 @@ namespace DCFApixels.DragonECS
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ref struct Entity
|
public readonly ref struct Entity
|
||||||
{
|
{
|
||||||
internal EcsWorld world;
|
internal readonly IEcsWorld world;
|
||||||
internal int id;
|
internal readonly int id;
|
||||||
public Entity(EcsWorld world, int id)
|
public Entity(IEcsWorld world, ent id)
|
||||||
{
|
{
|
||||||
this.world = world;
|
this.world = world;
|
||||||
this.id = id;
|
this.id = id;
|
||||||
|
|||||||
@ -1,32 +0,0 @@
|
|||||||
namespace DCFApixels.DragonECS
|
|
||||||
{
|
|
||||||
public readonly ref struct TableBuilder
|
|
||||||
{
|
|
||||||
private readonly EcsWorld _world;
|
|
||||||
private readonly EcsWorld.Mask _mask;
|
|
||||||
|
|
||||||
public TableBuilder(EcsWorld world, EcsWorld.Mask mask)
|
|
||||||
{
|
|
||||||
_world = world;
|
|
||||||
_mask = mask;
|
|
||||||
}
|
|
||||||
|
|
||||||
public EcsPool<T> Cache<T>(mem<T> member)
|
|
||||||
where T : struct
|
|
||||||
{
|
|
||||||
return _world.GetPool(member);
|
|
||||||
}
|
|
||||||
public EcsPool<T> Inc<T>(mem<T> member)
|
|
||||||
where T : struct
|
|
||||||
{
|
|
||||||
_mask.Inc(member);
|
|
||||||
return _world.GetPool(member);
|
|
||||||
}
|
|
||||||
public EcsPool<T> Exc<T>(mem<T> member)
|
|
||||||
where T : struct
|
|
||||||
{
|
|
||||||
_mask.Exc(member);
|
|
||||||
return _world.GetPool(member);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
38
src/Utils/BitMask.cs
Normal file
38
src/Utils/BitMask.cs
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace DCFApixels.DragonECS
|
||||||
|
{
|
||||||
|
public class BitMask
|
||||||
|
{
|
||||||
|
private int[] data;
|
||||||
|
|
||||||
|
public int Length { get; private set; }
|
||||||
|
|
||||||
|
public BitMask(int length)
|
||||||
|
{
|
||||||
|
Length = length;
|
||||||
|
data = new int[(length + 31) / 32];
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Resize(int newLength)
|
||||||
|
{
|
||||||
|
Length = newLength;
|
||||||
|
Array.Resize(ref data, (newLength + 31) / 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Set1(int index)
|
||||||
|
{
|
||||||
|
data[index / 32] |= 1 << (index % 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Set0(int index)
|
||||||
|
{
|
||||||
|
data[index / 32] &= ~(1 << (index % 32));
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Get(int index)
|
||||||
|
{
|
||||||
|
return (data[index / 32] & (1 << (index % 32))) != 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,5 +1,5 @@
|
|||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: 3ae306a1fd41f78428c59018eeaf21f3
|
guid: 88bc1ea51d98c0843a48314fbe00ad9e
|
||||||
MonoImporter:
|
MonoImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
@ -1,98 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
namespace DCFApixels.DragonECS
|
|
||||||
{
|
|
||||||
internal abstract class ComponentType
|
|
||||||
{
|
|
||||||
internal static int increment = 1;
|
|
||||||
internal static int capacity = 512;
|
|
||||||
}
|
|
||||||
internal sealed class ComponentType<T> : ComponentType
|
|
||||||
{
|
|
||||||
internal static int globalID;
|
|
||||||
|
|
||||||
static ComponentType()
|
|
||||||
{
|
|
||||||
globalID = increment++;
|
|
||||||
if (increment > capacity)
|
|
||||||
{
|
|
||||||
capacity <<= 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class ComponentTypeMap
|
|
||||||
{
|
|
||||||
private int[] _dense;
|
|
||||||
private int[] _sparse;
|
|
||||||
|
|
||||||
private int _count;
|
|
||||||
|
|
||||||
#region Properties
|
|
||||||
public int Count
|
|
||||||
{
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
get => _count;
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Constrcutors
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public ComponentTypeMap(int denseCapacity = 64)
|
|
||||||
{
|
|
||||||
_dense = new int[denseCapacity];
|
|
||||||
_sparse = new int[ComponentType.capacity];
|
|
||||||
|
|
||||||
_count = 0;
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Contains
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public bool Contains<T>() => Contains(ComponentType<T>.globalID);
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
private bool Contains(int globalID)
|
|
||||||
{
|
|
||||||
return globalID > 0 && globalID < _sparse.Length && _sparse[globalID] > 0;
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region GetID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public int GetID<T>()
|
|
||||||
{
|
|
||||||
int globalID = ComponentType<T>.globalID;
|
|
||||||
|
|
||||||
if (!Contains(globalID))
|
|
||||||
{
|
|
||||||
Add(globalID);
|
|
||||||
}
|
|
||||||
|
|
||||||
return _dense[globalID];
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Add
|
|
||||||
private void Add(int entityID)
|
|
||||||
{
|
|
||||||
if (Contains(entityID))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (++_count >= _dense.Length)
|
|
||||||
Array.Resize(ref _dense, _dense.Length << 1);
|
|
||||||
|
|
||||||
if (entityID > _sparse.Length)
|
|
||||||
{
|
|
||||||
int neadedSpace = _sparse.Length;
|
|
||||||
while (entityID >= neadedSpace)
|
|
||||||
neadedSpace <<= 1;
|
|
||||||
Array.Resize(ref _sparse, neadedSpace);
|
|
||||||
}
|
|
||||||
|
|
||||||
_dense[_count] = entityID;
|
|
||||||
_sparse[entityID] = _count;
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,11 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: cef3dbf379d584346bc8a9313c22c563
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
1036
src/Utils/IntSet.cs
1036
src/Utils/IntSet.cs
File diff suppressed because it is too large
Load Diff
@ -1,11 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 9cad30d5b37df1d48bc2abe5d1743649
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@ -1,63 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using DCFApixels;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
namespace DCFApixels.DragonECS
|
|
||||||
{
|
|
||||||
public class TransformTable : EcsTable
|
|
||||||
{
|
|
||||||
public readonly EcsPool<Vector3> position;
|
|
||||||
public readonly EcsPool<Quaternion> rotation;
|
|
||||||
public readonly EcsPool<Vector3> scale;
|
|
||||||
|
|
||||||
public TransformTable(ref TableBuilder tableBuilder) : base(ref tableBuilder)
|
|
||||||
{
|
|
||||||
position = tableBuilder.Inc(Mems.position);
|
|
||||||
rotation = tableBuilder.Inc(Mems.rotation);
|
|
||||||
scale = tableBuilder.Inc(Mems.scale);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class PositionTable : EcsTable
|
|
||||||
{
|
|
||||||
public readonly EcsPool<Vector3> position;
|
|
||||||
public readonly EcsPool<Quaternion> rotation;
|
|
||||||
public readonly EcsPool<Vector3> scale;
|
|
||||||
|
|
||||||
public PositionTable(ref TableBuilder tableBuilder) : base(ref tableBuilder)
|
|
||||||
{
|
|
||||||
position = tableBuilder.Inc(Mems.position);
|
|
||||||
rotation = tableBuilder.Cache(Mems.rotation);
|
|
||||||
scale = tableBuilder.Cache(Mems.scale);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class RotationTable : EcsTable
|
|
||||||
{
|
|
||||||
public readonly EcsPool<Vector3> position;
|
|
||||||
public readonly EcsPool<Quaternion> rotation;
|
|
||||||
public readonly EcsPool<Vector3> scale;
|
|
||||||
|
|
||||||
public RotationTable(ref TableBuilder tableBuilder) : base(ref tableBuilder)
|
|
||||||
{
|
|
||||||
position = tableBuilder.Cache(Mems.position);
|
|
||||||
rotation = tableBuilder.Inc(Mems.rotation);
|
|
||||||
scale = tableBuilder.Cache(Mems.scale);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class ScaleTable : EcsTable
|
|
||||||
{
|
|
||||||
public readonly EcsPool<Vector3> position;
|
|
||||||
public readonly EcsPool<Quaternion> rotation;
|
|
||||||
public readonly EcsPool<Vector3> scale;
|
|
||||||
|
|
||||||
public ScaleTable(ref TableBuilder tableBuilder) : base(ref tableBuilder)
|
|
||||||
{
|
|
||||||
position = tableBuilder.Cache(Mems.position);
|
|
||||||
rotation = tableBuilder.Cache(Mems.rotation);
|
|
||||||
scale = tableBuilder.Inc(Mems.scale);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,11 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: d6c6320184f942444b499e3f027a72a7
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
Loading…
Reference in New Issue
Block a user