DragonECS/src/Collections/EcsGroup.cs

849 lines
31 KiB
C#
Raw Normal View History

2023-06-26 02:53:55 +08:00
using DCFApixels.DragonECS.Internal;
using System;
2023-06-01 19:13:04 +08:00
using System.Collections;
using System.Collections.Generic;
2024-01-05 22:16:48 +08:00
using System.ComponentModel;
2023-05-28 06:29:04 +08:00
using System.Diagnostics;
2023-06-26 02:53:55 +08:00
using System.Linq;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
2023-05-26 04:25:09 +08:00
namespace DCFApixels.DragonECS
{
2023-12-22 18:11:41 +08:00
//_dense заполняется с индекса 1
2023-12-24 18:05:30 +08:00
//в операциях изменяющих состояние группы нельзя итерироваться по this, либо осторожно учитывать этот момент
[StructLayout(LayoutKind.Sequential, Pack = 0, Size = 8)]
2024-01-05 23:49:29 +08:00
[DebuggerTypeProxy(typeof(EcsGroup.DebuggerProxy))]
public readonly ref struct EcsReadonlyGroup
2023-02-14 03:26:34 +08:00
{
private readonly EcsGroup _source;
2023-04-24 00:19:07 +08:00
2023-04-01 22:29:34 +08:00
#region Properties
2024-03-02 04:20:34 +08:00
public bool IsNull
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return _source == null; }
}
2023-12-24 15:40:19 +08:00
public int WorldID
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-03-02 04:20:34 +08:00
get { return _source.WorldID; }
2023-12-24 15:40:19 +08:00
}
2023-04-24 00:31:03 +08:00
public EcsWorld World
2023-04-09 02:52:39 +08:00
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-03-02 04:20:34 +08:00
get { return _source.World; }
2023-04-09 02:52:39 +08:00
}
public int Count
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-03-02 04:20:34 +08:00
get { return _source.Count; }
}
2023-04-01 20:45:37 +08:00
public int CapacityDense
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-03-02 04:20:34 +08:00
get { return _source.CapacityDense; }
2023-04-01 20:45:37 +08:00
}
2023-04-15 00:23:46 +08:00
public bool IsReleazed
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-03-02 04:20:34 +08:00
get { return _source.IsReleased; }
2023-04-15 00:23:46 +08:00
}
public int this[int index]
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-03-02 04:20:34 +08:00
get { return _source[index]; }
}
#endregion
#region Constructors
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public EcsReadonlyGroup(EcsGroup source)
{
_source = source;
}
2023-04-01 22:29:34 +08:00
#endregion
#region Methods
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-03-02 04:20:34 +08:00
public bool Has(int entityID) { return _source.Has(entityID); }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-03-02 04:20:34 +08:00
public int IndexOf(int entityID) { return _source.IndexOf(entityID); }
2023-06-01 19:13:04 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-03-02 04:20:34 +08:00
public EcsGroup.Enumerator GetEnumerator() { return _source.GetEnumerator(); }
2023-04-15 00:23:46 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-03-02 04:20:34 +08:00
public EcsGroup Clone() { return _source.Clone(); }
2023-06-01 19:13:04 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-03-02 04:20:34 +08:00
public int[] Bake() { return _source.Bake(); }
2023-06-01 19:13:04 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-03-02 04:20:34 +08:00
public int Bake(ref int[] entities) { return _source.Bake(ref entities); }
2023-06-01 19:13:04 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-03-02 04:20:34 +08:00
public void Bake(List<int> entities) { _source.Bake(entities); }
2023-06-01 19:13:04 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-03-02 04:20:34 +08:00
public EcsSpan ToSpan() { return _source.ToSpan(); }
2023-07-02 21:41:06 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-03-02 04:20:34 +08:00
public EcsSpan ToSpan(int start, int length) { return _source.ToSpan(start, length); }
2023-07-02 21:41:06 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-03-02 04:20:34 +08:00
public EcsGroup.LongsIterator GetLongs() { return _source.GetLongs(); }
2023-06-01 19:13:04 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-03-02 04:20:34 +08:00
public int First() { return _source.First(); }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-03-02 04:20:34 +08:00
public int Last() { return _source.Last(); }
2023-12-24 15:54:34 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-03-02 04:20:34 +08:00
public bool SetEquals(EcsGroup group) { return _source.SetEquals(group); }
2023-12-24 15:54:34 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-03-02 04:20:34 +08:00
public bool SetEquals(EcsReadonlyGroup group) { return _source.SetEquals(group._source); }
2023-12-24 16:04:24 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-03-02 04:20:34 +08:00
public bool SetEquals(EcsSpan span) { return _source.SetEquals(span); }
2023-12-24 15:54:34 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-03-02 04:20:34 +08:00
public bool Overlaps(EcsGroup group) { return _source.Overlaps(group); }
2023-12-24 15:54:34 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-03-02 04:20:34 +08:00
public bool Overlaps(EcsReadonlyGroup group) { return _source.Overlaps(group._source); }
2023-12-24 16:04:24 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-03-02 04:20:34 +08:00
public bool Overlaps(EcsSpan span) { return _source.Overlaps(span); }
2023-12-24 15:54:34 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-03-02 04:20:34 +08:00
public bool IsSubsetOf(EcsGroup group) { return _source.IsSubsetOf(group); }
2024-01-29 01:09:17 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-03-02 04:20:34 +08:00
public bool IsSubsetOf(EcsReadonlyGroup group) { return _source.IsSubsetOf(group._source); }
2023-12-24 15:54:34 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-03-02 04:20:34 +08:00
public bool IsSupersetOf(EcsGroup group) { return _source.IsSupersetOf(group); }
2024-01-29 01:09:17 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-03-02 04:20:34 +08:00
public bool IsSupersetOf(EcsReadonlyGroup group) { return _source.IsSupersetOf(group._source); }
2023-04-01 22:29:34 +08:00
#endregion
2023-04-08 23:01:10 +08:00
#region Internal
2023-04-09 02:52:39 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-01-29 01:09:17 +08:00
internal EcsGroup GetSource_Internal() => _source;
2023-04-08 23:01:10 +08:00
#endregion
2023-04-15 00:23:46 +08:00
#region Other
2024-01-05 22:16:48 +08:00
public override string ToString()
{
return _source != null ? _source.ToString() : "NULL";
}
#pragma warning disable CS0809 // Устаревший член переопределяет неустаревший член
[Obsolete("Equals() on EcsGroup will always throw an exception. Use the equality operator instead.")]
[EditorBrowsable(EditorBrowsableState.Never)]
2024-03-02 04:20:34 +08:00
public override bool Equals(object obj) { throw new NotSupportedException(); }
2024-01-05 22:16:48 +08:00
[Obsolete("GetHashCode() on EcsGroup will always throw an exception.")]
[EditorBrowsable(EditorBrowsableState.Never)]
2024-03-02 04:20:34 +08:00
public override int GetHashCode() { throw new NotSupportedException(); }
2024-01-05 22:16:48 +08:00
#pragma warning restore CS0809 // Устаревший член переопределяет неустаревший член
2023-12-23 20:17:28 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-03-02 04:20:34 +08:00
public static implicit operator EcsSpan(EcsReadonlyGroup a) { return a.ToSpan(); }
2023-05-28 06:29:04 +08:00
#endregion
2023-02-14 03:26:34 +08:00
}
2023-05-28 06:29:04 +08:00
[DebuggerTypeProxy(typeof(DebuggerProxy))]
2024-03-02 04:20:34 +08:00
public class EcsGroup : IDisposable, IEnumerable<int>, IEntityStorage
{
private EcsWorld _source;
2023-03-30 10:46:57 +08:00
private int[] _dense;
private int[] _sparse;
2024-03-02 04:20:34 +08:00
private int _count = 0;
2023-05-28 06:29:04 +08:00
internal bool _isReleased = true;
2023-04-15 00:23:46 +08:00
#region Properties
2023-12-24 15:40:19 +08:00
public int WorldID
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _source.id;
}
2023-12-20 19:15:48 +08:00
public EcsWorld World
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _source;
}
2023-03-30 10:46:57 +08:00
public int Count
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _count;
}
2023-04-01 20:45:37 +08:00
public int CapacityDense
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _dense.Length;
}
public EcsReadonlyGroup Readonly
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => new EcsReadonlyGroup(this);
}
2023-05-26 00:24:38 +08:00
public bool IsReleased
2023-04-15 00:23:46 +08:00
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2023-05-26 00:24:38 +08:00
get => _isReleased;
2023-04-15 00:23:46 +08:00
}
public int this[int index]
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
2023-06-02 01:20:46 +08:00
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
2024-03-02 04:20:34 +08:00
if (index < 0 || index >= Count) { Throw.ArgumentOutOfRange(); }
#endif
2023-06-12 12:49:41 +08:00
return _dense[++index];
}
}
#endregion
2023-06-10 00:55:00 +08:00
#region Constrcutors/Dispose
2023-04-17 22:58:52 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static EcsGroup New(EcsWorld world)
2023-04-01 20:45:37 +08:00
{
2023-06-01 20:14:34 +08:00
return world.GetFreeGroup();
2023-04-08 21:29:18 +08:00
}
2023-05-26 00:24:38 +08:00
internal EcsGroup(EcsWorld world, int denseCapacity = 64)
2023-04-08 21:29:18 +08:00
{
2023-04-15 00:23:46 +08:00
_source = world;
2023-04-08 21:29:18 +08:00
_source.RegisterGroup(this);
2024-03-02 04:20:34 +08:00
_dense = new int[denseCapacity]; //TODO добавить в конфиг мира значение
2023-04-18 19:35:42 +08:00
_sparse = new int[world.Capacity];
}
2024-03-02 04:20:34 +08:00
public void Dispose()
{
_source.ReleaseGroup(this);
}
#endregion
2023-06-01 19:13:04 +08:00
#region Has/IndexOf
2023-03-30 10:46:57 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2023-04-24 16:48:18 +08:00
public bool Has(int entityID)
2023-03-30 10:46:57 +08:00
{
2023-04-15 00:23:46 +08:00
return _sparse[entityID] > 0;
2023-04-01 20:45:37 +08:00
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int IndexOf(int entityID)
{
return _sparse[entityID];
2023-03-30 10:46:57 +08:00
}
#endregion
2023-04-08 21:29:18 +08:00
#region Add/Remove
2024-03-02 04:20:34 +08:00
public void AddUnchecked(int entityID)
{
Add_Internal(entityID);
}
2023-12-22 18:11:41 +08:00
public bool Add(int entityID)
{
2023-12-22 18:11:41 +08:00
if (Has(entityID))
2024-03-02 04:20:34 +08:00
{
2023-12-22 18:11:41 +08:00
return false;
2024-03-02 04:20:34 +08:00
}
Add_Internal(entityID);
2023-12-22 18:11:41 +08:00
return true;
2023-04-01 20:45:37 +08:00
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-03-02 04:20:34 +08:00
internal void Add_Internal(int entityID)
2023-04-01 20:45:37 +08:00
{
2023-06-02 01:20:46 +08:00
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
2024-03-02 04:20:34 +08:00
if (Has(entityID)) { Throw.Group_AlreadyContains(entityID); }
#endif
2023-04-01 20:45:37 +08:00
if (++_count >= _dense.Length)
2024-03-02 04:20:34 +08:00
{
2023-03-30 10:46:57 +08:00
Array.Resize(ref _dense, _dense.Length << 1);
2024-03-02 04:20:34 +08:00
}
2023-03-30 10:46:57 +08:00
_dense[_count] = entityID;
_sparse[entityID] = _count;
}
2024-03-02 04:20:34 +08:00
public void RemoveUnchecked(int entityID)
{
Remove_Internal(entityID);
}
2023-12-22 18:11:41 +08:00
public bool Remove(int entityID)
2023-04-01 20:45:37 +08:00
{
2024-03-02 04:20:34 +08:00
if (Has(entityID) == false)
{
2023-12-22 18:11:41 +08:00
return false;
2024-03-02 04:20:34 +08:00
}
Remove_Internal(entityID);
2023-12-22 18:11:41 +08:00
return true;
2023-04-01 20:45:37 +08:00
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-03-02 04:20:34 +08:00
internal void Remove_Internal(int entityID)
{
2023-06-02 01:20:46 +08:00
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
2024-03-02 04:20:34 +08:00
if (!Has(entityID)) { Throw.Group_DoesNotContain(entityID); }
#endif
2023-03-30 10:46:57 +08:00
_dense[_sparse[entityID]] = _dense[_count];
_sparse[_dense[_count--]] = _sparse[entityID];
_sparse[entityID] = 0;
}
2023-04-24 16:48:18 +08:00
public void RemoveUnusedEntityIDs()
{
foreach (var e in this)
{
if (!_source.IsUsed(e))
2024-03-02 04:20:34 +08:00
{
Remove_Internal(e);
}
2023-04-24 16:48:18 +08:00
}
}
#endregion
2023-05-27 15:59:46 +08:00
#region Clear
2023-04-15 00:23:46 +08:00
public void Clear()
{
_count = 0;
for (int i = 0; i < _sparse.Length; i++)
2024-03-02 04:20:34 +08:00
{
2023-04-15 00:23:46 +08:00
_sparse[i] = 0;
2024-03-02 04:20:34 +08:00
}
2023-04-15 00:23:46 +08:00
}
#endregion
2023-06-01 19:13:04 +08:00
#region CopyFrom/Clone/Bake/ToSpan
2023-04-08 23:01:10 +08:00
public void CopyFrom(EcsGroup group)
2023-04-08 21:29:18 +08:00
{
2023-06-02 01:20:46 +08:00
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
2024-03-02 04:20:34 +08:00
if (group.World != _source) { Throw.Group_ArgumentDifferentWorldsException(); }
2023-04-09 02:52:39 +08:00
#endif
2023-05-30 18:30:10 +08:00
if (_count > 0)
2024-03-02 04:20:34 +08:00
{
2023-04-17 22:58:52 +08:00
Clear();
2024-03-02 04:20:34 +08:00
}
2023-04-09 02:52:39 +08:00
foreach (var item in group)
2024-03-02 04:20:34 +08:00
{
Add_Internal(item);
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void CopyFrom(EcsReadonlyGroup group)
{
CopyFrom(group.GetSource_Internal());
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void CopyFrom(EcsSpan span)
{
if (_count > 0)
{
Clear();
}
for (int i = 0; i < span.Count; i++)
2024-03-02 04:20:34 +08:00
{
Add_Internal(span[i]);
}
2023-04-09 02:52:39 +08:00
}
2023-04-15 00:23:46 +08:00
public EcsGroup Clone()
2023-04-09 02:52:39 +08:00
{
2023-06-01 20:14:34 +08:00
EcsGroup result = _source.GetFreeGroup();
2023-04-15 00:23:46 +08:00
result.CopyFrom(this);
return result;
2023-04-08 23:01:10 +08:00
}
2023-06-01 19:13:04 +08:00
public int[] Bake()
{
int[] result = new int[_count];
2023-06-12 00:59:22 +08:00
Array.Copy(_dense, 1, result, 0, _count);
2023-06-01 19:13:04 +08:00
return result;
}
public int Bake(ref int[] entities)
{
2023-06-22 14:39:12 +08:00
if (entities.Length < _count)
2024-03-02 04:20:34 +08:00
{
2023-06-01 19:13:04 +08:00
entities = new int[_count];
2024-03-02 04:20:34 +08:00
}
2023-06-12 00:59:22 +08:00
Array.Copy(_dense, 1, entities, 0, _count);
2023-06-01 19:13:04 +08:00
return _count;
}
public void Bake(List<int> entities)
{
entities.Clear();
foreach (var e in this)
2024-02-25 23:02:01 +08:00
{
2023-06-01 19:13:04 +08:00
entities.Add(e);
2024-02-25 23:02:01 +08:00
}
2023-06-01 19:13:04 +08:00
}
public EcsSpan ToSpan()
{
2024-02-25 23:02:01 +08:00
return new EcsSpan(WorldID, _dense, 1, _count);
}
public EcsSpan ToSpan(int start, int length)
2023-06-01 19:13:04 +08:00
{
2024-02-25 23:02:01 +08:00
start -= 1;
2023-06-02 01:20:46 +08:00
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
2024-03-02 04:20:34 +08:00
if (start < 0 || start + length > _count) { Throw.ArgumentOutOfRange(); }
2023-06-01 19:13:04 +08:00
#endif
return new EcsSpan(WorldID, _dense, start, length);
2023-06-01 19:13:04 +08:00
}
2023-04-15 00:23:46 +08:00
#endregion
2023-04-01 21:16:08 +08:00
2023-04-08 23:01:10 +08:00
#region Set operations
2023-12-22 18:11:41 +08:00
#region UnionWith
2023-04-08 23:01:10 +08:00
/// <summary>as Union sets</summary>
2023-04-15 00:23:46 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-01-29 01:09:17 +08:00
public void UnionWith(EcsReadonlyGroup group) => UnionWith(group.GetSource_Internal());
2023-04-09 02:52:39 +08:00
/// <summary>as Union sets</summary>
2023-04-15 00:23:46 +08:00
public void UnionWith(EcsGroup group)
2023-04-09 02:52:39 +08:00
{
2023-06-02 01:20:46 +08:00
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
2023-06-26 01:57:50 +08:00
if (_source != group.World) Throw.Group_ArgumentDifferentWorldsException();
2023-04-08 23:01:10 +08:00
#endif
foreach (var item in group)
2023-04-24 16:48:18 +08:00
if (!Has(item))
2024-03-02 04:20:34 +08:00
Add_Internal(item);
2023-04-08 21:29:18 +08:00
}
2023-12-24 15:48:24 +08:00
public void UnionWith(EcsSpan span)
2023-12-22 18:11:41 +08:00
{
2023-12-24 15:48:24 +08:00
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
2023-12-24 17:09:01 +08:00
if (_source.id != span.WorldID) Throw.Group_ArgumentDifferentWorldsException();
2023-12-24 15:48:24 +08:00
#endif
foreach (var item in span)
2023-12-22 18:11:41 +08:00
{
if (!Has(item))
2024-03-02 04:20:34 +08:00
Add_Internal(item);
2023-12-22 18:11:41 +08:00
}
}
#endregion
2023-04-15 00:23:46 +08:00
2023-12-22 18:11:41 +08:00
#region ExceptWith
2023-04-08 23:01:10 +08:00
/// <summary>as Except sets</summary>
2023-04-15 00:23:46 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-01-29 01:09:17 +08:00
public void ExceptWith(EcsReadonlyGroup group) => ExceptWith(group.GetSource_Internal());
2023-04-15 00:23:46 +08:00
/// <summary>as Except sets</summary>
public void ExceptWith(EcsGroup group)
2023-04-08 21:29:18 +08:00
{
2023-06-02 01:20:46 +08:00
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
2023-06-26 01:57:50 +08:00
if (_source != group.World) Throw.Group_ArgumentDifferentWorldsException();
2023-04-09 02:52:39 +08:00
#endif
2023-12-24 18:05:30 +08:00
//if (group.Count > Count) // вариант 1. есть итерация по this
//{
// foreach (var item in this)
// if (group.Has(item))
// RemoveInternal(item);
//}
//else
//{
// foreach (var item in group)
// if (Has(item))
// RemoveInternal(item);
//}
//foreach (var item in group) // вариант 2
// if (Has(item))
// RemoveInternal(item);
2023-12-22 18:11:41 +08:00
if (group.Count > Count)
{
2023-12-24 18:05:30 +08:00
for (int i = _count; i > 0; i--)//итерация в обратном порядке исключает ошибки при удалении элементов
{
int item = _dense[i];
2023-12-22 18:11:41 +08:00
if (group.Has(item))
2024-03-02 04:20:34 +08:00
Remove_Internal(item);
2023-12-24 18:05:30 +08:00
}
2023-12-22 18:11:41 +08:00
}
else
{
foreach (var item in group)
2023-12-24 18:05:30 +08:00
{
2023-12-22 18:11:41 +08:00
if (Has(item))
2024-03-02 04:20:34 +08:00
Remove_Internal(item);
2023-12-24 18:05:30 +08:00
}
2023-12-22 18:11:41 +08:00
}
}
2023-12-24 15:48:24 +08:00
public void ExceptWith(EcsSpan span)
2023-12-22 18:11:41 +08:00
{
2023-12-24 15:48:24 +08:00
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
2023-12-24 17:09:01 +08:00
if (_source.id != span.WorldID) Throw.Group_ArgumentDifferentWorldsException();
2023-12-24 15:48:24 +08:00
#endif
foreach (var item in span)
2023-12-22 18:11:41 +08:00
{
2023-12-22 23:25:31 +08:00
if (Has(item))
2024-03-02 04:20:34 +08:00
Remove_Internal(item);
2023-12-22 18:11:41 +08:00
}
2023-04-09 02:52:39 +08:00
}
2023-12-22 18:11:41 +08:00
#endregion
2023-04-15 00:23:46 +08:00
2023-12-22 18:11:41 +08:00
#region IntersectWith
2023-04-08 23:01:10 +08:00
/// <summary>as Intersect sets</summary>
2023-04-15 00:23:46 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-01-29 01:09:17 +08:00
public void IntersectWith(EcsReadonlyGroup group) => IntersectWith(group.GetSource_Internal());
2023-04-09 02:52:39 +08:00
/// <summary>as Intersect sets</summary>
public void IntersectWith(EcsGroup group)
2023-04-09 02:52:39 +08:00
{
2023-06-02 01:20:46 +08:00
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
2023-06-26 01:57:50 +08:00
if (World != group.World) Throw.Group_ArgumentDifferentWorldsException();
2023-04-08 21:29:18 +08:00
#endif
2023-12-24 18:05:30 +08:00
for (int i = _count; i > 0; i--)//итерация в обратном порядке исключает ошибки при удалении элементов
{
int item = _dense[i];
2023-04-24 16:48:18 +08:00
if (!group.Has(item))
2024-03-02 04:20:34 +08:00
Remove_Internal(item);
2023-12-24 18:05:30 +08:00
}
2023-04-08 21:29:18 +08:00
}
2023-12-22 18:11:41 +08:00
#endregion
2023-04-15 00:23:46 +08:00
2023-12-22 18:11:41 +08:00
#region SymmetricExceptWith
2023-04-08 23:01:10 +08:00
/// <summary>as Symmetric Except sets</summary>
2023-04-15 00:23:46 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-01-29 01:09:17 +08:00
public void SymmetricExceptWith(EcsReadonlyGroup group) => SymmetricExceptWith(group.GetSource_Internal());
2023-04-09 02:52:39 +08:00
/// <summary>as Symmetric Except sets</summary>
public void SymmetricExceptWith(EcsGroup group)
2023-04-09 02:52:39 +08:00
{
2023-06-02 01:20:46 +08:00
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
2023-06-26 01:57:50 +08:00
if (_source != group.World) Throw.Group_ArgumentDifferentWorldsException();
2023-04-08 21:29:18 +08:00
#endif
2023-04-08 23:01:10 +08:00
foreach (var item in group)
2023-04-24 16:48:18 +08:00
if (Has(item))
2024-03-02 04:20:34 +08:00
Remove_Internal(item);
2023-04-08 23:01:10 +08:00
else
2024-03-02 04:20:34 +08:00
Add_Internal(item);
2023-04-08 21:29:18 +08:00
}
2023-12-22 18:11:41 +08:00
#endregion
2023-12-20 19:15:48 +08:00
2023-12-22 18:11:41 +08:00
#region Inverse
2023-06-01 20:14:34 +08:00
public void Inverse()
{
foreach (var item in _source.Entities)
if (Has(item))
2024-03-02 04:20:34 +08:00
Remove_Internal(item);
2023-06-01 20:14:34 +08:00
else
2024-03-02 04:20:34 +08:00
Add_Internal(item);
2023-06-01 20:14:34 +08:00
}
2023-12-22 18:11:41 +08:00
#endregion
2023-12-20 19:15:48 +08:00
2023-12-22 18:11:41 +08:00
#region SetEquals
2023-12-20 19:15:48 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-01-29 01:09:17 +08:00
public bool SetEquals(EcsReadonlyGroup group) => SetEquals(group.GetSource_Internal());
2023-12-20 19:15:48 +08:00
public bool SetEquals(EcsGroup group)
{
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
if (_source != group.World) Throw.Group_ArgumentDifferentWorldsException();
#endif
if (group.Count != Count)
return false;
foreach (var item in group)
if (!Has(item))
return false;
return true;
}
2023-12-24 16:04:24 +08:00
public bool SetEquals(EcsSpan span)
{
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
2023-12-24 17:09:01 +08:00
if (_source.id != span.WorldID) Throw.Group_ArgumentDifferentWorldsException();
2023-12-24 16:04:24 +08:00
#endif
if (span.Count != Count)
2023-12-24 16:04:24 +08:00
return false;
foreach (var item in span)
if (!Has(item))
return false;
return true;
}
2023-12-22 18:11:41 +08:00
#endregion
2023-12-20 19:15:48 +08:00
2023-12-22 18:11:41 +08:00
#region Overlaps
2023-12-20 19:15:48 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-01-29 01:09:17 +08:00
public bool Overlaps(EcsReadonlyGroup group) => Overlaps(group.GetSource_Internal());
2023-12-20 19:15:48 +08:00
public bool Overlaps(EcsGroup group)
{
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
if (_source != group.World) Throw.Group_ArgumentDifferentWorldsException();
#endif
2024-01-07 19:32:16 +08:00
if (group.Count > Count)
2023-12-24 16:04:24 +08:00
{
foreach (var item in this)
if (group.Has(item))
return true;
}
else
{
foreach (var item in group)
if (Has(item))
return true;
}
return false;
}
public bool Overlaps(EcsSpan span)
{
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
2023-12-24 17:09:01 +08:00
if (_source.id != span.WorldID) Throw.Group_ArgumentDifferentWorldsException();
2023-12-24 16:04:24 +08:00
#endif
foreach (var item in span)
if (Has(item))
2023-12-20 19:15:48 +08:00
return true;
return false;
}
2023-12-22 18:11:41 +08:00
#endregion
2023-12-20 19:15:48 +08:00
2023-12-22 18:11:41 +08:00
#region IsSubsetOf
2023-12-20 19:15:48 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-01-29 01:09:17 +08:00
public bool IsSubsetOf(EcsReadonlyGroup group) => IsSubsetOf(group.GetSource_Internal());
2023-12-20 19:15:48 +08:00
public bool IsSubsetOf(EcsGroup group)
{
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
if (_source != group.World) Throw.Group_ArgumentDifferentWorldsException();
#endif
if (group.Count < Count)
return false;
foreach (var item in this)
if (!group.Has(item))
return false;
return true;
}
2023-12-22 18:11:41 +08:00
#endregion
2023-12-20 19:15:48 +08:00
2023-12-22 18:11:41 +08:00
#region IsSupersetOf
2023-12-20 19:15:48 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-01-29 01:09:17 +08:00
public bool IsSupersetOf(EcsReadonlyGroup group) => IsSupersetOf(group.GetSource_Internal());
2023-12-20 19:15:48 +08:00
public bool IsSupersetOf(EcsGroup group)
{
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
if (_source != group.World) Throw.Group_ArgumentDifferentWorldsException();
#endif
if (group.Count > Count)
return false;
foreach (var item in group)
if (!Has(item))
return false;
return true;
}
2023-02-14 03:26:34 +08:00
#endregion
2023-12-22 18:11:41 +08:00
#endregion
2023-04-10 22:22:17 +08:00
#region Static Set operations
2023-06-01 19:13:04 +08:00
/// <summary>as Intersect sets</summary>
/// <returns>new group from pool</returns>
public static EcsGroup Union(EcsGroup a, EcsGroup b)
{
2023-06-02 01:20:46 +08:00
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
2023-06-26 01:57:50 +08:00
if (a._source != b._source) Throw.Group_ArgumentDifferentWorldsException();
2023-06-01 19:13:04 +08:00
#endif
2023-06-01 20:14:34 +08:00
EcsGroup result = a._source.GetFreeGroup();
2023-06-01 19:13:04 +08:00
foreach (var item in a)
2024-03-02 04:20:34 +08:00
result.Add_Internal(item);
2023-06-01 19:13:04 +08:00
foreach (var item in b)
result.Add(item);
return result;
}
2023-04-10 22:22:17 +08:00
/// <summary>as Except sets</summary>
2023-04-15 00:23:46 +08:00
/// <returns>new group from pool</returns>
public static EcsGroup Except(EcsGroup a, EcsGroup b)
2023-04-10 22:22:17 +08:00
{
2023-06-02 01:20:46 +08:00
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
2023-06-26 01:57:50 +08:00
if (a._source != b._source) Throw.Group_ArgumentDifferentWorldsException();
2023-04-10 22:22:17 +08:00
#endif
2023-06-01 20:14:34 +08:00
EcsGroup result = a._source.GetFreeGroup();
2023-04-10 22:22:17 +08:00
foreach (var item in a)
2023-04-24 16:48:18 +08:00
if (!b.Has(item))
2024-03-02 04:20:34 +08:00
result.Add_Internal(item);
2023-04-15 00:23:46 +08:00
return result;
2023-04-10 22:22:17 +08:00
}
/// <summary>as Intersect sets</summary>
2023-04-15 00:23:46 +08:00
/// <returns>new group from pool</returns>
public static EcsGroup Intersect(EcsGroup a, EcsGroup b)
2023-04-10 22:22:17 +08:00
{
2023-06-02 01:20:46 +08:00
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
2023-06-26 01:57:50 +08:00
if (a._source != b._source) Throw.Group_ArgumentDifferentWorldsException();
2023-04-10 22:22:17 +08:00
#endif
2023-06-01 20:14:34 +08:00
EcsGroup result = a._source.GetFreeGroup();
2023-04-10 22:22:17 +08:00
foreach (var item in a)
2023-04-24 16:48:18 +08:00
if (b.Has(item))
2024-03-02 04:20:34 +08:00
result.Add_Internal(item);
2023-04-15 00:23:46 +08:00
return result;
}
2023-06-01 19:13:04 +08:00
/// <summary>as Symmetric Except sets</summary>
2023-04-15 00:23:46 +08:00
/// <returns>new group from pool</returns>
public static EcsGroup SymmetricExcept(EcsGroup a, EcsGroup b)
2023-04-15 00:23:46 +08:00
{
2023-06-02 01:20:46 +08:00
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
2023-06-26 01:57:50 +08:00
if (a._source != b._source) Throw.Group_ArgumentDifferentWorldsException();
2023-04-15 00:23:46 +08:00
#endif
2023-06-01 20:14:34 +08:00
EcsGroup result = a._source.GetFreeGroup();
2023-04-15 00:23:46 +08:00
foreach (var item in a)
2023-06-01 19:13:04 +08:00
if (!b.Has(item))
2024-03-02 04:20:34 +08:00
result.Add_Internal(item);
2023-06-01 19:13:04 +08:00
foreach (var item in b)
if (!a.Has(item))
2024-03-02 04:20:34 +08:00
result.Add_Internal(item);
2023-04-15 00:23:46 +08:00
return result;
2023-04-10 22:22:17 +08:00
}
2023-06-01 20:14:34 +08:00
public static EcsGroup Inverse(EcsGroup a)
{
EcsGroup result = a._source.GetFreeGroup();
foreach (var item in a._source.Entities)
if (!a.Has(item))
2024-03-02 04:20:34 +08:00
result.Add_Internal(item);
2023-06-01 20:14:34 +08:00
return result;
}
2023-04-10 22:22:17 +08:00
#endregion
2023-06-01 19:13:04 +08:00
#region Enumerator
2023-03-30 10:46:57 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2023-07-02 21:41:06 +08:00
public Enumerator GetEnumerator() => new Enumerator(this);
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
IEnumerator<int> IEnumerable<int>.GetEnumerator() => GetEnumerator();
2023-07-02 21:41:06 +08:00
public LongsIterator GetLongs() => new LongsIterator(this);
2023-12-24 15:40:19 +08:00
public struct Enumerator : IEnumerator<int>
{
2023-04-01 21:16:08 +08:00
private readonly int[] _dense;
private uint _index;
2023-03-30 10:46:57 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Enumerator(EcsGroup group)
{
2023-04-01 21:16:08 +08:00
_dense = group._dense;
2023-12-31 21:02:53 +08:00
_index = (uint)(group._count > _dense.Length ? _dense.Length : group._count) + 1;
}
2023-04-23 15:57:35 +08:00
public int Current
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2023-04-23 15:57:35 +08:00
get => _dense[_index];
}
2023-12-24 15:40:19 +08:00
object IEnumerator.Current => Current;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool MoveNext() => --_index > 0; // <= потму что отсчет начинается с индекса 1 //_count < _dense.Length дает среде понять что проверки на выход за границы не нужны
2023-12-24 15:40:19 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Dispose() { }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Reset() { }
}
2023-07-02 21:41:06 +08:00
public readonly struct LongsIterator : IEnumerable<entlong>
{
private readonly EcsGroup _group;
public LongsIterator(EcsGroup group) => _group = group;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Enumerator GetEnumerator() => new Enumerator(_group);
IEnumerator IEnumerable.GetEnumerator()
{
for (int i = 0; i < _group._count; i++)
yield return _group.World.GetEntityLong(_group._dense[i]);
}
IEnumerator<entlong> IEnumerable<entlong>.GetEnumerator()
{
for (int i = 0; i < _group._count; i++)
yield return _group.World.GetEntityLong(_group._dense[i]);
}
public struct Enumerator : IEnumerator<entlong>
2023-07-02 21:41:06 +08:00
{
private readonly EcsWorld world;
private readonly int[] _dense;
private uint _index;
2023-07-02 21:41:06 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Enumerator(EcsGroup group)
{
world = group.World;
_dense = group._dense;
2023-12-31 21:02:53 +08:00
_index = (uint)(group._count > _dense.Length ? _dense.Length : group._count) + 1;
2023-07-02 21:41:06 +08:00
}
public entlong Current
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => world.GetEntityLong(_dense[_index]);
}
object IEnumerator.Current => Current;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2023-12-31 21:02:53 +08:00
public bool MoveNext() => --_index > 0; // <= потму что отсчет начинается с индекса 1 //_count < _dense.Length дает среде понять что проверки на выход за границы не нужны
2023-07-02 21:41:06 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Dispose() { }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Reset() { }
2023-07-02 21:41:06 +08:00
}
}
#endregion
2023-04-08 23:01:10 +08:00
2023-12-24 15:40:19 +08:00
#region Other
public override string ToString()
{
2024-01-07 18:52:54 +08:00
return CollectionUtility.EntitiesToString(_dense.Skip(1).Take(_count), "group");
2023-12-24 15:40:19 +08:00
}
2023-04-15 00:23:46 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-03-02 04:20:34 +08:00
public int First() { return _dense[1]; }
2023-12-23 20:17:28 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-03-02 04:20:34 +08:00
public int Last() { return _dense[_count]; }
2023-12-23 20:17:28 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-03-02 04:20:34 +08:00
internal void OnWorldResize(int newSize) { Array.Resize(ref _sparse, newSize); }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-03-02 04:20:34 +08:00
public static implicit operator EcsReadonlyGroup(EcsGroup a) { return a.Readonly; }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-03-02 04:20:34 +08:00
public static implicit operator EcsSpan(EcsGroup a) { return a.ToSpan(); }
2023-05-28 06:29:04 +08:00
internal class DebuggerProxy
2023-04-01 20:45:37 +08:00
{
2023-05-28 06:29:04 +08:00
private EcsGroup _group;
2024-03-02 04:20:34 +08:00
public EcsWorld World { get { return _group.World; } }
public bool IsReleased { get { return _group.IsReleased; } }
2024-02-29 22:42:33 +08:00
public EntitySlotInfo[] Entities
2023-05-28 06:29:04 +08:00
{
get
{
2024-02-29 22:42:33 +08:00
EntitySlotInfo[] result = new EntitySlotInfo[_group.Count];
2023-05-28 06:29:04 +08:00
int i = 0;
foreach (var e in _group)
2024-02-29 22:42:33 +08:00
{
result[i++] = _group.World.GetEntitySlotInfoDebug(e);
}
2023-05-28 06:29:04 +08:00
return result;
}
}
2024-03-02 04:20:34 +08:00
public int Count { get { return _group.Count; } }
public int CapacityDense { get { return _group.CapacityDense; } }
public int CapacitySparce { get { return _group.CapacitySparce; } }
public override string ToString() { return _group.ToString(); }
public DebuggerProxy(EcsGroup group) { _group = group; }
2024-01-29 01:09:17 +08:00
public DebuggerProxy(EcsReadonlyGroup group) : this(group.GetSource_Internal()) { }
2023-04-01 20:45:37 +08:00
}
2023-05-28 06:29:04 +08:00
#endregion
2023-04-01 20:45:37 +08:00
}
2023-12-22 23:25:31 +08:00
#if false
public static class EcsGroupAliases
{
/// <summary>Alias for UnionWith</summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Add(this EcsGroup self, EcsGroup group)
{
self.UnionWith(group);
}
/// <summary>Alias for UnionWith</summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Add(this EcsGroup self, EcsReadonlyGroup group)
{
self.UnionWith(group);
}
/// <summary>Alias for ExceptWith</summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Remove(this EcsGroup self, EcsGroup group)
{
self.ExceptWith(group);
}
/// <summary>Alias for ExceptWith</summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Remove(this EcsGroup self, EcsReadonlyGroup group)
{
self.ExceptWith(group);
}
/// <summary>Alias for SymmetricExceptWith</summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Xor(this EcsGroup self, EcsGroup group)
{
self.SymmetricExceptWith(group);
}
/// <summary>Alias for SymmetricExceptWith</summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Xor(this EcsGroup self, EcsReadonlyGroup group)
{
self.SymmetricExceptWith(group);
}
/// <summary>Alias for IntersectWith</summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void And(this EcsGroup self, EcsGroup group)
{
self.IntersectWith(group);
}
/// <summary>Alias for IntersectWith</summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void And(this EcsGroup self, EcsReadonlyGroup group)
{
self.IntersectWith(group);
}
}
#endif
2023-05-28 06:29:04 +08:00
}