mirror of
https://github.com/DCFApixels/DragonECS-Graphs.git
synced 2025-09-18 03:34:35 +08:00
stash
This commit is contained in:
parent
50a5fb3b30
commit
487357a9de
41
README-RU.md
41
README-RU.md
@ -1,5 +1,5 @@
|
|||||||
<p align="center">
|
<p align="center">
|
||||||
<img width="400" src="https://github.com/user-attachments/assets/e2ae19e1-b121-46a2-94bc-eabf7378071b">
|
<img width="400" src="https://github.com/user-attachments/assets/4c1aaeea-7283-4980-b447-a3bc7e54aeb7">
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
@ -33,4 +33,41 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
</br>
|
</br>
|
||||||
|
|
||||||
|
Реализация связи сущностей в виде графа, где дугами выступают связывающие сущности.
|
||||||
|
|
||||||
|
> [!WARNING]
|
||||||
|
> Проект в стадии разработки. API может меняться.
|
||||||
|
|
||||||
|
# Оглавление
|
||||||
|
- [Установка](#установка)
|
||||||
|
- [Инициализация](#инициализация)
|
||||||
|
|
||||||
|
</br>
|
||||||
|
|
||||||
|
# Установка
|
||||||
|
Семантика версионирования - [Открыть](https://gist.github.com/DCFApixels/e53281d4628b19fe5278f3e77a7da9e8#file-dcfapixels_versioning_ru-md)
|
||||||
|
## Окружение
|
||||||
|
Обязательные требования:
|
||||||
|
+ Зависимость: [DragonECS](https://github.com/DCFApixels/DragonECS)
|
||||||
|
+ Минимальная версия C# 7.3;
|
||||||
|
|
||||||
|
Опционально:
|
||||||
|
+ Игровые движки с C#: Unity, Godot, MonoGame и т.д.
|
||||||
|
|
||||||
|
Протестировано:
|
||||||
|
+ **Unity:** Минимальная версия 2020.1.0;
|
||||||
|
|
||||||
|
## Установка для Unity
|
||||||
|
* ### Unity-модуль
|
||||||
|
Поддерживается установка в виде Unity-модуля в при помощи добавления git-URL [в PackageManager](https://docs.unity3d.com/2023.2/Documentation/Manual/upm-ui-giturl.html) или ручного добавления в `Packages/manifest.json`:
|
||||||
|
```
|
||||||
|
https://github.com/DCFApixels/DragonECS-Graphs.git
|
||||||
|
```
|
||||||
|
* ### В виде исходников
|
||||||
|
Пакет так же может быть добавлен в проект в виде исходников.
|
||||||
|
|
||||||
|
</br>
|
||||||
|
|
||||||
|
# Инициализация
|
||||||
|
33
README.md
33
README.md
@ -34,3 +34,36 @@
|
|||||||
</table>
|
</table>
|
||||||
|
|
||||||
</br>
|
</br>
|
||||||
|
|
||||||
|
Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text
|
||||||
|
|
||||||
|
> [!WARNING]
|
||||||
|
> The project is a work in progress, API may change.
|
||||||
|
>
|
||||||
|
> While the English version of the README is incomplete, you can view the [Russian version](https://github.com/DCFApixels/DragonECS-Graphs/blob/main/README-RU.md).
|
||||||
|
|
||||||
|
</br>
|
||||||
|
|
||||||
|
# Installation
|
||||||
|
Versioning semantics - [Open](https://gist.github.com/DCFApixels/e53281d4628b19fe5278f3e77a7da9e8#file-dcfapixels_versioning_ru-md)
|
||||||
|
## Environment
|
||||||
|
Requirements:
|
||||||
|
+ Dependency: [DragonECS](https://github.com/DCFApixels/DragonECS)
|
||||||
|
+ Minimum version of C# 7.3;
|
||||||
|
|
||||||
|
Optional:
|
||||||
|
+ Game engines with C#: Unity, Godot, MonoGame, etc.
|
||||||
|
|
||||||
|
Tested with:
|
||||||
|
+ **Unity:** Minimum version 2020.1.0;
|
||||||
|
|
||||||
|
## Unity Installation
|
||||||
|
* ### Unity Package
|
||||||
|
The package can be installed as a Unity package by adding the Git URL [in the PackageManager](https://docs.unity3d.com/2023.2/Documentation/Manual/upm-ui-giturl.html) or manually adding it to `Packages/manifest.json`:
|
||||||
|
```
|
||||||
|
https://github.com/DCFApixels/DragonECS-Graphs.git
|
||||||
|
```
|
||||||
|
* ### Source Code
|
||||||
|
The package can also be added to the project as source code.
|
||||||
|
|
||||||
|
</br>
|
||||||
|
@ -90,11 +90,11 @@ namespace DCFApixels.DragonECS.Graphs.Internal
|
|||||||
if (Mask.IsEmpty || _versionsChecker.CheckAndNext() == false)
|
if (Mask.IsEmpty || _versionsChecker.CheckAndNext() == false)
|
||||||
{
|
{
|
||||||
_filteredAllEntitiesCount = _iterator.IterateTo(World.Entities, ref _filteredAllEntities);
|
_filteredAllEntitiesCount = _iterator.IterateTo(World.Entities, ref _filteredAllEntities);
|
||||||
//Подготовка массивов
|
if (_sourceEntities.Length < _graph.World.Capacity * 2)
|
||||||
if (_sourceEntities.Length < _filteredAllEntitiesCount * 2)
|
|
||||||
{
|
{
|
||||||
_sourceEntities = new int[_filteredAllEntitiesCount * 2];
|
_sourceEntities = new int[_graph.World.Capacity * 2];
|
||||||
}
|
}
|
||||||
|
//Подготовка массивов
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -103,9 +103,9 @@ namespace DCFApixels.DragonECS.Graphs.Internal
|
|||||||
_currentFilteredEntitiesCount = _filteredAllEntitiesCount;
|
_currentFilteredEntitiesCount = _filteredAllEntitiesCount;
|
||||||
|
|
||||||
//Подготовка массивов
|
//Подготовка массивов
|
||||||
if (_targetWorldCapacity < World.Capacity)
|
if (_targetWorldCapacity < _graph.World.Capacity)
|
||||||
{
|
{
|
||||||
_targetWorldCapacity = World.Capacity;
|
_targetWorldCapacity = _graph.World.Capacity;
|
||||||
_linkedListSourceHeads = new LinkedListHead[_targetWorldCapacity];
|
_linkedListSourceHeads = new LinkedListHead[_targetWorldCapacity];
|
||||||
//_startEntities = new int[_targetWorldCapacity];
|
//_startEntities = new int[_targetWorldCapacity];
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Threading;
|
||||||
using TValue = System.Int32;
|
using TValue = System.Int32;
|
||||||
|
|
||||||
namespace DCFApixels.DragonECS.Graphs.Internal
|
namespace DCFApixels.DragonECS.Graphs.Internal
|
||||||
@ -10,12 +11,13 @@ namespace DCFApixels.DragonECS.Graphs.Internal
|
|||||||
public const int MIN_CAPACITY_BITS_OFFSET = 4;
|
public const int MIN_CAPACITY_BITS_OFFSET = 4;
|
||||||
public const int MIN_CAPACITY = 1 << MIN_CAPACITY_BITS_OFFSET;
|
public const int MIN_CAPACITY = 1 << MIN_CAPACITY_BITS_OFFSET;
|
||||||
|
|
||||||
|
private const int CHAIN_LENGTH_THRESHOLD = 5;
|
||||||
private const int MAX_CHAIN_LENGTH = 5;
|
private const float CHAIN_LENGTH_THRESHOLD_CAPCITY_THRESHOLD = 0.7f;
|
||||||
|
|
||||||
private UnsafeArray<Basket> _buckets;
|
private UnsafeArray<Basket> _buckets;
|
||||||
private UnsafeArray<Entry> _entries;
|
private UnsafeArray<Entry> _entries;
|
||||||
private int _capacity;
|
private int _capacity;
|
||||||
|
private int _count_Threshold;
|
||||||
|
|
||||||
private int _count;
|
private int _count;
|
||||||
|
|
||||||
@ -54,7 +56,7 @@ namespace DCFApixels.DragonECS.Graphs.Internal
|
|||||||
_freeList = 0;
|
_freeList = 0;
|
||||||
_freeCount = 0;
|
_freeCount = 0;
|
||||||
|
|
||||||
_capacity = minCapacity;
|
SetCapacity(minCapacity);
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@ -69,7 +71,7 @@ namespace DCFApixels.DragonECS.Graphs.Internal
|
|||||||
Throw.ArgumentException("Has(x, y) is true");
|
Throw.ArgumentException("Has(x, y) is true");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
int targetBucket = key.yHash & _modBitMask;
|
int targetBucket = key.YHash & _modBitMask;
|
||||||
AddInternal(key, targetBucket, value);
|
AddInternal(key, targetBucket, value);
|
||||||
}
|
}
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
@ -80,7 +82,7 @@ namespace DCFApixels.DragonECS.Graphs.Internal
|
|||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
int targetBucket = key.yHash & _modBitMask;
|
int targetBucket = key.YHash & _modBitMask;
|
||||||
AddInternal(key, targetBucket, value);
|
AddInternal(key, targetBucket, value);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -88,7 +90,7 @@ namespace DCFApixels.DragonECS.Graphs.Internal
|
|||||||
public void Set(int x, int y, TValue value)
|
public void Set(int x, int y, TValue value)
|
||||||
{
|
{
|
||||||
Key key = Key.FromXY(x, y);
|
Key key = Key.FromXY(x, y);
|
||||||
int targetBucket = key.yHash & _modBitMask;
|
int targetBucket = key.YHash & _modBitMask;
|
||||||
|
|
||||||
for (int i = _buckets[targetBucket].index; i >= 0; i = _entries[i].next)
|
for (int i = _buckets[targetBucket].index; i >= 0; i = _entries[i].next)
|
||||||
{
|
{
|
||||||
@ -109,9 +111,11 @@ namespace DCFApixels.DragonECS.Graphs.Internal
|
|||||||
if (_count == _capacity)
|
if (_count == _capacity)
|
||||||
{
|
{
|
||||||
Resize();
|
Resize();
|
||||||
targetBucket = key.yHash & _modBitMask;
|
// обновляем под новое значение _modBitMask
|
||||||
|
targetBucket = key.YHash & _modBitMask;
|
||||||
}
|
}
|
||||||
index = _count++;
|
index = Interlocked.Increment(ref _count);
|
||||||
|
//index = _count++;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -130,10 +134,13 @@ namespace DCFApixels.DragonECS.Graphs.Internal
|
|||||||
entry.next = basket.index;
|
entry.next = basket.index;
|
||||||
entry.key = key;
|
entry.key = key;
|
||||||
entry.value = value;
|
entry.value = value;
|
||||||
basket.count++;
|
Interlocked.Increment(ref basket.count);
|
||||||
|
//basket.count++;
|
||||||
basket.index = index;
|
basket.index = index;
|
||||||
|
|
||||||
if (basket.count >= MAX_CHAIN_LENGTH && Count / Capacity >= 0.7f)
|
if (basket.count >= CHAIN_LENGTH_THRESHOLD &&
|
||||||
|
_count > _count_Threshold)
|
||||||
|
//_count / _capacity >= CHAIN_LENGTH_THRESHOLD_CAPCITY_THRESHOLD)
|
||||||
{
|
{
|
||||||
Resize();
|
Resize();
|
||||||
}
|
}
|
||||||
@ -145,7 +152,7 @@ namespace DCFApixels.DragonECS.Graphs.Internal
|
|||||||
private int FindEntry(int x, int y)
|
private int FindEntry(int x, int y)
|
||||||
{
|
{
|
||||||
Key key = Key.FromXY(x, y);
|
Key key = Key.FromXY(x, y);
|
||||||
for (int i = _buckets[key.yHash & _modBitMask].index; i >= 0; i = _entries[i].next)
|
for (int i = _buckets[key.YHash & _modBitMask].index; i >= 0; i = _entries[i].next)
|
||||||
{
|
{
|
||||||
if (_entries[i].key == key)
|
if (_entries[i].key == key)
|
||||||
{
|
{
|
||||||
@ -157,7 +164,7 @@ namespace DCFApixels.DragonECS.Graphs.Internal
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private int FindEntry(Key key)
|
private int FindEntry(Key key)
|
||||||
{
|
{
|
||||||
for (int i = _buckets[key.yHash & _modBitMask].index; i >= 0; i = _entries[i].next)
|
for (int i = _buckets[key.YHash & _modBitMask].index; i >= 0; i = _entries[i].next)
|
||||||
{
|
{
|
||||||
if (_entries[i].key == key)
|
if (_entries[i].key == key)
|
||||||
{
|
{
|
||||||
@ -202,7 +209,7 @@ namespace DCFApixels.DragonECS.Graphs.Internal
|
|||||||
public bool TryDel(int x, int y)
|
public bool TryDel(int x, int y)
|
||||||
{
|
{
|
||||||
Key key = Key.FromXY(x, y);
|
Key key = Key.FromXY(x, y);
|
||||||
int targetBucket = key.yHash & _modBitMask;
|
int targetBucket = key.YHash & _modBitMask;
|
||||||
ref Basket basket = ref _buckets[targetBucket];
|
ref Basket basket = ref _buckets[targetBucket];
|
||||||
|
|
||||||
int last = -1;
|
int last = -1;
|
||||||
@ -269,10 +276,10 @@ namespace DCFApixels.DragonECS.Graphs.Internal
|
|||||||
UnsafeArray<Entry> newEntries = UnsafeArray<Entry>.Resize(_entries, newSize);
|
UnsafeArray<Entry> newEntries = UnsafeArray<Entry>.Resize(_entries, newSize);
|
||||||
for (int i = 0; i < _count; i++)
|
for (int i = 0; i < _count; i++)
|
||||||
{
|
{
|
||||||
if (newEntries[i].key.x >= 0)
|
if (newEntries[i].key.X >= 0)
|
||||||
{
|
{
|
||||||
ref Entry entry = ref newEntries[i];
|
ref Entry entry = ref newEntries[i];
|
||||||
ref Basket basket = ref newBuckets[entry.key.yHash & _modBitMask];
|
ref Basket basket = ref newBuckets[entry.key.YHash & _modBitMask];
|
||||||
entry.next = basket.index;
|
entry.next = basket.index;
|
||||||
basket.index = i;
|
basket.index = i;
|
||||||
basket.count++;
|
basket.count++;
|
||||||
@ -282,7 +289,13 @@ namespace DCFApixels.DragonECS.Graphs.Internal
|
|||||||
_buckets = newBuckets;
|
_buckets = newBuckets;
|
||||||
_entries = newEntries;
|
_entries = newEntries;
|
||||||
|
|
||||||
|
SetCapacity(newSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetCapacity(int newSize)
|
||||||
|
{
|
||||||
_capacity = newSize;
|
_capacity = newSize;
|
||||||
|
_count_Threshold = (int)(_count_Threshold * CHAIN_LENGTH_THRESHOLD_CAPCITY_THRESHOLD);
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
@ -301,7 +314,7 @@ namespace DCFApixels.DragonECS.Graphs.Internal
|
|||||||
public int next; // Index of next entry, -1 if last
|
public int next; // Index of next entry, -1 if last
|
||||||
public Key key;
|
public Key key;
|
||||||
public TValue value;
|
public TValue value;
|
||||||
public override string ToString() { return key.x == 0 ? "NULL" : $"{key} {value}"; }
|
public override string ToString() { return key.X == 0 ? "NULL" : $"{key} {value}"; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential, Pack = 4, Size = 8)]
|
[StructLayout(LayoutKind.Sequential, Pack = 4, Size = 8)]
|
||||||
@ -311,54 +324,63 @@ namespace DCFApixels.DragonECS.Graphs.Internal
|
|||||||
public int index;
|
public int index;
|
||||||
public int count;
|
public int count;
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public Basket(int index, int length)
|
public Basket(int index, int count)
|
||||||
{
|
{
|
||||||
this.index = index;
|
this.index = index;
|
||||||
this.count = length;
|
this.count = count;
|
||||||
}
|
}
|
||||||
public override string ToString() { return index < 0 ? "NULL" : $"{index} {count}"; }
|
public override string ToString() { return index < 0 ? "NULL" : $"{index} {count}"; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential, Pack = 4, Size = 8)]
|
[StructLayout(LayoutKind.Explicit, Pack = 4, Size = 8)]
|
||||||
public readonly struct Key : IEquatable<Key>
|
public readonly struct Key : IEquatable<Key>
|
||||||
{
|
{
|
||||||
public static readonly Key Null = new Key(-1, 0);
|
public static readonly Key Null = new Key(-1, 0);
|
||||||
public readonly int x;
|
|
||||||
public readonly int yHash;
|
[FieldOffset(0)]
|
||||||
|
public readonly long Full;
|
||||||
|
[FieldOffset(0)]
|
||||||
|
public readonly int X;
|
||||||
|
[FieldOffset(4)]
|
||||||
|
public readonly int YHash;
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private Key(int x, int yHash)
|
private Key(int x, int yHash) : this()
|
||||||
{
|
{
|
||||||
this.x = x;
|
this.X = x;
|
||||||
this.yHash = yHash;
|
this.YHash = yHash;
|
||||||
}
|
}
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static Key FromXY(int x, int y)
|
public static unsafe Key FromXY(int x, int y)
|
||||||
{
|
{
|
||||||
unchecked
|
unchecked
|
||||||
{
|
{
|
||||||
return new Key(x, x ^ y ^ XXX(y));
|
return new Key(x, x ^ y ^ Mixing(y));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private static int XXX(int x)
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private static int Mixing(int x)
|
||||||
{
|
{
|
||||||
x *= 3571;
|
unchecked
|
||||||
x ^= x << 13;
|
{
|
||||||
x ^= x >> 17;
|
x *= 3571;
|
||||||
return x;
|
x ^= x << 13;
|
||||||
|
x ^= x >> 17;
|
||||||
|
return x;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
internal static bool EqualsInFind(Key a, Key b) { return a.x == b.x; }
|
internal static bool EqualsInFind(Key a, Key b) { return a.X == b.X; }
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static bool operator ==(Key a, Key b) { return a.x == b.x && a.yHash == b.yHash; }
|
public static bool operator ==(Key a, Key b) { return a.X == b.X && a.YHash == b.YHash; }
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static bool operator !=(Key a, Key b) { return a.x != b.x || a.yHash != b.yHash; }
|
public static bool operator !=(Key a, Key b) { return a.X != b.X || a.YHash != b.YHash; }
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public override int GetHashCode() { return yHash; }
|
public override int GetHashCode() { return YHash; }
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public bool Equals(Key other) { return this == other; }
|
public bool Equals(Key other) { return this == other; }
|
||||||
public override bool Equals(object obj) { return obj is Key && Equals((Key)obj); }
|
public override bool Equals(object obj) { return obj is Key && Equals((Key)obj); }
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
public override string ToString() { return $"({X}, {YHash})"; }
|
||||||
public override string ToString() { return $"({x}, {yHash})"; }
|
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user