From c4fa4e8ca71365a523f1fb926edbbf761de3e6a0 Mon Sep 17 00:00:00 2001 From: Kirill Bazhaykin Date: Wed, 26 Aug 2026 13:03:36 +0300 Subject: [PATCH 01/11] actor/asset id refactoring --- .../Generate/GenerateTerrainHandler.cs | 12 +- .../Hexecs.Benchmarks.Noise/NoiseGame.cs | 3 +- .../Systems/MovementSystem.cs | 7 +- .../Systems/RenderSystem.cs | 1 - .../ActorCheckComponentExistsBenchmark.cs | 2 +- benchmarks/Hexecs.Benchmarks/Program.cs | 2 +- src/Hexecs/Actors/Actor.cs | 154 ++++--- src/Hexecs/Actors/Actor1.cs | 431 ------------------ src/Hexecs/Actors/ActorConstraint.Builder.cs | 2 +- .../Actors/ActorConstraint.Subscription.cs | 4 +- src/Hexecs/Actors/ActorConstraint.cs | 10 +- src/Hexecs/Actors/ActorContext.Bounds.cs | 6 +- src/Hexecs/Actors/ActorContext.Builders.cs | 25 +- src/Hexecs/Actors/ActorContext.Children.cs | 46 +- .../Actors/ActorContext.ChildrenEnumerator.cs | 10 +- .../ActorContext.ComponenetEnumerator.cs | 6 +- src/Hexecs/Actors/ActorContext.Components.cs | 50 +- src/Hexecs/Actors/ActorContext.Dictionary.cs | 7 +- src/Hexecs/Actors/ActorContext.Enumerator.cs | 2 +- src/Hexecs/Actors/ActorContext.Relations.cs | 12 +- src/Hexecs/Actors/ActorContext.cs | 180 ++------ src/Hexecs/Actors/ActorDictionary.cs | 25 +- src/Hexecs/Actors/ActorError.cs | 31 +- src/Hexecs/Actors/ActorFilter1.Dictionary.cs | 6 +- src/Hexecs/Actors/ActorFilter1.Enumerator.cs | 16 +- src/Hexecs/Actors/ActorFilter1.Operation.cs | 10 +- .../Actors/ActorFilter1.SkipTakeEnumerator.cs | 26 +- src/Hexecs/Actors/ActorFilter1.cs | 54 +-- src/Hexecs/Actors/ActorFilter2.Dictionary.cs | 6 +- src/Hexecs/Actors/ActorFilter2.Enumerator.cs | 18 +- src/Hexecs/Actors/ActorFilter2.Operation.cs | 10 +- .../Actors/ActorFilter2.SkipTakeEnumerator.cs | 30 +- src/Hexecs/Actors/ActorFilter2.cs | 55 +-- src/Hexecs/Actors/ActorFilter3.Dictionary.cs | 6 +- src/Hexecs/Actors/ActorFilter3.Enumerator.cs | 20 +- src/Hexecs/Actors/ActorFilter3.Operation.cs | 10 +- .../Actors/ActorFilter3.SkipTakeEnumerator.cs | 36 +- src/Hexecs/Actors/ActorFilter3.cs | 65 +-- src/Hexecs/Actors/ActorId.cs | 98 ++-- src/Hexecs/Actors/ActorId1.cs | 107 ----- src/Hexecs/Actors/ActorList.Enumerator.cs | 19 +- src/Hexecs/Actors/ActorList.cs | 64 ++- src/Hexecs/Actors/ActorRef1.cs | 157 ++++--- src/Hexecs/Actors/ActorRef2.cs | 104 +++-- src/Hexecs/Actors/ActorRef3.cs | 32 +- src/Hexecs/Actors/ActorRelation.cs | 53 ++- src/Hexecs/Actors/Bounds/BoundComponent.cs | 17 +- .../Actors/Bounds/BoundComponentDebugProxy.cs | 2 +- .../ActorComponentPool.Dictionary.cs | 7 +- .../ActorComponentPool.Enumerator.cs | 2 +- .../Actors/Components/ActorComponentPool.cs | 56 ++- .../Actors/Components/IActorComponentPool.cs | 12 +- .../Actors/Delegates/ActorComponentAdded.cs | 2 +- .../Delegates/ActorComponentRemoving.cs | 2 +- .../Delegates/ActorComponentUpdating.cs | 2 +- .../Actors/Development/ActorDebugProxy.cs | 19 - .../Actors/Development/ActorIdDebugProxy.cs | 16 +- .../Actors/Development/ActorRefDebugProxy.cs | 6 +- .../Development/ActorRelationDebugProxy.cs | 2 +- src/Hexecs/Actors/IActorFilter.cs | 13 +- src/Hexecs/Actors/Loggers/ActorIdLogWriter.cs | 30 +- src/Hexecs/Actors/Loggers/ActorLogWriter.cs | 28 +- src/Hexecs/Actors/Nodes/ActorNodeComponent.cs | 8 +- .../Relations/ActorRelationComponent.cs | 2 +- .../Relations/ActorRelationPool.Enumerator.cs | 10 +- .../Actors/Relations/ActorRelationPool.cs | 175 ++++--- .../Actors/Relations/IActorRelationPool.cs | 6 +- src/Hexecs/Actors/Systems/ParallelSystem.cs | 22 +- src/Hexecs/Actors/Systems/UpdateSystem1.cs | 4 +- src/Hexecs/Actors/Systems/UpdateSystem2.cs | 6 +- src/Hexecs/Actors/Systems/UpdateSystem3.cs | 4 +- src/Hexecs/Assets/Asset.cs | 66 ++- src/Hexecs/Assets/Asset1.cs | 214 --------- src/Hexecs/Assets/AssetConstraint.Builder.cs | 2 +- .../Assets/AssetConstraint.Subscription.cs | 4 +- src/Hexecs/Assets/AssetConstraint.cs | 2 +- .../AssetContext.ComponentEnumerator.cs | 6 +- src/Hexecs/Assets/AssetContext.Components.cs | 21 +- src/Hexecs/Assets/AssetContext.Dictionary.cs | 2 +- src/Hexecs/Assets/AssetContext.Enumerator.cs | 2 +- src/Hexecs/Assets/AssetContext.Loader.cs | 62 +-- src/Hexecs/Assets/AssetContext.cs | 112 +++-- src/Hexecs/Assets/AssetError.cs | 24 +- src/Hexecs/Assets/AssetFilter1.DebugProxy.cs | 2 +- src/Hexecs/Assets/AssetFilter1.Enumerator.cs | 19 +- src/Hexecs/Assets/AssetFilter1.cs | 12 +- src/Hexecs/Assets/AssetFilter2.DebugProxy.cs | 2 +- src/Hexecs/Assets/AssetFilter2.Enumerator.cs | 4 +- src/Hexecs/Assets/AssetFilter2.cs | 12 +- src/Hexecs/Assets/AssetFilter3.DebugProxy.cs | 2 +- src/Hexecs/Assets/AssetFilter3.Enumerator.cs | 4 +- src/Hexecs/Assets/AssetFilter3.cs | 12 +- src/Hexecs/Assets/AssetId.cs | 97 ++-- src/Hexecs/Assets/AssetId1.cs | 118 ----- src/Hexecs/Assets/AssetRef1.cs | 38 +- src/Hexecs/Assets/AssetRef2.cs | 61 +-- src/Hexecs/Assets/AssetRef3.cs | 37 +- .../Assets/Components/AssetComponentPool.cs | 94 ++-- .../Assets/Components/IAssetComponentPool.cs | 6 +- src/Hexecs/Assets/Delegates/AssetPredicate.cs | 15 + .../Assets/Development/ActorIdDebugProxy.cs | 30 -- .../Assets/Development/AssetDebugProxy.cs | 19 - .../Assets/Development/AssetIdDebugProxy.cs | 14 + .../Assets/Development/AssetRefDebugProxy.cs | 6 +- src/Hexecs/Assets/IAssetFilter.cs | 2 +- src/Hexecs/Assets/Loggers/AssetIdLogWriter.cs | 30 +- src/Hexecs/Assets/Loggers/AssetLogWriter.cs | 28 +- .../Assets/Sources/AssetConfigurator.cs | 12 +- src/Hexecs/Assets/Sources/IAssetLoader.cs | 10 +- src/Hexecs/Loggers/LogBuilder.cs | 4 - .../Serializations/JsonWriterExtensions.cs | 16 - src/Hexecs/Threading/IParallelJob.cs | 2 +- src/Hexecs/Utils/ValueStringBuilder.cs | 4 +- .../Actors/ActorConstraintShould.cs | 16 +- .../Hexecs.Tests/Actors/ActorContextShould.cs | 86 ++-- .../Hexecs.Tests/Actors/ActorFilter1Should.cs | 6 +- tests/Hexecs.Tests/Actors/ActorListShould.cs | 33 +- .../Actors/ActorMethodsConsistencyTests.cs | 1 - tests/Hexecs.Tests/Actors/ActorShould.cs | 33 +- tests/Hexecs.Tests/Actors/ActorTestFixture.cs | 12 +- .../Hexecs.Tests/Assets/AssetContextShould.cs | 6 +- .../Hexecs.Tests/Assets/AssetFilter1Should.cs | 28 +- .../Hexecs.Tests/Assets/AssetFilter2Should.cs | 29 +- .../Hexecs.Tests/Assets/AssetFilter3Should.cs | 21 +- .../Assets/AssetMethodsConsistencyTests.cs | 163 +++++++ tests/Hexecs.Tests/Assets/AssetTestFixture.cs | 14 +- 126 files changed, 1660 insertions(+), 2500 deletions(-) delete mode 100644 src/Hexecs/Actors/Actor1.cs delete mode 100644 src/Hexecs/Actors/ActorId1.cs delete mode 100644 src/Hexecs/Assets/Asset1.cs delete mode 100644 src/Hexecs/Assets/AssetId1.cs create mode 100644 src/Hexecs/Assets/Delegates/AssetPredicate.cs delete mode 100644 src/Hexecs/Assets/Development/ActorIdDebugProxy.cs create mode 100644 src/Hexecs/Assets/Development/AssetIdDebugProxy.cs create mode 100644 tests/Hexecs.Tests/Assets/AssetMethodsConsistencyTests.cs diff --git a/benchmarks/Hexecs.Benchmarks.City/Terrains/Commands/Generate/GenerateTerrainHandler.cs b/benchmarks/Hexecs.Benchmarks.City/Terrains/Commands/Generate/GenerateTerrainHandler.cs index 6bf9b33..e80c003 100644 --- a/benchmarks/Hexecs.Benchmarks.City/Terrains/Commands/Generate/GenerateTerrainHandler.cs +++ b/benchmarks/Hexecs.Benchmarks.City/Terrains/Commands/Generate/GenerateTerrainHandler.cs @@ -18,9 +18,9 @@ public GenerateTerrainHandler( public override Result Handle(in GenerateTerrainCommand terrainCommand) { - var ground = Assets.GetAsset(TerrainAsset.Ground); - var river = Assets.GetAsset(TerrainAsset.River); - var urbanConcrete = Assets.GetAsset(TerrainAsset.UrbanConcrete); + var ground = Assets.GetAsset(TerrainAsset.Ground); + var river = Assets.GetAsset(TerrainAsset.River); + var urbanConcrete = Assets.GetAsset(TerrainAsset.UrbanConcrete); var height = _settings.Height; var width = _settings.Width; @@ -32,17 +32,17 @@ public override Result Handle(in GenerateTerrainCommand terrainCommand) var args = Args.Rent(nameof(Point), new Point(x, y)); if (x is > 45 and < 55) // river { - Context.BuildActor(river, + Context.BuildActor(river, args.Set(nameof(Terrain.Elevation), Elevation.FromValue(-10)) .Set(nameof(Terrain.Moisture), Moisture.FromValue(35))); } else if (x < 10 && y < 10) // urban concrete { - Context.BuildActor(urbanConcrete, args); + Context.BuildActor(urbanConcrete, args); } else // just ground { - Context.BuildActor(ground, args); + Context.BuildActor(ground, args); } } } diff --git a/benchmarks/Hexecs.Benchmarks.Noise/NoiseGame.cs b/benchmarks/Hexecs.Benchmarks.Noise/NoiseGame.cs index d7db849..7337a22 100644 --- a/benchmarks/Hexecs.Benchmarks.Noise/NoiseGame.cs +++ b/benchmarks/Hexecs.Benchmarks.Noise/NoiseGame.cs @@ -59,8 +59,7 @@ protected override void Initialize() .ConfigureComponentPool(color => color.Capacity(InitialEntityCount)) .ConfigureComponentPool(position => position.Capacity(InitialEntityCount)) .ConfigureComponentPool(velocity => velocity.Capacity(InitialEntityCount)) - .CreateUpdateSystem(ctx => - new MovementSystem(ctx, ctx.GetRequiredService(), width, height)) + .CreateUpdateSystem(ctx => new MovementSystem(ctx, ctx.GetRequiredService(), width, height)) .CreateDrawSystem(ctx => new RenderSystem(ctx, GraphicsDevice, MaxEntityCount * 2))) .Build(); diff --git a/benchmarks/Hexecs.Benchmarks.Noise/Systems/MovementSystem.cs b/benchmarks/Hexecs.Benchmarks.Noise/Systems/MovementSystem.cs index 82d3117..cdf6040 100644 --- a/benchmarks/Hexecs.Benchmarks.Noise/Systems/MovementSystem.cs +++ b/benchmarks/Hexecs.Benchmarks.Noise/Systems/MovementSystem.cs @@ -20,8 +20,8 @@ protected override void Update( in ActorRef actor, in WorldTime time) { - var pos = actor.Component1; - var vel = actor.Component2; + ref var pos = ref actor.Component1; + ref var vel = ref actor.Component2; pos.Value += vel.Value * time.DeltaTime; @@ -35,8 +35,5 @@ protected override void Update( { vel.Value.Y *= -1; } - - actor.Update(pos); - actor.Update(vel); } } \ No newline at end of file diff --git a/benchmarks/Hexecs.Benchmarks.Noise/Systems/RenderSystem.cs b/benchmarks/Hexecs.Benchmarks.Noise/Systems/RenderSystem.cs index 206e3d3..81a315d 100644 --- a/benchmarks/Hexecs.Benchmarks.Noise/Systems/RenderSystem.cs +++ b/benchmarks/Hexecs.Benchmarks.Noise/Systems/RenderSystem.cs @@ -62,7 +62,6 @@ public override void Draw(in WorldTime time) var count = _filter.Length; if (count <= 0) return; - // Наполняем буфер инстансов данными из HexECS var i = 0; foreach (var actor in _filter) { diff --git a/benchmarks/Hexecs.Benchmarks/Actors/ActorCheckComponentExistsBenchmark.cs b/benchmarks/Hexecs.Benchmarks/Actors/ActorCheckComponentExistsBenchmark.cs index f560637..c95130d 100644 --- a/benchmarks/Hexecs.Benchmarks/Actors/ActorCheckComponentExistsBenchmark.cs +++ b/benchmarks/Hexecs.Benchmarks/Actors/ActorCheckComponentExistsBenchmark.cs @@ -124,7 +124,7 @@ public int Hexecs_Is() // ReSharper disable once ForeachCanBeConvertedToQueryUsingAnotherGetEnumerator foreach (var actor in _context) { - if (actor.Is(out _)) + if (actor.IsRef(out _)) { result++; } diff --git a/benchmarks/Hexecs.Benchmarks/Program.cs b/benchmarks/Hexecs.Benchmarks/Program.cs index c06c904..903dae0 100644 --- a/benchmarks/Hexecs.Benchmarks/Program.cs +++ b/benchmarks/Hexecs.Benchmarks/Program.cs @@ -2,5 +2,5 @@ using Hexecs.Benchmarks.Actors; using Hexecs.Benchmarks.Collections; -BenchmarkRunner.Run(); +BenchmarkRunner.Run(); //BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args); diff --git a/src/Hexecs/Actors/Actor.cs b/src/Hexecs/Actors/Actor.cs index 80f11db..34d6ff0 100644 --- a/src/Hexecs/Actors/Actor.cs +++ b/src/Hexecs/Actors/Actor.cs @@ -15,18 +15,13 @@ namespace Hexecs.Actors; [DebuggerTypeProxy(typeof(ActorDebugProxy))] public readonly struct Actor : IEquatable { - /// - /// Константа, представляющая собой пустой идентификатор актёра. - /// - internal const uint EmptyId = 0; - /// /// Пустой актёр, используемый по умолчанию. /// public static Actor Empty { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => new(null!, EmptyId); + get => new(null!, ActorId.Empty); } /// @@ -55,7 +50,7 @@ public bool IsEmpty /// /// Уникальный идентификатор актёра. /// - public readonly uint Id; + public readonly ActorId Id; /// /// Внутренний конструктор для создания актёра. @@ -63,7 +58,7 @@ public bool IsEmpty /// Контекст актёра. /// Идентификатор актёра. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal Actor(ActorContext context, uint id) + internal Actor(ActorContext context, ActorId id) { Context = context; Id = id; @@ -76,7 +71,10 @@ internal Actor(ActorContext context, uint id) /// Компонент для добавления. /// Выбрасывается, если актёр не найден в контексте или компонент уже существует. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Add(in T component) where T : struct, IActorComponent => Context.AddComponent(Id, in component); + public void Add(in T component) where T : struct, IActorComponent + { + Context.AddComponent(Id, in component); + } /// /// Добавляет дочернего актёра к текущему. @@ -84,7 +82,10 @@ internal Actor(ActorContext context, uint id) /// Дочерний актёр. /// Выбрасывается, если один из актёров не найден или дочерний актёр уже добавлен. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void AddChild(in Actor child) => Context.AddChild(Id, child.Id); + public void AddChild(in Actor child) + { + Context.AddChild(Id, child.Id); + } /// /// Добавляет отношение между текущим актёром и указанным родственным актёром. @@ -107,16 +108,11 @@ public ref T AddRelation(in Actor relative, in T relation) where T : struct /// Типизированный актёр с указанным компонентом. /// Выбрасывается, если актёр не найден или не содержит указанный компонент. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Actor As() where T : struct, IActorComponent => Context.GetActor(Id); - - /// - /// Преобразует актёра в ссылку на типизированного актёра. - /// - /// Тип компонента. - /// Ссылка на типизированного актёра. - /// Выбрасывается, если актёр не найден или не содержит указанный компонент. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ActorRef AsRef() where T : struct, IActorComponent => Context.GetActorRef(Id); + public ActorRef AsRef() + where T : struct, IActorComponent + { + return Context.GetActorRef(Id); + } /// /// Возвращает перечислитель дочерних актёров. @@ -124,14 +120,20 @@ public ref T AddRelation(in Actor relative, in T relation) where T : struct /// Перечислитель дочерних актёров. /// Выбрасывается, если актёр не найден. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ActorContext.ChildrenEnumerator Children() => Context.Children(Id); + public ActorContext.ChildrenEnumerator Children() + { + return Context.Children(Id); + } /// /// Уничтожает актёра. /// /// Возвращает true, если актёр был успешно уничтожен; иначе false. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Destroy() => Context.DestroyActor(Id); + public bool Destroy() + { + return Context.DestroyActor(Id); + } /// /// Получает компонент актёра указанного типа. @@ -140,7 +142,11 @@ public ref T AddRelation(in Actor relative, in T relation) where T : struct /// Ссылка на компонент. /// Выбрасывается, если актёр не найден или не содержит указанный компонент. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ref T Get() where T : struct, IActorComponent => ref Context.GetComponent(Id); + public ref T Get() + where T : struct, IActorComponent + { + return ref Context.GetComponent(Id); + } /// /// Получает ассет, связанный с актёром. @@ -148,7 +154,10 @@ public ref T AddRelation(in Actor relative, in T relation) where T : struct /// Ассет, связанный с актёром. /// Выбрасывается, если актёр не найден или с ним не связан ассет. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Asset GetAsset() => Context.GetBoundAsset(Id); + public Asset GetAsset() + { + return Context.GetBoundAsset(Id); + } /// /// Получает отношение между текущим актёром и указанным родственным актёром. @@ -158,7 +167,11 @@ public ref T AddRelation(in Actor relative, in T relation) where T : struct /// Ссылка на отношение. /// Выбрасывается, если актёр не найден или отношение не существует. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ref T GetRelation(in Actor relative) where T : struct => ref Context.GetRelation(Id, relative.Id); + public ref T GetRelation(in Actor relative) + where T : struct + { + return ref Context.GetRelation(Id, relative.Id); + } /// /// Проверяет, содержит ли актёр компонент указанного типа. @@ -167,11 +180,17 @@ public ref T AddRelation(in Actor relative, in T relation) where T : struct /// Возвращает true, если актёр содержит компонент; иначе false. /// Выбрасывается, если актёр не найден. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Has() where T : struct, IActorComponent => Context.HasComponent(Id); + public bool Has() where T : struct, IActorComponent + { + return Context.HasComponent(Id); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool HasChild(in Actor child) => Context.HasChild(Id, child.Id); - + public bool HasChild(in Actor child) + { + return Context.HasChild(Id, child.Id); + } + /// /// Проверяет, существует ли отношение между текущим актёром и указанным родственным актёром. /// @@ -180,7 +199,11 @@ public ref T AddRelation(in Actor relative, in T relation) where T : struct /// Возвращает true, если отношение существует; иначе false. /// Выбрасывается, если один из актёров не найден. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool HasRelation(in Actor relative) where T : struct => Context.HasRelation(Id, relative.Id); + public bool HasRelation(in Actor relative) + where T : struct + { + return Context.HasRelation(Id, relative.Id); + } /// /// Проверяет, можно ли преобразовать актёра в типизированного актёра с указанным компонентом. @@ -189,15 +212,6 @@ public ref T AddRelation(in Actor relative, in T relation) where T : struct /// Результирующий типизированный актёр. /// Возвращает true, если преобразование успешно; иначе false. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Is(out Actor actor) where T : struct, IActorComponent => Context.TryGetActor(Id, out actor); - - /// - /// Проверяет, можно ли преобразовать актёра в ссылку на типизированного актёра. - /// - /// Тип компонента. - /// Результирующая ссылка на типизированного актёра. - /// Возвращает true, если преобразование успешно; иначе false. - [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool IsRef(out ActorRef actor) where T : struct, IActorComponent { return Context.TryGetActorRef(Id, out actor); @@ -213,7 +227,11 @@ public bool IsRef(out ActorRef actor) where T : struct, IActorComponent /// Метод достаточно медленный, не рекомендуется применять его в "горячих" местах. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ActorRelationEnumerator Relations() where T : struct => Context.Relations(Id); + public ActorRelationEnumerator Relations() + where T : struct + { + return Context.Relations(Id); + } /// /// Удаляет компонент указанного типа из актёра. @@ -222,7 +240,11 @@ public bool IsRef(out ActorRef actor) where T : struct, IActorComponent /// Возвращает true, если компонент был успешно удален; иначе false. /// Выбрасывается, если актёр не найден. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Remove() where T : struct, IActorComponent => Context.RemoveComponent(Id); + public bool Remove() + where T : struct, IActorComponent + { + return Context.RemoveComponent(Id); + } /// /// Удаляет компонент указанного типа из актёра и возвращает его значение. @@ -232,7 +254,8 @@ public bool IsRef(out ActorRef actor) where T : struct, IActorComponent /// Возвращает true, если компонент был успешно удален; иначе false. /// Выбрасывается, если актёр не найден. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Remove(out T component) where T : struct, IActorComponent + public bool Remove(out T component) + where T : struct, IActorComponent { return Context.RemoveComponent(Id, out component); } @@ -244,7 +267,10 @@ public bool Remove(out T component) where T : struct, IActorComponent /// Возвращает true, если дочерний актёр был успешно удален; иначе false. /// Выбрасывается, если один из актёров не найден. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool RemoveChild(in Actor child) => Context.RemoveChild(Id, child.Id); + public bool RemoveChild(in Actor child) + { + return Context.RemoveChild(Id, child.Id); + } /// /// Удаляет отношение указанного типа между текущим актёром и указанным родственным актёром. @@ -254,7 +280,11 @@ public bool Remove(out T component) where T : struct, IActorComponent /// Возвращает true, если отношение было успешно удалено; иначе false. /// Выбрасывается, если один из актёров не найден. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool RemoveRelation(in Actor relative) where T : struct => Context.RemoveRelation(Id, relative.Id); + public bool RemoveRelation(in Actor relative) + where T : struct + { + return Context.RemoveRelation(Id, relative.Id); + } /// /// Удаляет отношение указанного типа между текущим актёром и указанным родственным актёром и возвращает его значение. @@ -274,9 +304,12 @@ public bool RemoveRelation(in Actor relative, out T relation) where T : struc /// Возвращает строковое представление актёра. /// /// Строковое представление актёра. - public override string ToString() => Context == null - ? StringUtils.EmptyValue - : Context.GetDescription(Id); + public override string ToString() + { + return Context == null + ? StringUtils.EmptyValue + : Context.GetDescription(Id); + } /// /// Пытается добавить компонент к актёру, если он еще не существует. @@ -286,7 +319,11 @@ public override string ToString() => Context == null /// Возвращает true, если компонент был успешно добавлен; иначе false, если он уже существует. /// Выбрасывается, если актёр не найден. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool TryAdd(in T component) where T : struct, IActorComponent => Context.TryAdd(Id, in component); + public bool TryAdd(in T component) + where T : struct, IActorComponent + { + return Context.TryAdd(Id, in component); + } /// /// Пытается получить ассет, связанный с актёром. @@ -295,7 +332,10 @@ public override string ToString() => Context == null /// Возвращает true, если ассет был успешно получен; иначе false. /// Выбрасывается, если актёр не найден. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool TryGetAsset(out Asset asset) => Context.TryGetBoundAsset(Id, out asset); + public bool TryGetAsset(out Asset asset) + { + return Context.TryGetBoundAsset(Id, out asset); + } /// /// Пытается получить ссылку на компонент актёра указанного типа. @@ -304,7 +344,11 @@ public override string ToString() => Context == null /// Ссылка на компонент или на пустой компонент , если он не существует. /// Выбрасывается, если актёр не найден. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ref T TryGetRef() where T : struct, IActorComponent => ref Context.TryGetComponentRef(Id); + public ref T TryGetRef() + where T : struct, IActorComponent + { + return ref Context.TryGetComponentRef(Id); + } /// /// Пытается получить родительского актёра для текущего. @@ -313,23 +357,27 @@ public override string ToString() => Context == null /// Возвращает true, если родительский актёр существует; иначе false. /// Выбрасывается, если актёр не найден. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool TryGetParent(out Actor parent) => Context.TryGetParent(Id, out parent); + public bool TryGetParent(out Actor parent) + { + return Context.TryGetParent(Id, out parent); + } /// /// Обновляет существующий компонент или создает новый, если он не существует. /// + /// Вызывает событие обновления /// Тип компонента. /// Компонент для обновления. /// Возвращает true, чтобы создать компонент, если он не существует; иначе false. /// Возвращает true, если компонент был успешно обновлен или создан; иначе false. /// Выбрасывается, если актёр не найден. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Update(in T component, bool createIfNotExists = true) + public bool Update(in T component, bool createIfNotExists = true) where T : struct, IActorComponent { return Context.UpdateComponent(Id, in component, createIfNotExists); } - + #region Equality /// @@ -389,7 +437,7 @@ public bool Update(in T component, bool createIfNotExists = true) /// Актёр для преобразования. /// Идентификатор актёра. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator ActorId(in Actor actor) => new(actor.Id); + public static implicit operator ActorId(in Actor actor) => actor.Id; #endregion } \ No newline at end of file diff --git a/src/Hexecs/Actors/Actor1.cs b/src/Hexecs/Actors/Actor1.cs deleted file mode 100644 index 1d13a9d..0000000 --- a/src/Hexecs/Actors/Actor1.cs +++ /dev/null @@ -1,431 +0,0 @@ -using Hexecs.Actors.Development; -using Hexecs.Actors.Relations; -using Hexecs.Assets; - -namespace Hexecs.Actors; - -/// -/// Структура, представляющая собой типизированного актёра в системе с компонентом типа . -/// -/// Тип компонента актёра -/// -/// Актёр - это базовый объект, который содержит идентификатор и ссылку на контекст, -/// позволяющий взаимодействовать с компонентами и отношениями. -/// -[DebuggerDisplay("{ToString()}")] -[DebuggerTypeProxy(typeof(ActorDebugProxy<>))] -public readonly struct Actor : IEquatable> - where T1 : struct, IActorComponent -{ - /// - /// Константа, представляющая собой пустой идентификатор актёра. - /// - private const uint EmptyId = 0; - - /// - /// Контекст актёра, управляющий его жизненным циклом и взаимодействием с компонентами. - /// - public readonly ActorContext Context; - - /// - /// Уникальный идентификатор актёра. - /// - public readonly uint Id; - - /// - /// Пустой актёр, используемый по умолчанию. - /// - public static Actor Empty - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => new(null!, EmptyId); - } - - /// - /// Проверяет, существует ли актёр в системе. - /// - public bool Alive - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => Context != null && Context.ActorAlive(Id); - } - - /// - /// Предоставляет доступ к первому компоненту актёра. - /// - public ref T1 Component1 - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => ref Context.GetComponent(Id); - } - - /// - /// Проверяет, является ли актёр пустым (без контекста). - /// - public bool IsEmpty - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => Context == null; - } - - /// - /// Внутренний конструктор для создания актёра. - /// - /// Контекст актёра. - /// Идентификатор актёра. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal Actor(ActorContext context, uint id) - { - Context = context; - Id = id; - } - - /// - /// Добавляет компонент к актёру. - /// - /// Тип компонента, должен быть структурой и реализовывать IActorComponent. - /// Компонент для добавления. - /// Выбрасывается, если актёр не найден в контексте или компонент уже существует. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Add(in T component) where T : struct, IActorComponent => Context.AddComponent(Id, in component); - - /// - /// Добавляет дочернего актёра к текущему. - /// - /// Дочерний актёр. - /// Выбрасывается, если один из актёров не найден или дочерний актёр уже добавлен. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void AddChild(in Actor child) => Context.AddChild(Id, child.Id); - - /// - /// Добавляет отношение между текущим актёром и указанным родственным актёром. - /// - /// Тип отношения. - /// Родственный актёр. - /// Отношение для добавления. - /// Ссылка на добавленное отношение. - /// Выбрасывается, если один из актёров не найден. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ref T AddRelation(in Actor relative, in T relation) where T : struct - { - return ref Context.AddRelation(Id, relative.Id, in relation); - } - - /// - /// Преобразует актёра в типизированного актёра с указанным компонентом. - /// - /// Тип компонента. - /// Типизированный актёр с указанным компонентом. - /// Выбрасывается, если актёр не найден или не содержит указанный компонент. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Actor As() where T : struct, IActorComponent => Context.GetActor(Id); - - /// - /// Преобразует актёра в ссылку на типизированного актёра. - /// - /// Ссылка на типизированного актёра. - /// Выбрасывается, если актёр не найден или не содержит указанный компонент. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ActorRef AsRef() => new(Context, Id, ref Context.GetComponent(Id)); - - /// - /// Преобразует актёра в ссылку на типизированного актёра. - /// - /// Тип компонента. - /// Ссылка на типизированного актёра. - /// Выбрасывается, если актёр не найден или не содержит указанный компонент. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ActorRef AsRef() where T : struct, IActorComponent => Context.GetActorRef(Id); - - /// - /// Возвращает перечислитель дочерних актёров. - /// - /// Перечислитель дочерних актёров. - /// Выбрасывается, если актёр не найден. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ActorContext.ChildrenEnumerator Children() => Context.Children(Id); - - /// - /// Уничтожает актёра. - /// - /// Возвращает true, если актёр был успешно уничтожен; иначе false. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Destroy() => Context.DestroyActor(Id); - - /// - /// Получает компонент актёра указанного типа. - /// - /// Тип компонента. - /// Ссылка на компонент. - /// Выбрасывается, если актёр не найден или не содержит указанный компонент. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ref T Get() where T : struct, IActorComponent => ref Context.GetComponent(Id); - - /// - /// Получает ассет, связанный с актёром. - /// - /// Ассет, связанный с актёром. - /// Выбрасывается, если актёр не найден или с ним не связан ассет. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Asset GetAsset() => Context.GetBoundAsset(Id); - - /// - /// Получает отношение между текущим актёром и указанным родственным актёром. - /// - /// Тип отношения. - /// Родственный актёр. - /// Ссылка на отношение. - /// Выбрасывается, если актёр не найден или отношение не существует. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ref T GetRelation(in Actor relative) where T : struct => ref Context.GetRelation(Id, relative.Id); - - /// - /// Проверяет, содержит ли актёр компонент указанного типа. - /// - /// Тип компонента. - /// Возвращает true, если актёр содержит компонент; иначе false. - /// Выбрасывается, если актёр не найден. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Has() where T : struct, IActorComponent => Context.HasComponent(Id); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool HasChild(in Actor child) => Context.HasChild(Id, child.Id); - - /// - /// Проверяет, существует ли отношение между текущим актёром и указанным родственным актёром. - /// - /// Тип отношения. - /// Родственный актёр. - /// Возвращает true, если отношение существует; иначе false. - /// Выбрасывается, если один из актёров не найден. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool HasRelation(in Actor relative) where T : struct => Context.HasRelation(Id, relative.Id); - - /// - /// Проверяет, можно ли преобразовать актёра в типизированного актёра с указанным компонентом. - /// - /// Тип компонента. - /// Результирующий типизированный актёр. - /// Возвращает true, если преобразование успешно; иначе false. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Is(out Actor actor) where T : struct, IActorComponent => Context.TryGetActor(Id, out actor); - - /// - /// Проверяет, можно ли преобразовать актёра в ссылку на типизированного актёра. - /// - /// Тип компонента. - /// Результирующая ссылка на типизированного актёра. - /// Возвращает true, если преобразование успешно; иначе false. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool IsRef(out ActorRef actor) where T : struct, IActorComponent - { - return Context.TryGetActorRef(Id, out actor); - } - - /// - /// Возвращает перечислитель отношений указанного типа. - /// - /// Тип отношения. - /// Перечислитель отношений. - /// Выбрасывается, если актёр не найден. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ActorRelationEnumerator Relations() where T : struct => Context.Relations(Id); - - /// - /// Удаляет компонент указанного типа из актёра. - /// - /// Тип компонента. - /// Возвращает true, если компонент был успешно удален; иначе false. - /// Выбрасывается, если актёр не найден. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Remove() where T : struct, IActorComponent => Context.RemoveComponent(Id); - - /// - /// Удаляет компонент указанного типа из актёра и возвращает его значение. - /// - /// Тип компонента. - /// Удаленный компонент. - /// Возвращает true, если компонент был успешно удален; иначе false. - /// Выбрасывается, если актёр не найден. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Remove(out T component) where T : struct, IActorComponent - { - return Context.RemoveComponent(Id, out component); - } - - /// - /// Удаляет дочернего актёра из текущего. - /// - /// Дочерний актёр для удаления. - /// Возвращает true, если дочерний актёр был успешно удален; иначе false. - /// Выбрасывается, если один из актёров не найден. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool RemoveChild(in Actor child) => Context.RemoveChild(Id, child.Id); - - /// - /// Удаляет отношение указанного типа между текущим актёром и указанным родственным актёром. - /// - /// Тип отношения. - /// Родственный актёр. - /// Возвращает true, если отношение было успешно удалено; иначе false. - /// Выбрасывается, если один из актёров не найден. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool RemoveRelation(in Actor relative) where T : struct => Context.RemoveRelation(Id, relative.Id); - - /// - /// Удаляет отношение указанного типа между текущим актёром и указанным родственным актёром и возвращает его значение. - /// - /// Тип отношения. - /// Родственный актёр. - /// Удаленное отношение. - /// Возвращает true, если отношение было успешно удалено; иначе false. - /// Выбрасывается, если один из актёров не найден. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool RemoveRelation(in Actor relative, out T relation) where T : struct - { - return Context.RemoveRelation(Id, relative.Id, out relation); - } - - /// - /// Возвращает строковое представление актёра. - /// - /// Строковое представление актёра. - public override string ToString() => Context == null - ? StringUtils.EmptyValue - : Context.GetDescription(Id); - - /// - /// Пытается добавить компонент к актёру, если он еще не существует. - /// - /// Тип компонента. - /// Компонент для добавления. - /// Возвращает true, если компонент был успешно добавлен; иначе false, если он уже существует. - /// Выбрасывается, если актёр не найден. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool TryAdd(in T component) where T : struct, IActorComponent => Context.TryAdd(Id, in component); - - /// - /// Пытается получить ассет, связанный с актёром. - /// - /// Результирующий ассет. - /// Возвращает true, если ассет был успешно получен; иначе false. - /// Выбрасывается, если актёр не найден. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool TryGetAsset(out Asset asset) => Context.TryGetBoundAsset(Id, out asset); - - /// - /// Пытается получить ссылку на компонент актёра указанного типа. - /// - /// Тип компонента. - /// Ссылка на компонент или на пустой компонент, если он не существует. - /// Выбрасывается, если актёр не найден. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ref T TryGetRef() where T : struct, IActorComponent => ref Context.TryGetComponentRef(Id); - - /// - /// Пытается получить родительского актёра для текущего. - /// - /// Результирующий родительский актёр. - /// Возвращает true, если родительский актёр существует; иначе false. - /// Выбрасывается, если актёр не найден. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool TryGetParent(out Actor parent) => Context.TryGetParent(Id, out parent); - - /// - /// Обновляет существующий компонент или создает новый, если он не существует. - /// - /// Тип компонента. - /// Компонент для обновления. - /// Возвращает true, чтобы создать компонент, если он не существует; иначе false. - /// Возвращает true, если компонент был успешно обновлен или создан; иначе false. - /// Выбрасывается, если актёр не найден. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Update(in T component, bool createIfNotExists = true) where T : struct, IActorComponent - { - return Context.UpdateComponent(Id, in component, createIfNotExists); - } - - #region Equality - - /// - /// Проверяет равенство между двумя актёрами. - /// - /// Актёр для сравнения. - /// Возвращает true, если актёры равны; иначе false. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(Actor other) => Id == other.Id && ReferenceEquals(Context, other.Context); - - /// - /// Проверяет равенство с другим объектом. - /// - /// Объект для сравнения. - /// Возвращает true, если объекты равны; иначе false. - public override bool Equals(object? obj) => obj switch - { - Actor other => Equals(other), - Actor actor => actor.Is(out var expected) && Equals(expected), - _ => false - }; - - /// - /// Возвращает хеш-код для актёра. - /// - /// Хеш-код актёра. - public override int GetHashCode() => HashCode.Combine(Id); - - /// - /// Сравнивает двух актёров на равенство. - /// - /// Левый актёр. - /// Правый актёр. - /// Возвращает true, если актёры равны; иначе false. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(in Actor left, in Actor right) => left.Equals(right); - - /// - /// Сравнивает двух актёров на неравенство. - /// - /// Левый актёр. - /// Правый актёр. - /// Возвращает true, если актёры не равны; иначе false. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(in Actor left, in Actor right) => !left.Equals(right); - - #endregion - - #region Implicit - - /// - /// Неявное преобразование актёра в bool. - /// - /// Актёр для преобразования. - /// Возвращает true, если актёр не пустой; иначе false. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator bool(in Actor actor) => !actor.IsEmpty; - - /// - /// Неявное преобразование актёра в . - /// - /// Актёр для преобразования. - /// Идентификатор актёра. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator ActorId(in Actor actor) => new(actor.Id); - - /// - /// Неявное преобразование актёра в типизированный идентификатор . - /// - /// Актёр для преобразования. - /// Типизированный идентификатор актёра. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator ActorId(in Actor actor) => new(actor.Id); - - /// - /// Неявное преобразование типизированного актёра в базовый актёр. - /// - /// Типизированный актёр для преобразования. - /// Базовый актёр. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator Actor(in Actor actor) => new(actor.Context, actor.Id); - - #endregion -} \ No newline at end of file diff --git a/src/Hexecs/Actors/ActorConstraint.Builder.cs b/src/Hexecs/Actors/ActorConstraint.Builder.cs index a81b9fb..00b5dbb 100644 --- a/src/Hexecs/Actors/ActorConstraint.Builder.cs +++ b/src/Hexecs/Actors/ActorConstraint.Builder.cs @@ -72,7 +72,7 @@ public Builder Include() where T : struct, IActorComponent } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void AddSubscription(bool include, IActorComponentPool pool, Func check) + private void AddSubscription(bool include, IActorComponentPool pool, Func check) where T : struct, IActorComponent { var id = ActorComponentType.Id; diff --git a/src/Hexecs/Actors/ActorConstraint.Subscription.cs b/src/Hexecs/Actors/ActorConstraint.Subscription.cs index 4fb5da8..ea2feac 100644 --- a/src/Hexecs/Actors/ActorConstraint.Subscription.cs +++ b/src/Hexecs/Actors/ActorConstraint.Subscription.cs @@ -23,7 +23,7 @@ public ushort ComponentId /// /// Функция проверки актёра на соответствие ограничению. /// - public readonly Func Check; + public readonly Func Check; /// /// Флаг, указывающий, является ли подписка включающей (true) или исключающей (false). @@ -42,7 +42,7 @@ public ushort ComponentId /// Пул компонентов для подписки /// Функция проверки актёра [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Subscription(bool include, IActorComponentPool pool, Func check) + public Subscription(bool include, IActorComponentPool pool, Func check) { Check = check; diff --git a/src/Hexecs/Actors/ActorConstraint.cs b/src/Hexecs/Actors/ActorConstraint.cs index 2f56054..c770a3c 100644 --- a/src/Hexecs/Actors/ActorConstraint.cs +++ b/src/Hexecs/Actors/ActorConstraint.cs @@ -66,12 +66,12 @@ public static Builder Include(ActorContext context) /// /// Событие, вызываемое при добавлении актёра, соответствующего ограничениям. /// - public event Action? Added; + public event Action? Added; /// /// Событие, вызываемое при удалении актёра, который ранее соответствовал ограничениям. /// - public event Action? Removing; + public event Action? Removing; private readonly int _contextId; private readonly int _hash; @@ -94,7 +94,7 @@ private ActorConstraint(int contextId, int hash, Subscription[] subscriptions) /// /// Идентификатор актёра для проверки /// Возвращает true, если актёр соответствует всем ограничениям; иначе false - public bool Applicable(uint actorId) + public bool Applicable(ActorId actorId) { // ReSharper disable once LoopCanBeConvertedToQuery foreach (var subscription in _subscriptions) @@ -105,9 +105,9 @@ public bool Applicable(uint actorId) return true; } - private void OnExclude(uint actorId) => Removing?.Invoke(actorId); + private void OnExclude(ActorId actorId) => Removing?.Invoke(actorId); - private void OnInclude(uint actorId) + private void OnInclude(ActorId actorId) { // ReSharper disable once LoopCanBeConvertedToQuery foreach (var subscription in _subscriptions) diff --git a/src/Hexecs/Actors/ActorContext.Bounds.cs b/src/Hexecs/Actors/ActorContext.Bounds.cs index b0a77e1..7b3c282 100644 --- a/src/Hexecs/Actors/ActorContext.Bounds.cs +++ b/src/Hexecs/Actors/ActorContext.Bounds.cs @@ -11,7 +11,7 @@ public sealed partial class ActorContext /// Идентификатор актёра /// Ассет, привязанный к актёру /// Возникает, если актёр не имеет привязанного ассета - public Asset GetBoundAsset(uint actorId) + public Asset GetBoundAsset(ActorId actorId) { ref var component = ref TryGetComponentRef(actorId); if (Unsafe.IsNullRef(ref component)) ActorError.AssetNotFound(actorId); @@ -25,7 +25,7 @@ public Asset GetBoundAsset(uint actorId) /// Идентификатор актёра /// Переменная для сохранения найденного ассета /// Возвращает true, если актёр имеет привязанный ассет, иначе false - public bool TryGetBoundAsset(uint actorId, out Asset asset) + public bool TryGetBoundAsset(ActorId actorId, out Asset asset) { ref var component = ref TryGetComponentRef(actorId); if (Unsafe.IsNullRef(ref component)) @@ -43,7 +43,7 @@ public bool TryGetBoundAsset(uint actorId, out Asset asset) /// /// Идентификатор актёра /// Ассет для привязки - internal void SetBoundAsset(uint actorId, in Asset asset) + internal void SetBoundAsset(ActorId actorId, in Asset asset) { var pool = GetOrCreateComponentPool(); if (asset.IsEmpty) diff --git a/src/Hexecs/Actors/ActorContext.Builders.cs b/src/Hexecs/Actors/ActorContext.Builders.cs index 1ecdbb0..c7f88f3 100644 --- a/src/Hexecs/Actors/ActorContext.Builders.cs +++ b/src/Hexecs/Actors/ActorContext.Builders.cs @@ -20,11 +20,11 @@ public sealed partial class ActorContext /// public Actor BuildActor(in Asset asset, Args? args = null) { - var actorId = GetNextActorId(); + var actorIdRaw = GetNextActorId(); - AddEntry(actorId); + AddEntry(actorIdRaw); - var actor = new Actor(this, actorId); + var actor = new Actor(this, new ActorId(actorIdRaw)); if (asset.IsEmpty) return actor; @@ -40,25 +40,8 @@ public Actor BuildActor(in Asset asset, Args? args = null) return actor; } - /// - /// Создает типизированного актёра с компонентом указанного типа на основе ассета. - /// - /// Тип компонента, который будет иметь актёр. - /// Ассет, используемый для построения актёра. - /// Дополнительные аргументы для построения актёра. Если не указаны, будут арендованы пустые аргументы. - /// Типизированный актёр с компонентом указанного типа. - /// - /// Метод создает обычного актёра с помощью , а затем преобразует его в типизированного актёра. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Actor BuildActor(in Asset asset, Args? args = null) - where TComponent : struct, IActorComponent - { - return BuildActor(in asset, args).As(); - } - internal void LoadBuilders(IEnumerable builders) { - _builders = builders.ToArray(); + _builders = [.. builders]; } } \ No newline at end of file diff --git a/src/Hexecs/Actors/ActorContext.Children.cs b/src/Hexecs/Actors/ActorContext.Children.cs index 571e14e..654ac46 100644 --- a/src/Hexecs/Actors/ActorContext.Children.cs +++ b/src/Hexecs/Actors/ActorContext.Children.cs @@ -4,7 +4,7 @@ namespace Hexecs.Actors; public sealed partial class ActorContext { - public void AddChild(uint parentId, uint childId) + public void AddChild(ActorId parentId, ActorId childId) { if (parentId == childId) return; @@ -13,7 +13,7 @@ public void AddChild(uint parentId, uint childId) if (childNode.ParentId == parentId) return; // Если у ребенка уже есть родитель — отсоединяем - if (childNode.ParentId != 0) + if (childNode.ParentId.IsNotEmpty) { RemoveChild(childNode.ParentId, childId); } @@ -24,9 +24,9 @@ public void AddChild(uint parentId, uint childId) var oldFirstId = parentNode.FirstChildId; childNode.ParentId = parentId; childNode.NextSiblingId = oldFirstId; - childNode.PrevSiblingId = 0; + childNode.PrevSiblingId = ActorId.Empty; - if (oldFirstId != 0) + if (oldFirstId.IsNotEmpty) { ref var oldFirstNode = ref GetComponent(oldFirstId); oldFirstNode.PrevSiblingId = childId; @@ -36,18 +36,18 @@ public void AddChild(uint parentId, uint childId) parentNode.ChildCount++; } - public ChildrenEnumerator Children(uint parentId) + public ChildrenEnumerator Children(ActorId parentId) { ref var component = ref TryGetComponentRef(parentId); - return Unsafe.IsNullRef(ref component) || component.FirstChildId == 0 + return Unsafe.IsNullRef(ref component) || component.FirstChildId.IsEmpty ? ChildrenEnumerator.Empty : new ChildrenEnumerator(this, component.FirstChildId, component.ChildCount); } - public bool HasChild(uint parentId, uint childId) + public bool HasChild(ActorId parentId, ActorId childId) { ref var component = ref TryGetComponentRef(parentId); - if (Unsafe.IsNullRef(ref component) || component.FirstChildId == 0) return false; + if (Unsafe.IsNullRef(ref component) || component.FirstChildId.IsEmpty) return false; foreach (var child in Children(parentId)) { @@ -57,7 +57,7 @@ public bool HasChild(uint parentId, uint childId) return false; } - public bool RemoveChild(uint parentId, uint childId) + public bool RemoveChild(ActorId parentId, ActorId childId) { ref var parentNode = ref TryGetComponentRef(parentId); if (Unsafe.IsNullRef(ref parentNode)) return false; @@ -66,7 +66,7 @@ public bool RemoveChild(uint parentId, uint childId) if (Unsafe.IsNullRef(ref childNode) || childNode.ParentId != parentId) return false; // 1. Обновляем ссылку у предыдущего соседа или у родителя - if (childNode.PrevSiblingId != 0) + if (childNode.PrevSiblingId.IsNotEmpty) { ref var prevNode = ref GetComponent(childNode.PrevSiblingId); prevNode.NextSiblingId = childNode.NextSiblingId; @@ -78,25 +78,25 @@ public bool RemoveChild(uint parentId, uint childId) } // 2. Обновляем ссылку у следующего соседа - if (childNode.NextSiblingId != 0) + if (childNode.NextSiblingId.IsNotEmpty) { ref var nextNode = ref GetComponent(childNode.NextSiblingId); nextNode.PrevSiblingId = childNode.PrevSiblingId; } // 3. Сбрасываем данные узла - childNode.ParentId = 0; - childNode.NextSiblingId = 0; - childNode.PrevSiblingId = 0; + childNode.ParentId = ActorId.Empty; + childNode.NextSiblingId = ActorId.Empty; + childNode.PrevSiblingId = ActorId.Empty; parentNode.ChildCount--; return true; } - public bool TryGetParent(uint childId, out Actor parent) + public bool TryGetParent(ActorId childId, out Actor parent) { ref var component = ref TryGetComponentRef(childId); - if (!Unsafe.IsNullRef(ref component) && component.ParentId != 0) + if (!Unsafe.IsNullRef(ref component) && component.ParentId.IsNotEmpty) { parent = new Actor(this, component.ParentId); return true; @@ -109,7 +109,7 @@ public bool TryGetParent(uint childId, out Actor parent) private void OnNodeRemoving(ref ActorNodeComponent node) { var parentId = node.ParentId; - if (parentId != 0) + if (parentId.IsNotEmpty) { ref var parentNode = ref TryGetComponentRef(parentId); if (!Unsafe.IsNullRef(ref parentNode)) @@ -117,7 +117,7 @@ private void OnNodeRemoving(ref ActorNodeComponent node) var prevId = node.PrevSiblingId; var nextId = node.NextSiblingId; - if (prevId != 0) + if (prevId.IsNotEmpty) { ref var prevNode = ref TryGetComponentRef(prevId); if (!Unsafe.IsNullRef(ref prevNode)) prevNode.NextSiblingId = nextId; @@ -127,7 +127,7 @@ private void OnNodeRemoving(ref ActorNodeComponent node) parentNode.FirstChildId = nextId; } - if (nextId != 0) + if (nextId.IsNotEmpty) { ref var nextNode = ref TryGetComponentRef(nextId); if (!Unsafe.IsNullRef(ref nextNode)) nextNode.PrevSiblingId = prevId; @@ -139,16 +139,16 @@ private void OnNodeRemoving(ref ActorNodeComponent node) // 2. У всех детей обнуляем ссылки (теперь они сироты без соседей) var currentChildId = node.FirstChildId; - while (currentChildId != 0) + while (currentChildId.IsNotEmpty) { ref var childNode = ref TryGetComponentRef(currentChildId); if (Unsafe.IsNullRef(ref childNode)) break; var nextSiblingId = childNode.NextSiblingId; - childNode.ParentId = 0; - childNode.PrevSiblingId = 0; - childNode.NextSiblingId = 0; + childNode.ParentId = ActorId.Empty; + childNode.PrevSiblingId = ActorId.Empty; + childNode.NextSiblingId = ActorId.Empty; currentChildId = nextSiblingId; } diff --git a/src/Hexecs/Actors/ActorContext.ChildrenEnumerator.cs b/src/Hexecs/Actors/ActorContext.ChildrenEnumerator.cs index 114832e..718ba0f 100644 --- a/src/Hexecs/Actors/ActorContext.ChildrenEnumerator.cs +++ b/src/Hexecs/Actors/ActorContext.ChildrenEnumerator.cs @@ -25,15 +25,15 @@ public readonly int Length } private readonly ActorContext _context; - private uint _currentId; - private uint _nextId; + private ActorId _currentId; + private ActorId _nextId; private readonly uint _count; [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal ChildrenEnumerator(ActorContext context, uint firstChildId, uint count) + internal ChildrenEnumerator(ActorContext context, ActorId firstChildId, uint count) { _context = context; - _currentId = 0; + _currentId = ActorId.Empty; _nextId = firstChildId; _count = count; } @@ -41,7 +41,7 @@ internal ChildrenEnumerator(ActorContext context, uint firstChildId, uint count) [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool MoveNext() { - if (_nextId == 0) return false; + if (_nextId.IsEmpty) return false; _currentId = _nextId; ref var node = ref _context.GetComponent(_currentId); diff --git a/src/Hexecs/Actors/ActorContext.ComponenetEnumerator.cs b/src/Hexecs/Actors/ActorContext.ComponenetEnumerator.cs index 3974a88..1e27bd0 100644 --- a/src/Hexecs/Actors/ActorContext.ComponenetEnumerator.cs +++ b/src/Hexecs/Actors/ActorContext.ComponenetEnumerator.cs @@ -25,7 +25,7 @@ public readonly int Length } private int _index; - private readonly uint _actorId; + private readonly ActorId _actorId; private readonly ReadOnlySpan _componentIds; private readonly IActorComponentPool?[] _pools; @@ -33,13 +33,13 @@ public readonly int Length public ComponentEnumerator() { _index = -1; - _actorId = 0; + _actorId = ActorId.Empty; _componentIds = ReadOnlySpan.Empty; _pools = []; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal ComponentEnumerator(uint actorId, IActorComponentPool?[] pools, ReadOnlySpan componentIds) + internal ComponentEnumerator(ActorId actorId, IActorComponentPool?[] pools, ReadOnlySpan componentIds) { _index = -1; _actorId = actorId; diff --git a/src/Hexecs/Actors/ActorContext.Components.cs b/src/Hexecs/Actors/ActorContext.Components.cs index d2b0017..0d5a3b0 100644 --- a/src/Hexecs/Actors/ActorContext.Components.cs +++ b/src/Hexecs/Actors/ActorContext.Components.cs @@ -21,13 +21,13 @@ public sealed partial class ActorContext /// Идентификатор актёра. /// Компонент для добавления. /// Ссылка на добавленный компонент в пуле. - public ref T AddComponent(uint actorId, in T component) + public ref T AddComponent(ActorId actorId, in T component) where T : struct, IActorComponent { var pool = GetOrCreateComponentPool(); ref var result = ref pool.Add(actorId, in component); - ref var entry = ref GetEntryRefExact(actorId); + ref var entry = ref GetEntryRefExact(actorId.Value); entry.Add(ActorComponentType.Id); return ref result; @@ -42,12 +42,12 @@ public ref T AddComponent(uint actorId, in T component) /// Ссылка на клонированный компонент в пуле. /// Выбрасывается, если компонент типа не найден у актёра-владельца. /// Выбрасывается, если компонент типа уже существует у того актёра, которому клонируется компонент. - public ref T CloneComponent(uint ownerId, uint cloneId) where T : struct, IActorComponent + public ref T CloneComponent(ActorId ownerId, ActorId cloneId) where T : struct, IActorComponent { var pool = GetComponentPool(); if (pool == null) ActorError.ComponentNotFound(ownerId); - ref var clone = ref GetEntryRefExact(cloneId); + ref var clone = ref GetEntryRefExact(cloneId.Value); if (clone.TryAdd(ActorComponentType.Id)) { return ref pool.Clone(ownerId, cloneId); @@ -63,9 +63,9 @@ public ref T CloneComponent(uint ownerId, uint cloneId) where T : struct, IAc /// Идентификатор актёра. /// Не нужно использовать этот метод в "горячих" местах кода /// Перечислитель компонентов. Возвращает , если актёр не найден. - public ComponentEnumerator Components(uint actorId) + public ComponentEnumerator Components(ActorId actorId) { - ref var entry = ref GetEntryRef(actorId); + ref var entry = ref GetEntryRef(actorId.Value); return Unsafe.IsNullRef(ref entry) ? ComponentEnumerator.Empty : new ComponentEnumerator(actorId, _componentPools, entry.ToArray()); @@ -78,7 +78,7 @@ public ComponentEnumerator Components(uint actorId) /// Идентификатор актёра. /// Ссылка на компонент в пуле. /// Выбрасывается, если актёр не имеет компонента типа . - public ref T GetComponent(uint actorId) where T : struct, IActorComponent + public ref T GetComponent(ActorId actorId) where T : struct, IActorComponent { var pool = GetComponentPool(); if (pool == null) ActorError.ComponentNotFound(actorId); @@ -86,14 +86,14 @@ public ref T GetComponent(uint actorId) where T : struct, IActorComponent } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ComponentsAccess GetComponents() where T: struct, IActorComponent + public ComponentsAccess GetComponents() where T : struct, IActorComponent { var pool = GetComponentPool(); - return pool != null - ? pool.GetComponentAccess() + return pool != null + ? pool.GetComponentAccess() : new ComponentsAccess(); } - + /// /// Получает компонент указанного типа для заданного актёра или добавляет его, используя фабричный метод, если компонент отсутствует. /// @@ -101,7 +101,7 @@ public ComponentsAccess GetComponents() where T: struct, IActorComponent /// Идентификатор актёра. /// Фабричный метод для создания компонента /// Ссылка на существующий или вновь созданный компонент. - public ref T GetOrAddComponent(uint actorId, Func? factory = null) + public ref T GetOrAddComponent(ActorId actorId, Func? factory = null) where T : struct, IActorComponent { var pool = GetOrCreateComponentPool(); @@ -110,7 +110,7 @@ public ref T GetOrAddComponent(uint actorId, Func? factory = null) // ReSharper disable once InvertIf if (added) { - ref var entry = ref GetEntryRefExact(actorId); + ref var entry = ref GetEntryRefExact(actorId.Value); entry.Add(ActorComponentType.Id); } @@ -124,7 +124,7 @@ public ref T GetOrAddComponent(uint actorId, Func? factory = null) /// Идентификатор актёра. /// true, если актёр имеет компонент; в противном случае false. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool HasComponent(uint actorId) where T : struct, IActorComponent + public bool HasComponent(ActorId actorId) where T : struct, IActorComponent { var pool = GetComponentPool(); return pool != null && pool.Has(actorId); @@ -135,7 +135,7 @@ public bool HasComponent(uint actorId) where T : struct, IActorComponent /// /// Тип компонента. Должен быть структурой и реализовывать . /// Обработчик, принимающий идентификатор актёра. - public void OnComponentAdded(Action handler) + public void OnComponentAdded(Action handler) where T : struct, IActorComponent { var pool = GetOrCreateComponentPool(); @@ -159,7 +159,7 @@ public void OnComponentAdded(ActorComponentAdded handler) /// /// Тип компонента. Должен быть структурой и реализовывать . /// Обработчик, принимающий идентификатор актёра. - public void OnComponentRemoving(Action handler) + public void OnComponentRemoving(Action handler) where T : struct, IActorComponent { var pool = GetOrCreateComponentPool(); @@ -196,13 +196,13 @@ public void OnComponentUpdating(ActorComponentUpdating handler) /// Тип компонента. Должен быть структурой и реализовывать . /// Идентификатор актёра. /// true, если компонент был успешно удален; в противном случае false (например, если компонент не найден). - public bool RemoveComponent(uint actorId) + public bool RemoveComponent(ActorId actorId) where T : struct, IActorComponent { var pool = GetComponentPool(); if (pool != null && pool.Remove(actorId)) { - ref var entry = ref GetEntryRefExact(actorId); + ref var entry = ref GetEntryRefExact(actorId.Value); entry.Remove(ActorComponentType.Id); return true; } @@ -217,7 +217,7 @@ public bool RemoveComponent(uint actorId) /// Идентификатор актёра. /// Удаленный компонент. /// true, если компонент был успешно удален; в противном случае false. - public bool RemoveComponent(uint actorId, out T component) + public bool RemoveComponent(ActorId actorId, out T component) where T : struct, IActorComponent { var pool = GetComponentPool(); @@ -227,7 +227,7 @@ public bool RemoveComponent(uint actorId, out T component) return false; } - ref var entry = ref GetEntryRefExact(actorId); + ref var entry = ref GetEntryRefExact(actorId.Value); entry.Remove(ActorComponentType.Id); return true; @@ -240,7 +240,7 @@ public bool RemoveComponent(uint actorId, out T component) /// Идентификатор актёра. /// Компонент для добавления. /// true, если компонент успешно добавлен; false, если актёр уже имеет компонент данного типа. - public bool TryAdd(uint actorId, in T component) + public bool TryAdd(ActorId actorId, in T component) where T : struct, IActorComponent { var pool = GetOrCreateComponentPool(); @@ -248,7 +248,7 @@ public bool TryAdd(uint actorId, in T component) if (!result) return false; - ref var entry = ref GetEntryRefExact(actorId); + ref var entry = ref GetEntryRefExact(actorId.Value); entry.Add(ActorComponentType.Id); return true; } @@ -260,13 +260,13 @@ public bool TryAdd(uint actorId, in T component) /// Идентификатор актёра. /// Ссылка на компонент, если он существует; в противном случае . [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ref T TryGetComponentRef(uint actorId) + public ref T TryGetComponentRef(ActorId actorId) where T : struct, IActorComponent { var pool = GetComponentPool(); if (pool != null) { - return ref pool.TryGet(actorId); + return ref pool.TryGet(actorId.Value); } return ref Unsafe.NullRef(); @@ -280,7 +280,7 @@ public ref T TryGetComponentRef(uint actorId) /// Новое значение компонента. /// Если true, компонент будет добавлен, если он не существует. По умолчанию true. /// true, если компонент был обновлен или добавлен; false, если пул компонентов не найден или равен false и компонент не существует. - public bool UpdateComponent(uint actorId, in T component, bool createIfNotExists = true) + public bool UpdateComponent(ActorId actorId, in T component, bool createIfNotExists = true) where T : struct, IActorComponent { var pool = GetComponentPool(); diff --git a/src/Hexecs/Actors/ActorContext.Dictionary.cs b/src/Hexecs/Actors/ActorContext.Dictionary.cs index b187cf0..5c6d4df 100644 --- a/src/Hexecs/Actors/ActorContext.Dictionary.cs +++ b/src/Hexecs/Actors/ActorContext.Dictionary.cs @@ -26,7 +26,7 @@ private ref Entry AddEntry(uint actorId) ref var entry = ref TryAddEntry(actorId); if (!Unsafe.IsNullRef(ref entry)) { - Created?.Invoke(actorId); + Created?.Invoke(new ActorId(actorId)); return ref entry; } @@ -34,8 +34,9 @@ private ref Entry AddEntry(uint actorId) return ref Unsafe.NullRef(); } - private void ClearEntry(uint actorId, ref Entry entry) + private void ClearEntry(uint actorIdRaw, ref Entry entry) { + var actorId = new ActorId(actorIdRaw); ref var node = ref TryGetComponentRef(actorId); if (!Unsafe.IsNullRef(ref node)) { @@ -152,7 +153,7 @@ private bool RemoveEntry(uint actorId) if (_dense[denseIndex] != actorId) return false; // 1. Уведомляем системы ПЕРЕД какими-либо изменениями структуры - Destroying?.Invoke(actorId); + Destroying?.Invoke(new ActorId(actorId)); // 2. Очищаем данные сущности (пулы компонентов и т.д.) ref var entryToRemove = ref _values[denseIndex]; diff --git a/src/Hexecs/Actors/ActorContext.Enumerator.cs b/src/Hexecs/Actors/ActorContext.Enumerator.cs index b8afbb5..603173a 100644 --- a/src/Hexecs/Actors/ActorContext.Enumerator.cs +++ b/src/Hexecs/Actors/ActorContext.Enumerator.cs @@ -15,7 +15,7 @@ public struct Enumerator : IEnumerator, IEnumerable public readonly Actor Current { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => new(_context, _dense[_index]); + get => new(_context, new ActorId(_dense[_index])); } public readonly int Length diff --git a/src/Hexecs/Actors/ActorContext.Relations.cs b/src/Hexecs/Actors/ActorContext.Relations.cs index eaa3945..436a39c 100644 --- a/src/Hexecs/Actors/ActorContext.Relations.cs +++ b/src/Hexecs/Actors/ActorContext.Relations.cs @@ -20,7 +20,7 @@ public sealed partial class ActorContext /// Данные отношения. /// Ссылка на добавленное отношение. /// Вызывается, если отношение между указанными актёрами уже существует. - public ref T AddRelation(uint subject, uint relative, in T relation) + public ref T AddRelation(ActorId subject, ActorId relative, in T relation) where T : struct { var relationPool = GetOrCreateRelationPool(); @@ -45,7 +45,7 @@ public ref T AddRelation(uint subject, uint relative, in T relation) /// Идентификатор второго актёра (относительного). /// Ссылка на найденное отношение. /// Вызывается, если отношение не найдено. - public ref T GetRelation(uint subject, uint relative) where T : struct + public ref T GetRelation(ActorId subject, ActorId relative) where T : struct { var pool = GetRelationPool(); if (pool == null) ActorError.RelationNotFound(subject, relative); @@ -59,7 +59,7 @@ public ref T GetRelation(uint subject, uint relative) where T : struct /// Идентификатор первого актёра (субъекта). /// Идентификатор второго актёра (относительного). /// True, если отношение существует, иначе false. - public bool HasRelation(uint subject, uint relative) where T : struct + public bool HasRelation(ActorId subject, ActorId relative) where T : struct { var pool = GetRelationPool(); return pool != null && pool.Has(subject, relative); @@ -71,7 +71,7 @@ public bool HasRelation(uint subject, uint relative) where T : struct /// Тип отношения. Должен быть структурой. /// Идентификатор актёра (субъекта). /// Перечислитель отношений. - public ActorRelationEnumerator Relations(uint subject) where T : struct + public ActorRelationEnumerator Relations(ActorId subject) where T : struct { var pool = GetRelationPool(); @@ -88,7 +88,7 @@ public ActorRelationEnumerator Relations(uint subject) where T : struct /// Идентификатор первого актёра (субъекта). /// Идентификатор второго актёра (относительного). /// True, если отношение было успешно удалено, иначе false. - public bool RemoveRelation(uint subject, uint relative) where T : struct + public bool RemoveRelation(ActorId subject, ActorId relative) where T : struct { return RemoveRelation(subject, relative, out _); } @@ -102,7 +102,7 @@ public bool RemoveRelation(uint subject, uint relative) where T : struct /// Удаленное отношение. /// True, если отношение было успешно удалено, иначе false. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool RemoveRelation(uint subject, uint relative, out T relation) where T : struct + public bool RemoveRelation(ActorId subject, ActorId relative, out T relation) where T : struct { var pool = GetRelationPool(); if (pool == null) diff --git a/src/Hexecs/Actors/ActorContext.cs b/src/Hexecs/Actors/ActorContext.cs index cd88df8..05ffe79 100644 --- a/src/Hexecs/Actors/ActorContext.cs +++ b/src/Hexecs/Actors/ActorContext.cs @@ -24,12 +24,12 @@ public sealed partial class ActorContext : IEnumerable, IDisposable /// /// Событие, вызываемое при завершении создания актёра. /// - public event Action? Created; + public event Action? Created; /// /// Событие, вызываемое в начале удаления актёра. /// - public event Action? Destroying; + public event Action? Destroying; /// /// Уникальный идентификатор контекста актёров. @@ -100,7 +100,10 @@ internal ActorContext(bool isDefault, /// Идентификатор актёра для проверки /// Возвращает true, если актёр существует, иначе false [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool ActorAlive(uint actorId) => !Unsafe.IsNullRef(ref GetEntryRef(actorId)); + public bool ActorAlive(ActorId actorId) + { + return !Unsafe.IsNullRef(ref GetEntryRef(actorId.Value)); + } /// /// Очищает контекст актёров, удаляя всех актёров и их компоненты. @@ -133,12 +136,13 @@ public void Clear() /// Флаг, указывающий нужно ли сохранять родительскую связь /// Новый актёр, являющийся клоном исходного /// Возникает, если актёр с указанным идентификатором не найден - public Actor Clone(uint actorId, bool withParent = true) + public Actor Clone(ActorId actorId, bool withParent = true) { - var cloneId = GetNextActorId(); - ref var cloneEntry = ref AddEntry(cloneId); + var cloneIdRaw = GetNextActorId(); + ref var cloneEntry = ref AddEntry(cloneIdRaw); - ref var entry = ref GetEntryRefExact(actorId); + var cloneId = new ActorId(cloneIdRaw); + ref var entry = ref GetEntryRefExact(actorId.Value); foreach (var componentId in entry) { var componentPool = _componentPools[componentId]!; @@ -164,11 +168,11 @@ public Actor Clone(uint actorId, bool withParent = true) [MethodImpl(MethodImplOptions.AggressiveInlining)] public Actor CreateActor(uint? expectedId = null) { - if (expectedId == Actor.EmptyId) ActorError.InvalidId(); + if (expectedId == ActorId.EmptyId) ActorError.InvalidId(); var actorId = expectedId ?? GetNextActorId(); AddEntry(actorId); - return new Actor(this, actorId); + return new Actor(this, new ActorId(actorId)); } /// @@ -177,11 +181,11 @@ public Actor CreateActor(uint? expectedId = null) /// Идентификатор уничтожаемого актёра /// Возвращает true, если актёр был успешно уничтожен, иначе false [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool DestroyActor(uint actorId) + public bool DestroyActor(ActorId actorId) { - if (RemoveEntry(actorId)) + if (RemoveEntry(actorId.Value)) { - _freeIds.Push(actorId); + _freeIds.Push(actorId.Value); return true; } @@ -217,7 +221,7 @@ public void Dispose() /// Идентификатор актёра /// Актёр с указанным идентификатором /// Возникает, если актёр с указанным идентификатором не найден - public Actor GetActor(uint actorId) + public Actor GetActor(ActorId actorId) { if (!ActorAlive(actorId)) ActorError.NotFound(actorId); return new Actor(this, actorId); @@ -229,75 +233,45 @@ public Actor GetActor(uint actorId) /// Тип компонента /// Первый найденный актёр с компонентом указанного типа /// Возникает, если актёр с компонентом указанного типа не найден - public Actor GetActor() - where T1 : struct, IActorComponent - { - var pool = GetComponentPool(); - if (pool is { Length: > 0 }) return pool.First(); - - ActorError.NotFound(); - return Actor.Empty; - } - - /// - /// Получает первого актёра с компонентом указанного типа, удовлетворяющего предикату. - /// - /// Тип компонента - /// Предикат для фильтрации актёров - /// Первый найденный актёр, удовлетворяющий предикату - /// Возникает, если подходящий актёр не найден - public Actor GetActor(ActorPredicate predicate) + public ActorRef GetActorRef() where T1 : struct, IActorComponent { var pool = GetComponentPool(); if (pool != null) { - var exists = pool.First(predicate); - if (exists) return new Actor(this, exists.Id); + var first = pool.First(); + if (!first.IsEmpty) + { + return first; + } } - ActorError.ApplicableNotFound(); - return Actor.Empty; + ActorError.NotFound(); + return ActorRef.Empty; } /// - /// Получает актёра с указанным идентификатором и компонентом указанного типа. + /// Получает ссылку на актёра с указанным идентификатором и компонентом указанного типа. /// /// Тип компонента /// Идентификатор актёра - /// Актёр с указанным идентификатором и компонентом + /// Ссылка на актёра с указанным идентификатором и компонентом /// Возникает, если актёр не найден или не содержит указанный компонент - public Actor GetActor(uint actorId) + public ActorRef GetActorRef(ActorId actorId) where T1 : struct, IActorComponent { - var pool = GetComponentPool(); - if (pool == null || !pool.Has(actorId)) ActorError.ComponentNotFound(actorId); - - return new Actor(this, actorId); - } - - /// - /// Получает ссылку на первого актёра с компонентом указанного типа. - /// - /// Тип компонента - /// Ссылка на первого найденного актёра с компонентом указанного типа - /// Возникает, если актёр с компонентом указанного типа не найден - public ActorRef GetActorRef() - where T1 : struct, IActorComponent - { - var pool = GetComponentPool(); - if (pool is { Length: > 0 }) return pool.First(); + ref var component = ref TryGetComponentRef(actorId); + if (Unsafe.IsNullRef(ref component)) ActorError.ComponentNotFound(actorId); - ActorError.NotFound(); - return ActorRef.Empty; + return new ActorRef(this, actorId, ref component); } /// - /// Получает ссылку на первого актёра с компонентом указанного типа, удовлетворяющего предикату. + /// Получает первого актёра с компонентом указанного типа, удовлетворяющего предикату. /// /// Тип компонента /// Предикат для фильтрации актёров - /// Ссылка на первого найденного актёра, удовлетворяющего предикату + /// Первый найденный актёр, удовлетворяющий предикату /// Возникает, если подходящий актёр не найден public ActorRef GetActorRef(ActorPredicate predicate) where T1 : struct, IActorComponent @@ -306,29 +280,16 @@ public ActorRef GetActorRef(ActorPredicate predicate) if (pool != null) { var exists = pool.First(predicate); - if (exists) return exists; + if (!exists.IsEmpty) + { + return exists; + } } ActorError.ApplicableNotFound(); return ActorRef.Empty; } - /// - /// Получает ссылку на актёра с указанным идентификатором и компонентом указанного типа. - /// - /// Тип компонента - /// Идентификатор актёра - /// Ссылка на актёра с указанным идентификатором и компонентом - /// Возникает, если актёр не найден или не содержит указанный компонент - public ActorRef GetActorRef(uint actorId) - where T1 : struct, IActorComponent - { - ref var component = ref TryGetComponentRef(actorId); - if (Unsafe.IsNullRef(ref component)) ActorError.ComponentNotFound(actorId); - - return new ActorRef(this, actorId, ref component); - } - /// /// Получает текстовое описание актёра. /// @@ -336,27 +297,28 @@ public ActorRef GetActorRef(uint actorId) /// Максимальное количество отображаемых компонентов /// Текстовое описание актёра [SkipLocalsInit] - public string GetDescription(uint actorId, int maxComponentDescription = 5) + public string GetDescription(ActorId actorId, int maxComponentDescription = 5) { var builder = new ValueStringBuilder(stackalloc char[512]); GetDescription(actorId, ref builder, maxComponentDescription); return builder.Flush(); } - - public void GetDescription(uint actorId, ref ValueStringBuilder builder, int maxComponentDescription = 5) + public void GetDescription(ActorId actorId, ref ValueStringBuilder builder, int maxComponentDescription = 5) { - ref var entry = ref GetEntryRef(actorId); + ref var entry = ref GetEntryRef(actorId.Value); if (Unsafe.IsNullRef(ref entry)) { builder.Append('\''); builder.Append(StringUtils.EmptyValue); builder.Append('\''); + + return; } builder.Append("Id = "); - builder.Append(actorId); - + builder.Append(actorId.Value); + var componentsLength = entry.Length; if (componentsLength == 0) return; @@ -397,33 +359,8 @@ public void GetDescription(uint actorId, ref ValueStringBuilder builder, int max if (printMore) builder.Append(", ..."); builder.Append(')'); - - pool.Return(buffer); - } - /// - /// Получает единственный актёр с компонентом указанного типа. - /// - /// Тип компонента - /// Единственный актёр с компонентом указанного типа - /// Возникает, если актёр не найден или найдено более одного актёра - public Actor Single() - where T1 : struct, IActorComponent - { - var componentId = ActorComponentType.Id; - if (_singles.TryGetValue(componentId, out var exists)) - { - return new Actor(this, exists); - } - - var pool = GetComponentPool(); - if (pool == null) ActorError.SingleNotFound(); - if (pool.Length > 1) ActorError.NotSingle(); - - var single = pool.First(); - _singles.Add(componentId, single.Id); - - return single; + pool.Return(buffer); } /// @@ -447,32 +384,11 @@ public ActorRef SingleRef() if (pool.Length > 1) ActorError.NotSingle(); var single = pool.First(); - _singles.Add(componentId, single.Id); + _singles.Add(componentId, single.Id.Value); return single; } - /// - /// Пытается получить актёра с указанным идентификатором и компонентом указанного типа. - /// - /// Тип компонента - /// Идентификатор актёра - /// Переменная для сохранения найденного актёра - /// Возвращает true, если актёр найден и содержит указанный компонент, иначе false - public bool TryGetActor(uint actorId, out Actor actor) - where T1 : struct, IActorComponent - { - var pool = GetComponentPool(); - if (pool == null || !pool.Has(actorId)) - { - actor = Actor.Empty; - return false; - } - - actor = new Actor(this, actorId); - return true; - } - /// /// Пытается получить ссылку на актёра с указанным идентификатором и компонентом указанного типа. /// @@ -480,7 +396,7 @@ public bool TryGetActor(uint actorId, out Actor actor) /// Идентификатор актёра /// Переменная для сохранения ссылки на найденного актёра /// Возвращает true, если актёр найден и содержит указанный компонент, иначе false - public bool TryGetActorRef(uint actorId, out ActorRef actor) + public bool TryGetActorRef(ActorId actorId, out ActorRef actor) where T1 : struct, IActorComponent { ref var component = ref TryGetComponentRef(actorId); @@ -506,7 +422,7 @@ private uint GetNextActorId() } var actorId = Interlocked.Increment(ref _nextActorId); - while (ActorAlive(actorId)) + while (!Unsafe.IsNullRef(ref GetEntryRef(actorId))) // is alive { actorId = Interlocked.Increment(ref _nextActorId); } diff --git a/src/Hexecs/Actors/ActorDictionary.cs b/src/Hexecs/Actors/ActorDictionary.cs index 99643b8..eacf224 100644 --- a/src/Hexecs/Actors/ActorDictionary.cs +++ b/src/Hexecs/Actors/ActorDictionary.cs @@ -15,7 +15,7 @@ public int Length get => _actors.Count; } - private readonly Dictionary _actors; + private readonly Dictionary _actors; private readonly Func _keyExtractor; private readonly ActorComponentPool _pool; @@ -30,8 +30,8 @@ public ActorDictionary( Context = context; _actors = comparer == null - ? new Dictionary(capacity) - : new Dictionary(capacity, comparer); + ? new Dictionary(capacity) + : new Dictionary(capacity, comparer); _keyExtractor = keyExtractor; _pool = context.GetOrCreateComponentPool(); @@ -42,13 +42,16 @@ public ActorDictionary( context.Cleared += OnCleared; } - public void Add(Actor actor) + public void Add(ActorRef actor) { ObjectDisposedException.ThrowIf(_disposed, this); _actors.Add(_keyExtractor(actor.Component1), actor.Id); } - public bool ContainsKey(TKey key) => !_disposed && _actors.ContainsKey(key); + public bool ContainsKey(TKey key) + { + return !_disposed && _actors.ContainsKey(key); + } public void Dispose() { @@ -79,9 +82,9 @@ public void Fill(bool clearBefore = true) public ActorRef GetActorRef(TKey key) { - if (!_disposed && _actors.TryGetValue(key, out var entry)) + if (!_disposed && _actors.TryGetValue(key, out var actorId)) { - return new ActorRef(Context, entry, ref _pool.Get(entry)); + return new ActorRef(Context, actorId, ref _pool.Get(actorId)); } ActorError.KeyNotFound(); @@ -90,9 +93,9 @@ public ActorRef GetActorRef(TKey key) public bool TryGetActorRef(TKey key, out ActorRef actor) { - if (!_disposed && _actors.TryGetValue(key, out var entry)) + if (!_disposed && _actors.TryGetValue(key, out var actorId)) { - actor = new ActorRef(Context, entry, ref _pool.Get(entry)); + actor = new ActorRef(Context, actorId, ref _pool.Get(actorId)); return true; } @@ -111,12 +114,12 @@ private void OnCleared() _actors.Clear(); } - private void OnComponentRemoving(uint actorId, ref T1 component) + private void OnComponentRemoving(ActorId actorId, ref T1 component) { _actors.Remove(_keyExtractor(component)); } - private void OnComponentUpdating(uint actorId, ref T1 exists, in T1 expected) + private void OnComponentUpdating(ActorId actorId, ref T1 exists, in T1 expected) { _actors.Remove(_keyExtractor(exists), out _); _actors.Add(_keyExtractor(expected), actorId); diff --git a/src/Hexecs/Actors/ActorError.cs b/src/Hexecs/Actors/ActorError.cs index c339f7e..adaa743 100644 --- a/src/Hexecs/Actors/ActorError.cs +++ b/src/Hexecs/Actors/ActorError.cs @@ -40,9 +40,9 @@ public static void AlreadyExists(uint actorId) /// /// Идентификатор актёра [DoesNotReturn] - public static void AssetNotFound(uint actorId) + public static void AssetNotFound(ActorId actorId) { - throw new Exception($"Actor {actorId} don't have associated asset"); + throw new Exception($"Actor '{actorId.Value}' don't have associated asset"); } /// @@ -95,9 +95,9 @@ public static void ConstraintExists() /// Тип компонента /// Идентификатор актёра [DoesNotReturn] - public static void ComponentExists(uint actorId) + public static void ComponentExists(ActorId actorId) { - throw new Exception($"Actor {actorId} already has component {TypeOf.GetTypeName()}"); + throw new Exception($"Actor '{actorId.Value}' already has component {TypeOf.GetTypeName()}"); } /// @@ -107,9 +107,9 @@ public static void ComponentExists(uint actorId) /// Идентификатор актёра [DoesNotReturn] [MethodImpl(MethodImplOptions.NoInlining)] - public static ref T ComponentNotFound(uint actorId) + public static ref T ComponentNotFound(ActorId actorId) { - throw new Exception($"Actor {actorId} don't have component {TypeOf.GetTypeName()}"); + throw new Exception($"Actor '{actorId.Value}' doesn't have component {TypeOf.GetTypeName()}"); } /// @@ -148,7 +148,7 @@ public static void InvalidId() { throw new Exception("Invalid actor id"); } - + /// /// Генерирует исключение, когда актёр с указанным ключом не найден. /// @@ -158,6 +158,13 @@ public static void KeyNotFound() throw new KeyNotFoundException("Actor with given key isn't found"); } + /// + /// Генерирует исключение, когда актёр с указанным идентификатором не найден. + /// + /// Идентификатор актёра + [DoesNotReturn] + public static void NotFound(ActorId actorId) => NotFound(actorId.Value); + /// /// Генерирует исключение, когда актёр с указанным идентификатором не найден. /// @@ -165,7 +172,7 @@ public static void KeyNotFound() [DoesNotReturn] public static void NotFound(uint actorId) { - throw new Exception($"Actor with id {actorId} isn't found"); + throw new Exception($"Actor '{actorId}' isn't found"); } /// @@ -205,9 +212,9 @@ public static void ParallelWorkerNotRegistered() } [DoesNotReturn] - public static void RelationAlreadyExists(uint subject, uint relative) + public static void RelationAlreadyExists(ActorId subject, ActorId relative) { - throw new Exception($"Actor '{subject}' already has relation {TypeOf.GetTypeName()} with '{relative}'"); + throw new Exception($"Actor '{subject.Value}' already has relation {TypeOf.GetTypeName()} with '{relative.Value}'"); } /// @@ -217,9 +224,9 @@ public static void RelationAlreadyExists(uint subject, uint relative) /// Идентификатор субъекта связи /// Идентификатор связанного актёра [DoesNotReturn] - public static void RelationNotFound(uint subject, uint relative) + public static void RelationNotFound(ActorId subject, ActorId relative) { - throw new Exception($"Actor {subject} don't have relation {TypeOf.GetTypeName()} with {relative}"); + throw new Exception($"Actor {subject.Value} don't have relation {TypeOf.GetTypeName()} with {relative.Value}"); } /// diff --git a/src/Hexecs/Actors/ActorFilter1.Dictionary.cs b/src/Hexecs/Actors/ActorFilter1.Dictionary.cs index 0bf9a83..207a75e 100644 --- a/src/Hexecs/Actors/ActorFilter1.Dictionary.cs +++ b/src/Hexecs/Actors/ActorFilter1.Dictionary.cs @@ -89,7 +89,7 @@ private bool RemoveEntry(uint actorId) _sparse[actorId] = 0; _count = lastIndex; - Removed?.Invoke(actorId); + Removed?.Invoke(new ActorId(actorId)); return true; } } @@ -111,7 +111,7 @@ private bool TryAddEntry(uint actorId) _dense[idx] = actorId; _count++; - Added?.Invoke(actorId); + Added?.Invoke(new ActorId(actorId)); return true; } @@ -137,7 +137,7 @@ private bool TryAddEntrySlow(uint actorId) _dense[denseIndex] = actorId; _count++; - Added?.Invoke(actorId); + Added?.Invoke(new ActorId(actorId)); return true; } } \ No newline at end of file diff --git a/src/Hexecs/Actors/ActorFilter1.Enumerator.cs b/src/Hexecs/Actors/ActorFilter1.Enumerator.cs index 7c264c1..93b259f 100644 --- a/src/Hexecs/Actors/ActorFilter1.Enumerator.cs +++ b/src/Hexecs/Actors/ActorFilter1.Enumerator.cs @@ -19,13 +19,6 @@ public Enumerator GetEnumerator() public ref struct Enumerator { - private readonly ActorContext _context; - private readonly ActorFilter _filter; - private readonly ComponentsAccess _pool1; - - private readonly ReadOnlySpan _ids; - private int _index; - public readonly ActorRef Current { [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -35,7 +28,7 @@ public readonly ActorRef Current return new ActorRef( _context, - id, + new ActorId(id), ref _pool1[id]); } } @@ -45,6 +38,13 @@ public readonly int Length [MethodImpl(MethodImplOptions.AggressiveInlining)] get => _ids.Length; } + + private readonly ActorContext _context; + private readonly ActorFilter _filter; + private readonly ComponentsAccess _pool1; + + private readonly ReadOnlySpan _ids; + private int _index; [MethodImpl(MethodImplOptions.AggressiveInlining)] internal Enumerator(ActorFilter filter) diff --git a/src/Hexecs/Actors/ActorFilter1.Operation.cs b/src/Hexecs/Actors/ActorFilter1.Operation.cs index c764c1d..ddb0e04 100644 --- a/src/Hexecs/Actors/ActorFilter1.Operation.cs +++ b/src/Hexecs/Actors/ActorFilter1.Operation.cs @@ -9,23 +9,23 @@ private readonly struct Operation private const byte TypeRemove = 2; private const byte TypeClear = 3; - public readonly uint Id; + public readonly ActorId Id; public readonly byte Type; public bool IsAdd => Type == TypeAdd; public bool IsClear => Type == TypeClear; [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Operation Add(uint id) => new(id, TypeAdd); + public static Operation Add(ActorId id) => new(id, TypeAdd); [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Operation Remove(uint id) => new(id, TypeRemove); + public static Operation Remove(ActorId id) => new(id, TypeRemove); [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Operation Clear() => new(0, TypeClear); + public static Operation Clear() => new(ActorId.Empty, TypeClear); [MethodImpl(MethodImplOptions.AggressiveInlining)] - private Operation(uint id, byte type) + private Operation(ActorId id, byte type) { Id = id; Type = type; diff --git a/src/Hexecs/Actors/ActorFilter1.SkipTakeEnumerator.cs b/src/Hexecs/Actors/ActorFilter1.SkipTakeEnumerator.cs index e0b625a..73b7589 100644 --- a/src/Hexecs/Actors/ActorFilter1.SkipTakeEnumerator.cs +++ b/src/Hexecs/Actors/ActorFilter1.SkipTakeEnumerator.cs @@ -1,6 +1,4 @@ -using Hexecs.Actors.Components; - -namespace Hexecs.Actors; +namespace Hexecs.Actors; public sealed partial class ActorFilter { @@ -21,13 +19,6 @@ public SkipTakeEnumerator Skip(int skip, int take = int.MaxValue) public ref struct SkipTakeEnumerator { - private readonly ActorContext _context; - private readonly ActorFilter _filter; - private readonly ActorComponentPool _pool1; - - private readonly ReadOnlySpan _ids; - private int _index; - public readonly ActorRef Current { [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -37,8 +28,8 @@ public readonly ActorRef Current return new ActorRef( _context, - id, - ref _pool1.Get(id)); + new ActorId(id), + ref _pool1[id]); } } @@ -48,12 +39,19 @@ public readonly int Length get => _filter.Length; } + private readonly ActorContext _context; + private readonly ActorFilter _filter; + private readonly ComponentsAccess _pool1; + + private readonly ReadOnlySpan _ids; + private int _index; + [MethodImpl(MethodImplOptions.AggressiveInlining)] internal SkipTakeEnumerator(ActorFilter filter, int skip, int take = int.MaxValue) { - _filter = filter; _context = filter.Context; - _pool1 = filter._pool1; + _filter = filter; + _pool1 = filter._pool1.GetComponentAccess(); var count = filter._count; var actualSkip = Math.Min(skip, count); diff --git a/src/Hexecs/Actors/ActorFilter1.cs b/src/Hexecs/Actors/ActorFilter1.cs index c6cf506..9aa1a2e 100644 --- a/src/Hexecs/Actors/ActorFilter1.cs +++ b/src/Hexecs/Actors/ActorFilter1.cs @@ -9,9 +9,9 @@ namespace Hexecs.Actors; public sealed partial class ActorFilter : IActorFilter where T1 : struct, IActorComponent { - public event Action? Added; + public event Action? Added; public event Action? Cleared; - public event Action? Removed; + public event Action? Removed; public readonly ActorConstraint? Constraint; public readonly ActorContext Context; @@ -63,22 +63,13 @@ internal ActorFilter(ActorContext context, ActorConstraint? constraint = null, i #region Contains [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Contains(uint actorId) => ContainsEntry(actorId); + public bool Contains(ActorId actorId) => ContainsEntry(actorId.Value); [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Contains(in ActorId actorId) => ContainsEntry(actorId.Value); + public bool Contains(in Actor actor) => ContainsEntry(actor.Id.Value); [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Contains(in ActorId actorId) => ContainsEntry(actorId.Value); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Contains(in Actor actor) => ContainsEntry(actor.Id); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Contains(in Actor actor) => ContainsEntry(actor.Id); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Contains(in ActorRef actor) => ContainsEntry(actor.Id); + public bool Contains(in ActorRef actor) => ContainsEntry(actor.Id.Value); #endregion @@ -102,9 +93,9 @@ public void Dispose() } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ActorRef GetRef(uint actorId) + public ActorRef GetRef(ActorId actorId) { - if (!ContainsEntry(actorId)) ActorError.NotFound(actorId); + if (!ContainsEntry(actorId.Value)) ActorError.NotFound(actorId); return new ActorRef( Context, @@ -145,7 +136,7 @@ public Actor[] ToArray() for (var i = 0; i < count; i++) { - actors[i] = new Actor(ctx, keys[i]); + actors[i] = new Actor(ctx, new ActorId(keys[i])); } return actors; @@ -156,7 +147,7 @@ public Actor[] ToArray() } } - private void OnAdded(uint actorId) + private void OnAdded(ActorId actorId) { if (_pool1.Has(actorId)) { @@ -164,7 +155,10 @@ private void OnAdded(uint actorId) } } - private void OnAddedComponent1(uint actorId, ref T1 component) => Add(actorId); + private void OnAddedComponent1(ActorId actorId, ref T1 component) + { + Add(actorId); + } private void OnCleared() { @@ -188,11 +182,17 @@ private void OnCleared() _postponedUpdates.Enqueue(Operation.Clear()); } - private void OnRemoving(uint actorId) => Remove(actorId); + private void OnRemoving(ActorId actorId) + { + Remove(actorId); + } - private void OnRemovingComponent1(uint actorId, ref T1 component) => Remove(actorId); + private void OnRemovingComponent1(ActorId actorId, ref T1 component) + { + Remove(actorId); + } - private void Add(uint actorId) + private void Add(ActorId actorId) { if (Constraint != null && !Constraint.Applicable(actorId)) return; @@ -206,7 +206,7 @@ private void Add(uint actorId) { if (Volatile.Read(ref _postponedReadersCount) == 0) { - AddEntry(actorId); + AddEntry(actorId.Value); } } } @@ -239,11 +239,11 @@ private void ProcessPostponedUpdates() } else if (operation.IsAdd) { - AddEntry(operation.Id); + AddEntry(operation.Id.Value); } else { - RemoveEntry(operation.Id); + RemoveEntry(operation.Id.Value); } } } @@ -252,7 +252,7 @@ private void ProcessPostponedUpdates() if (isClear) Cleared?.Invoke(); } - private void Remove(uint actorId) + private void Remove(ActorId actorId) { if (Volatile.Read(ref _postponedReadersCount) == 0) { @@ -264,7 +264,7 @@ private void Remove(uint actorId) { if (Volatile.Read(ref _postponedReadersCount) == 0) { - RemoveEntry(actorId); + RemoveEntry(actorId.Value); } } } diff --git a/src/Hexecs/Actors/ActorFilter2.Dictionary.cs b/src/Hexecs/Actors/ActorFilter2.Dictionary.cs index a3486ab..bec2e47 100644 --- a/src/Hexecs/Actors/ActorFilter2.Dictionary.cs +++ b/src/Hexecs/Actors/ActorFilter2.Dictionary.cs @@ -89,7 +89,7 @@ private bool RemoveEntry(uint actorId) _sparse[actorId] = 0; _count = lastIndex; - Removed?.Invoke(actorId); + Removed?.Invoke(new ActorId(actorId)); return true; } } @@ -111,7 +111,7 @@ private bool TryAddEntry(uint actorId) _dense[idx] = actorId; _count++; - Added?.Invoke(actorId); + Added?.Invoke(new ActorId(actorId)); return true; } @@ -137,7 +137,7 @@ private bool TryAddEntrySlow(uint actorId) _dense[denseIndex] = actorId; _count++; - Added?.Invoke(actorId); + Added?.Invoke(new ActorId(actorId)); return true; } } \ No newline at end of file diff --git a/src/Hexecs/Actors/ActorFilter2.Enumerator.cs b/src/Hexecs/Actors/ActorFilter2.Enumerator.cs index 16a5f24..e9e9f44 100644 --- a/src/Hexecs/Actors/ActorFilter2.Enumerator.cs +++ b/src/Hexecs/Actors/ActorFilter2.Enumerator.cs @@ -19,14 +19,6 @@ public Enumerator GetEnumerator() public ref struct Enumerator { - private readonly ActorContext _context; - private readonly ActorFilter _filter; - private readonly ComponentsAccess _pool1; - private readonly ComponentsAccess _pool2; - - private readonly ReadOnlySpan _ids; - private int _index; - public readonly ActorRef Current { [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -36,7 +28,7 @@ public readonly ActorRef Current return new ActorRef( _context, - id, + new ActorId(id), ref _pool1[id], ref _pool2[id]); } @@ -47,6 +39,14 @@ public readonly int Length [MethodImpl(MethodImplOptions.AggressiveInlining)] get => _ids.Length; } + + private readonly ActorContext _context; + private readonly ActorFilter _filter; + private readonly ComponentsAccess _pool1; + private readonly ComponentsAccess _pool2; + + private readonly ReadOnlySpan _ids; + private int _index; [MethodImpl(MethodImplOptions.AggressiveInlining)] internal Enumerator(ActorFilter filter) diff --git a/src/Hexecs/Actors/ActorFilter2.Operation.cs b/src/Hexecs/Actors/ActorFilter2.Operation.cs index 0587649..148b0d8 100644 --- a/src/Hexecs/Actors/ActorFilter2.Operation.cs +++ b/src/Hexecs/Actors/ActorFilter2.Operation.cs @@ -9,23 +9,23 @@ private readonly struct Operation private const byte TypeRemove = 2; private const byte TypeClear = 3; - public readonly uint Id; + public readonly ActorId Id; public readonly byte Type; public bool IsAdd => Type == TypeAdd; public bool IsClear => Type == TypeClear; [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Operation Add(uint id) => new(id, TypeAdd); + public static Operation Add(ActorId id) => new(id, TypeAdd); [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Operation Remove(uint id) => new(id, TypeRemove); + public static Operation Remove(ActorId id) => new(id, TypeRemove); [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Operation Clear() => new(0, TypeClear); + public static Operation Clear() => new(ActorId.Empty, TypeClear); [MethodImpl(MethodImplOptions.AggressiveInlining)] - private Operation(uint id, byte type) + private Operation(ActorId id, byte type) { Id = id; Type = type; diff --git a/src/Hexecs/Actors/ActorFilter2.SkipTakeEnumerator.cs b/src/Hexecs/Actors/ActorFilter2.SkipTakeEnumerator.cs index 31d20ab..8448f13 100644 --- a/src/Hexecs/Actors/ActorFilter2.SkipTakeEnumerator.cs +++ b/src/Hexecs/Actors/ActorFilter2.SkipTakeEnumerator.cs @@ -1,5 +1,3 @@ -using Hexecs.Actors.Components; - namespace Hexecs.Actors; public sealed partial class ActorFilter @@ -21,14 +19,6 @@ public SkipTakeEnumerator Skip(int skip, int take = int.MaxValue) public ref struct SkipTakeEnumerator { - private readonly ActorContext _context; - private readonly ActorFilter _filter; - private readonly ActorComponentPool _pool1; - private readonly ActorComponentPool _pool2; - - private readonly ReadOnlySpan _ids; - private int _index; - public readonly ActorRef Current { [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -38,9 +28,9 @@ public readonly ActorRef Current return new ActorRef( _context, - id, - ref _pool1.Get(id), - ref _pool2.Get(id)); + new ActorId(id), + ref _pool1[id], + ref _pool2[id]); } } @@ -50,13 +40,21 @@ public readonly int Length get => _filter.Length; } + private readonly ActorContext _context; + private readonly ActorFilter _filter; + private readonly ComponentsAccess _pool1; + private readonly ComponentsAccess _pool2; + + private readonly ReadOnlySpan _ids; + private int _index; + [MethodImpl(MethodImplOptions.AggressiveInlining)] internal SkipTakeEnumerator(ActorFilter filter, int skip, int take = int.MaxValue) { - _filter = filter; _context = filter.Context; - _pool1 = filter._pool1; - _pool2 = filter._pool2; + _filter = filter; + _pool1 = filter._pool1.GetComponentAccess(); + _pool2 = filter._pool2.GetComponentAccess(); var count = filter._count; var actualSkip = Math.Min(skip, count); diff --git a/src/Hexecs/Actors/ActorFilter2.cs b/src/Hexecs/Actors/ActorFilter2.cs index 833f320..9f875cc 100644 --- a/src/Hexecs/Actors/ActorFilter2.cs +++ b/src/Hexecs/Actors/ActorFilter2.cs @@ -10,9 +10,9 @@ public sealed partial class ActorFilter : IActorFilter where T1 : struct, IActorComponent where T2 : struct, IActorComponent { - public event Action? Added; + public event Action? Added; public event Action? Cleared; - public event Action? Removed; + public event Action? Removed; public readonly ActorConstraint? Constraint; public readonly ActorContext Context; @@ -68,28 +68,13 @@ internal ActorFilter(ActorContext context, ActorConstraint? constraint = null, i #region Contains [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Contains(uint actorId) => ContainsEntry(actorId); + public bool Contains(ActorId actorId) => ContainsEntry(actorId.Value); [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Contains(in ActorId actorId) => ContainsEntry(actorId.Value); + public bool Contains(in Actor actor) => ContainsEntry(actor.Id.Value); [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Contains(in ActorId actorId) => ContainsEntry(actorId.Value); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Contains(in ActorId actorId) => ContainsEntry(actorId.Value); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Contains(in Actor actor) => ContainsEntry(actor.Id); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Contains(in Actor actor) => ContainsEntry(actor.Id); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Contains(in Actor actor) => ContainsEntry(actor.Id); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Contains(in ActorRef actor) => ContainsEntry(actor.Id); + public bool Contains(in ActorRef actor) => ContainsEntry(actor.Id.Value); #endregion @@ -115,9 +100,9 @@ public void Dispose() } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ActorRef GetRef(uint actorId) + public ActorRef GetRef(ActorId actorId) { - if (!ContainsEntry(actorId)) ActorError.NotFound(actorId); + if (!ContainsEntry(actorId.Value)) ActorError.NotFound(actorId); return new ActorRef( Context, @@ -159,7 +144,7 @@ public Actor[] ToArray() for (var i = 0; i < count; i++) { - actors[i] = new Actor(ctx, keys[i]); + actors[i] = new Actor(ctx, new ActorId(keys[i])); } return actors; @@ -170,7 +155,7 @@ public Actor[] ToArray() } } - private void OnAdded(uint actorId) + private void OnAdded(ActorId actorId) { if (_pool1.Has(actorId) && _pool2.Has(actorId)) { @@ -178,7 +163,7 @@ private void OnAdded(uint actorId) } } - private void OnAddedComponent1(uint actorId, ref T1 component) + private void OnAddedComponent1(ActorId actorId, ref T1 component) { if (_pool2.Has(actorId)) { @@ -186,7 +171,7 @@ private void OnAddedComponent1(uint actorId, ref T1 component) } } - private void OnAddedComponent2(uint actorId, ref T2 component) + private void OnAddedComponent2(ActorId actorId, ref T2 component) { if (_pool1.Has(actorId)) { @@ -216,13 +201,13 @@ private void OnCleared() _postponedUpdates.Enqueue(Operation.Clear()); } - private void OnRemoving(uint actorId) => Remove(actorId); + private void OnRemoving(ActorId actorId) => Remove(actorId); - private void OnRemovingComponent1(uint actorId, ref T1 component) => Remove(actorId); + private void OnRemovingComponent1(ActorId actorId, ref T1 component) => Remove(actorId); - private void OnRemovingComponent2(uint actorId, ref T2 component) => Remove(actorId); + private void OnRemovingComponent2(ActorId actorId, ref T2 component) => Remove(actorId); - private void Add(uint actorId) + private void Add(ActorId actorId) { if (Constraint != null && !Constraint.Applicable(actorId)) return; @@ -236,7 +221,7 @@ private void Add(uint actorId) { if (Volatile.Read(ref _postponedReadersCount) == 0) { - AddEntry(actorId); + AddEntry(actorId.Value); } } } @@ -269,11 +254,11 @@ private void ProcessPostponedUpdates() } else if (operation.IsAdd) { - AddEntry(operation.Id); + AddEntry(operation.Id.Value); } else { - RemoveEntry(operation.Id); + RemoveEntry(operation.Id.Value); } } } @@ -282,7 +267,7 @@ private void ProcessPostponedUpdates() if (isClear) Cleared?.Invoke(); } - private void Remove(uint actorId) + private void Remove(ActorId actorId) { if (Volatile.Read(ref _postponedReadersCount) == 0) { @@ -294,7 +279,7 @@ private void Remove(uint actorId) { if (Volatile.Read(ref _postponedReadersCount) == 0) { - RemoveEntry(actorId); + RemoveEntry(actorId.Value); } } } diff --git a/src/Hexecs/Actors/ActorFilter3.Dictionary.cs b/src/Hexecs/Actors/ActorFilter3.Dictionary.cs index b60149f..2167956 100644 --- a/src/Hexecs/Actors/ActorFilter3.Dictionary.cs +++ b/src/Hexecs/Actors/ActorFilter3.Dictionary.cs @@ -89,7 +89,7 @@ private bool RemoveEntry(uint actorId) _sparse[actorId] = 0; _count = lastIndex; - Removed?.Invoke(actorId); + Removed?.Invoke(new ActorId(actorId)); return true; } } @@ -111,7 +111,7 @@ private bool TryAddEntry(uint actorId) _dense[idx] = actorId; _count++; - Added?.Invoke(actorId); + Added?.Invoke(new ActorId(actorId)); return true; } @@ -137,7 +137,7 @@ private bool TryAddEntrySlow(uint actorId) _dense[denseIndex] = actorId; _count++; - Added?.Invoke(actorId); + Added?.Invoke(new ActorId(actorId)); return true; } } \ No newline at end of file diff --git a/src/Hexecs/Actors/ActorFilter3.Enumerator.cs b/src/Hexecs/Actors/ActorFilter3.Enumerator.cs index e6337a2..bd60051 100644 --- a/src/Hexecs/Actors/ActorFilter3.Enumerator.cs +++ b/src/Hexecs/Actors/ActorFilter3.Enumerator.cs @@ -19,15 +19,6 @@ public Enumerator GetEnumerator() public ref struct Enumerator { - private readonly ActorContext _context; - private readonly ActorFilter _filter; - private readonly ComponentsAccess _pool1; - private readonly ComponentsAccess _pool2; - private readonly ComponentsAccess _pool3; - - private readonly ReadOnlySpan _ids; - private int _index; - public readonly ActorRef Current { [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -37,7 +28,7 @@ public readonly ActorRef Current return new ActorRef( _context, - id, + new ActorId(id), ref _pool1[id], ref _pool2[id], ref _pool3[id]); @@ -50,6 +41,15 @@ public readonly int Length get => _ids.Length; } + private readonly ActorContext _context; + private readonly ActorFilter _filter; + private readonly ComponentsAccess _pool1; + private readonly ComponentsAccess _pool2; + private readonly ComponentsAccess _pool3; + + private readonly ReadOnlySpan _ids; + private int _index; + [MethodImpl(MethodImplOptions.AggressiveInlining)] internal Enumerator(ActorFilter filter) { diff --git a/src/Hexecs/Actors/ActorFilter3.Operation.cs b/src/Hexecs/Actors/ActorFilter3.Operation.cs index 2a8221c..a0044dd 100644 --- a/src/Hexecs/Actors/ActorFilter3.Operation.cs +++ b/src/Hexecs/Actors/ActorFilter3.Operation.cs @@ -9,23 +9,23 @@ private readonly struct Operation private const byte TypeRemove = 2; private const byte TypeClear = 3; - public readonly uint Id; + public readonly ActorId Id; public readonly byte Type; public bool IsAdd => Type == TypeAdd; public bool IsClear => Type == TypeClear; [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Operation Add(uint id) => new(id, TypeAdd); + public static Operation Add(ActorId id) => new(id, TypeAdd); [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Operation Remove(uint id) => new(id, TypeRemove); + public static Operation Remove(ActorId id) => new(id, TypeRemove); [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Operation Clear() => new(0, TypeClear); + public static Operation Clear() => new(ActorId.Empty, TypeClear); [MethodImpl(MethodImplOptions.AggressiveInlining)] - private Operation(uint id, byte type) + private Operation(ActorId id, byte type) { Id = id; Type = type; diff --git a/src/Hexecs/Actors/ActorFilter3.SkipTakeEnumerator.cs b/src/Hexecs/Actors/ActorFilter3.SkipTakeEnumerator.cs index 741f0df..660669b 100644 --- a/src/Hexecs/Actors/ActorFilter3.SkipTakeEnumerator.cs +++ b/src/Hexecs/Actors/ActorFilter3.SkipTakeEnumerator.cs @@ -1,6 +1,4 @@ -using Hexecs.Actors.Components; - -namespace Hexecs.Actors; +namespace Hexecs.Actors; public sealed partial class ActorFilter { @@ -21,15 +19,6 @@ public SkipTakeEnumerator Skip(int skip, int take = int.MaxValue) public ref struct SkipTakeEnumerator { - private readonly ActorContext _context; - private readonly ActorFilter _filter; - private readonly ActorComponentPool _pool1; - private readonly ActorComponentPool _pool2; - private readonly ActorComponentPool _pool3; - - private readonly ReadOnlySpan _ids; - private int _index; - public readonly ActorRef Current { [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -39,10 +28,10 @@ public readonly ActorRef Current return new ActorRef( _context, - id, - ref _pool1.Get(id), - ref _pool2.Get(id), - ref _pool3.Get(id)); + new ActorId(id), + ref _pool1[id], + ref _pool2[id], + ref _pool3[id]); } } @@ -52,14 +41,23 @@ public readonly int Length get => _filter.Length; } + private readonly ActorContext _context; + private readonly ActorFilter _filter; + private readonly ComponentsAccess _pool1; + private readonly ComponentsAccess _pool2; + private readonly ComponentsAccess _pool3; + + private readonly ReadOnlySpan _ids; + private int _index; + [MethodImpl(MethodImplOptions.AggressiveInlining)] internal SkipTakeEnumerator(ActorFilter filter, int skip, int take = int.MaxValue) { _filter = filter; _context = filter.Context; - _pool1 = filter._pool1; - _pool2 = filter._pool2; - _pool3 = filter._pool3; + _pool1 = filter._pool1.GetComponentAccess(); + _pool2 = filter._pool2.GetComponentAccess(); + _pool3 = filter._pool3.GetComponentAccess(); var count = filter._count; var actualSkip = Math.Min(skip, count); diff --git a/src/Hexecs/Actors/ActorFilter3.cs b/src/Hexecs/Actors/ActorFilter3.cs index 8f35647..f4a8ab9 100644 --- a/src/Hexecs/Actors/ActorFilter3.cs +++ b/src/Hexecs/Actors/ActorFilter3.cs @@ -11,9 +11,9 @@ public sealed partial class ActorFilter : IActorFilter where T2 : struct, IActorComponent where T3 : struct, IActorComponent { - public event Action? Added; + public event Action? Added; public event Action? Cleared; - public event Action? Removed; + public event Action? Removed; public readonly ActorConstraint? Constraint; public readonly ActorContext Context; @@ -73,34 +73,13 @@ internal ActorFilter(ActorContext context, ActorConstraint? constraint = null, i #region Contains [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Contains(uint actorId) => ContainsEntry(actorId); + public bool Contains(ActorId actorId) => ContainsEntry(actorId.Value); [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Contains(in ActorId actorId) => ContainsEntry(actorId.Value); + public bool Contains(in Actor actor) => ContainsEntry(actor.Id.Value); [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Contains(in ActorId actorId) => ContainsEntry(actorId.Value); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Contains(in ActorId actorId) => ContainsEntry(actorId.Value); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Contains(in ActorId actorId) => ContainsEntry(actorId.Value); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Contains(in Actor actor) => ContainsEntry(actor.Id); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Contains(in Actor actor) => ContainsEntry(actor.Id); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Contains(in Actor actor) => ContainsEntry(actor.Id); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Contains(in Actor actor) => ContainsEntry(actor.Id); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Contains(in ActorRef actor) => ContainsEntry(actor.Id); + public bool Contains(in ActorRef actor) => ContainsEntry(actor.Id.Value); #endregion @@ -128,9 +107,9 @@ public void Dispose() } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ActorRef GetRef(uint actorId) + public ActorRef GetRef(ActorId actorId) { - if (!ContainsEntry(actorId)) ActorError.NotFound(actorId); + if (!ContainsEntry(actorId.Value)) ActorError.NotFound(actorId); return new ActorRef( Context, @@ -173,7 +152,7 @@ public Actor[] ToArray() for (var i = 0; i < count; i++) { - actors[i] = new Actor(ctx, keys[i]); + actors[i] = new Actor(ctx, new ActorId(keys[i])); } return actors; @@ -184,7 +163,7 @@ public Actor[] ToArray() } } - private void OnAdded(uint actorId) + private void OnAdded(ActorId actorId) { if (_pool1.Has(actorId) && _pool2.Has(actorId) && _pool3.Has(actorId)) { @@ -192,7 +171,7 @@ private void OnAdded(uint actorId) } } - private void OnAddedComponent1(uint actorId, ref T1 component) + private void OnAddedComponent1(ActorId actorId, ref T1 component) { if (_pool2.Has(actorId) && _pool3.Has(actorId)) { @@ -200,7 +179,7 @@ private void OnAddedComponent1(uint actorId, ref T1 component) } } - private void OnAddedComponent2(uint actorId, ref T2 component) + private void OnAddedComponent2(ActorId actorId, ref T2 component) { if (_pool1.Has(actorId) && _pool3.Has(actorId)) { @@ -208,7 +187,7 @@ private void OnAddedComponent2(uint actorId, ref T2 component) } } - private void OnAddedComponent3(uint actorId, ref T3 component) + private void OnAddedComponent3(ActorId actorId, ref T3 component) { if (_pool1.Has(actorId) && _pool2.Has(actorId)) { @@ -238,15 +217,15 @@ private void OnCleared() _postponedUpdates.Enqueue(Operation.Clear()); } - private void OnRemoving(uint actorId) => Remove(actorId); + private void OnRemoving(ActorId actorId) => Remove(actorId); - private void OnRemovingComponent1(uint actorId, ref T1 component) => Remove(actorId); + private void OnRemovingComponent1(ActorId actorId, ref T1 component) => Remove(actorId); - private void OnRemovingComponent2(uint actorId, ref T2 component) => Remove(actorId); + private void OnRemovingComponent2(ActorId actorId, ref T2 component) => Remove(actorId); - private void OnRemovingComponent3(uint actorId, ref T3 component) => Remove(actorId); + private void OnRemovingComponent3(ActorId actorId, ref T3 component) => Remove(actorId); - private void Add(uint actorId) + private void Add(ActorId actorId) { if (Constraint != null && !Constraint.Applicable(actorId)) return; @@ -260,7 +239,7 @@ private void Add(uint actorId) { if (Volatile.Read(ref _postponedReadersCount) == 0) { - AddEntry(actorId); + AddEntry(actorId.Value); } } } @@ -293,11 +272,11 @@ private void ProcessPostponedUpdates() } else if (operation.IsAdd) { - AddEntry(operation.Id); + AddEntry(operation.Id.Value); } else { - RemoveEntry(operation.Id); + RemoveEntry(operation.Id.Value); } } } @@ -306,7 +285,7 @@ private void ProcessPostponedUpdates() if (isClear) Cleared?.Invoke(); } - private void Remove(uint actorId) + private void Remove(ActorId actorId) { if (Volatile.Read(ref _postponedReadersCount) == 0) { @@ -318,7 +297,7 @@ private void Remove(uint actorId) { if (Volatile.Read(ref _postponedReadersCount) == 0) { - RemoveEntry(actorId); + RemoveEntry(actorId.Value); } } } diff --git a/src/Hexecs/Actors/ActorId.cs b/src/Hexecs/Actors/ActorId.cs index 8083fb5..0604f9f 100644 --- a/src/Hexecs/Actors/ActorId.cs +++ b/src/Hexecs/Actors/ActorId.cs @@ -13,13 +13,18 @@ namespace Hexecs.Actors; [DebuggerDisplay("{ToString()}")] public readonly struct ActorId : IEquatable { + /// + /// Константа, представляющая собой пустой идентификатор актёра. + /// + internal const uint EmptyId = 0; + /// /// Пустой идентификатор актёра, используемый по умолчанию. /// public static ActorId Empty { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => new(Actor.EmptyId); + get => new(EmptyId); } /// @@ -33,7 +38,16 @@ public static ActorId Empty public bool IsEmpty { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => Value == Actor.EmptyId; + get => Value == EmptyId; + } + + /// + /// Проверяет, является ли идентификатор НЕ пустым. + /// + public bool IsNotEmpty + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => Value != EmptyId; } /// @@ -52,79 +66,53 @@ internal ActorId(uint value) /// Контекст актёра. /// Актёр с данным идентификатором. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Actor Unwrap(ActorContext context) => context.GetActor(Value); - - /// - /// Преобразует идентификатор в типизированного актёра с указанным контекстом и компонентом. - /// - /// Тип компонента. - /// Контекст актёра. - /// Типизированный актёр с данным идентификатором и компонентом. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Actor Unwrap(ActorContext context) where T : struct, IActorComponent => context.GetActor(Value); + public Actor Unwrap(ActorContext context) + { + return context.GetActor(this); + } - /// - /// Возвращает строковое представление идентификатора актёра. - /// - /// Строковое представление идентификатора. - public override string ToString() => ActorMarshal.TryGetDebugContext(out var context) - ? context.GetDescription(Value) - : IsEmpty - ? StringUtils.EmptyValue - : Value.ToString(); + public override string ToString() + { + return ActorMarshal.TryGetDebugContext(out var context) + ? context.GetDescription(this) + : IsEmpty + ? StringUtils.EmptyValue + : Value.ToString(); + } #region Equality - /// - /// Проверяет равенство между двумя идентификаторами актёров. - /// - /// Идентификатор для сравнения. - /// Возвращает true, если идентификаторы равны; иначе false. [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(ActorId other) => Value == other.Value; - /// - /// Проверяет равенство с другим объектом. - /// - /// Объект для сравнения. - /// Возвращает true, если объекты равны; иначе false. public override bool Equals(object? obj) => obj is ActorId other && Equals(other); - /// - /// Возвращает хеш-код для идентификатора актёра. - /// - /// Хеш-код идентификатора. public override int GetHashCode() => HashCode.Combine(Value); - /// - /// Сравнивает два идентификатора актёров на равенство. - /// - /// Левый идентификатор. - /// Правый идентификатор. - /// Возвращает true, если идентификаторы равны; иначе false. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(in ActorId left, in ActorId right) => left.Equals(right); + public static bool operator ==(in ActorId left, in ActorId right) => left.Value == right.Value; - /// - /// Сравнивает два идентификатора актёров на неравенство. - /// - /// Левый идентификатор. - /// Правый идентификатор. - /// Возвращает true, если идентификаторы не равны; иначе false. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(in ActorId left, in ActorId right) => !left.Equals(right); + public static bool operator !=(in ActorId left, in ActorId right) => left.Value != right.Value; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator <(in ActorId left, in ActorId right) => left.Value < right.Value; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator >(in ActorId left, in ActorId right) => left.Value > right.Value; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator <=(in ActorId left, in ActorId right) => left.Value <= right.Value; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator >=(in ActorId left, in ActorId right) => left.Value >= right.Value; #endregion #region Implicit - /// - /// Неявное преобразование идентификатора актёра в bool. - /// - /// Идентификатор для преобразования. - /// Возвращает true, если идентификатор не пустой; иначе false. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator bool(in ActorId actor) => !actor.IsEmpty; + public static implicit operator bool(in ActorId actor) => actor.IsNotEmpty; #endregion } \ No newline at end of file diff --git a/src/Hexecs/Actors/ActorId1.cs b/src/Hexecs/Actors/ActorId1.cs deleted file mode 100644 index def89ac..0000000 --- a/src/Hexecs/Actors/ActorId1.cs +++ /dev/null @@ -1,107 +0,0 @@ -using Hexecs.Actors.Development; - -namespace Hexecs.Actors; - -/// -/// Структура, представляющая собой типизированный идентификатор актёра в системе. -/// -/// -/// ActorId<T1> - это легковесная структура, которая хранит идентификатор актёра -/// и информацию о требуемом компоненте, используется для типобезопасной ссылки на актёра. -/// -/// Тип компонента, который должен иметь актёр. -[DebuggerTypeProxy(typeof(ActorIdDebugProxy<>))] -[DebuggerDisplay("{ToString()}")] -public readonly struct ActorId : IEquatable> - where T1 : struct, IActorComponent -{ - /// - /// Пустой типизированный идентификатор актёра, используемый по умолчанию. - /// - public static ActorId Empty - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => new(Actor.EmptyId); - } - - /// - /// Значение идентификатора актёра. - /// - public readonly uint Value; - - /// - /// Внутренний конструктор для создания типизированного идентификатора актёра. - /// - /// Значение идентификатора. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal ActorId(uint value) - { - Value = value; - } - - /// - /// Проверяет, является ли идентификатор пустым. - /// - public bool IsEmpty - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => Value == Actor.EmptyId; - } - - /// - /// Возвращает строковое представление идентификатора актёра. - /// - /// Строковое представление идентификатора. - public override string ToString() => ActorMarshal.TryGetDebugContext(out var context) - ? context.GetDescription(Value) - : IsEmpty - ? StringUtils.EmptyValue - : Value.ToString(); - - /// - /// Преобразует типизированный идентификатор в актёра с указанным контекстом и компонентом. - /// - /// Контекст актёра. - /// Типизированный актёр с данным идентификатором и компонентом. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Actor Unwrap(ActorContext context) => context.GetActor(Value); - - #region Equality - - /// - /// Проверяет равенство между двумя типизированными идентификаторами актёров. - /// - /// Идентификатор для сравнения. - /// Возвращает true, если идентификаторы равны; иначе false. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(ActorId other) => Value == other.Value; - - /// - /// Проверяет равенство с другим объектом. - /// - /// Объект для сравнения. - /// Возвращает true, если объекты равны; иначе false. - public override bool Equals(object? obj) => obj is ActorId other && Equals(other); - - public override int GetHashCode() => HashCode.Combine(Value); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(in ActorId left, in ActorId right) => left.Equals(right); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(in ActorId left, in ActorId right) => !left.Equals(right); - - #endregion - - #region Implicit - - /// - /// Неявное преобразование типизированного идентификатора актёра в bool. - /// - /// Идентификатор для преобразования. - /// Возвращает true, если идентификатор не пустой; иначе false. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator bool(in ActorId actor) => !actor.IsEmpty; - - #endregion -} \ No newline at end of file diff --git a/src/Hexecs/Actors/ActorList.Enumerator.cs b/src/Hexecs/Actors/ActorList.Enumerator.cs index 796c9b9..405cfa7 100644 --- a/src/Hexecs/Actors/ActorList.Enumerator.cs +++ b/src/Hexecs/Actors/ActorList.Enumerator.cs @@ -17,7 +17,10 @@ public readonly ActorRef Current get { var id = _ids[_index]; - return new ActorRef(_pool.Context, id, ref _pool.Get(id)); + return new ActorRef( + context: _pool.Context, + id: id, + component1: ref _pool.Get(id)); } } @@ -26,9 +29,9 @@ public readonly int Length [MethodImpl(MethodImplOptions.AggressiveInlining)] get => _ids.Length; } - + private readonly ActorComponentPool _pool; - private readonly Span _ids; + private readonly Span _ids; private int _index; [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -36,7 +39,7 @@ public Enumerator() { _index = -1; _pool = null!; - _ids = Span.Empty; + _ids = Span.Empty; } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -52,16 +55,16 @@ internal Enumerator(ActorList list) [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Enumerator GetEnumerator() => this; - - public Actor[] ToArray() + + public Actor[] ToArray() { var count = 0; - var actors = ArrayUtils.Create>(_ids.Length); + var actors = ArrayUtils.Create(_ids.Length); foreach (var actor in this) { actors[count++] = actor; } - + return actors; } } diff --git a/src/Hexecs/Actors/ActorList.cs b/src/Hexecs/Actors/ActorList.cs index 0f342ae..c4507e9 100644 --- a/src/Hexecs/Actors/ActorList.cs +++ b/src/Hexecs/Actors/ActorList.cs @@ -19,16 +19,23 @@ public int Length get => _length; } - private uint[] _array; + private readonly ArrayPool _arrayPool; + + private ActorId[] _array; private bool _disposed; private int _length; private readonly ActorComponentPool _pool; - public ActorList(ActorContext context, int capacity = 8) + public ActorList( + ActorContext context, + ArrayPool? arrayPool = null, + int capacity = 8) { + _arrayPool = arrayPool ?? ArrayPool.Shared; + _array = capacity == 0 ? [] - : ArrayPool.Shared.Rent(capacity); + : _arrayPool.Rent(capacity); _length = 0; _pool = context.GetOrCreateComponentPool(); @@ -37,35 +44,35 @@ public ActorList(ActorContext context, int capacity = 8) context.Cleared += OnCleared; } - private void OnCleared() => Clear(); - - public void Add(in Actor actor) => Add(actor.Id); - public void Add(in ActorRef actor) => Add(actor.Id); [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Add(uint actorId) + public void Add(ActorId actorId) { if (_disposed) ActorError.Disposed(typeof(ActorList)); - ArrayUtils.Insert(ref _array, ArrayPool.Shared, _length, actorId); + ArrayUtils.Insert(ref _array, _arrayPool, _length, actorId); _length++; } public void Clear() { - if (_array.Length > 0) ArrayPool.Shared.Return(_array); + if (_array.Length > 0) _arrayPool.Return(_array); _array = []; _length = 0; } - public bool Contains(in Actor actor) => Contains(actor.Id); - - public bool Contains(in ActorRef actor) => Contains(actor.Id); + public bool Contains(in ActorRef actor) + { + return Contains(actor.Id); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Contains(uint actorId) => Array.IndexOf(_array, actorId, 0, _length) != -1; + public bool Contains(ActorId actorId) + { + return Array.IndexOf(_array, actorId, 0, _length) != -1; + } public void Dispose() { @@ -79,16 +86,20 @@ public void Dispose() } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Enumerator GetEnumerator() => _length == 0 - ? Enumerator.Empty - : new Enumerator(this); - - public bool Remove(in Actor actor) => Remove(actor.Id); + public Enumerator GetEnumerator() + { + return _length == 0 + ? Enumerator.Empty + : new Enumerator(this); + } - public bool Remove(in ActorRef actor) => Remove(actor.Id); + public bool Remove(in ActorRef actor) + { + return Remove(actor.Id); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Remove(uint actorId) + public bool Remove(ActorId actorId) { var index = Array.IndexOf(_array, actorId, 0, _length); if (index == -1) return false; @@ -100,9 +111,14 @@ public bool Remove(uint actorId) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private Span AsSpan() => _length == 0 - ? Span.Empty + private Span AsSpan() => _length == 0 + ? Span.Empty : _array.AsSpan(0, _length); - private void OnRemoved(uint actorId) => Remove(actorId); + private void OnCleared() => Clear(); + + private void OnRemoved(ActorId actorId) + { + Remove(actorId); + } } \ No newline at end of file diff --git a/src/Hexecs/Actors/ActorRef1.cs b/src/Hexecs/Actors/ActorRef1.cs index f320e2e..18de0b6 100644 --- a/src/Hexecs/Actors/ActorRef1.cs +++ b/src/Hexecs/Actors/ActorRef1.cs @@ -30,8 +30,8 @@ public readonly ref struct ActorRef /// /// Уникальный идентификатор актёра. /// - public readonly uint Id; - + public readonly ActorId Id; + /// /// Пустая ссылка на актёра, используемая по умолчанию. /// @@ -75,7 +75,7 @@ public bool IsEmpty /// Идентификатор актёра. /// Ссылка на первый компонент актёра. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal ActorRef(ActorContext context, uint id, ref T1 component1) + internal ActorRef(ActorContext context, ActorId id, ref T1 component1) { Context = context; _component1 = ref component1; @@ -120,21 +120,11 @@ public ref T AddRelation(in Actor relative, in T relation) where T : struct /// Типизированный актёр с указанным компонентом. /// Выбрасывается, если актёр не найден или не содержит указанный компонент. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Actor As() where T : struct, IActorComponent => Context.GetActor(Id); - - /// - /// Преобразует ссылку на актёра в ссылку на типизированного актёра. - /// - /// Тип компонента. - /// Ссылка на типизированного актёра. - /// Выбрасывается, если актёр не найден или не содержит указанный компонент. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ActorRef AsRef() where T : struct, IActorComponent => Context.GetActorRef(Id); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Actor AsActor() => IsEmpty - ? Actor.Empty - : new Actor(Context, Id); + public ActorRef AsRef() + where T : struct, IActorComponent + { + return Context.GetActorRef(Id); + } /// /// Возвращает перечислитель дочерних актёров. @@ -142,14 +132,20 @@ public Actor AsActor() => IsEmpty /// Перечислитель дочерних актёров. /// Выбрасывается, если актёр не найден. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ActorContext.ChildrenEnumerator Children() => Context.Children(Id); + public ActorContext.ChildrenEnumerator Children() + { + return Context.Children(Id); + } /// /// Уничтожает актёра. /// /// Возвращает true, если актёр был успешно уничтожен; иначе false. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Destroy() => Context.DestroyActor(Id); + public bool Destroy() + { + return Context.DestroyActor(Id); + } /// /// Получает компонент актёра указанного типа. @@ -166,7 +162,10 @@ public Actor AsActor() => IsEmpty /// Ассет, связанный с актёром. /// Выбрасывается, если актёр не найден или с ним не связан ассет. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Asset GetAsset() => Context.GetBoundAsset(Id); + public Asset GetAsset() + { + return Context.GetBoundAsset(Id); + } /// /// Получает отношение между текущим актёром и указанным родственным актёром. @@ -176,7 +175,11 @@ public Actor AsActor() => IsEmpty /// Ссылка на отношение. /// Выбрасывается, если актёр не найден или отношение не существует. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ref T GetRelation(in Actor relative) where T : struct => ref Context.GetRelation(Id, relative.Id); + public ref T GetRelation(in Actor relative) + where T : struct + { + return ref Context.GetRelation(Id, relative.Id); + } /// /// Проверяет, содержит ли актёр компонент указанного типа. @@ -185,11 +188,18 @@ public Actor AsActor() => IsEmpty /// Возвращает true, если актёр содержит компонент; иначе false. /// Выбрасывается, если актёр не найден. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Has() where T : struct, IActorComponent => Context.HasComponent(Id); + public bool Has() + where T : struct, IActorComponent + { + return Context.HasComponent(Id); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool HasChild(in Actor child) => Context.HasChild(Id, child.Id); - + public bool HasChild(in Actor child) + { + return Context.HasChild(Id, child.Id); + } + /// /// Проверяет, существует ли отношение между текущим актёром и указанным родственным актёром. /// @@ -198,7 +208,11 @@ public Actor AsActor() => IsEmpty /// Возвращает true, если отношение существует; иначе false. /// Выбрасывается, если один из актёров не найден. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool HasRelation(in Actor relative) where T : struct => Context.HasRelation(Id, relative.Id); + public bool HasRelation(in Actor relative) + where T : struct + { + return Context.HasRelation(Id, relative.Id); + } /// /// Проверяет, можно ли преобразовать ссылку на актёра в типизированного актёра с указанным компонентом. @@ -207,16 +221,8 @@ public Actor AsActor() => IsEmpty /// Результирующий типизированный актёр. /// Возвращает true, если преобразование успешно; иначе false. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Is(out Actor actor) where T : struct, IActorComponent => Context.TryGetActor(Id, out actor); - - /// - /// Проверяет, можно ли преобразовать ссылку на актёра в ссылку на типизированного актёра. - /// - /// Тип компонента. - /// Результирующая ссылка на типизированного актёра. - /// Возвращает true, если преобразование успешно; иначе false. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool IsRef(out ActorRef actor) where T : struct, IActorComponent + public bool IsRef(out ActorRef actor) + where T : struct, IActorComponent { return Context.TryGetActorRef(Id, out actor); } @@ -228,7 +234,11 @@ public bool IsRef(out ActorRef actor) where T : struct, IActorComponent /// Перечислитель отношений. /// Выбрасывается, если актёр не найден. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ActorRelationEnumerator Relations() where T : struct => Context.Relations(Id); + public ActorRelationEnumerator Relations() + where T : struct + { + return Context.Relations(Id); + } /// /// Удаляет компонент указанного типа из актёра. @@ -237,7 +247,11 @@ public bool IsRef(out ActorRef actor) where T : struct, IActorComponent /// Возвращает true, если компонент был успешно удален; иначе false. /// Выбрасывается, если актёр не найден. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Remove() where T : struct, IActorComponent => Context.RemoveComponent(Id); + public bool Remove() + where T : struct, IActorComponent + { + return Context.RemoveComponent(Id); + } /// /// Удаляет компонент указанного типа из актёра и возвращает его значение. @@ -247,7 +261,8 @@ public bool IsRef(out ActorRef actor) where T : struct, IActorComponent /// Возвращает true, если компонент был успешно удален; иначе false. /// Выбрасывается, если актёр не найден. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Remove(out T component) where T : struct, IActorComponent + public bool Remove(out T component) + where T : struct, IActorComponent { return Context.RemoveComponent(Id, out component); } @@ -259,7 +274,10 @@ public bool Remove(out T component) where T : struct, IActorComponent /// Возвращает true, если дочерний актёр был успешно удален; иначе false. /// Выбрасывается, если один из актёров не найден. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool RemoveChild(in Actor child) => Context.RemoveChild(Id, child.Id); + public bool RemoveChild(in Actor child) + { + return Context.RemoveChild(Id, child.Id); + } /// /// Удаляет отношение указанного типа между текущим актёром и указанным родственным актёром. @@ -269,7 +287,11 @@ public bool Remove(out T component) where T : struct, IActorComponent /// Возвращает true, если отношение было успешно удалено; иначе false. /// Выбрасывается, если один из актёров не найден. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool RemoveRelation(in Actor relative) where T : struct => Context.RemoveRelation(Id, relative.Id); + public bool RemoveRelation(in Actor relative) + where T : struct + { + return Context.RemoveRelation(Id, relative.Id); + } /// /// Удаляет отношение указанного типа между текущим актёром и указанным родственным актёром и возвращает его значение. @@ -289,9 +311,12 @@ public bool RemoveRelation(in Actor relative, out T relation) where T : struc /// Возвращает строковое представление ссылки на актёра. /// /// Строковое представление ссылки на актёра. - public override string ToString() => Context == null - ? StringUtils.EmptyValue - : Context.GetDescription(Id); + public override string ToString() + { + return Context == null + ? StringUtils.EmptyValue + : Context.GetDescription(Id); + } /// /// Пытается добавить компонент к актёру, если он еще не существует. @@ -301,7 +326,11 @@ public override string ToString() => Context == null /// Возвращает true, если компонент был успешно добавлен; иначе false, если он уже существует. /// Выбрасывается, если актёр не найден. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool TryAdd(in T component) where T : struct, IActorComponent => Context.TryAdd(Id, in component); + public bool TryAdd(in T component) + where T : struct, IActorComponent + { + return Context.TryAdd(Id, in component); + } /// /// Пытается получить ассет, связанный с актёром. @@ -310,7 +339,10 @@ public override string ToString() => Context == null /// Возвращает true, если ассет был успешно получен; иначе false. /// Выбрасывается, если актёр не найден. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool TryGetAsset(out Asset asset) => Context.TryGetBoundAsset(Id, out asset); + public bool TryGetAsset(out Asset asset) + { + return Context.TryGetBoundAsset(Id, out asset); + } /// /// Пытается получить ссылку на компонент актёра указанного типа. @@ -319,7 +351,11 @@ public override string ToString() => Context == null /// Ссылка на компонент или на пустой компонент, если он не существует. /// Выбрасывается, если актёр не найден. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ref T TryGetRef() where T : struct, IActorComponent => ref Context.TryGetComponentRef(Id); + public ref T TryGetRef() + where T : struct, IActorComponent + { + return ref Context.TryGetComponentRef(Id); + } /// /// Пытается получить родительского актёра для текущего. @@ -328,7 +364,10 @@ public override string ToString() => Context == null /// Возвращает true, если родительский актёр существует; иначе false. /// Выбрасывается, если актёр не найден. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool TryGetParent(out Actor parent) => Context.TryGetParent(Id, out parent); + public bool TryGetParent(out Actor parent) + { + return Context.TryGetParent(Id, out parent); + } /// /// Обновляет существующий компонент или создает новый, если он не существует. @@ -339,7 +378,8 @@ public override string ToString() => Context == null /// Возвращает true, если компонент был успешно обновлен или создан; иначе false. /// Выбрасывается, если актёр не найден. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Update(in T component, bool createIfNotExists = true) where T : struct, IActorComponent + public bool Update(in T component, bool createIfNotExists = true) + where T : struct, IActorComponent { return Context.UpdateComponent(Id, in component, createIfNotExists); } @@ -361,7 +401,6 @@ public bool Update(in T component, bool createIfNotExists = true) where T : s /// Возвращает true, если объекты равны; иначе false. public override bool Equals(object? obj) => obj switch { - Actor other => other.Id == Id, Actor actor => actor.IsRef(out var expected) && Equals(expected), _ => false }; @@ -408,15 +447,7 @@ public bool Update(in T component, bool createIfNotExists = true) where T : s /// Ссылка на актёра для преобразования. /// Идентификатор актёра. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator ActorId(in ActorRef actor) => new(actor.Id); - - /// - /// Неявное преобразование ссылки на актёра в типизированный идентификатор актёра. - /// - /// Ссылка на актёра для преобразования. - /// Типизированный идентификатор актёра. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator ActorId(in ActorRef actor) => new(actor.Id); + public static implicit operator ActorId(in ActorRef actor) => actor.Id; /// /// Неявное преобразование ссылки на актёра в актёра. @@ -426,13 +457,5 @@ public bool Update(in T component, bool createIfNotExists = true) where T : s [MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator Actor(in ActorRef actor) => new(actor.Context, actor.Id); - /// - /// Неявное преобразование ссылки на актёра в типизированного актёра. - /// - /// Ссылка на актёра для преобразования. - /// Типизированный актёр. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator Actor(in ActorRef actor) => new(actor.Context, actor.Id); - #endregion } \ No newline at end of file diff --git a/src/Hexecs/Actors/ActorRef2.cs b/src/Hexecs/Actors/ActorRef2.cs index 3fa1cc8..556fb1f 100644 --- a/src/Hexecs/Actors/ActorRef2.cs +++ b/src/Hexecs/Actors/ActorRef2.cs @@ -21,7 +21,7 @@ public readonly ref struct ActorRef /// /// Уникальный идентификатор актёра. /// - public readonly uint Id; + public readonly ActorId Id; public static ActorRef Empty { @@ -54,7 +54,7 @@ public bool IsEmpty } [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal ActorRef(ActorContext context, uint id, ref T1 component1, ref T2 component2) + internal ActorRef(ActorContext context, ActorId id, ref T1 component1, ref T2 component2) { Context = context; @@ -76,9 +76,6 @@ public ref T AddRelation(in Actor relative, in T relation) where T : struct return ref Context.AddRelation(Id, relative.Id, in relation); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Actor As() where T : struct, IActorComponent => Context.GetActor(Id); - [MethodImpl(MethodImplOptions.AggressiveInlining)] public ActorRef AsRef() where T : struct, IActorComponent => Context.GetActorRef(Id); @@ -98,62 +95,105 @@ public ref T AddRelation(in Actor relative, in T relation) where T : struct public ref T GetRelation(in Actor relative) where T : struct => ref Context.GetRelation(Id, relative.Id); [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Has() where T : struct, IActorComponent => Context.HasComponent(Id); + public bool Has() + where T : struct, IActorComponent + { + return Context.HasComponent(Id); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool HasChild(in Actor child) => Context.HasChild(Id, child.Id); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool HasRelation(in Actor relative) where T : struct => Context.HasRelation(Id, relative.Id); + public bool HasChild(in Actor child) + { + return Context.HasChild(Id, child.Id); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Is(out Actor actor) where T : struct, IActorComponent => Context.TryGetActor(Id, out actor); + public bool HasRelation(in Actor relative) + where T : struct + { + return Context.HasRelation(Id, relative.Id); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool IsRef(out ActorRef actor) where T : struct, IActorComponent + public bool IsRef(out ActorRef actor) + where T : struct, IActorComponent { return Context.TryGetActorRef(Id, out actor); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ActorRelationEnumerator Relations() where T : struct => Context.Relations(Id); + public ActorRelationEnumerator Relations() + where T : struct + { + return Context.Relations(Id); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Remove() where T : struct, IActorComponent => Context.RemoveComponent(Id); + public bool Remove() + where T : struct, IActorComponent + { + return Context.RemoveComponent(Id); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Remove(out T component) where T : struct, IActorComponent + public bool Remove(out T component) + where T : struct, IActorComponent { return Context.RemoveComponent(Id, out component); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool RemoveChild(in Actor child) => Context.RemoveChild(Id, child.Id); + public bool RemoveChild(in Actor child) + { + return Context.RemoveChild(Id, child.Id); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool RemoveRelation(in Actor relative) where T : struct => Context.RemoveRelation(Id, relative.Id); + public bool RemoveRelation(in Actor relative) + where T : struct + { + return Context.RemoveRelation(Id, relative.Id); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool RemoveRelation(in Actor relative, out T relation) where T : struct + public bool RemoveRelation(in Actor relative, out T relation) + where T : struct { return Context.RemoveRelation(Id, relative.Id, out relation); } - public override string ToString() => Context == null - ? StringUtils.EmptyValue - : Context.GetDescription(Id); + public override string ToString() + { + return Context == null + ? StringUtils.EmptyValue + : Context.GetDescription(Id); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool TryAdd(in T component) where T : struct, IActorComponent => Context.TryAdd(Id, in component); + public bool TryAdd(in T component) + where T : struct, IActorComponent + { + return Context.TryAdd(Id, in component); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool TryGetAsset(out Asset asset) => Context.TryGetBoundAsset(Id, out asset); + public bool TryGetAsset(out Asset asset) + { + return Context.TryGetBoundAsset(Id, out asset); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ref T TryGetRef() where T : struct, IActorComponent => ref Context.TryGetComponentRef(Id); + public ref T TryGetRef() + where T : struct, IActorComponent + { + return ref Context.TryGetComponentRef(Id); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool TryGetParent(out Actor parent) => Context.TryGetParent(Id, out parent); + public bool TryGetParent(out Actor parent) + { + return Context.TryGetParent(Id, out parent); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Update(in T component, bool createIfNotExists = true) where T : struct, IActorComponent @@ -184,23 +224,11 @@ public bool Update(in T component, bool createIfNotExists = true) where T : s public static implicit operator bool(in ActorRef actor) => !actor.IsEmpty; [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator ActorId(in ActorRef actor) => new(actor.Id); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator ActorId(in ActorRef actor) => new(actor.Id); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator ActorId(in ActorRef actor) => new(actor.Id); + public static implicit operator ActorId(in ActorRef actor) => actor.Id; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator Actor(in ActorRef actor) => new(actor.Context, actor.Id); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator Actor(in ActorRef actor) => new(actor.Context, actor.Id); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator Actor(in ActorRef actor) => new(actor.Context, actor.Id); - [MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator ActorRef(in ActorRef actor) => new( actor.Context, diff --git a/src/Hexecs/Actors/ActorRef3.cs b/src/Hexecs/Actors/ActorRef3.cs index 5643ebd..a51402e 100644 --- a/src/Hexecs/Actors/ActorRef3.cs +++ b/src/Hexecs/Actors/ActorRef3.cs @@ -23,7 +23,7 @@ public readonly ref struct ActorRef /// /// Уникальный идентификатор актёра. /// - public readonly uint Id; + public readonly ActorId Id; public static ActorRef Empty { @@ -62,7 +62,7 @@ public bool IsEmpty } [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal ActorRef(ActorContext context, uint id, ref T1 component1, ref T2 component2, ref T3 component3) + internal ActorRef(ActorContext context, ActorId id, ref T1 component1, ref T2 component2, ref T3 component3) { Context = context; @@ -85,9 +85,6 @@ public ref T AddRelation(in Actor relative, in T relation) where T : struct return ref Context.AddRelation(Id, relative.Id, in relation); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Actor As() where T : struct, IActorComponent => Context.GetActor(Id); - [MethodImpl(MethodImplOptions.AggressiveInlining)] public ActorRef AsRef() where T : struct, IActorComponent => Context.GetActorRef(Id); @@ -111,12 +108,9 @@ public ref T AddRelation(in Actor relative, in T relation) where T : struct [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool HasChild(in Actor child) => Context.HasChild(Id, child.Id); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool HasRelation(in Actor relative) where T : struct => Context.HasRelation(Id, relative.Id); [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Is(out Actor actor) where T : struct, IActorComponent => Context.TryGetActor(Id, out actor); + public bool HasRelation(in Actor relative) where T : struct => Context.HasRelation(Id, relative.Id); [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool IsRef(out ActorRef actor) where T : struct, IActorComponent @@ -193,29 +187,11 @@ public bool Update(in T component, bool createIfNotExists = true) where T : s public static implicit operator bool(in ActorRef actor) => !actor.IsEmpty; [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator ActorId(in ActorRef actor) => new(actor.Id); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator ActorId(in ActorRef actor) => new(actor.Id); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator ActorId(in ActorRef actor) => new(actor.Id); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator ActorId(in ActorRef actor) => new(actor.Id); + public static implicit operator ActorId(in ActorRef actor) => actor.Id; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator Actor(in ActorRef actor) => new(actor.Context, actor.Id); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator Actor(in ActorRef actor) => new(actor.Context, actor.Id); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator Actor(in ActorRef actor) => new(actor.Context, actor.Id); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator Actor(in ActorRef actor) => new(actor.Context, actor.Id); - [MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator ActorRef(in ActorRef actor) => new( actor.Context, diff --git a/src/Hexecs/Actors/ActorRelation.cs b/src/Hexecs/Actors/ActorRelation.cs index de01c35..fb4a58d 100644 --- a/src/Hexecs/Actors/ActorRelation.cs +++ b/src/Hexecs/Actors/ActorRelation.cs @@ -11,10 +11,10 @@ public readonly ref struct ActorRelation public ActorRelation Empty { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => new(null!, Actor.EmptyId, ref Unsafe.NullRef()); + get => new(null!, ActorId.Empty, ref Unsafe.NullRef()); } - public readonly uint Id; + public readonly ActorId Id; public readonly ActorContext Context; @@ -33,7 +33,7 @@ public ref T1 Relation private readonly ref T1 _relation; [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal ActorRelation(ActorContext context, uint id, ref T1 relation) + internal ActorRelation(ActorContext context, ActorId id, ref T1 relation) { Id = id; Context = context; @@ -42,34 +42,56 @@ internal ActorRelation(ActorContext context, uint id, ref T1 relation) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Add(in T component) where T : struct, IActorComponent => Context.AddComponent(Id, in component); + public void Add(in T component) + where T : struct, IActorComponent + { + Context.AddComponent(Id, in component); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void AddChild(in Actor child) => Context.AddChild(Id, child.Id); + public void AddChild(in Actor child) + { + Context.AddChild(Id, child.Id); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ref T AddRelation(in Actor relative, in T relation) where T : struct + public ref T AddRelation(in Actor relative, in T relation) + where T : struct { return ref Context.AddRelation(Id, relative.Id, in relation); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Actor As() where T : struct, IActorComponent => Context.GetActor(Id); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ActorRef AsRef() where T : struct, IActorComponent => Context.GetActorRef(Id); + public ActorRef AsRef() + where T : struct, IActorComponent + { + return Context.GetActorRef(Id); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ActorContext.ChildrenEnumerator Children() => Context.Children(Id); + public ActorContext.ChildrenEnumerator Children() + { + return Context.Children(Id); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Destroy() => Context.DestroyActor(Id); + public bool Destroy() + { + return Context.DestroyActor(Id); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ref T Get() where T : struct, IActorComponent => ref Context.GetComponent(Id); + public ref T Get() + where T : struct, IActorComponent + { + return ref Context.GetComponent(Id); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Asset GetAsset() => Context.GetBoundAsset(Id); + public Asset GetAsset() + { + return Context.GetBoundAsset(Id); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] public ref T GetRelation(in Actor relative) where T : struct => ref Context.GetRelation(Id, relative.Id); @@ -80,9 +102,6 @@ public ref T AddRelation(in Actor relative, in T relation) where T : struct [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool HasRelation(in Actor relative) where T : struct => Context.HasRelation(Id, relative.Id); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Is(out Actor actor) where T : struct, IActorComponent => Context.TryGetActor(Id, out actor); - [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool IsRef(out ActorRef actor) where T : struct, IActorComponent { diff --git a/src/Hexecs/Actors/Bounds/BoundComponent.cs b/src/Hexecs/Actors/Bounds/BoundComponent.cs index 1701af7..06cc966 100644 --- a/src/Hexecs/Actors/Bounds/BoundComponent.cs +++ b/src/Hexecs/Actors/Bounds/BoundComponent.cs @@ -12,7 +12,7 @@ namespace Hexecs.Actors.Bounds; [DebuggerDisplay("Asset: {ToString()}")] [DebuggerTypeProxy(typeof(BoundComponentDebugProxy))] [method: MethodImpl(MethodImplOptions.AggressiveInlining)] -internal readonly struct BoundComponent(uint assetId) : IActorComponent +internal readonly struct BoundComponent(AssetId assetId) : IActorComponent { public static ActorComponentConfiguration CreatePoolConfiguration() { @@ -26,11 +26,14 @@ public static ActorComponentConfiguration CreatePoolConfiguratio /// /// Идентификатор ресурса (), привязанного к актёру /// - public readonly uint AssetId = assetId; + public readonly AssetId AssetId = assetId; - public override string ToString() => AssetMarshal.TryGetDebugContext(out var context) - ? context.GetDescription(AssetId) - : AssetId == Asset.EmptyId - ? StringUtils.EmptyValue - : AssetId.ToString(); + public override string ToString() + { + return AssetMarshal.TryGetDebugContext(out var context) + ? context.GetDescription(AssetId) + : AssetId.IsEmpty + ? StringUtils.EmptyValue + : AssetId.ToString(); + } } \ No newline at end of file diff --git a/src/Hexecs/Actors/Bounds/BoundComponentDebugProxy.cs b/src/Hexecs/Actors/Bounds/BoundComponentDebugProxy.cs index a3bb391..4e2ea43 100644 --- a/src/Hexecs/Actors/Bounds/BoundComponentDebugProxy.cs +++ b/src/Hexecs/Actors/Bounds/BoundComponentDebugProxy.cs @@ -10,7 +10,7 @@ internal sealed class BoundComponentDebugProxy public BoundComponentDebugProxy(BoundComponent bound) { - if (bound.AssetId == Asset.EmptyId) + if (bound.AssetId.IsEmpty) { Components = []; return; diff --git a/src/Hexecs/Actors/Components/ActorComponentPool.Dictionary.cs b/src/Hexecs/Actors/Components/ActorComponentPool.Dictionary.cs index 0f94df1..53afa5f 100644 --- a/src/Hexecs/Actors/Components/ActorComponentPool.Dictionary.cs +++ b/src/Hexecs/Actors/Components/ActorComponentPool.Dictionary.cs @@ -2,7 +2,7 @@ namespace Hexecs.Actors.Components; internal sealed partial class ActorComponentPool { - private uint[] _sparse; + private uint[] _sparse; private uint[] _dense; private T[] _values; private int _count; @@ -78,8 +78,9 @@ private bool RemoveEntry(uint ownerId, out T value) ref var componentRef = ref _values[denseIndex]; value = componentRef; - Removing?.Invoke(ownerId); - ComponentRemoving?.Invoke(ownerId, ref componentRef); + var actorId = new ActorId(_dense[denseIndex]); + Removing?.Invoke(actorId); + ComponentRemoving?.Invoke(actorId, ref componentRef); _disposeHandler?.Invoke(ref componentRef); var lastIndex = _count - 1; diff --git a/src/Hexecs/Actors/Components/ActorComponentPool.Enumerator.cs b/src/Hexecs/Actors/Components/ActorComponentPool.Enumerator.cs index 3e3556d..bd9badd 100644 --- a/src/Hexecs/Actors/Components/ActorComponentPool.Enumerator.cs +++ b/src/Hexecs/Actors/Components/ActorComponentPool.Enumerator.cs @@ -15,7 +15,7 @@ public readonly ActorRef Current var index = _index; return new ActorRef( _context, - _dense[index], + new ActorId(_dense[index]), ref _values[index]); } } diff --git a/src/Hexecs/Actors/Components/ActorComponentPool.cs b/src/Hexecs/Actors/Components/ActorComponentPool.cs index aa5d52d..13cacdd 100644 --- a/src/Hexecs/Actors/Components/ActorComponentPool.cs +++ b/src/Hexecs/Actors/Components/ActorComponentPool.cs @@ -9,8 +9,8 @@ namespace Hexecs.Actors.Components; internal sealed partial class ActorComponentPool : IActorComponentPool where T : struct, IActorComponent { - public event Action? Added; - public event Action? Removing; + public event Action? Added; + public event Action? Removing; public event ActorComponentAdded? ComponentAdded; public event ActorComponentRemoving? ComponentRemoving; @@ -49,9 +49,9 @@ public ActorComponentPool(ActorContext context, ActorComponentConfiguration c _disposeHandler = configuration.DisposeHandler; } - public ref T Add(uint ownerId, in T component) + public ref T Add(ActorId ownerId, in T component) { - var result = TryAddEntry(ownerId); + var result = TryAddEntry(ownerId.Value); if (result.IsSuccess) { ref var componentRef = ref result.Component; @@ -90,9 +90,9 @@ public void Clear() _count = 0; } - public ref T Clone(uint ownerId, uint cloneId) + public ref T Clone(ActorId ownerId, ActorId cloneId) { - ref var ownerEntry = ref GetEntryRef(ownerId); + ref var ownerEntry = ref GetEntryRef(ownerId.Value); if (Unsafe.IsNullRef(ref ownerEntry)) ActorError.ComponentNotFound(ownerId); if (_cloneHandler == null) @@ -107,7 +107,7 @@ public ref T Clone(uint ownerId, uint cloneId) public ActorRef First() { return _count > 0 - ? new ActorRef(Context, _dense[0], ref _values[0]) + ? new ActorRef(Context, new ActorId(_dense[0]), ref _values[0]) : ActorRef.Empty; } @@ -120,7 +120,7 @@ public ActorRef First(ActorPredicate predicate) for (var i = 0; i < count; i++) { - var actor = new ActorRef(context, keys[i], ref values[i]); + var actor = new ActorRef(context, new ActorId(keys[i]), ref values[i]); if (predicate(in actor)) { return actor; @@ -131,9 +131,9 @@ public ActorRef First(ActorPredicate predicate) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ref T Get(uint ownerId) + public ref T Get(ActorId ownerId) { - ref var entry = ref GetEntryRef(ownerId); + ref var entry = ref GetEntryRef(ownerId.Value); if (!Unsafe.IsNullRef(ref entry)) { return ref entry; @@ -145,9 +145,9 @@ public ref T Get(uint ownerId) [MethodImpl(MethodImplOptions.AggressiveInlining)] public ComponentsAccess GetComponentAccess() => new(_sparse, _values); - public ref T GetOrCreate(uint ownerId, out bool added, Func? factory = null) + public ref T GetOrCreate(ActorId ownerId, out bool added, Func? factory = null) { - var result = UpsertEntry(ownerId, out var exists); + var result = UpsertEntry(ownerId.Value, out var exists); ref var componentRef = ref result.Component; if (exists) @@ -167,20 +167,32 @@ public ref T GetOrCreate(uint ownerId, out bool added, Func? factory = } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Span GetValues() => _values.AsSpan(0, _count); + public Span GetValues() + { + return _values.AsSpan(0, _count); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Has(uint ownerId) => ContainsEntry(ownerId); + public bool Has(ActorId ownerId) + { + return ContainsEntry(ownerId.Value); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Remove(uint ownerId) => RemoveEntry(ownerId, out _); + public bool Remove(ActorId ownerId) + { + return RemoveEntry(ownerId.Value, out _); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Remove(uint ownerId, out T component) => RemoveEntry(ownerId, out component); + public bool Remove(ActorId ownerId, out T component) + { + return RemoveEntry(ownerId.Value, out component); + } - public bool TryAdd(uint ownerId, in T component) + public bool TryAdd(ActorId ownerId, in T component) { - var result = TryAddEntry(ownerId); + var result = TryAddEntry(ownerId.Value); if (!result.IsSuccess) return false; @@ -196,9 +208,9 @@ public bool TryAdd(uint ownerId, in T component) [MethodImpl(MethodImplOptions.AggressiveInlining)] public ref T TryGet(uint ownerId) => ref GetEntryRef(ownerId); - public bool Update(uint ownerId, in T component) + public bool Update(ActorId ownerId, in T component) { - ref var exists = ref GetEntryRef(ownerId); + ref var exists = ref GetEntryRef(ownerId.Value); if (Unsafe.IsNullRef(ref exists)) return false; ComponentUpdating?.Invoke(ownerId, ref exists, in component); @@ -215,9 +227,9 @@ ActorContext IActorComponentPool.Context get => Context; } - void IActorComponentPool.Clone(uint ownerId, uint cloneId) => Clone(ownerId, cloneId); + void IActorComponentPool.Clone(ActorId ownerId, ActorId cloneId) => Clone(ownerId, cloneId); - IActorComponent IActorComponentPool.Get(uint ownerId) => Get(ownerId); + IActorComponent IActorComponentPool.Get(ActorId ownerId) => Get(ownerId); #endregion } \ No newline at end of file diff --git a/src/Hexecs/Actors/Components/IActorComponentPool.cs b/src/Hexecs/Actors/Components/IActorComponentPool.cs index 9b87eef..84dd887 100644 --- a/src/Hexecs/Actors/Components/IActorComponentPool.cs +++ b/src/Hexecs/Actors/Components/IActorComponentPool.cs @@ -11,12 +11,12 @@ internal interface IActorComponentPool /// /// Событие, вызываемое при добавлении компонента к актёру с указанным идентификатором. /// - event Action? Added; + event Action? Added; /// /// Событие, вызываемое перед удалением компонента у актёра с указанным идентификатором. /// - event Action? Removing; + event Action? Removing; /// /// Контекст актёра, к которому принадлежит этот пул компонентов. @@ -48,28 +48,28 @@ internal interface IActorComponentPool /// /// Идентификатор актёра-источника. /// Идентификатор актёра-получателя. - void Clone(uint ownerId, uint cloneId); + void Clone(ActorId ownerId, ActorId cloneId); /// /// Получает компонент для актёра с указанным идентификатором. /// /// Идентификатор актёра. /// Компонент актёра. - IActorComponent Get(uint ownerId); + IActorComponent Get(ActorId ownerId); /// /// Проверяет, есть ли компонент у актёра с указанным идентификатором. /// /// Идентификатор актёра. /// Возвращает true, если компонент существует; иначе false. - bool Has(uint ownerId); + bool Has(ActorId ownerId); /// /// Удаляет компонент у актёра с указанным идентификатором. /// /// Идентификатор актёра. /// Возвращает true, если компонент был удален; иначе false. - bool Remove(uint ownerId); + bool Remove(ActorId ownerId); /// /// Сериализует содержимое пула компонентов в формат JSON. diff --git a/src/Hexecs/Actors/Delegates/ActorComponentAdded.cs b/src/Hexecs/Actors/Delegates/ActorComponentAdded.cs index e41d3d4..5a0b7f9 100644 --- a/src/Hexecs/Actors/Delegates/ActorComponentAdded.cs +++ b/src/Hexecs/Actors/Delegates/ActorComponentAdded.cs @@ -6,5 +6,5 @@ /// Тип компонента, должен быть структурой и реализовывать интерфейс IActorComponent. /// Идентификатор актёра, к которому был добавлен компонент. /// Ссылка на добавленный компонент. -public delegate void ActorComponentAdded(uint actorId, ref T component) +public delegate void ActorComponentAdded(ActorId actorId, ref T component) where T : struct, IActorComponent; diff --git a/src/Hexecs/Actors/Delegates/ActorComponentRemoving.cs b/src/Hexecs/Actors/Delegates/ActorComponentRemoving.cs index 38ad5d0..1996ed2 100644 --- a/src/Hexecs/Actors/Delegates/ActorComponentRemoving.cs +++ b/src/Hexecs/Actors/Delegates/ActorComponentRemoving.cs @@ -6,5 +6,5 @@ /// Тип компонента, должен быть структурой и реализовывать интерфейс . /// Идентификатор актёра, к которому был добавлен компонент. /// Удалённый компонент. -public delegate void ActorComponentRemoving(uint actorId, ref T component) +public delegate void ActorComponentRemoving(ActorId actorId, ref T component) where T : struct, IActorComponent; \ No newline at end of file diff --git a/src/Hexecs/Actors/Delegates/ActorComponentUpdating.cs b/src/Hexecs/Actors/Delegates/ActorComponentUpdating.cs index 0daac8e..cd8deae 100644 --- a/src/Hexecs/Actors/Delegates/ActorComponentUpdating.cs +++ b/src/Hexecs/Actors/Delegates/ActorComponentUpdating.cs @@ -7,5 +7,5 @@ /// Идентификатор актёра, чей компонент обновляется. /// Текущее состояние компонента актёра. /// Ожидаемое (новое) состояние компонента актёра. -public delegate void ActorComponentUpdating(uint actorId, ref T exists, in T expected) +public delegate void ActorComponentUpdating(ActorId actorId, ref T exists, in T expected) where T : struct, IActorComponent; \ No newline at end of file diff --git a/src/Hexecs/Actors/Development/ActorDebugProxy.cs b/src/Hexecs/Actors/Development/ActorDebugProxy.cs index d44010a..505e0ee 100644 --- a/src/Hexecs/Actors/Development/ActorDebugProxy.cs +++ b/src/Hexecs/Actors/Development/ActorDebugProxy.cs @@ -8,24 +8,5 @@ internal sealed class ActorDebugProxy(Actor actor) ? [] : actor.Context.Components(actor.Id).ToArray(); - private IActorComponent[]? _components; -} - -[ExcludeFromCodeCoverage] -[SuppressMessage("ReSharper", "NotAccessedField.Global")] -internal sealed class ActorDebugProxy(Actor actor) - where T1: struct, IActorComponent -{ - public T1 Component1 - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => actor.Context.GetComponent(actor.Id); - } - - [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] - public IActorComponent[] Components => _components ??= actor.IsEmpty - ? [] - : actor.Context.Components(actor.Id).ToArray(); - private IActorComponent[]? _components; } \ No newline at end of file diff --git a/src/Hexecs/Actors/Development/ActorIdDebugProxy.cs b/src/Hexecs/Actors/Development/ActorIdDebugProxy.cs index 92d716b..aef5304 100644 --- a/src/Hexecs/Actors/Development/ActorIdDebugProxy.cs +++ b/src/Hexecs/Actors/Development/ActorIdDebugProxy.cs @@ -7,21 +7,7 @@ internal sealed class ActorIdDebugProxy(ActorId actorId) public IActorComponent[] Components => _components ??= actorId.IsEmpty ? [] : ActorMarshal.TryGetDebugContext(out var actorContext) - ? actorContext.Components(actorId.Value).ToArray() - : []; - - private IActorComponent[]? _components; -} - -[ExcludeFromCodeCoverage] -[SuppressMessage("ReSharper", "NotAccessedField.Global")] -internal sealed class ActorIdDebugProxy(ActorId actorId) - where T1 : struct, IActorComponent -{ - public IActorComponent[] Components => _components ??= actorId.IsEmpty - ? [] - : ActorMarshal.TryGetDebugContext(out var actorContext) - ? actorContext.Components(actorId.Value).ToArray() + ? actorContext.Components(actorId).ToArray() : []; private IActorComponent[]? _components; diff --git a/src/Hexecs/Actors/Development/ActorRefDebugProxy.cs b/src/Hexecs/Actors/Development/ActorRefDebugProxy.cs index fdfc741..4532532 100644 --- a/src/Hexecs/Actors/Development/ActorRefDebugProxy.cs +++ b/src/Hexecs/Actors/Development/ActorRefDebugProxy.cs @@ -15,7 +15,7 @@ public T1 Component1 ? _context.Components(_actorId).ToArray() : []; - private readonly uint _actorId = actor.Id; + private readonly ActorId _actorId = actor.Id; private readonly ActorContext _context = actor.Context; private IActorComponent[]? _components; } @@ -42,7 +42,7 @@ public T2 Component2 ? _context.Components(_actorId).ToArray() : []; - private readonly uint _actorId = actor.Id; + private readonly ActorId _actorId = actor.Id; private readonly ActorContext _context = actor.Context; private IActorComponent[]? _components; } @@ -76,7 +76,7 @@ public T3 Component3 ? _context.Components(_actorId).ToArray() : []; - private readonly uint _actorId = actor.Id; + private readonly ActorId _actorId = actor.Id; private readonly ActorContext _context = actor.Context; private IActorComponent[]? _components; } \ No newline at end of file diff --git a/src/Hexecs/Actors/Development/ActorRelationDebugProxy.cs b/src/Hexecs/Actors/Development/ActorRelationDebugProxy.cs index 6cfe763..098a930 100644 --- a/src/Hexecs/Actors/Development/ActorRelationDebugProxy.cs +++ b/src/Hexecs/Actors/Development/ActorRelationDebugProxy.cs @@ -11,7 +11,7 @@ internal sealed class ActorRelationDebugProxy(ActorRelation relation) ? _context.Components(_actorId).ToArray() : []; - private readonly uint _actorId = relation.Id; + private readonly ActorId _actorId = relation.Id; private readonly ActorContext _context = relation.Context; private IActorComponent[]? _components; } \ No newline at end of file diff --git a/src/Hexecs/Actors/IActorFilter.cs b/src/Hexecs/Actors/IActorFilter.cs index b32e7de..e885d72 100644 --- a/src/Hexecs/Actors/IActorFilter.cs +++ b/src/Hexecs/Actors/IActorFilter.cs @@ -13,7 +13,7 @@ public interface IActorFilter : IDisposable /// Событие, вызываемое при добавлении актёра в фильтр. /// Параметр содержит идентификатор добавленного актёра. /// - event Action? Added; + event Action? Added; /// /// Событие, вызываемое при очистке всего фильтра. @@ -25,7 +25,7 @@ public interface IActorFilter : IDisposable /// Событие, вызываемое при удалении актёра из фильтра. /// Параметр содержит идентификатор удаленного актёра. /// - event Action? Removed; + event Action? Removed; /// /// Ограничение, определяющее критерии фильтрации актёров. @@ -49,14 +49,7 @@ public interface IActorFilter : IDisposable /// /// Числовой идентификатор актёра. /// Возвращает true, если актёр удовлетворяет условиям фильтра; иначе false. - bool Contains(uint actorId); - - /// - /// Проверяет, содержится ли актёр с указанным структурным идентификатором в фильтре. - /// - /// Структурный идентификатор актёра. - /// Возвращает true, если актёр удовлетворяет условиям фильтра; иначе false. - bool Contains(in ActorId actorId); + bool Contains(ActorId actorId); /// /// Проверяет, содержится ли указанный актёр в фильтре. diff --git a/src/Hexecs/Actors/Loggers/ActorIdLogWriter.cs b/src/Hexecs/Actors/Loggers/ActorIdLogWriter.cs index df18b66..713e23d 100644 --- a/src/Hexecs/Actors/Loggers/ActorIdLogWriter.cs +++ b/src/Hexecs/Actors/Loggers/ActorIdLogWriter.cs @@ -2,31 +2,14 @@ namespace Hexecs.Actors.Loggers; -internal sealed class ActorIdLogWriter : ILogValueWriter, ILogValueWriterFactory +internal sealed class ActorIdLogWriter : ILogValueWriter { public static readonly ActorIdLogWriter Instance = new(); - public static ILogValueWriterFactory Factory => Instance; private ActorIdLogWriter() { } - public bool TryCreateWriter(out ILogValueWriter writer) - { - var type = typeof(T); - if (type is { IsValueType: true, IsGenericType: true }) - { - if (type.GetGenericTypeDefinition() == typeof(ActorId<>)) - { - writer = new LikeActorIdStruct(); - return true; - } - } - - writer = null!; - return false; - } - public void Write(ref ValueStringBuilder stringBuilder, ActorId actor) { if (actor.IsEmpty) @@ -37,7 +20,7 @@ public void Write(ref ValueStringBuilder stringBuilder, ActorId actor) { if (ActorMarshal.TryGetDebugContext(out var context)) { - context.GetDescription(actor.Value, ref stringBuilder); + context.GetDescription(actor, ref stringBuilder); } else { @@ -45,13 +28,4 @@ public void Write(ref ValueStringBuilder stringBuilder, ActorId actor) } } } - - private sealed class LikeActorIdStruct : ILogValueWriter - { - public void Write(ref ValueStringBuilder stringBuilder, T arg) - { - ref readonly var actor = ref Unsafe.As(ref arg); - Instance.Write(ref stringBuilder, actor); - } - } } \ No newline at end of file diff --git a/src/Hexecs/Actors/Loggers/ActorLogWriter.cs b/src/Hexecs/Actors/Loggers/ActorLogWriter.cs index 728f259..9414012 100644 --- a/src/Hexecs/Actors/Loggers/ActorLogWriter.cs +++ b/src/Hexecs/Actors/Loggers/ActorLogWriter.cs @@ -2,31 +2,14 @@ namespace Hexecs.Actors.Loggers; -internal sealed class ActorLogWriter : ILogValueWriter, ILogValueWriterFactory +internal sealed class ActorLogWriter : ILogValueWriter { public static readonly ActorLogWriter Instance = new(); - public static ILogValueWriterFactory Factory => Instance; private ActorLogWriter() { } - public bool TryCreateWriter(out ILogValueWriter writer) - { - var type = typeof(T); - if (type is { IsValueType: true, IsGenericType: true }) - { - if (type.GetGenericTypeDefinition() == typeof(Actor<>)) - { - writer = new LikeActorStruct(); - return true; - } - } - - writer = null!; - return false; - } - public void Write(ref ValueStringBuilder stringBuilder, Actor actor) { if (actor.IsEmpty) @@ -38,13 +21,4 @@ public void Write(ref ValueStringBuilder stringBuilder, Actor actor) actor.Context.GetDescription(actor.Id, ref stringBuilder); } } - - private sealed class LikeActorStruct : ILogValueWriter - { - public void Write(ref ValueStringBuilder stringBuilder, T arg) - { - ref readonly var actor = ref Unsafe.As(ref arg); - Instance.Write(ref stringBuilder, actor); - } - } } \ No newline at end of file diff --git a/src/Hexecs/Actors/Nodes/ActorNodeComponent.cs b/src/Hexecs/Actors/Nodes/ActorNodeComponent.cs index 26e0043..ce7c117 100644 --- a/src/Hexecs/Actors/Nodes/ActorNodeComponent.cs +++ b/src/Hexecs/Actors/Nodes/ActorNodeComponent.cs @@ -5,10 +5,10 @@ namespace Hexecs.Actors.Nodes; [StructLayout(LayoutKind.Sequential, Size = 32)] internal struct ActorNodeComponent : IActorComponent { - public uint NextSiblingId; - public uint FirstChildId; - public uint ParentId; - public uint PrevSiblingId; + public ActorId NextSiblingId; + public ActorId FirstChildId; + public ActorId ParentId; + public ActorId PrevSiblingId; public uint ChildCount; public static ActorComponentConfiguration CreatePoolConfiguration() diff --git a/src/Hexecs/Actors/Relations/ActorRelationComponent.cs b/src/Hexecs/Actors/Relations/ActorRelationComponent.cs index 53c39dd..66d7b6b 100644 --- a/src/Hexecs/Actors/Relations/ActorRelationComponent.cs +++ b/src/Hexecs/Actors/Relations/ActorRelationComponent.cs @@ -6,7 +6,7 @@ namespace Hexecs.Actors.Relations; [method: MethodImpl(MethodImplOptions.AggressiveInlining)] internal struct ActorRelationComponent(int capacity) : IActorComponent, IDisposable { - public static ActorRelationComponent Create(uint actorId) => new(4); + public static ActorRelationComponent Create(ActorId _) => new(4); public static ActorComponentConfiguration CreatePoolConfiguration() { diff --git a/src/Hexecs/Actors/Relations/ActorRelationPool.Enumerator.cs b/src/Hexecs/Actors/Relations/ActorRelationPool.Enumerator.cs index a51886e..3a6a03c 100644 --- a/src/Hexecs/Actors/Relations/ActorRelationPool.Enumerator.cs +++ b/src/Hexecs/Actors/Relations/ActorRelationPool.Enumerator.cs @@ -6,7 +6,7 @@ public ref struct ActorRelationEnumerator public static ActorRelationEnumerator Empty { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => new(null!, ReadOnlySpan.Empty); + get => new(null!, ReadOnlySpan.Empty, ActorId.Empty); } public readonly ActorRelation Current @@ -16,7 +16,9 @@ public readonly ActorRelation Current var index = _indices[_currentIndex]; var key = _pool.Keys[index]; ref var reference = ref _pool.Values[index]; - return new ActorRelation(_pool.Context, key.First == _subject ? key.Second : key.First, ref reference); + return new ActorRelation(_pool.Context, + key.First == _subject ? key.Second : key.First, + ref reference); } } @@ -28,10 +30,10 @@ public readonly int Length private readonly ReadOnlySpan _indices; private readonly ActorRelationPool _pool; - private readonly uint _subject; + private readonly ActorId _subject; private int _currentIndex; - internal ActorRelationEnumerator(ActorRelationPool pool, ReadOnlySpan indices, uint subject = 0) + internal ActorRelationEnumerator(ActorRelationPool pool, ReadOnlySpan indices, ActorId subject) { _pool = pool; _indices = indices; diff --git a/src/Hexecs/Actors/Relations/ActorRelationPool.cs b/src/Hexecs/Actors/Relations/ActorRelationPool.cs index 34c4f00..03740b8 100644 --- a/src/Hexecs/Actors/Relations/ActorRelationPool.cs +++ b/src/Hexecs/Actors/Relations/ActorRelationPool.cs @@ -23,7 +23,7 @@ public Type Type private RelationKey[] _keys; private int _count; private readonly Dictionary _indexMap; - + private Bucket[]?[] _sparsePages; private const int PageBits = 10; // 1024 private const int PageSize = 1 << PageBits; @@ -45,7 +45,7 @@ public ActorRelationPool(ActorContext context, int capacity = 16) _count = 0; } - public ref T Add(uint subject, uint relative, in T value) + public ref T Add(ActorId subject, ActorId relative, in T value) { var key = new RelationKey(subject, relative); // Если такая связь уже есть (неважно, кто субъект, а кто цель), выбрасываем ошибку @@ -64,64 +64,16 @@ public ref T Add(uint subject, uint relative, in T value) _indexMap[key] = index; // ВАЖНО: Добавляем индекс в списки ОБОИХ участников - AddToAdjacency(subject, index); + AddToAdjacency(subject.Value, index); // Если это не связь сам с собой, добавляем и второму if (subject != relative) { - AddToAdjacency(relative, index); + AddToAdjacency(relative.Value, index); } return ref _values[index]; } - private void AddToAdjacency(uint actorId, int index) - { - var pageIndex = (int)(actorId >> PageBits); - if (pageIndex >= _sparsePages.Length) - { - ArrayUtils.EnsureCapacity(ref _sparsePages, pageIndex + 1); - } - - ref var page = ref _sparsePages[pageIndex]; - page ??= new Bucket[PageSize]; - - ref var bucket = ref page[actorId & PageMask]; - bucket.Add(index); - } - - private void RemoveFromAdjacency(uint actorId, int index) - { - var pageIndex = (int)(actorId >> PageBits); - var page = _sparsePages[pageIndex]; - ref var bucket = ref page![actorId & PageMask]; - - var span = bucket.AsSpan(); - for (var i = 0; i < span.Length; i++) - { - if (span[i] == index) - { - bucket.RemoveAtSwapBack(i); - return; - } - } - } - - private void ReplaceInAdjacency(uint actorId, int oldIndex, int newIndex) - { - var pageIndex = (int)(actorId >> PageBits); - var page = _sparsePages[pageIndex]; - ref var bucket = ref page![actorId & PageMask]; - var span = bucket.AsSpan(); - for (var i = 0; i < span.Length; i++) - { - if (span[i] == oldIndex) - { - span[i] = newIndex; - return; - } - } - } - public void Clear() { _indexMap.Clear(); @@ -140,16 +92,25 @@ public void Clear() _count = 0; } - public int Count(uint subject) + public int Count(ActorId subject) { - var pageIndex = (int)(subject >> PageBits); - if (pageIndex >= _sparsePages.Length) return 0; + var subjectIdRaw = subject.Value; + var pageIndex = (int)(subjectIdRaw >> PageBits); + if (pageIndex >= _sparsePages.Length) + { + return 0; + } + var page = _sparsePages[pageIndex]; - if (page == null) return 0; - return page[subject & PageMask].Length; + if (page == null) + { + return 0; + } + + return page[subjectIdRaw & PageMask].Length; } - public ref T Get(uint subject, uint relative) + public ref T Get(ActorId subject, ActorId relative) { var key = new RelationKey(subject, relative); if (_indexMap.TryGetValue(key, out var index)) @@ -161,30 +122,44 @@ public ref T Get(uint subject, uint relative) return ref Unsafe.NullRef(); } - public ActorRelationEnumerator GetRelations(uint subject) + public ActorRelationEnumerator GetRelations(ActorId subject) { - var pageIndex = (int)(subject >> PageBits); - if (pageIndex >= _sparsePages.Length) return ActorRelationEnumerator.Empty; + var subjectIdRaw = subject.Value; + + var pageIndex = (int)(subjectIdRaw >> PageBits); + if (pageIndex >= _sparsePages.Length) + { + return ActorRelationEnumerator.Empty; + } + var page = _sparsePages[pageIndex]; - if (page == null) return ActorRelationEnumerator.Empty; + if (page == null) + { + return ActorRelationEnumerator.Empty; + } - return new ActorRelationEnumerator(this, page[subject & PageMask].AsReadOnlySpan(), subject); + return new ActorRelationEnumerator( + pool: this, + indices: page[subjectIdRaw & PageMask].AsReadOnlySpan(), + subject); } - public bool Has(uint subject, uint relative) + public bool Has(ActorId subject, ActorId relative) { var key = new RelationKey(subject, relative); return _indexMap.ContainsKey(key); } - public bool Remove(uint subject) + public bool Remove(ActorId subject) { - var pageIndex = (int)(subject >> PageBits); + var subjectIdRaw = subject.Value; + + var pageIndex = (int)(subjectIdRaw >> PageBits); if (pageIndex >= _sparsePages.Length) return false; var page = _sparsePages[pageIndex]; if (page == null) return false; - ref var bucket = ref page[subject & PageMask]; + ref var bucket = ref page[subjectIdRaw & PageMask]; if (bucket.Length == 0) return false; var removedAny = false; @@ -209,7 +184,7 @@ public bool Remove(uint subject) return removedAny; } - public bool Remove(uint subject, uint relative, out T removed) + public bool Remove(ActorId subject, ActorId relative, out T removed) { var key = new RelationKey(subject, relative); if (!_indexMap.TryGetValue(key, out var index)) @@ -222,10 +197,10 @@ public bool Remove(uint subject, uint relative, out T removed) _indexMap.Remove(key); // Удаляем из списков смежности ОБОИХ участников - RemoveFromAdjacency(key.First, index); + RemoveFromAdjacency(key.First.Value, index); if (key.First != key.Second) { - RemoveFromAdjacency(key.Second, index); + RemoveFromAdjacency(key.Second.Value, index); } var lastIndex = _count - 1; @@ -239,10 +214,10 @@ public bool Remove(uint subject, uint relative, out T removed) _indexMap[lastKey] = index; // Обновляем индексы в списках смежности для перемещенной связи у ОБОИХ участников - ReplaceInAdjacency(lastKey.First, lastIndex, index); + ReplaceInAdjacency(lastKey.First.Value, lastIndex, index); if (lastKey.First != lastKey.Second) { - ReplaceInAdjacency(lastKey.Second, lastIndex, index); + ReplaceInAdjacency(lastKey.Second.Value, lastIndex, index); } } @@ -253,13 +228,61 @@ public bool Remove(uint subject, uint relative, out T removed) return true; } + private void AddToAdjacency(uint actorId, int index) + { + var pageIndex = (int)(actorId >> PageBits); + if (pageIndex >= _sparsePages.Length) + { + ArrayUtils.EnsureCapacity(ref _sparsePages, pageIndex + 1); + } + + ref var page = ref _sparsePages[pageIndex]; + page ??= new Bucket[PageSize]; + + ref var bucket = ref page[actorId & PageMask]; + bucket.Add(index); + } + + private void RemoveFromAdjacency(uint actorId, int index) + { + var pageIndex = (int)(actorId >> PageBits); + var page = _sparsePages[pageIndex]; + ref var bucket = ref page![actorId & PageMask]; + + var span = bucket.AsSpan(); + for (var i = 0; i < span.Length; i++) + { + if (span[i] == index) + { + bucket.RemoveAtSwapBack(i); + return; + } + } + } + + private void ReplaceInAdjacency(uint actorId, int oldIndex, int newIndex) + { + var pageIndex = (int)(actorId >> PageBits); + var page = _sparsePages[pageIndex]; + ref var bucket = ref page![actorId & PageMask]; + var span = bucket.AsSpan(); + for (var i = 0; i < span.Length; i++) + { + if (span[i] == oldIndex) + { + span[i] = newIndex; + return; + } + } + } + [DebuggerDisplay("{First} to {Second}")] internal readonly struct RelationKey : IEquatable { - public readonly uint First; - public readonly uint Second; + public readonly ActorId First; + public readonly ActorId Second; - public RelationKey(uint first, uint second) + public RelationKey(ActorId first, ActorId second) { if (first < second) { @@ -280,7 +303,7 @@ public RelationKey(uint first, uint second) public override bool Equals(object? obj) => obj is RelationKey key && Equals(key); [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Is(uint value) => First == value || Second == value; + public bool Is(ActorId value) => First == value || Second == value; } ActorContext IActorRelationPool.Context => Context; diff --git a/src/Hexecs/Actors/Relations/IActorRelationPool.cs b/src/Hexecs/Actors/Relations/IActorRelationPool.cs index 9e323dd..d0d7297 100644 --- a/src/Hexecs/Actors/Relations/IActorRelationPool.cs +++ b/src/Hexecs/Actors/Relations/IActorRelationPool.cs @@ -12,11 +12,11 @@ internal interface IActorRelationPool void Clear(); - int Count(uint subject); + int Count(ActorId subject); - bool Has(uint subject, uint relative); + bool Has(ActorId subject, ActorId relative); - bool Remove(uint subject); + bool Remove(ActorId subject); /// /// Сериализует содержимое пула отношений в формат JSON. diff --git a/src/Hexecs/Actors/Systems/ParallelSystem.cs b/src/Hexecs/Actors/Systems/ParallelSystem.cs index 821d75a..22f0c64 100644 --- a/src/Hexecs/Actors/Systems/ParallelSystem.cs +++ b/src/Hexecs/Actors/Systems/ParallelSystem.cs @@ -31,17 +31,6 @@ public ParallelSystem( _worker = worker; } - public void Execute(int workerIndex, int workerCount) - { - var skip = workerIndex * _batchSize; - var batch = _systems.AsSpan(skip, _batchSize); - - foreach (var updateSystem in batch) - { - updateSystem.Update(_currentTime); - } - } - public bool TryGetSystem([NotNullWhen(true)] out T? system) where T : class, IUpdateSystem { @@ -68,4 +57,15 @@ public void Update(in WorldTime time) ActorContext IUpdateSystem.Context => Context; ActorContext IParallelJob.Context => Context; + + void IParallelJob.Execute(int workerIndex, int workersCount) + { + var skip = workerIndex * _batchSize; + var batch = _systems.AsSpan(skip, _batchSize); + + foreach (var updateSystem in batch) + { + updateSystem.Update(_currentTime); + } + } } \ No newline at end of file diff --git a/src/Hexecs/Actors/Systems/UpdateSystem1.cs b/src/Hexecs/Actors/Systems/UpdateSystem1.cs index 4347726..d4a0ee9 100644 --- a/src/Hexecs/Actors/Systems/UpdateSystem1.cs +++ b/src/Hexecs/Actors/Systems/UpdateSystem1.cs @@ -74,14 +74,14 @@ public sealed override void Update(in WorldTime time) protected abstract void Update(in ActorRef actor, in WorldTime time); - void IParallelJob.Execute(int workerIndex, int workerCount) + void IParallelJob.Execute(int workerIndex, int workersCount) { var start = workerIndex * _currentBatchSize; var length = _currentLength; if ((uint)start < (uint)length) { - var batch = workerIndex == workerCount + var batch = workerIndex == workersCount ? Filter.Skip(start) : Filter.Skip(start, _currentBatchSize); diff --git a/src/Hexecs/Actors/Systems/UpdateSystem2.cs b/src/Hexecs/Actors/Systems/UpdateSystem2.cs index e272196..2e552e3 100644 --- a/src/Hexecs/Actors/Systems/UpdateSystem2.cs +++ b/src/Hexecs/Actors/Systems/UpdateSystem2.cs @@ -42,7 +42,7 @@ protected virtual void AfterUpdate(in WorldTime time) /// Время мира /// Если возвращает false, то обновление не происходит protected virtual bool BeforeUpdate(in WorldTime time) => true; - + public sealed override void Update(in WorldTime time) { if (Enabled) @@ -74,14 +74,14 @@ public sealed override void Update(in WorldTime time) protected abstract void Update(in ActorRef actor, in WorldTime time); - void IParallelJob.Execute(int workerIndex, int workerCount) + void IParallelJob.Execute(int workerIndex, int workersCount) { var start = workerIndex * _currentBatchSize; var length = _currentLength; if ((uint)start < (uint)length) { - var batch = workerIndex == workerCount + var batch = workerIndex == workersCount ? Filter.Skip(start) : Filter.Skip(start, _currentBatchSize); diff --git a/src/Hexecs/Actors/Systems/UpdateSystem3.cs b/src/Hexecs/Actors/Systems/UpdateSystem3.cs index 73543a6..7c87590 100644 --- a/src/Hexecs/Actors/Systems/UpdateSystem3.cs +++ b/src/Hexecs/Actors/Systems/UpdateSystem3.cs @@ -76,14 +76,14 @@ public sealed override void Update(in WorldTime time) protected abstract void Update(in ActorRef actor, in WorldTime time); - void IParallelJob.Execute(int workerIndex, int workerCount) + void IParallelJob.Execute(int workerIndex, int workersCount) { var start = workerIndex * _currentBatchSize; var length = _currentLength; if ((uint)start < (uint)length) { - var batch = workerIndex == workerCount + var batch = workerIndex == workersCount ? Filter.Skip(start) : Filter.Skip(start, _currentBatchSize); diff --git a/src/Hexecs/Assets/Asset.cs b/src/Hexecs/Assets/Asset.cs index c7ab7f1..a9f68f2 100644 --- a/src/Hexecs/Assets/Asset.cs +++ b/src/Hexecs/Assets/Asset.cs @@ -10,18 +10,13 @@ namespace Hexecs.Assets; [DebuggerTypeProxy(typeof(AssetDebugProxy))] public readonly struct Asset : IEquatable { - /// - /// Константа, представляющая идентификатор пустого ассета. - /// - internal const uint EmptyId = 0; - /// /// Возвращает пустой экземпляр ассета. /// public static Asset Empty { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => new(null!, EmptyId); + get => new(null!, AssetId.Empty); } /// @@ -41,7 +36,7 @@ public bool IsEmpty /// /// Уникальный идентификатор ассета в контексте. /// - public readonly uint Id; + public readonly AssetId Id; /// /// Создает новый экземпляр ассета с указанным контекстом и идентификатором. @@ -49,21 +44,12 @@ public bool IsEmpty /// Контекст ассета /// Идентификатор ассета [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal Asset(AssetContext context, uint id) + internal Asset(AssetContext context, AssetId id) { Context = context; Id = id; } - /// - /// Преобразует ассет в типизированный ассет с указанным компонентом. - /// - /// Тип компонента ассета - /// Выбрасывает ошибку, если компонент отсутствует в ассете - /// Типизированный ассет - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Asset As() where T : struct, IAssetComponent => Context.GetAsset(Id); - /// /// Преобразует ассет в ссылку на типизированный ассет с указанным компонентом. /// @@ -71,7 +57,11 @@ internal Asset(AssetContext context, uint id) /// Выбрасывает ошибку, если компонент отсутствует в ассете /// Ссылка на типизированный ассет [MethodImpl(MethodImplOptions.AggressiveInlining)] - public AssetRef AsRef() where T : struct, IAssetComponent => Context.GetAssetRef(Id); + public AssetRef AsRef() + where T : struct, IAssetComponent + { + return Context.GetAssetRef(Id); + } /// /// Получает компонент указанного типа для данного ассета. @@ -80,7 +70,11 @@ internal Asset(AssetContext context, uint id) /// Выбрасывает ошибку, если компонент отсутствует в ассете /// Ссылка на компонент [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ref readonly T Get() where T : struct, IAssetComponent => ref Context.GetComponent(Id); + public ref readonly T Get() + where T : struct, IAssetComponent + { + return ref Context.GetComponent(Id); + } /// /// Проверяет наличие компонента указанного типа у ассета. @@ -88,17 +82,11 @@ internal Asset(AssetContext context, uint id) /// Тип компонента /// Возвращает true, если компонент существует; иначе false [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Has() where T : struct, IAssetComponent => Context.HasComponent(Id); - - /// - /// Проверяет, является ли ассет ассетом с указанным типом компонента. - /// В случае успеха возвращает типизированный ассет. - /// - /// Тип компонента - /// Результирующий типизированный ассет - /// Возвращает true, если ассет содержит указанный компонент; иначе false - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Is(out Asset asset) where T : struct, IAssetComponent => Context.TryGetAsset(Id, out asset); + public bool Has() + where T : struct, IAssetComponent + { + return Context.HasComponent(Id); + } /// /// Проверяет, является ли ассет ссылкой на ассет с указанным типом компонента. @@ -108,7 +96,8 @@ internal Asset(AssetContext context, uint id) /// Результирующая ссылка на типизированный ассет /// Возвращает true, если ассет содержит указанный компонент; иначе false [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool IsRef(out AssetRef asset) where T : struct, IAssetComponent + public bool IsRef(out AssetRef asset) + where T : struct, IAssetComponent { return Context.TryGetAssetRef(Id, out asset); } @@ -117,10 +106,13 @@ public bool IsRef(out AssetRef asset) where T : struct, IAssetComponent /// Возвращает строковое представление ассета. /// Для пустого ассета возвращает специальное значение, иначе - описание из контекста. /// - public override string ToString() => Context == null - ? StringUtils.EmptyValue - : Context.GetDescription(Id); - + public override string ToString() + { + return Context == null + ? StringUtils.EmptyValue + : Context.GetDescription(Id); + } + #region Equality /// @@ -181,7 +173,7 @@ public override string ToString() => Context == null /// Ассет для преобразования /// Идентификатор ассета [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator AssetId(in Asset asset) => new(asset.Id); - + public static implicit operator AssetId(in Asset asset) => asset.Id; + #endregion } \ No newline at end of file diff --git a/src/Hexecs/Assets/Asset1.cs b/src/Hexecs/Assets/Asset1.cs deleted file mode 100644 index 11eb8c1..0000000 --- a/src/Hexecs/Assets/Asset1.cs +++ /dev/null @@ -1,214 +0,0 @@ -using Hexecs.Assets.Development; - -namespace Hexecs.Assets; - -/// -/// Структура, представляющая типизированный ассет с компонентом типа . -/// Обеспечивает доступ к компонентам ассета и предоставляет операции над ассетами. -/// -/// Тип компонента ассета, должен быть структурой и реализовывать интерфейс . -[DebuggerDisplay("{ToString()}")] -[DebuggerTypeProxy(typeof(AssetDebugProxy<>))] -public readonly struct Asset : IEquatable> - where T1 : struct, IAssetComponent -{ - /// - /// Возвращает пустой экземпляр ассет с компонентом. - /// - public static Asset Empty - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => new(null!, Asset.EmptyId); - } - - /// - /// Первый компонент ассета. - /// - public T1 Component1 - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => Context.GetComponent(Id); - } - - /// - /// Определяет, является ли ассет пустым. - /// - public bool IsEmpty - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => Context == null; - } - - /// - /// Контекст ассета, управляющий его жизненным циклом и содержащий коллекции компонентов. - /// - public readonly AssetContext Context; - - /// - /// Уникальный идентификатор ассета. - /// - public readonly uint Id; - - /// - /// Инициализирует новый экземпляр ассета. - /// - /// Контекст ассета. - /// Идентификатор ассета. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal Asset(AssetContext context, uint id) - { - Context = context; - Id = id; - } - - /// - /// Преобразует ассет в типизированный ассет с указанным компонентом. - /// - /// Тип компонента ассета - /// Выбрасывает ошибку, если компонент отсутствует в ассете - /// Типизированный ассет - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Asset As() where T : struct, IAssetComponent => Context.GetAsset(Id); - - /// - /// Преобразует ассет в ссылку на типизированный ассет с указанным компонентом. - /// - /// Тип компонента ассета - /// Выбрасывает ошибку, если компонент отсутствует в ассете - /// Ссылка на типизированный ассет - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public AssetRef AsRef() where T : struct, IAssetComponent => Context.GetAssetRef(Id); - - /// - /// Получает компонент указанного типа для данного ассета. - /// - /// Тип компонента - /// Выбрасывает ошибку, если компонент отсутствует в ассете - /// Ссылка на компонент - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ref readonly T Get() where T : struct, IAssetComponent => ref Context.GetComponent(Id); - - /// - /// Проверяет наличие компонента указанного типа у ассета. - /// - /// Тип компонента - /// Возвращает true, если компонент существует; иначе false - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Has() where T : struct, IAssetComponent => Context.HasComponent(Id); - - /// - /// Проверяет, является ли ассет ассетом с указанным типом компонента. - /// В случае успеха возвращает типизированный ассет. - /// - /// Тип компонента - /// Результирующий типизированный ассет - /// Возвращает true, если ассет содержит указанный компонент; иначе false - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Is(out Asset asset) where T : struct, IAssetComponent => Context.TryGetAsset(Id, out asset); - - /// - /// Проверяет, является ли ассет ссылкой на ассет с указанным типом компонента. - /// В случае успеха возвращает ссылку на типизированный ассет. - /// - /// Тип компонента - /// Результирующая ссылка на типизированный ассет - /// Возвращает true, если ассет содержит указанный компонент; иначе false - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool IsRef(out AssetRef asset) where T : struct, IAssetComponent - { - return Context.TryGetAssetRef(Id, out asset); - } - - /// - /// Возвращает строковое представление ассета. - /// Для пустого ассета возвращает специальное значение, иначе - описание из контекста. - /// - public override string ToString() => Context == null - ? StringUtils.EmptyValue - : Context.GetDescription(Id); - - #region Equality - - /// - /// Определяет, равен ли текущий ассет указанному ассету. - /// - /// Ассет для сравнения с текущим. - /// Возвращает true, если ассеты равны; иначе false. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(Asset other) => Id == other.Id && ReferenceEquals(Context, other.Context); - - /// - /// Определяет, равен ли текущий ассет указанному объекту. - /// - /// Объект для сравнения с текущим ассетом. - /// Возвращает true, если объект является ассетом того же типа и равен текущему; иначе false. - public override bool Equals(object? obj) => obj switch - { - Asset other => Equals(other), - Asset asset => asset.Is(out var expected) && Equals(expected), - _ => false - }; - - /// - /// Возвращает хеш-код для текущего ассета. - /// - /// Хеш-код для текущего ассета. - public override int GetHashCode() => HashCode.Combine(Id); - - /// - /// Оператор равенства для ассетов. - /// - /// Первый ассет для сравнения. - /// Второй ассет для сравнения. - /// Возвращает true, если ассеты равны; иначе false. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(in Asset left, in Asset right) => left.Equals(right); - - /// - /// Оператор неравенства для ассетов. - /// - /// Первый ассет для сравнения. - /// Второй ассет для сравнения. - /// Возвращает true, если ассеты не равны; иначе false. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(in Asset left, in Asset right) => !left.Equals(right); - - #endregion - - #region Implicit - - /// - /// Неявное преобразование ассета в булево значение. - /// Возвращает true, если ассет не пустой. - /// - /// Ассет для преобразования. - /// Возвращает true, если ассет не пустой; иначе false. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator bool(in Asset asset) => !asset.IsEmpty; - - /// - /// Неявное преобразование ассета в идентификатор ассета. - /// - /// Ассет для преобразования. - /// Идентификатор ассета. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator AssetId(in Asset asset) => new(asset.Id); - - /// - /// Неявное преобразование ассета в типизированный идентификатор ассета. - /// - /// Ассет для преобразования. - /// Типизированный идентификатор ассета. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator AssetId(in Asset asset) => new(asset.Id); - - /// - /// Неявное преобразование типизированного ассета в нетипизированный ассет. - /// - /// Типизированный ассет для преобразования. - /// Нетипизированный ассет. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator Asset(in Asset asset) => new(asset.Context, asset.Id); - - #endregion -} \ No newline at end of file diff --git a/src/Hexecs/Assets/AssetConstraint.Builder.cs b/src/Hexecs/Assets/AssetConstraint.Builder.cs index 12f8eed..db47d95 100644 --- a/src/Hexecs/Assets/AssetConstraint.Builder.cs +++ b/src/Hexecs/Assets/AssetConstraint.Builder.cs @@ -72,7 +72,7 @@ public Builder Include() where T : struct, IAssetComponent } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void AddSubscription(bool include, IAssetComponentPool pool, Func check) + private void AddSubscription(bool include, IAssetComponentPool pool, Func check) where T : struct, IAssetComponent { var id = AssetComponentType.Id; diff --git a/src/Hexecs/Assets/AssetConstraint.Subscription.cs b/src/Hexecs/Assets/AssetConstraint.Subscription.cs index bd2a4b6..9b741cc 100644 --- a/src/Hexecs/Assets/AssetConstraint.Subscription.cs +++ b/src/Hexecs/Assets/AssetConstraint.Subscription.cs @@ -12,13 +12,13 @@ public ushort ComponentId get => _pool.Id; } - public readonly Func Check; + public readonly Func Check; private readonly bool _include; private readonly IAssetComponentPool _pool; [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Subscription(bool include, IAssetComponentPool pool, Func check) + public Subscription(bool include, IAssetComponentPool pool, Func check) { Check = check; diff --git a/src/Hexecs/Assets/AssetConstraint.cs b/src/Hexecs/Assets/AssetConstraint.cs index a16c769..522859a 100644 --- a/src/Hexecs/Assets/AssetConstraint.cs +++ b/src/Hexecs/Assets/AssetConstraint.cs @@ -68,7 +68,7 @@ private AssetConstraint(int hash, Subscription[] subscriptions) _subscriptions = subscriptions; } - public bool Applicable(uint assetId) + public bool Applicable(AssetId assetId) { // ReSharper disable once LoopCanBeConvertedToQuery foreach (var subscription in _subscriptions) diff --git a/src/Hexecs/Assets/AssetContext.ComponentEnumerator.cs b/src/Hexecs/Assets/AssetContext.ComponentEnumerator.cs index f464fad..e4e37d3 100644 --- a/src/Hexecs/Assets/AssetContext.ComponentEnumerator.cs +++ b/src/Hexecs/Assets/AssetContext.ComponentEnumerator.cs @@ -28,7 +28,7 @@ public readonly int Length } private int _index; - private readonly uint _assetId; + private readonly AssetId _assetId; private readonly ReadOnlySpan _componentIds; private readonly IAssetComponentPool?[] _pools; @@ -36,13 +36,13 @@ public readonly int Length public ComponentEnumerator() { _index = -1; - _assetId = 0; + _assetId = AssetId.Empty; _componentIds = ReadOnlySpan.Empty; _pools = []; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal ComponentEnumerator(uint assetId, IAssetComponentPool?[] pools, ReadOnlySpan componentIds) + internal ComponentEnumerator(AssetId assetId, IAssetComponentPool?[] pools, ReadOnlySpan componentIds) { _index = -1; _assetId = assetId; diff --git a/src/Hexecs/Assets/AssetContext.Components.cs b/src/Hexecs/Assets/AssetContext.Components.cs index 1344a18..2c916af 100644 --- a/src/Hexecs/Assets/AssetContext.Components.cs +++ b/src/Hexecs/Assets/AssetContext.Components.cs @@ -16,9 +16,9 @@ public sealed partial class AssetContext /// /// Идентификатор ассета /// Перечислитель компонентов ассета - public ComponentEnumerator Components(uint assetId) + public ComponentEnumerator Components(AssetId assetId) { - ref var entry = ref GetEntry(assetId); + ref var entry = ref GetEntry(assetId.Value); return Unsafe.IsNullRef(ref entry) ? ComponentEnumerator.Empty : new ComponentEnumerator(assetId, _componentPools, entry.ToArray()); @@ -30,7 +30,8 @@ public ComponentEnumerator Components(uint assetId) /// Тип компонента /// Идентификатор ассета /// Возвращает true, если компонент существует; иначе false - public bool HasComponent(uint assetId) where T : struct, IAssetComponent + public bool HasComponent(AssetId assetId) + where T : struct, IAssetComponent { var pool = GetComponentPool(); return pool != null && pool.Has(assetId); @@ -43,19 +44,21 @@ public bool HasComponent(uint assetId) where T : struct, IAssetComponent /// Идентификатор ассета /// Ссылка на компонент ассета /// Возникает, если компонент не найден - public ref readonly T GetComponent(uint assetId) where T : struct, IAssetComponent + public ref readonly T GetComponent(AssetId assetId) + where T : struct, IAssetComponent { var pool = GetComponentPool(); if (pool == null) AssetError.ComponentNotFound(assetId); return ref pool.Get(assetId); } - public AssetComponentRef GetComponentRef(uint actorId) where T : struct, IAssetComponent + public AssetComponentRef GetComponentRef(AssetId assetId) + where T : struct, IAssetComponent { var pool = GetComponentPool(); if (pool == null) return AssetComponentRef.Empty; - var index = pool.TryGetIndex(actorId); + var index = pool.TryGetIndex(assetId); return index == -1 ? AssetComponentRef.Empty @@ -68,7 +71,8 @@ public AssetComponentRef GetComponentRef(uint actorId) where T : struct, I /// Тип компонента /// Пул компонентов указанного типа или null, если пул не существует [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal AssetComponentPool? GetComponentPool() where T : struct, IAssetComponent + internal AssetComponentPool? GetComponentPool() + where T : struct, IAssetComponent { var id = AssetComponentType.Id; @@ -84,7 +88,8 @@ public AssetComponentRef GetComponentRef(uint actorId) where T : struct, I /// /// Тип компонента /// Пул компонентов указанного типа - internal AssetComponentPool GetOrCreateComponentPool() where T : struct, IAssetComponent + internal AssetComponentPool GetOrCreateComponentPool() + where T : struct, IAssetComponent { var id = AssetComponentType.Id; if (id < _componentPools.Length) diff --git a/src/Hexecs/Assets/AssetContext.Dictionary.cs b/src/Hexecs/Assets/AssetContext.Dictionary.cs index fb6823b..a1a213e 100644 --- a/src/Hexecs/Assets/AssetContext.Dictionary.cs +++ b/src/Hexecs/Assets/AssetContext.Dictionary.cs @@ -12,7 +12,7 @@ public int Length private ref Entry AddEntry(uint id) { - if (id == Asset.EmptyId) AssetError.InvalidId(); + if (id == AssetId.EmptyId) AssetError.InvalidId(); ref var entry = ref CollectionsMarshal.GetValueRefOrAddDefault(_entries, id, out var exists); if (exists) AssetError.AlreadyExists(id); return ref entry; diff --git a/src/Hexecs/Assets/AssetContext.Enumerator.cs b/src/Hexecs/Assets/AssetContext.Enumerator.cs index 94324c4..8f82530 100644 --- a/src/Hexecs/Assets/AssetContext.Enumerator.cs +++ b/src/Hexecs/Assets/AssetContext.Enumerator.cs @@ -11,7 +11,7 @@ public struct Enumerator : IEnumerator, IEnumerable public readonly Asset Current { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => new(_context, _enumerator.Current); + get => new(_context, new AssetId(_enumerator.Current)); } public readonly int Length diff --git a/src/Hexecs/Assets/AssetContext.Loader.cs b/src/Hexecs/Assets/AssetContext.Loader.cs index 5c114cb..8facea1 100644 --- a/src/Hexecs/Assets/AssetContext.Loader.cs +++ b/src/Hexecs/Assets/AssetContext.Loader.cs @@ -79,21 +79,24 @@ public AssetConfigurator CreateAsset(in T1 component1, in T2 compone public AssetConfigurator CreateAsset(uint id) { EnsureNotDisposed(); + Context.AddEntry(id); - return new AssetConfigurator(id, this); + return new AssetConfigurator(new AssetId(id), this); } public AssetConfigurator CreateAsset(uint id, in T1 component1) where T1 : struct, IAssetComponent { EnsureNotDisposed(); + ref var entry = ref Context.AddEntry(id); + var assetId = new AssetId(id); var pool1 = Context.GetOrCreateComponentPool(); - pool1.Set(id, in component1); + pool1.Set(assetId, in component1); entry.Add(AssetComponentType.Id); - return new AssetConfigurator(id, this); + return new AssetConfigurator(assetId, this); } public AssetConfigurator CreateAsset(uint id, in T1 component1, in T2 component2) @@ -101,17 +104,19 @@ public AssetConfigurator CreateAsset(uint id, in T1 component1, in T2 co where T2 : struct, IAssetComponent { EnsureNotDisposed(); + ref var entry = ref Context.AddEntry(id); + var assetId = new AssetId(id); var pool1 = Context.GetOrCreateComponentPool(); - pool1.Set(id, in component1); + pool1.Set(assetId, in component1); entry.Add(AssetComponentType.Id); var pool2 = Context.GetOrCreateComponentPool(); - pool2.Set(id, in component2); + pool2.Set(assetId, in component2); entry.Add(AssetComponentType.Id); - return new AssetConfigurator(id, this); + return new AssetConfigurator(assetId, this); } public AssetConfigurator CreateAsset( @@ -123,33 +128,34 @@ public AssetConfigurator CreateAsset( { EnsureNotDisposed(); ref var entry = ref Context.AddEntry(id); + var assetId = new AssetId(id); var pool1 = Context.GetOrCreateComponentPool(); - pool1.Set(id, in component1); + pool1.Set(assetId, in component1); entry.Add(AssetComponentType.Id); var pool2 = Context.GetOrCreateComponentPool(); - pool2.Set(id, in component2); + pool2.Set(assetId, in component2); entry.Add(AssetComponentType.Id); var pool3 = Context.GetOrCreateComponentPool(); - pool3.Set(id, in component3); + pool3.Set(assetId, in component3); entry.Add(AssetComponentType.Id); - return new AssetConfigurator(id, this); + return new AssetConfigurator(assetId, this); } public AssetConfigurator CreateAsset(string alias) { var id = GetId(alias); - return CreateAsset(id); + return CreateAsset(id.Value); } public AssetConfigurator CreateAsset(string alias, in T1 component1) where T1 : struct, IAssetComponent { var id = GetId(alias); - return CreateAsset(id, in component1); + return CreateAsset(id.Value, in component1); } public AssetConfigurator CreateAsset(string alias, in T1 component1, in T2 component2) @@ -157,7 +163,7 @@ public AssetConfigurator CreateAsset(string alias, in T1 component1, in where T2 : struct, IAssetComponent { var id = GetId(alias); - return CreateAsset(id, in component1, in component2); + return CreateAsset(id.Value, in component1, in component2); } public AssetConfigurator CreateAsset( @@ -168,7 +174,7 @@ public AssetConfigurator CreateAsset( where T3 : struct, IAssetComponent { var id = GetId(alias); - return CreateAsset(id, in component1, in component2, in component3); + return CreateAsset(id.Value, in component1, in component2, in component3); } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -178,37 +184,33 @@ public void EnsureNotDisposed() } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Asset GetAsset(uint assetId) => Context.GetAsset(assetId); + public Asset GetAsset(AssetId assetId) => Context.GetAsset(assetId); [MethodImpl(MethodImplOptions.AggressiveInlining)] public Asset GetAsset(string alias) => Context.GetAsset(GetId(alias)); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Asset GetAsset(uint assetId) - where T1 : struct, IAssetComponent => Context.GetAsset(assetId); - - public Asset GetAsset(string alias) - where T1 : struct, IAssetComponent => Context.GetAsset(GetId(alias)); - - public string GetAlias(uint assetId) + public string GetAlias(AssetId assetId) { // ReSharper disable once ForeachCanBePartlyConvertedToQueryUsingAnotherGetEnumerator foreach (var alias in _aliases) { - if (alias.Value == assetId) return alias.Key; + if (alias.Value == assetId.Value) return alias.Key; } AssetError.AliasNotFound(assetId); return string.Empty; } - public uint GetId(string assetAlias) + public AssetId GetId(string assetAlias) { - if (_aliases.TryGetValue(assetAlias, out var exists)) return exists; + if (_aliases.TryGetValue(assetAlias, out var exists)) + { + return new AssetId(exists); + } var id = GetNextAssetId(); _aliases.Add(assetAlias, id); - return id; + return new AssetId(id); } public AssetBlockBuilder RentBlockBuilder( @@ -228,10 +230,10 @@ public void ReturnBlockBuilder(AssetBlockBuilder b _blockBuilders.TryAdd(typeof(AssetBlockBuilder), builder); } - public ref T SetComponent(uint assetId, in T component) where T : struct, IAssetComponent + public ref T SetComponent(AssetId assetId, in T component) where T : struct, IAssetComponent { EnsureNotDisposed(); - ref var entry = ref Context.GetEntryExact(assetId); + ref var entry = ref Context.GetEntryExact(assetId.Value); var pool = Context.GetOrCreateComponentPool(); ref var reference = ref pool.Set(assetId, in component); @@ -246,7 +248,7 @@ private uint GetNextAssetId() EnsureNotDisposed(); var id = Interlocked.Increment(ref _nextId); - while (Context.ExistsAsset(id)) + while (Context.ExistsAsset(new AssetId(id))) { id = Interlocked.Increment(ref _nextId); } diff --git a/src/Hexecs/Assets/AssetContext.cs b/src/Hexecs/Assets/AssetContext.cs index 8f07617..e60fb9f 100644 --- a/src/Hexecs/Assets/AssetContext.cs +++ b/src/Hexecs/Assets/AssetContext.cs @@ -1,4 +1,5 @@ using Hexecs.Assets.Components; +using Hexecs.Assets.Delegates; using Hexecs.Worlds; namespace Hexecs.Assets; @@ -12,7 +13,7 @@ public sealed partial class AssetContext : IEnumerable, IDisposable public readonly World World; private readonly Dictionary _aliases; - + private bool _disposed; internal AssetContext(World world, int capacity = 256) @@ -32,20 +33,20 @@ public void Dispose() { if (_disposed) return; _disposed = true; - + ClearEntries(); - + _aliases.Clear(); } - + /// /// Проверяет существование ассета с указанным идентификатором. /// /// Идентификатор ассета для проверки /// Возвращаем true, если ассет существует; иначе false - public bool ExistsAsset(uint assetId) + public bool ExistsAsset(AssetId assetId) { - ref var entry = ref GetEntry(assetId); + ref var entry = ref GetEntry(assetId.Value); return !Unsafe.IsNullRef(ref entry); } @@ -55,7 +56,7 @@ public bool ExistsAsset(uint assetId) /// Идентификатор ассета /// Объект ассета /// Выбрасывается, если ассет не найден - public Asset GetAsset(uint assetId) + public Asset GetAsset(AssetId assetId) { if (!ExistsAsset(assetId)) AssetError.NotFound(assetId); return new Asset(this, assetId); @@ -71,7 +72,7 @@ public Asset GetAsset(string alias) { if (_aliases.TryGetValue(alias, out var assetId)) { - return GetAsset(assetId); + return GetAsset(new AssetId(assetId)); } AssetError.NotFound(alias); @@ -84,37 +85,21 @@ public Asset GetAsset(string alias) /// Тип компонента /// Ассет с таким компонентом не существует /// Первый ассет, у которого есть этот компонент. - public Asset GetAsset() + public AssetRef GetAssetRef() where T1 : struct, IAssetComponent { var pool = GetComponentPool(); if (pool != null) { - var firstId = pool.FirstId(); - if (firstId != Asset.EmptyId) + var first = pool.First(); + if (!first.IsEmpty) { - return new Asset(this, firstId); + return first; } } AssetError.NotFound(); - return Asset.Empty; - } - - /// - /// Получает типизированный ассет, содержащий указанный компонент. - /// - /// Тип компонента ассета - /// Идентификатор ассета - /// Типизированный объект ассета - /// Выбрасывается, если ассет не найден или не содержит нужный компонент - public Asset GetAsset(uint assetId) - where T1 : struct, IAssetComponent - { - var pool = GetComponentPool(); - if (pool == null || !pool.Has(assetId)) AssetError.ComponentNotFound(assetId); - - return new Asset(this, assetId); + return AssetRef.Empty; } /// @@ -124,16 +109,24 @@ public Asset GetAsset(uint assetId) /// Строковый алиас ассета /// Типизированный объект ассета /// Выбрасывается, если ассет не найден или не содержит нужный компонент - public Asset GetAsset(string alias) + public AssetRef GetAssetRef(string alias) where T1 : struct, IAssetComponent { - if (_aliases.TryGetValue(alias, out var assetId)) + if (_aliases.TryGetValue(alias, out var assetIdRaw)) { - return GetAsset(assetId); + var assetId = new AssetId(assetIdRaw); + + var pool = GetComponentPool(); + if (pool == null) AssetError.ComponentNotFound(assetId); + + ref var component = ref pool.Get(assetId); + if (Unsafe.IsNullRef(ref component)) AssetError.ComponentNotFound(assetId); + + return new AssetRef(this, assetId, ref component); } AssetError.NotFound(alias); - return Asset.Empty; + return AssetRef.Empty; } /// @@ -143,7 +136,7 @@ public Asset GetAsset(string alias) /// Идентификатор ассета /// Ссылка на компонент ассета /// Выбрасывается, если ассет не найден или не содержит нужный компонент - public AssetRef GetAssetRef(uint assetId) + public AssetRef GetAssetRef(AssetId assetId) where T1 : struct, IAssetComponent { var pool = GetComponentPool(); @@ -155,6 +148,23 @@ public AssetRef GetAssetRef(uint assetId) return new AssetRef(this, assetId, ref component); } + public AssetRef GetActorRef(AssetPredicate predicate) + where T1 : struct, IAssetComponent + { + var pool = GetComponentPool(); + if (pool != null) + { + var exists = pool.First(predicate); + if (!exists.IsEmpty) + { + return exists; + } + } + + AssetError.ApplicableNotFound(); + return AssetRef.Empty; + } + /// /// Формирует строковое описание ассета с перечислением его компонентов. /// @@ -162,27 +172,27 @@ public AssetRef GetAssetRef(uint assetId) /// Максимальное количество компонентов для отображения /// Строковое описание ассета [SkipLocalsInit] - public string GetDescription(uint assetId, int maxComponentDescription = 5) + public string GetDescription(AssetId assetId, int maxComponentDescription = 5) { var builder = new ValueStringBuilder(stackalloc char[512]); GetDescription(assetId, ref builder, maxComponentDescription); return builder.Flush(); } - public void GetDescription(uint assetId, ref ValueStringBuilder builder, int maxComponentDescription = 5) + public void GetDescription(AssetId assetId, ref ValueStringBuilder builder, int maxComponentDescription = 5) { - ref var entry = ref GetEntry(assetId); + ref var entry = ref GetEntry(assetId.Value); if (Unsafe.IsNullRef(ref entry)) { builder.Append('\''); builder.Append(StringUtils.EmptyValue); builder.Append('\''); - + return; } builder.Append("Id = "); - builder.Append(assetId); + builder.Append(assetId.Value); ref var components = ref entry; var componentsLength = components.Length; @@ -225,26 +235,8 @@ public void GetDescription(uint assetId, ref ValueStringBuilder builder, int max if (printMore) builder.Append(", ..."); builder.Append(')'); - } - - /// - /// Пытается получить типизированный ассет с указанным идентификатором. - /// - /// Тип компонента ассета - /// Идентификатор ассета - /// Результирующий типизированный ассет, если найден - /// Возвращает true, если ассет найден и содержит указанный компонент; иначе false - public bool TryGetAsset(uint assetId, out Asset asset) where T1 : struct, IAssetComponent - { - var pool = GetComponentPool(); - if (pool == null || !pool.Has(assetId)) - { - asset = Asset.Empty; - return false; - } - - asset = new Asset(this, assetId); - return true; + + pool.Return(buffer); } /// @@ -254,7 +246,7 @@ public bool TryGetAsset(uint assetId, out Asset asset) where T1 : struct /// Идентификатор ассета /// Результирующая ссылка на компонент ассета, если компонент найден /// Возвращает true, если ассет найден и содержит указанный компонент; иначе false - public bool TryGetAssetRef(uint assetId, out AssetRef asset) where T1 : struct, IAssetComponent + public bool TryGetAssetRef(AssetId assetId, out AssetRef asset) where T1 : struct, IAssetComponent { var pool = GetComponentPool(); if (pool == null) diff --git a/src/Hexecs/Assets/AssetError.cs b/src/Hexecs/Assets/AssetError.cs index c9aee92..60c98b4 100644 --- a/src/Hexecs/Assets/AssetError.cs +++ b/src/Hexecs/Assets/AssetError.cs @@ -11,9 +11,9 @@ internal static class AssetError /// /// Идентификатор ассета, для которого не найден псевдоним. [DoesNotReturn] - public static void AliasNotFound(uint assetId) + public static void AliasNotFound(AssetId assetId) { - throw new Exception($"Alias for asset {assetId} isn't found"); + throw new Exception($"Alias for asset '{assetId.Value}' isn't found"); } /// @@ -71,9 +71,9 @@ public static void NotFound(string alias) /// Тип компонента, который уже существует в ассете. /// Идентификатор ассета. [DoesNotReturn] - public static void ComponentAlreadyExists(uint assetId) + public static void ComponentAlreadyExists(AssetId assetId) { - throw new Exception($"Asset {assetId} already has component {TypeOf.GetTypeName()}"); + throw new Exception($"Asset '{assetId.Value}' already has component {TypeOf.GetTypeName()}"); } /// @@ -82,9 +82,9 @@ public static void ComponentAlreadyExists(uint assetId) /// Тип компонента, который отсутствует в ассете. /// Идентификатор ассета. [DoesNotReturn] - public static void ComponentNotFound(uint assetId) + public static void ComponentNotFound(AssetId assetId) { - throw new Exception($"Asset {assetId} don't have component {TypeOf.GetTypeName()}"); + throw new Exception($"Asset '{assetId.Value}' doesn't have component {TypeOf.GetTypeName()}"); } /// @@ -129,6 +129,16 @@ public static void NotFound() [DoesNotReturn] public static void NotFound(uint assetId) { - throw new Exception($"Asset with id {assetId} isn't found"); + throw new Exception($"Asset '{assetId}' isn't found"); + } + + /// + /// Генерирует исключение, когда ассет с указанным идентификатором не найден. + /// + /// Идентификатор ассета, который не найден. + [DoesNotReturn] + public static void NotFound(AssetId assetId) + { + throw new Exception($"Asset '{assetId.Value}' isn't found"); } } \ No newline at end of file diff --git a/src/Hexecs/Assets/AssetFilter1.DebugProxy.cs b/src/Hexecs/Assets/AssetFilter1.DebugProxy.cs index e3e8bc7..bd1b43b 100644 --- a/src/Hexecs/Assets/AssetFilter1.DebugProxy.cs +++ b/src/Hexecs/Assets/AssetFilter1.DebugProxy.cs @@ -8,7 +8,7 @@ private sealed class DebugProxy(AssetFilter filter) public IEnumerable Assets { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => filter._dictionary.Keys.Select(key => new Asset(filter.Context, key)); + get => filter._dictionary.Keys.Select(key => new Asset(filter.Context, new AssetId(key))); } } } \ No newline at end of file diff --git a/src/Hexecs/Assets/AssetFilter1.Enumerator.cs b/src/Hexecs/Assets/AssetFilter1.Enumerator.cs index 859ded5..7349d55 100644 --- a/src/Hexecs/Assets/AssetFilter1.Enumerator.cs +++ b/src/Hexecs/Assets/AssetFilter1.Enumerator.cs @@ -14,14 +14,14 @@ public readonly AssetRef Current get { var filter = _filter; - var (actorId, entry) = _enumerator.Current; + var (assetId, entry) = _enumerator.Current; return new AssetRef( filter.Context, - actorId, + new AssetId(assetId), ref filter._pool1.GetByIndex(entry.Index1)); } } - + public readonly int Length { [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -38,23 +38,10 @@ internal Enumerator(AssetFilter filter) _enumerator = filter._dictionary.GetEnumerator(); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool MoveNext() => _enumerator.MoveNext(); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Enumerator GetEnumerator() => this; - - public Asset[] ToArray() - { - var count = 0; - var assets = ArrayUtils.Create(_filter.Length); - foreach (var asset in this) - { - assets[count++] = asset; - } - - return assets; - } } } \ No newline at end of file diff --git a/src/Hexecs/Assets/AssetFilter1.cs b/src/Hexecs/Assets/AssetFilter1.cs index 90618a3..a832121 100644 --- a/src/Hexecs/Assets/AssetFilter1.cs +++ b/src/Hexecs/Assets/AssetFilter1.cs @@ -30,11 +30,11 @@ internal AssetFilter(AssetContext context, AssetConstraint? constraint = null) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Contains(uint assetId) => _dictionary.ContainsKey(assetId); + public bool Contains(AssetId assetId) => _dictionary.ContainsKey(assetId.Value); - public AssetRef Get(uint assetId) + public AssetRef Get(AssetId assetId) { - if (!_dictionary.TryGetValue(assetId, out var entry)) AssetError.NotFound(assetId); + if (!_dictionary.TryGetValue(assetId.Value, out var entry)) AssetError.NotFound(assetId); return new AssetRef( Context, @@ -55,7 +55,7 @@ public Asset[] ToArray() var index = 0; foreach (var assetId in dictionary.Keys) { - assets[index++] = new Asset(ctx, assetId); + assets[index++] = new Asset(ctx, new AssetId(assetId)); } return assets; @@ -71,7 +71,7 @@ private static FrozenDictionary Collect( var length = 0; var constraintFunction = constraint == null - ? DelegateUtils.AlwaysTrue + ? DelegateUtils.AlwaysTrue : constraint.Applicable; foreach (var asset in context) @@ -87,7 +87,7 @@ private static FrozenDictionary Collect( ref buffer, bufferPool, length, - new KeyValuePair(assetId, new Entry(index1))); + new KeyValuePair(assetId.Value, new Entry(index1))); length++; } diff --git a/src/Hexecs/Assets/AssetFilter2.DebugProxy.cs b/src/Hexecs/Assets/AssetFilter2.DebugProxy.cs index 40f9536..943a4f2 100644 --- a/src/Hexecs/Assets/AssetFilter2.DebugProxy.cs +++ b/src/Hexecs/Assets/AssetFilter2.DebugProxy.cs @@ -8,7 +8,7 @@ private sealed class DebugProxy(AssetFilter filter) public IEnumerable Assets { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => filter._dictionary.Keys.Select(key => new Asset(filter.Context, key)); + get => filter._dictionary.Keys.Select(key => new Asset(filter.Context, new AssetId(key))); } } } \ No newline at end of file diff --git a/src/Hexecs/Assets/AssetFilter2.Enumerator.cs b/src/Hexecs/Assets/AssetFilter2.Enumerator.cs index 77c6671..ac5b34b 100644 --- a/src/Hexecs/Assets/AssetFilter2.Enumerator.cs +++ b/src/Hexecs/Assets/AssetFilter2.Enumerator.cs @@ -14,10 +14,10 @@ public readonly AssetRef Current get { var filter = _filter; - var (actorId, entry) = _enumerator.Current; + var (assetId, entry) = _enumerator.Current; return new AssetRef( filter.Context, - actorId, + new AssetId(assetId), ref filter._pool1.GetByIndex(entry.Index1), ref filter._pool2.GetByIndex(entry.Index2)); } diff --git a/src/Hexecs/Assets/AssetFilter2.cs b/src/Hexecs/Assets/AssetFilter2.cs index 5d74b22..68808bb 100644 --- a/src/Hexecs/Assets/AssetFilter2.cs +++ b/src/Hexecs/Assets/AssetFilter2.cs @@ -33,11 +33,11 @@ internal AssetFilter(AssetContext context, AssetConstraint? constraint = null) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Contains(uint assetId) => _dictionary.ContainsKey(assetId); + public bool Contains(AssetId assetId) => _dictionary.ContainsKey(assetId.Value); - public AssetRef Get(uint assetId) + public AssetRef Get(AssetId assetId) { - if (!_dictionary.TryGetValue(assetId, out var entry)) AssetError.NotFound(assetId); + if (!_dictionary.TryGetValue(assetId.Value, out var entry)) AssetError.NotFound(assetId); return new AssetRef( Context, @@ -59,7 +59,7 @@ public Asset[] ToArray() var index = 0; foreach (var assetId in dictionary.Keys) { - assets[index++] = new Asset(ctx, assetId); + assets[index++] = new Asset(ctx, new AssetId(assetId)); } return assets; @@ -76,7 +76,7 @@ private static FrozenDictionary Collect( var length = 0; var constraintFunction = constraint == null - ? DelegateUtils.AlwaysTrue + ? DelegateUtils.AlwaysTrue : constraint.Applicable; foreach (var asset in context) @@ -95,7 +95,7 @@ private static FrozenDictionary Collect( ref buffer, bufferPool, length, - new KeyValuePair(assetId, new Entry(index1, index2))); + new KeyValuePair(assetId.Value, new Entry(index1, index2))); length++; } diff --git a/src/Hexecs/Assets/AssetFilter3.DebugProxy.cs b/src/Hexecs/Assets/AssetFilter3.DebugProxy.cs index 5f49585..074002b 100644 --- a/src/Hexecs/Assets/AssetFilter3.DebugProxy.cs +++ b/src/Hexecs/Assets/AssetFilter3.DebugProxy.cs @@ -8,7 +8,7 @@ private sealed class DebugProxy(AssetFilter filter) public IEnumerable Assets { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => filter._dictionary.Keys.Select(key => new Asset(filter.Context, key)); + get => filter._dictionary.Keys.Select(key => new Asset(filter.Context, new AssetId(key))); } } } \ No newline at end of file diff --git a/src/Hexecs/Assets/AssetFilter3.Enumerator.cs b/src/Hexecs/Assets/AssetFilter3.Enumerator.cs index 533d3b0..fd2dfd1 100644 --- a/src/Hexecs/Assets/AssetFilter3.Enumerator.cs +++ b/src/Hexecs/Assets/AssetFilter3.Enumerator.cs @@ -14,10 +14,10 @@ public readonly AssetRef Current get { var filter = _filter; - var (actorId, entry) = _enumerator.Current; + var (assetId, entry) = _enumerator.Current; return new AssetRef( filter.Context, - actorId, + new AssetId(assetId), ref filter._pool1.GetByIndex(entry.Index1), ref filter._pool2.GetByIndex(entry.Index2), ref filter._pool3.GetByIndex(entry.Index3)); diff --git a/src/Hexecs/Assets/AssetFilter3.cs b/src/Hexecs/Assets/AssetFilter3.cs index 279d0c9..9462d6b 100644 --- a/src/Hexecs/Assets/AssetFilter3.cs +++ b/src/Hexecs/Assets/AssetFilter3.cs @@ -36,11 +36,11 @@ internal AssetFilter(AssetContext context, AssetConstraint? constraint = null) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Contains(uint assetId) => _dictionary.ContainsKey(assetId); + public bool Contains(AssetId assetId) => _dictionary.ContainsKey(assetId.Value); - public AssetRef Get(uint assetId) + public AssetRef Get(AssetId assetId) { - if (!_dictionary.TryGetValue(assetId, out var entry)) AssetError.NotFound(assetId); + if (!_dictionary.TryGetValue(assetId.Value, out var entry)) AssetError.NotFound(assetId); return new AssetRef( Context, @@ -63,7 +63,7 @@ public Asset[] ToArray() var index = 0; foreach (var assetId in dictionary.Keys) { - assets[index++] = new Asset(ctx, assetId); + assets[index++] = new Asset(ctx, new AssetId(assetId)); } return assets; @@ -81,7 +81,7 @@ private static FrozenDictionary Collect( var length = 0; var constraintFunction = constraint == null - ? DelegateUtils.AlwaysTrue + ? DelegateUtils.AlwaysTrue : constraint.Applicable; foreach (var asset in context) @@ -103,7 +103,7 @@ private static FrozenDictionary Collect( ref buffer, bufferPool, length, - new KeyValuePair(assetId, new Entry(index1, index2, index3))); + new KeyValuePair(assetId.Value, new Entry(index1, index2, index3))); length++; } diff --git a/src/Hexecs/Assets/AssetId.cs b/src/Hexecs/Assets/AssetId.cs index a59d995..a578e08 100644 --- a/src/Hexecs/Assets/AssetId.cs +++ b/src/Hexecs/Assets/AssetId.cs @@ -12,13 +12,18 @@ namespace Hexecs.Assets; [DebuggerDisplay("{ToString()}")] public readonly struct AssetId : IEquatable { + /// + /// Константа, представляющая идентификатор пустого ассета. + /// + internal const uint EmptyId = 0; + /// /// Возвращает пустой идентификатор ассета. /// public static AssetId Empty { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => new(Asset.EmptyId); + get => new(EmptyId); } /// @@ -32,7 +37,16 @@ public static AssetId Empty public bool IsEmpty { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => Value == Asset.EmptyId; + get => Value == EmptyId; + } + + /// + /// Проверяет, является ли идентификатор НЕ пустым. + /// + public bool IsNotEmpty + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => Value != EmptyId; } /// @@ -45,14 +59,14 @@ internal AssetId(uint value) Value = value; } - /// - /// Возвращает строковое представление идентификатора ассета. - /// - public override string ToString() => AssetMarshal.TryGetDebugContext(out var context) - ? context.GetDescription(Value) - : IsEmpty - ? StringUtils.EmptyValue - : Value.ToString(); + public override string ToString() + { + return AssetMarshal.TryGetDebugContext(out var context) + ? context.GetDescription(this) + : IsEmpty + ? StringUtils.EmptyValue + : Value.ToString(); + } /// /// Преобразует идентификатор в , используя указанный контекст. @@ -60,69 +74,44 @@ public override string ToString() => AssetMarshal.TryGetDebugContext(out var con /// Контекст ассетов /// Ассет [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Asset Unwrap(AssetContext context) => context.GetAsset(Value); - - /// - /// Преобразует идентификатор в с указанным компонентом. - /// - /// Тип компонента ассета - /// Контекст ассетов - /// Типизированный ассет - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Asset Unwrap(AssetContext context) where T : struct, IAssetComponent => context.GetAsset(Value); + public Asset Unwrap(AssetContext context) + { + return context.GetAsset(this); + } #region Equality - /// - /// Проверяет равенство с другим идентификатором ассета. - /// - /// Идентификатор ассета для сравнения - /// Возвращает true, если идентификаторы равны; иначе false [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(AssetId other) => Value == other.Value; - /// - /// Проверяет равенство с другим объектом. - /// - /// Объект для сравнения - /// Возвращает true, если объект является идентификатором ассета и равен текущему; иначе false public override bool Equals(object? obj) => obj is AssetId other && Equals(other); - /// - /// Вычисляет хеш-код идентификатора ассета. - /// public override int GetHashCode() => HashCode.Combine(Value); - /// - /// Оператор равенства для идентификаторов ассетов. - /// - /// Первый идентификатор - /// Второй идентификатор - /// Возвращает true, если идентификаторы равны; иначе false [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(in AssetId left, in AssetId right) => left.Equals(right); + public static bool operator ==(in AssetId left, in AssetId right) => left.Value == right.Value; - /// - /// Оператор неравенства для идентификаторов ассетов. - /// - /// Первый идентификатор - /// Второй идентификатор - /// Возвращает true, если идентификаторы не равны; иначе false [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(in AssetId left, in AssetId right) => !left.Equals(right); + public static bool operator !=(in AssetId left, in AssetId right) => left.Value != right.Value; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator <(in AssetId left, in AssetId right) => left.Value < right.Value; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator >(in AssetId left, in AssetId right) => left.Value > right.Value; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator <=(in AssetId left, in AssetId right) => left.Value <= right.Value; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator >=(in AssetId left, in AssetId right) => left.Value >= right.Value; #endregion #region Implicit - /// - /// Неявное преобразование идентификатора ассета в булево значение. - /// Возвращает true, если идентификатор не пустой. - /// - /// Идентификатор ассета - /// Возвращает true, если идентификатор не пустой; иначе false [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator bool(in AssetId asset) => !asset.IsEmpty; + public static implicit operator bool(in AssetId asset) => asset.IsNotEmpty; #endregion } \ No newline at end of file diff --git a/src/Hexecs/Assets/AssetId1.cs b/src/Hexecs/Assets/AssetId1.cs deleted file mode 100644 index b2460f9..0000000 --- a/src/Hexecs/Assets/AssetId1.cs +++ /dev/null @@ -1,118 +0,0 @@ -using Hexecs.Assets.Development; - -namespace Hexecs.Assets; - -/// -/// Типизированный идентификатор ассета, гарантирующий наличие указанного компонента. -/// -/// Тип компонента ассета -[DebuggerTypeProxy(typeof(AssetIdDebugProxy<>))] -[DebuggerDisplay("{ToString()}")] -public readonly struct AssetId : IEquatable> - where T1 : struct, IAssetComponent -{ - /// - /// Возвращает пустой типизированный идентификатор ассета. - /// - public static AssetId Empty - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => new(Asset.EmptyId); - } - - /// - /// Числовой идентификатор ассета. - /// - public readonly uint Value; - - /// - /// Создает новый типизированный идентификатор ассета с указанным числовым значением. - /// - /// Числовое значение идентификатора - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal AssetId(uint value) - { - Value = value; - } - - /// - /// Проверяет, является ли идентификатор пустым. - /// - public bool IsEmpty - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => Value == Asset.EmptyId; - } - - /// - /// Возвращает строковое представление типизированного идентификатора ассета. - /// - public override string ToString() => AssetMarshal.TryGetDebugContext(out var context) - ? context.GetDescription(Value) - : IsEmpty - ? StringUtils.EmptyValue - : Value.ToString(); - - /// - /// Преобразует типизированный идентификатор в , используя указанный контекст. - /// - /// Контекст ассетов - /// Типизированный ассет - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Asset Unwrap(AssetContext context) => context.GetAsset(Value); - - #region Equality - - /// - /// Проверяет равенство с другим типизированным идентификатором ассета. - /// - /// Типизированный идентификатор ассета для сравнения - /// Возвращает true, если идентификаторы равны; иначе false - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(AssetId other) => Value == other.Value; - - /// - /// Проверяет равенство с другим объектом. - /// - /// Объект для сравнения - /// Возвращает true, если объект является типизированным идентификатором ассета и равен текущему; иначе false - public override bool Equals(object? obj) => obj is AssetId other && Equals(other); - - /// - /// Вычисляет хеш-код типизированного идентификатора ассета. - /// - public override int GetHashCode() => HashCode.Combine(Value); - - /// - /// Оператор равенства для типизированных идентификаторов ассетов. - /// - /// Первый идентификатор - /// Второй идентификатор - /// Возвращает true, если идентификаторы равны; иначе false - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(in AssetId left, in AssetId right) => left.Equals(right); - - /// - /// Оператор неравенства для типизированных идентификаторов ассетов. - /// - /// Первый идентификатор - /// Второй идентификатор - /// Возвращает true, если идентификаторы не равны; иначе false - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(in AssetId left, in AssetId right) => !left.Equals(right); - - #endregion - - #region Implicit - - /// - /// Неявное преобразование типизированного идентификатора ассета в булево значение. - /// Возвращает true, если идентификатор не пустой. - /// - /// Типизированный идентификатор ассета - /// Возвращает true, если идентификатор не пустой; иначе false - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator bool(in AssetId asset) => !asset.IsEmpty; - - #endregion -} \ No newline at end of file diff --git a/src/Hexecs/Assets/AssetRef1.cs b/src/Hexecs/Assets/AssetRef1.cs index f2e10c7..fa870b6 100644 --- a/src/Hexecs/Assets/AssetRef1.cs +++ b/src/Hexecs/Assets/AssetRef1.cs @@ -11,7 +11,7 @@ namespace Hexecs.Assets; /// Тип компонента ассета, должен быть структурой и реализовывать интерфейс . [DebuggerDisplay("{ToString()}")] [DebuggerTypeProxy(typeof(AssetRefDebugProxy<>))] -public readonly ref struct AssetRef +public readonly ref struct AssetRef : IEquatable where T1 : struct, IAssetComponent { /// @@ -20,7 +20,7 @@ public readonly ref struct AssetRef public static AssetRef Empty { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => new(null!, Asset.EmptyId, ref Unsafe.NullRef()); + get => new(null!, AssetId.Empty, ref Unsafe.NullRef()); } /// @@ -39,12 +39,12 @@ public bool IsEmpty } public readonly AssetContext Context; - public readonly uint Id; + public readonly AssetId Id; private readonly ref T1 _component1; [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal AssetRef(AssetContext context, uint id, ref T1 component1) + internal AssetRef(AssetContext context, AssetId id, ref T1 component1) { Context = context; Id = id; @@ -53,20 +53,22 @@ internal AssetRef(AssetContext context, uint id, ref T1 component1) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Asset As() where T : struct, IAssetComponent => Context.GetAsset(Id); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public AssetRef AsRef() where T : struct, IAssetComponent => Context.GetAssetRef(Id); + public AssetRef AsRef() + where T : struct, IAssetComponent + { + return Context.GetAssetRef(Id); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ref readonly T Get() where T : struct, IAssetComponent => ref Context.GetComponent(Id); + public ref readonly T Get() + where T : struct, IAssetComponent + { + return ref Context.GetComponent(Id); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Has() where T : struct, IAssetComponent => Context.HasComponent(Id); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Is(out Asset asset) where T : struct, IAssetComponent => Context.TryGetAsset(Id, out asset); - [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool IsRef(out AssetRef asset) where T : struct, IAssetComponent { @@ -79,12 +81,14 @@ public override string ToString() => Context == null #region Equality + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Equals(Asset other) => Id == other.Id && ReferenceEquals(Context, other.Context); + [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(AssetRef other) => Id == other.Id && ReferenceEquals(Context, other.Context); public override bool Equals(object? obj) => obj switch { - Asset other => other.Id == Id, Asset asset => asset.IsRef(out var expected) && Equals(expected), _ => false }; @@ -105,16 +109,10 @@ public override string ToString() => Context == null public static implicit operator bool(in AssetRef asset) => !asset.IsEmpty; [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator AssetId(in AssetRef asset) => new(asset.Id); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator AssetId(in AssetRef asset) => new(asset.Id); + public static implicit operator AssetId(in AssetRef asset) => asset.Id; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator Asset(in AssetRef asset) => new(asset.Context, asset.Id); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator Asset(in AssetRef asset) => new(asset.Context, asset.Id); - #endregion } \ No newline at end of file diff --git a/src/Hexecs/Assets/AssetRef2.cs b/src/Hexecs/Assets/AssetRef2.cs index 02283c7..21c8d1d 100644 --- a/src/Hexecs/Assets/AssetRef2.cs +++ b/src/Hexecs/Assets/AssetRef2.cs @@ -12,7 +12,7 @@ namespace Hexecs.Assets; /// Тип компонента ассета, должен быть структурой и реализовывать интерфейс . [DebuggerDisplay("{ToString()}")] [DebuggerTypeProxy(typeof(AssetRefDebugProxy<,>))] -public readonly ref struct AssetRef +public readonly ref struct AssetRef : IEquatable where T1 : struct, IAssetComponent where T2 : struct, IAssetComponent { @@ -22,7 +22,7 @@ public readonly ref struct AssetRef public static AssetRef Empty { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => new(null!, Asset.EmptyId, ref Unsafe.NullRef(), ref Unsafe.NullRef()); + get => new(null!, AssetId.Empty, ref Unsafe.NullRef(), ref Unsafe.NullRef()); } /// @@ -50,13 +50,13 @@ public bool IsEmpty } public readonly AssetContext Context; - public readonly uint Id; + public readonly AssetId Id; private readonly ref T1 _component1; private readonly ref T2 _component2; [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal AssetRef(AssetContext context, uint id, ref T1 component1, ref T2 component2) + internal AssetRef(AssetContext context, AssetId id, ref T1 component1, ref T2 component2) { Context = context; Id = id; @@ -66,32 +66,45 @@ internal AssetRef(AssetContext context, uint id, ref T1 component1, ref T2 compo } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Asset As() where T : struct, IAssetComponent => Context.GetAsset(Id); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public AssetRef AsRef() where T : struct, IAssetComponent => Context.GetAssetRef(Id); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ref readonly T Get() where T : struct, IAssetComponent => ref Context.GetComponent(Id); + public AssetRef AsRef() + where T : struct, IAssetComponent + { + return Context.GetAssetRef(Id); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Has() where T : struct, IAssetComponent => Context.HasComponent(Id); + public ref readonly T Get() + where T : struct, IAssetComponent + { + return ref Context.GetComponent(Id); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Is(out Asset asset) where T : struct, IAssetComponent => Context.TryGetAsset(Id, out asset); + public bool Has() + where T : struct, IAssetComponent + { + return Context.HasComponent(Id); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool IsRef(out AssetRef asset) where T : struct, IAssetComponent + public bool IsRef(out AssetRef asset) + where T : struct, IAssetComponent { return Context.TryGetAssetRef(Id, out asset); } - public override string ToString() => Context == null - ? StringUtils.EmptyValue - : Context.GetDescription(Id); + public override string ToString() + { + return Context == null + ? StringUtils.EmptyValue + : Context.GetDescription(Id); + } #region Equality + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Equals(Asset other) => Id == other.Id && ReferenceEquals(Context, other.Context); + [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(AssetRef other) => Id == other.Id && ReferenceEquals(Context, other.Context); @@ -113,23 +126,11 @@ public override string ToString() => Context == null public static implicit operator bool(in AssetRef asset) => !asset.IsEmpty; [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator AssetId(in AssetRef asset) => new(asset.Id); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator AssetId(in AssetRef asset) => new(asset.Id); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator AssetId(in AssetRef asset) => new(asset.Id); + public static implicit operator AssetId(in AssetRef asset) => asset.Id; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator Asset(in AssetRef asset) => new(asset.Context, asset.Id); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator Asset(in AssetRef asset) => new(asset.Context, asset.Id); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator Asset(in AssetRef asset) => new(asset.Context, asset.Id); - [MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator AssetRef(in AssetRef actor) => new( actor.Context, diff --git a/src/Hexecs/Assets/AssetRef3.cs b/src/Hexecs/Assets/AssetRef3.cs index d0672b8..ecfa2fd 100644 --- a/src/Hexecs/Assets/AssetRef3.cs +++ b/src/Hexecs/Assets/AssetRef3.cs @@ -13,7 +13,7 @@ namespace Hexecs.Assets; /// Тип компонента ассета, должен быть структурой и реализовывать интерфейс . [DebuggerDisplay("{ToString()}")] [DebuggerTypeProxy(typeof(AssetRefDebugProxy<,,>))] -public readonly ref struct AssetRef +public readonly ref struct AssetRef : IEquatable where T1 : struct, IAssetComponent where T2 : struct, IAssetComponent where T3 : struct, IAssetComponent @@ -24,7 +24,7 @@ public readonly ref struct AssetRef public static AssetRef Empty { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => new(null!, Asset.EmptyId, ref Unsafe.NullRef(), ref Unsafe.NullRef(), ref Unsafe.NullRef()); + get => new(null!, AssetId.Empty, ref Unsafe.NullRef(), ref Unsafe.NullRef(), ref Unsafe.NullRef()); } /// @@ -61,14 +61,14 @@ public bool IsEmpty } public readonly AssetContext Context; - public readonly uint Id; + public readonly AssetId Id; private readonly ref T1 _component1; private readonly ref T2 _component2; private readonly ref T3 _component3; [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal AssetRef(AssetContext context, uint id, ref T1 component1, ref T2 component2, ref T3 component3) + internal AssetRef(AssetContext context, AssetId id, ref T1 component1, ref T2 component2, ref T3 component3) { Context = context; Id = id; @@ -78,9 +78,6 @@ internal AssetRef(AssetContext context, uint id, ref T1 component1, ref T2 compo _component3 = ref component3; } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Asset As() where T : struct, IAssetComponent => Context.GetAsset(Id); - [MethodImpl(MethodImplOptions.AggressiveInlining)] public AssetRef AsRef() where T : struct, IAssetComponent => Context.GetAssetRef(Id); @@ -90,9 +87,6 @@ internal AssetRef(AssetContext context, uint id, ref T1 component1, ref T2 compo [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Has() where T : struct, IAssetComponent => Context.HasComponent(Id); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Is(out Asset asset) where T : struct, IAssetComponent => Context.TryGetAsset(Id, out asset); - [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool IsRef(out AssetRef asset) where T : struct, IAssetComponent { @@ -105,6 +99,9 @@ public override string ToString() => Context == null #region Equality + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Equals(Asset other) => Id == other.Id && ReferenceEquals(Context, other.Context); + [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(AssetRef other) => Id == other.Id && ReferenceEquals(Context, other.Context); @@ -126,29 +123,11 @@ public override string ToString() => Context == null public static implicit operator bool(in AssetRef asset) => !asset.IsEmpty; [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator AssetId(in AssetRef asset) => new(asset.Id); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator AssetId(in AssetRef asset) => new(asset.Id); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator AssetId(in AssetRef asset) => new(asset.Id); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator AssetId(in AssetRef asset) => new(asset.Id); + public static implicit operator AssetId(in AssetRef asset) => asset.Id; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator Asset(in AssetRef asset) => new(asset.Context, asset.Id); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator Asset(in AssetRef asset) => new(asset.Context, asset.Id); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator Asset(in AssetRef asset) => new(asset.Context, asset.Id); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator Asset(in AssetRef asset) => new(asset.Context, asset.Id); - [MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator AssetRef(in AssetRef actor) => new( actor.Context, diff --git a/src/Hexecs/Assets/Components/AssetComponentPool.cs b/src/Hexecs/Assets/Components/AssetComponentPool.cs index 873144f..6ccf821 100644 --- a/src/Hexecs/Assets/Components/AssetComponentPool.cs +++ b/src/Hexecs/Assets/Components/AssetComponentPool.cs @@ -1,11 +1,11 @@ +using Hexecs.Assets.Delegates; + namespace Hexecs.Assets.Components; [DebuggerDisplay("{Length}")] internal sealed class AssetComponentPool : IAssetComponentPool where T : struct, IAssetComponent { - //private const int EmptySlot = 0; - private const int PageBits = 12; private const int PageSize = 1 << PageBits; // 4096 private const int PageMask = PageSize - 1; @@ -40,23 +40,46 @@ public AssetComponentPool(AssetContext context, int capacity = 8) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public uint FirstId() => _count > 0 - ? _dense[0] - : Asset.EmptyId; + public AssetRef First() + { + return _count > 0 + ? new AssetRef(Context, new AssetId(_dense[0]), ref _values[0]) + : AssetRef.Empty; + } + + public AssetRef First(AssetPredicate predicate) + { + var count = _count; + var keys = _dense; + var values = _values; + var context = Context; + + for (var i = 0; i < count; i++) + { + var actor = new AssetRef(context, new AssetId(keys[i]), ref values[i]); + if (predicate(in actor)) + { + return actor; + } + } - public ref T Get(uint assetId) + return AssetRef.Empty; + } + + public ref T Get(AssetId assetId) { - var pageIndex = (int)(assetId >> PageBits); + var assetIdRaw = assetId.Value; + var pageIndex = (int)(assetIdRaw >> PageBits); if ((uint)pageIndex < (uint)_sparsePages.Length) { var page = _sparsePages[pageIndex]; if (page != null) { - var denseIndexPlusOne = page[assetId & PageMask]; + var denseIndexPlusOne = page[assetIdRaw & PageMask]; if (denseIndexPlusOne != 0) { var index = (int)denseIndexPlusOne - 1; - if (_dense[index] == assetId) + if (_dense[index] == assetIdRaw) { return ref _values[index]; } @@ -71,9 +94,10 @@ public ref T Get(uint assetId) public ref T GetByIndex(int index) => ref _values[index]; [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Has(uint assetId) + public bool Has(AssetId assetId) { - var pageIndex = (int)(assetId >> PageBits); + var assetIdRaw = assetId.Value; + var pageIndex = (int)(assetIdRaw >> PageBits); var pages = _sparsePages; if ((uint)pageIndex < (uint)pages.Length) @@ -81,17 +105,18 @@ public bool Has(uint assetId) var page = pages[pageIndex]; if (page != null) { - var denseIndexPlusOne = page[assetId & PageMask]; - return denseIndexPlusOne != 0 && _dense[denseIndexPlusOne - 1] == assetId; + var denseIndexPlusOne = page[assetIdRaw & PageMask]; + return denseIndexPlusOne != 0 && _dense[denseIndexPlusOne - 1] == assetIdRaw; } } return false; } - public ref T Set(uint assetId, in T component) + public ref T Set(AssetId assetId, in T component) { - var pageIndex = (int)(assetId >> PageBits); + var assetIdRaw = assetId.Value; + var pageIndex = (int)(assetIdRaw >> PageBits); var pages = _sparsePages; // Максимально компактная проверка на готовность страницы и места @@ -100,12 +125,12 @@ public ref T Set(uint assetId, in T component) var page = pages[pageIndex]; if (page != null && (uint)_count < (uint)_dense.Length) { - ref var slot = ref page[assetId & PageMask]; + ref var slot = ref page[assetIdRaw & PageMask]; if (slot == 0) // Чистая вставка (самый частый случай в ECS) { var idx = (uint)_count; slot = idx + 1; - _dense[idx] = assetId; + _dense[idx] = assetIdRaw; ref var internalRef = ref _values[idx]; _values[idx] = component; @@ -115,7 +140,7 @@ public ref T Set(uint assetId, in T component) } // Если не 0, проверяем на дубликат (чуть медленнее) - if (_dense[slot - 1] == assetId) + if (_dense[slot - 1] == assetIdRaw) { AssetError.ComponentAlreadyExists(assetId); } @@ -125,19 +150,20 @@ public ref T Set(uint assetId, in T component) return ref SetSlow(assetId, in component); } - public ref T TryGet(uint assetId) + public ref T TryGet(AssetId assetId) { - var pageIndex = (int)(assetId >> PageBits); + var assetIdRaw = assetId.Value; + var pageIndex = (int)(assetIdRaw >> PageBits); if ((uint)pageIndex < (uint)_sparsePages.Length) { var page = _sparsePages[pageIndex]; if (page != null) { - var denseIndexPlusOne = page[assetId & PageMask]; + var denseIndexPlusOne = page[assetIdRaw & PageMask]; if (denseIndexPlusOne != 0) { var index = (int)denseIndexPlusOne - 1; - if (_dense[index] == assetId) + if (_dense[index] == assetIdRaw) { return ref _values[index]; } @@ -148,9 +174,11 @@ public ref T TryGet(uint assetId) return ref Unsafe.NullRef(); } - public int TryGetIndex(uint assetId) + public int TryGetIndex(AssetId assetId) { - var pageIndex = (int)(assetId >> PageBits); + var assetIdRaw = assetId.Value; + + var pageIndex = (int)(assetIdRaw >> PageBits); var pages = _sparsePages; if ((uint)pageIndex < (uint)pages.Length) @@ -158,11 +186,11 @@ public int TryGetIndex(uint assetId) var page = pages[pageIndex]; if (page != null) { - var slot = page[assetId & PageMask]; + var slot = page[assetIdRaw & PageMask]; if (slot != 0) { var denseIndex = (int)slot - 1; - if (_dense[denseIndex] == assetId) + if (_dense[denseIndex] == assetIdRaw) { return denseIndex; } @@ -193,10 +221,12 @@ private void EnsurePageArraySize(int pageIndex) } [MethodImpl(MethodImplOptions.NoInlining)] - private ref T SetSlow(uint assetId, in T component) + private ref T SetSlow(AssetId assetId, in T component) { + var assetIdRaw = assetId.Value; + EnsureDenseCapacity(); - var pageIndex = (int)(assetId >> PageBits); + var pageIndex = (int)(assetIdRaw >> PageBits); EnsurePageArraySize(pageIndex); ref var page = ref _sparsePages[pageIndex]; @@ -206,10 +236,10 @@ private ref T SetSlow(uint assetId, in T component) Array.Clear(page, 0, page.Length); } - ref var denseIndexPlusOne = ref page[assetId & PageMask]; + ref var denseIndexPlusOne = ref page[assetIdRaw & PageMask]; if (denseIndexPlusOne != 0) { - if (_dense[denseIndexPlusOne - 1] == assetId) + if (_dense[denseIndexPlusOne - 1] == assetIdRaw) { AssetError.ComponentAlreadyExists(assetId); } @@ -217,7 +247,7 @@ private ref T SetSlow(uint assetId, in T component) var denseIndex = (uint)_count; denseIndexPlusOne = denseIndex + 1; - _dense[denseIndex] = assetId; + _dense[denseIndex] = assetIdRaw; ref var internalRef = ref _values[denseIndex]; internalRef = component; @@ -233,5 +263,5 @@ AssetContext IAssetComponentPool.Context get => Context; } - IAssetComponent IAssetComponentPool.Get(uint assetId) => Get(assetId); + IAssetComponent IAssetComponentPool.Get(AssetId assetId) => Get(assetId); } \ No newline at end of file diff --git a/src/Hexecs/Assets/Components/IAssetComponentPool.cs b/src/Hexecs/Assets/Components/IAssetComponentPool.cs index ab571fc..0d3478d 100644 --- a/src/Hexecs/Assets/Components/IAssetComponentPool.cs +++ b/src/Hexecs/Assets/Components/IAssetComponentPool.cs @@ -5,10 +5,10 @@ public interface IAssetComponentPool AssetContext Context { get; } int Length { get; } - + ushort Id { get; } - IAssetComponent Get(uint assetId); + IAssetComponent Get(AssetId assetId); - bool Has(uint assetId); + bool Has(AssetId assetId); } \ No newline at end of file diff --git a/src/Hexecs/Assets/Delegates/AssetPredicate.cs b/src/Hexecs/Assets/Delegates/AssetPredicate.cs new file mode 100644 index 0000000..4e481c5 --- /dev/null +++ b/src/Hexecs/Assets/Delegates/AssetPredicate.cs @@ -0,0 +1,15 @@ +using Hexecs.Actors; + +namespace Hexecs.Assets.Delegates; + +public delegate bool AssetPredicate(in AssetRef component) + where T1 : struct, IAssetComponent; + +public delegate bool AssetPredicate(in AssetRef component) + where T1 : struct, IAssetComponent + where T2 : struct, IAssetComponent; + +public delegate bool AssetPredicate(in AssetRef component) + where T1 : struct, IAssetComponent + where T2 : struct, IAssetComponent + where T3 : struct, IAssetComponent; \ No newline at end of file diff --git a/src/Hexecs/Assets/Development/ActorIdDebugProxy.cs b/src/Hexecs/Assets/Development/ActorIdDebugProxy.cs deleted file mode 100644 index 529bce0..0000000 --- a/src/Hexecs/Assets/Development/ActorIdDebugProxy.cs +++ /dev/null @@ -1,30 +0,0 @@ -using Hexecs.Actors; - -namespace Hexecs.Assets.Development; - -[ExcludeFromCodeCoverage] -[SuppressMessage("ReSharper", "NotAccessedField.Global")] -internal sealed class AssetIdDebugProxy(AssetId assetId) -{ - public IAssetComponent[] Components => _components ??= assetId.IsEmpty - ? [] - : AssetMarshal.TryGetDebugContext(out var assetContext) - ? assetContext.Components(assetId.Value).ToArray() - : []; - - private IAssetComponent[]? _components; -} - -[ExcludeFromCodeCoverage] -[SuppressMessage("ReSharper", "NotAccessedField.Global")] -internal sealed class AssetIdDebugProxy(ActorId actorId) - where T1 : struct, IActorComponent -{ - public IAssetComponent[] Components => _components ??= actorId.IsEmpty - ? [] - : AssetMarshal.TryGetDebugContext(out var assetContext) - ? assetContext.Components(actorId.Value).ToArray() - : []; - - private IAssetComponent[]? _components; -} \ No newline at end of file diff --git a/src/Hexecs/Assets/Development/AssetDebugProxy.cs b/src/Hexecs/Assets/Development/AssetDebugProxy.cs index 17238d7..9950843 100644 --- a/src/Hexecs/Assets/Development/AssetDebugProxy.cs +++ b/src/Hexecs/Assets/Development/AssetDebugProxy.cs @@ -15,23 +15,4 @@ public AssetDebugProxy(Asset asset) { _asset = asset; } -} - -[ExcludeFromCodeCoverage] -[SuppressMessage("ReSharper", "NotAccessedField.Global")] -internal sealed class AssetDebugProxy(Asset asset) - where T1 : struct, IAssetComponent -{ - public T1 Component1 - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => asset.Context.GetComponent(asset.Id); - } - - [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] - public IAssetComponent[] Components => _components ??= asset.IsEmpty - ? [] - : asset.Context.Components(asset.Id).ToArray(); - - private IAssetComponent[]? _components; } \ No newline at end of file diff --git a/src/Hexecs/Assets/Development/AssetIdDebugProxy.cs b/src/Hexecs/Assets/Development/AssetIdDebugProxy.cs new file mode 100644 index 0000000..b8ed624 --- /dev/null +++ b/src/Hexecs/Assets/Development/AssetIdDebugProxy.cs @@ -0,0 +1,14 @@ +namespace Hexecs.Assets.Development; + +[ExcludeFromCodeCoverage] +[SuppressMessage("ReSharper", "NotAccessedField.Global")] +internal sealed class AssetIdDebugProxy(AssetId assetId) +{ + public IAssetComponent[] Components => _components ??= assetId.IsEmpty + ? [] + : AssetMarshal.TryGetDebugContext(out var assetContext) + ? assetContext.Components(assetId).ToArray() + : []; + + private IAssetComponent[]? _components; +} \ No newline at end of file diff --git a/src/Hexecs/Assets/Development/AssetRefDebugProxy.cs b/src/Hexecs/Assets/Development/AssetRefDebugProxy.cs index a740f19..831b8cd 100644 --- a/src/Hexecs/Assets/Development/AssetRefDebugProxy.cs +++ b/src/Hexecs/Assets/Development/AssetRefDebugProxy.cs @@ -15,7 +15,7 @@ public T1 Component1 ? _context.Components(_assetId).ToArray() : []; - private readonly uint _assetId = asset.Id; + private readonly AssetId _assetId = asset.Id; private readonly AssetContext _context = asset.Context; private IAssetComponent[]? _components; } @@ -42,7 +42,7 @@ public T2 Component2 ? _context.Components(_assetId).ToArray() : []; - private readonly uint _assetId = asset.Id; + private readonly AssetId _assetId = asset.Id; private readonly AssetContext _context = asset.Context; private IAssetComponent[]? _components; } @@ -76,7 +76,7 @@ public T3 Component3 ? _context.Components(_assetId).ToArray() : []; - private readonly uint _assetId = asset.Id; + private readonly AssetId _assetId = asset.Id; private readonly AssetContext _context = asset.Context; private IAssetComponent[]? _components; } \ No newline at end of file diff --git a/src/Hexecs/Assets/IAssetFilter.cs b/src/Hexecs/Assets/IAssetFilter.cs index a810092..44eeba5 100644 --- a/src/Hexecs/Assets/IAssetFilter.cs +++ b/src/Hexecs/Assets/IAssetFilter.cs @@ -20,5 +20,5 @@ public interface IAssetFilter /// int Length { get; } - bool Contains(uint actorId); + bool Contains(AssetId assetId); } \ No newline at end of file diff --git a/src/Hexecs/Assets/Loggers/AssetIdLogWriter.cs b/src/Hexecs/Assets/Loggers/AssetIdLogWriter.cs index 1b56cb3..623cd81 100644 --- a/src/Hexecs/Assets/Loggers/AssetIdLogWriter.cs +++ b/src/Hexecs/Assets/Loggers/AssetIdLogWriter.cs @@ -2,31 +2,14 @@ namespace Hexecs.Assets.Loggers; -internal sealed class AssetIdLogWriter : ILogValueWriter, ILogValueWriterFactory +internal sealed class AssetIdLogWriter : ILogValueWriter { public static readonly AssetIdLogWriter Instance = new(); - public static ILogValueWriterFactory Factory => Instance; private AssetIdLogWriter() { } - public bool TryCreateWriter(out ILogValueWriter writer) - { - var type = typeof(T); - if (type is { IsValueType: true, IsGenericType: true }) - { - if (type.GetGenericTypeDefinition() == typeof(AssetId<>)) - { - writer = new LikeAssetIdStruct(); - return true; - } - } - - writer = null!; - return false; - } - public void Write(ref ValueStringBuilder stringBuilder, AssetId asset) { if (asset.IsEmpty) @@ -37,7 +20,7 @@ public void Write(ref ValueStringBuilder stringBuilder, AssetId asset) { if (AssetMarshal.TryGetDebugContext(out var context)) { - context.GetDescription(asset.Value, ref stringBuilder); + context.GetDescription(asset, ref stringBuilder); } else { @@ -45,13 +28,4 @@ public void Write(ref ValueStringBuilder stringBuilder, AssetId asset) } } } - - private sealed class LikeAssetIdStruct : ILogValueWriter - { - public void Write(ref ValueStringBuilder stringBuilder, T arg) - { - ref readonly var asset = ref Unsafe.As(ref arg); - Instance.Write(ref stringBuilder, asset); - } - } } \ No newline at end of file diff --git a/src/Hexecs/Assets/Loggers/AssetLogWriter.cs b/src/Hexecs/Assets/Loggers/AssetLogWriter.cs index 3ac162e..84f5256 100644 --- a/src/Hexecs/Assets/Loggers/AssetLogWriter.cs +++ b/src/Hexecs/Assets/Loggers/AssetLogWriter.cs @@ -2,31 +2,14 @@ namespace Hexecs.Assets.Loggers; -internal sealed class AssetLogWriter : ILogValueWriter, ILogValueWriterFactory +internal sealed class AssetLogWriter : ILogValueWriter { public static readonly AssetLogWriter Instance = new(); - public static ILogValueWriterFactory Factory => Instance; private AssetLogWriter() { } - - public bool TryCreateWriter(out ILogValueWriter writer) - { - var type = typeof(T); - if (type is { IsValueType: true, IsGenericType: true }) - { - if (type.GetGenericTypeDefinition() == typeof(Asset<>)) - { - writer = new LikeAssetStruct(); - return true; - } - } - writer = null!; - return false; - } - public void Write(ref ValueStringBuilder stringBuilder, Asset asset) { if (asset.IsEmpty) @@ -38,13 +21,4 @@ public void Write(ref ValueStringBuilder stringBuilder, Asset asset) asset.Context.GetDescription(asset.Id, ref stringBuilder); } } - - private sealed class LikeAssetStruct : ILogValueWriter - { - public void Write(ref ValueStringBuilder stringBuilder, T arg) - { - ref readonly var actor = ref Unsafe.As(ref arg); - Instance.Write(ref stringBuilder, actor); - } - } } \ No newline at end of file diff --git a/src/Hexecs/Assets/Sources/AssetConfigurator.cs b/src/Hexecs/Assets/Sources/AssetConfigurator.cs index 18618a0..08e8bf3 100644 --- a/src/Hexecs/Assets/Sources/AssetConfigurator.cs +++ b/src/Hexecs/Assets/Sources/AssetConfigurator.cs @@ -5,7 +5,7 @@ public readonly struct AssetConfigurator /// /// Идентификатор ассета, который уже присвоен ему при создании /// - public uint Id + public AssetId Id { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => _id; @@ -17,18 +17,22 @@ public IAssetLoader Loader get => _loader; } - private readonly uint _id; + private readonly AssetId _id; private readonly AssetContext.Loader _loader; [method: MethodImpl(MethodImplOptions.AggressiveInlining)] - internal AssetConfigurator(uint id, AssetContext.Loader loader) + internal AssetConfigurator(AssetId id, AssetContext.Loader loader) { _id = id; _loader = loader; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Has() where T : struct, IAssetComponent => _loader.Context.HasComponent(_id); + public bool Has() + where T : struct, IAssetComponent + { + return _loader.Context.HasComponent(_id); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] public ref readonly T Get() where T : struct, IAssetComponent => ref _loader.Context.GetComponent(_id); diff --git a/src/Hexecs/Assets/Sources/IAssetLoader.cs b/src/Hexecs/Assets/Sources/IAssetLoader.cs index 211dc11..8291f27 100644 --- a/src/Hexecs/Assets/Sources/IAssetLoader.cs +++ b/src/Hexecs/Assets/Sources/IAssetLoader.cs @@ -46,17 +46,13 @@ AssetConfigurator CreateAsset(string alias, in T1 component1, in T2 void EnsureNotDisposed(); - Asset GetAsset(uint assetId); + Asset GetAsset(AssetId assetId); Asset GetAsset(string alias); - Asset GetAsset(uint assetId) where T1 : struct, IAssetComponent; + string GetAlias(AssetId assetId); - Asset GetAsset(string alias) where T1 : struct, IAssetComponent; - - string GetAlias(uint assetId); - - uint GetId(string assetAlias); + AssetId GetId(string assetAlias); AssetBlockBuilder RentBlockBuilder( Func, TArray> blockBuilder) diff --git a/src/Hexecs/Loggers/LogBuilder.cs b/src/Hexecs/Loggers/LogBuilder.cs index 3560cf3..3fca481 100644 --- a/src/Hexecs/Loggers/LogBuilder.cs +++ b/src/Hexecs/Loggers/LogBuilder.cs @@ -36,10 +36,6 @@ internal LogBuilder() ], ReferenceComparer.Instance); _valueFactories = new Queue(4); - _valueFactories.Enqueue(ActorLogWriter.Factory); - _valueFactories.Enqueue(ActorIdLogWriter.Factory); - _valueFactories.Enqueue(AssetLogWriter.Factory); - _valueFactories.Enqueue(AssetIdLogWriter.Factory); } internal LogService Build() diff --git a/src/Hexecs/Serializations/JsonWriterExtensions.cs b/src/Hexecs/Serializations/JsonWriterExtensions.cs index 3833b3b..efe570c 100644 --- a/src/Hexecs/Serializations/JsonWriterExtensions.cs +++ b/src/Hexecs/Serializations/JsonWriterExtensions.cs @@ -42,14 +42,6 @@ public Utf8JsonWriter WriteProperty(string propertyName, ActorId value) return writer; } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Utf8JsonWriter WriteProperty(string propertyName, ActorId value) - where T : struct, IActorComponent - { - writer.WriteNumber(propertyName, value.Value); - return writer; - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] public Utf8JsonWriter WriteProperty(string propertyName, AssetId value) { @@ -57,14 +49,6 @@ public Utf8JsonWriter WriteProperty(string propertyName, AssetId value) return writer; } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Utf8JsonWriter WriteProperty(string propertyName, AssetId value) - where T : struct, IAssetComponent - { - writer.WriteNumber(propertyName, value.Value); - return writer; - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] public Utf8JsonWriter WriteProperty(string propertyName, bool value) { diff --git a/src/Hexecs/Threading/IParallelJob.cs b/src/Hexecs/Threading/IParallelJob.cs index 7a2e4fe..cfd4551 100644 --- a/src/Hexecs/Threading/IParallelJob.cs +++ b/src/Hexecs/Threading/IParallelJob.cs @@ -6,5 +6,5 @@ public interface IParallelJob { ActorContext Context { get; } - void Execute(int workerIndex, int workerCount); + void Execute(int workerIndex, int workersCount); } \ No newline at end of file diff --git a/src/Hexecs/Utils/ValueStringBuilder.cs b/src/Hexecs/Utils/ValueStringBuilder.cs index 4b86f73..03fb7bd 100644 --- a/src/Hexecs/Utils/ValueStringBuilder.cs +++ b/src/Hexecs/Utils/ValueStringBuilder.cs @@ -1,4 +1,6 @@ using System.Globalization; +using Hexecs.Actors; +using Hexecs.Assets; namespace Hexecs.Utils; @@ -186,7 +188,7 @@ public void Append(scoped ReadOnlySpan value) value.CopyTo(_buffer[_length..]); _length += value.Length; } - + #endregion [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/tests/Hexecs.Tests/Actors/ActorConstraintShould.cs b/tests/Hexecs.Tests/Actors/ActorConstraintShould.cs index 974102d..6f010b6 100644 --- a/tests/Hexecs.Tests/Actors/ActorConstraintShould.cs +++ b/tests/Hexecs.Tests/Actors/ActorConstraintShould.cs @@ -45,8 +45,10 @@ public void Should_Raise_Added_When_Actor_Becomes_Valid() actor.Add(new Description()); // Теперь актор соответствует Include // Assert - monitoredSubject.Should().Raise(nameof(constraint.Added)) - .WithArgs(id => id == actor.Id); + monitoredSubject + .Should() + .Raise(nameof(constraint.Added)) + .WithArgs(id => id == actor.Id); } [Fact(DisplayName = "Должен вызывать событие Removing, когда актор перестает соответствовать фильтру")] @@ -62,8 +64,10 @@ public void Should_Raise_Removing_When_Actor_Becomes_Invalid() actor.Remove(); // Assert - monitoredSubject.Should().Raise(nameof(constraint.Removing)) - .WithArgs(id => id == actor.Id); + monitoredSubject + .Should() + .Raise(nameof(constraint.Removing)) + .WithArgs(id => id == actor.Id); } [Fact(DisplayName = "Builder должен выбрасывать исключение при добавлении дублирующегося компонента")] @@ -129,6 +133,8 @@ public void Should_Unsubscribe_On_Dispose() actor.Add(new Description()); // Assert - monitoredSubject.Should().NotRaise(nameof(constraint.Added)); + monitoredSubject + .Should() + .NotRaise(nameof(constraint.Added)); } } \ No newline at end of file diff --git a/tests/Hexecs.Tests/Actors/ActorContextShould.cs b/tests/Hexecs.Tests/Actors/ActorContextShould.cs index 289e7c8..dad30e9 100644 --- a/tests/Hexecs.Tests/Actors/ActorContextShould.cs +++ b/tests/Hexecs.Tests/Actors/ActorContextShould.cs @@ -12,7 +12,7 @@ public void BuildActor() { // arrange - var asset = fixture.Assets.GetAsset(); + var asset = fixture.Assets.GetAssetRef(); // act @@ -46,8 +46,8 @@ public void CreateActorWithExpectedId() var actor = fixture.Actors.CreateActor(expectedId); // assert - actor.Id.Should().Be(expectedId); - fixture.Actors.ActorAlive(expectedId).Should().BeTrue(); + actor.Id.Value.Should().Be(expectedId); + fixture.Actors.ActorAlive(new ActorId(expectedId)).Should().BeTrue(); } [Fact(DisplayName = "Проверять существование актёра")] @@ -59,7 +59,7 @@ public void CheckIfActorIsAlive() // act var actorExists = fixture.Actors.ActorAlive(actor.Id); - var nonExistentActorExists = fixture.Actors.ActorAlive(nonExistentId); + var nonExistentActorExists = fixture.Actors.ActorAlive(new ActorId(nonExistentId)); // assert actorExists.Should().BeTrue(); @@ -97,7 +97,7 @@ public void GetActorById() public void CloneActor() { // arrange - var asset = fixture.Assets.GetAsset(); + var asset = fixture.Assets.GetAssetRef(); var originalActor = fixture.Actors.BuildActor(asset); // act @@ -141,9 +141,9 @@ public void TryGetActorWithComponent(int attackValue, int defenceValue) actor.Add(new Defence { Value = defenceValue }); // act - var hasAttack = actors.TryGetActor(actor.Id, out var actorWithAttack); - var hasDefence = actors.TryGetActor(actor.Id, out var actorWithDefence); - var hasNonExistentComponent = actors.TryGetActor(actor.Id, out _); + var hasAttack = actors.TryGetActorRef(actor.Id, out var actorWithAttack); + var hasDefence = actors.TryGetActorRef(actor.Id, out var actorWithDefence); + var hasNonExistentComponent = actors.TryGetActorRef(actor.Id, out _); // assert hasAttack.Should().BeTrue(); @@ -169,16 +169,16 @@ public void GetActorDescription() var description = fixture.Actors.GetDescription(actor.Id); // assert - description.Should().Contain(actor.Id.ToString()); - description.Should().Contain(typeof(Attack).Name); - description.Should().Contain(typeof(Defence).Name); + description.Should().Contain(actor.Id.Value.ToString()); + description.Should().Contain(nameof(Attack)); + description.Should().Contain(nameof(Defence)); } [Fact(DisplayName = "Привязывать и получать ассет к актёру")] public void BindAndGetAsset() { // arrange - var asset = fixture.Assets.GetAsset(); + var asset = fixture.Assets.GetAssetRef(); var actor = fixture.Actors.CreateActor(); // act @@ -311,13 +311,13 @@ public void CallHandlerWhenComponentAdded() var actor = fixture.Actors.CreateActor(); uint? addedActorId = null; - fixture.Actors.OnComponentAdded(id => addedActorId = id); + fixture.Actors.OnComponentAdded(id => addedActorId = id.Value); // act fixture.Actors.AddComponent(actor.Id, new Attack { Value = 10 }); // assert - addedActorId.Should().Be(actor.Id); + addedActorId.Should().Be(actor.Id.Value); } [Fact(DisplayName = "Вызывать обработчик со значением при добавлении компонента")] @@ -328,9 +328,9 @@ public void CallHandlerWithValueWhenComponentAdded() uint? addedActorId = null; Attack? addedComponent = null; - fixture.Actors.OnComponentAdded((uint id, ref Attack component) => + fixture.Actors.OnComponentAdded((ActorId id, ref Attack component) => { - addedActorId = id; + addedActorId = id.Value; addedComponent = component; }); @@ -338,7 +338,7 @@ public void CallHandlerWithValueWhenComponentAdded() fixture.Actors.AddComponent(actor.Id, new Attack { Value = 15 }); // assert - addedActorId.Should().Be(actor.Id); + addedActorId.Should().Be(actor.Id.Value); addedComponent.Should().NotBeNull(); addedComponent?.Value.Should().Be(15); } @@ -351,13 +351,13 @@ public void CallHandlerWhenComponentRemoved() fixture.Actors.AddComponent(actor.Id, new Attack { Value = 10 }); uint? removedActorId = null; - fixture.Actors.OnComponentRemoving(id => removedActorId = id); + fixture.Actors.OnComponentRemoving(id => removedActorId = id.Value); // act fixture.Actors.RemoveComponent(actor.Id); // assert - removedActorId.Should().Be(actor.Id); + removedActorId.Should().Be(actor.Id.Value); } [Fact(DisplayName = "Вызывать обработчик со значением при удалении компонента")] @@ -370,9 +370,9 @@ public void CallHandlerWithValueWhenComponentRemoved() uint? removedActorId = null; Attack? removedComponent = null; - fixture.Actors.OnComponentRemoving((uint id, ref Attack component) => + fixture.Actors.OnComponentRemoving((ActorId id, ref Attack component) => { - removedActorId = id; + removedActorId = id.Value; removedComponent = component; }); @@ -380,7 +380,7 @@ public void CallHandlerWithValueWhenComponentRemoved() fixture.Actors.RemoveComponent(actor.Id); // assert - removedActorId.Should().Be(actor.Id); + removedActorId.Should().Be(actor.Id.Value); removedComponent.Should().NotBeNull(); removedComponent?.Value.Should().Be(20); } @@ -396,9 +396,9 @@ public void CallHandlerWhenComponentUpdated() Attack? oldComponent = null; Attack? newComponent = null; - fixture.Actors.OnComponentUpdating((uint id, ref Attack oldValue, in Attack newValue) => + fixture.Actors.OnComponentUpdating((ActorId id, ref Attack oldValue, in Attack newValue) => { - updatedActorId = id; + updatedActorId = id.Value; oldComponent = oldValue; newComponent = newValue; }); @@ -408,7 +408,7 @@ public void CallHandlerWhenComponentUpdated() fixture.Actors.UpdateComponent(actor.Id, updatedAttack); // assert - updatedActorId.Should().Be(actor.Id); + updatedActorId.Should().Be(actor.Id.Value); oldComponent.Should().NotBeNull(); oldComponent?.Value.Should().Be(10); newComponent.Should().NotBeNull(); @@ -529,7 +529,7 @@ public void CreateComponentWhenUpdatingIfNotExists(int value) public void TryGetBoundAsset() { // arrange - var asset = fixture.Assets.GetAsset(); + var asset = fixture.Assets.GetAssetRef(); var actor = fixture.Actors.CreateActor(); fixture.Actors.SetBoundAsset(actor.Id, asset); @@ -595,7 +595,7 @@ public void GetActorFromActorRef() // act var actorRef = fixture.Actors.GetActorRef(actor.Id); - var retrievedActor = actorRef.AsActor(); + Actor retrievedActor = actorRef; // assert retrievedActor.Id.Should().Be(actor.Id); @@ -617,11 +617,18 @@ public void GetActorWithPredicate() actor3.Add(new Attack { Value = 15 }); // act - var actorWithAttack10 = fixture.Actors.GetActor((in ActorRef actor) => actor.Get().Value == 10); + var actorWithAttack10 = + fixture.Actors.GetActorRef((in ActorRef actor) => actor.Get().Value == 10); // assert - actorWithAttack10.Id.Should().Be(actor2.Id); - actorWithAttack10.Get().Value.Should().Be(10); + actorWithAttack10.Id + .Should() + .Be(actor2.Id); + + actorWithAttack10 + .Get().Value + .Should() + .Be(10); } [Fact(DisplayName = "Получать единственного актёра с компонентом")] @@ -633,11 +640,18 @@ public void GetSingleActorWithComponent() actor.Add(new NonExistentComponent()); // act - var singleActor = fixture.Actors.Single(); + var singleActor = fixture.Actors.SingleRef(); // assert - singleActor.Id.Should().Be(actor.Id); - singleActor.Has().Should().BeTrue(); + singleActor + .Id + .Should() + .Be(actor.Id); + + singleActor + .Has() + .Should() + .BeTrue(); } [Fact(DisplayName = "Генерировать исключение при получении Single, когда нет актёров с компонентом")] @@ -647,7 +661,7 @@ public void ThrowWhenGettingSingleWithNoMatchingActors() fixture.Actors.Clear(); // act - Action action = () => fixture.Actors.Single(); + Action action = () => fixture.Actors.SingleRef(); // assert action.Should().Throw(); @@ -665,7 +679,7 @@ public void ThrowWhenGettingSingleWithMultipleMatchingActors() actor2.Add(new Attack { Value = 20 }); // act - Action action = () => fixture.Actors.Single(); + Action action = () => fixture.Actors.SingleRef(); // assert action.Should().Throw(); @@ -675,7 +689,7 @@ public void ThrowWhenGettingSingleWithMultipleMatchingActors() public void RemoveBoundAssetWhenSettingEmptyAsset() { // arrange - var asset = fixture.Assets.GetAsset(); + var asset = fixture.Assets.GetAssetRef(); var actor = fixture.Actors.CreateActor(); fixture.Actors.SetBoundAsset(actor.Id, asset); diff --git a/tests/Hexecs.Tests/Actors/ActorFilter1Should.cs b/tests/Hexecs.Tests/Actors/ActorFilter1Should.cs index d16fee7..e09ef39 100644 --- a/tests/Hexecs.Tests/Actors/ActorFilter1Should.cs +++ b/tests/Hexecs.Tests/Actors/ActorFilter1Should.cs @@ -11,7 +11,7 @@ public void ContainsActorCreatedBeforeFilter() // arrange var component = fixture.CreateComponent(); - Actor actor = fixture.CreateActor(component1: component); + Actor actor = fixture.CreateActor(component1: component); // act @@ -73,10 +73,10 @@ public void ContainsAllActors() .Filter(); actors - .Where(actor => actor.Id % 2 == 0) + .Where(actor => actor.Id.Value % 2 == 0) .Do(actor => actor.Destroy()); - var expectedActors = actors.Where(actor => actor.Id % 2 != 0); + var expectedActors = actors.Where(actor => actor.Id.Value % 2 != 0); // act diff --git a/tests/Hexecs.Tests/Actors/ActorListShould.cs b/tests/Hexecs.Tests/Actors/ActorListShould.cs index 04adaae..7143703 100644 --- a/tests/Hexecs.Tests/Actors/ActorListShould.cs +++ b/tests/Hexecs.Tests/Actors/ActorListShould.cs @@ -24,7 +24,7 @@ public void Should_Return_False_When_Removing_Non_Existent_Actor() { // Arrange using var list = new ActorList(fixture.Actors); - uint fakeId = 999; + var fakeId = new ActorId(999); // Act var result = list.Remove(fakeId); @@ -58,11 +58,17 @@ public void Should_Automatically_Remove_Actor_When_Component_Is_Removed() list.Add(actor); // Act + actor.Remove(); // Это вызывает событие Removing в пуле // Assert - list.Contains(actor).Should().BeFalse(); - list.Length.Should().Be(0); + list.Contains(actor) + .Should() + .BeFalse(); + + list.Length + .Should() + .Be(0); } [Fact(DisplayName = "Должен корректно итерироваться по добавленным акторам")] @@ -76,7 +82,7 @@ public void Should_Enumerate_Added_Actors() list.Add(actor2); // Act - var resultIds = new List(); + var resultIds = new List(); foreach (var actor in list) { resultIds.Add(actor.Id); @@ -98,10 +104,14 @@ public void Should_Throw_When_Adding_To_Disposed_List() var actor = fixture.CreateActor(); // Act + var action = () => list.Add(actor); // Assert - action.Should().Throw() + + action + .Should() + .Throw() .WithMessage("*disposed*"); } @@ -115,12 +125,21 @@ public void Should_Add_Using_Different_References(bool useActorRef) var actor = fixture.CreateActor(); // Act + if (useActorRef) - list.Add(actor.AsRef()); + { + list.Add(actor.AsRef()); + } else + { list.Add(actor); + } + // Assert - list.Contains(actor.Id).Should().BeTrue(); + list + .Contains(actor.Id) + .Should() + .BeTrue(); } } \ No newline at end of file diff --git a/tests/Hexecs.Tests/Actors/ActorMethodsConsistencyTests.cs b/tests/Hexecs.Tests/Actors/ActorMethodsConsistencyTests.cs index 82f249b..2463f14 100644 --- a/tests/Hexecs.Tests/Actors/ActorMethodsConsistencyTests.cs +++ b/tests/Hexecs.Tests/Actors/ActorMethodsConsistencyTests.cs @@ -10,7 +10,6 @@ public class ActorMethodsConsistencyTests private static readonly Type[] ActorTypes = [ typeof(Actor), - typeof(Actor<>), typeof(ActorRef<>), typeof(ActorRef<,>), typeof(ActorRef<,,>) diff --git a/tests/Hexecs.Tests/Actors/ActorShould.cs b/tests/Hexecs.Tests/Actors/ActorShould.cs index 6e8cc89..dd69d7f 100644 --- a/tests/Hexecs.Tests/Actors/ActorShould.cs +++ b/tests/Hexecs.Tests/Actors/ActorShould.cs @@ -83,7 +83,7 @@ public void AsActor1() // act - var actor1 = actor.As(); + var actor1 = actor.AsRef(); // assert @@ -143,17 +143,13 @@ public void BeIs() // act expected - .Is(out var actual) + .IsRef(out var actual) .Should() .BeTrue(); // assert - expected - .Should() - .Be(actual); - - expected.Component1 + expected.Get() .Should() .Be(actual.Component1); } @@ -289,7 +285,7 @@ public void GetBoundAsset() { // arrange - var asset = fixture.Assets.GetAsset(); + var asset = fixture.Assets.GetAssetRef(); var actor = fixture.Actors.BuildActor(asset); // act @@ -297,9 +293,10 @@ public void GetBoundAsset() // assert retrievedAsset - .As() + .AsRef() + .Equals(asset) .Should() - .Be(asset); + .BeTrue(); } [Fact(DisplayName = "Получить ссылку на компонент")] @@ -373,7 +370,9 @@ public void ImplicitCastToActorId() ActorId actorId = actor; // assert - actorId.Value.Should().Be(actor.Id); + actorId + .Should() + .Be(actor.Id); } [Fact(DisplayName = "Удалить отношение между акторами")] @@ -423,15 +422,16 @@ public void NotBeIs() // act expected - .Is(out var actual) + .IsRef(out var actual) .Should() .BeFalse(); // assert expected + .Equals(actual) .Should() - .NotBe(actual); + .BeFalse(); } [Fact(DisplayName = "Не удалить несуществующий компонент")] @@ -567,7 +567,7 @@ public void TryGetBoundAsset() { // arrange - var asset = fixture.Assets.GetAsset(); + var asset = fixture.Assets.GetAssetRef(); var actor = fixture.Actors.BuildActor(asset); // act @@ -580,9 +580,10 @@ public void TryGetBoundAsset() .BeTrue(); actualAsset - .As() + .AsRef() + .Equals(asset) .Should() - .Be(asset); + .BeTrue(); } [Fact(DisplayName = "Успешно пробовать получить существующий компонент")] diff --git a/tests/Hexecs.Tests/Actors/ActorTestFixture.cs b/tests/Hexecs.Tests/Actors/ActorTestFixture.cs index 965b6e4..b3a649d 100644 --- a/tests/Hexecs.Tests/Actors/ActorTestFixture.cs +++ b/tests/Hexecs.Tests/Actors/ActorTestFixture.cs @@ -29,16 +29,16 @@ public Actor CreateActor(uint? id = null) return actor; } - public Actor CreateActor(uint? id = null, T1? component1 = null) + public Actor CreateActor(uint? id = null, T1? component1 = null) where T1 : struct, IActorComponent { var actor = Actors.CreateActor(id); actor.Add(component1 ?? CreateComponent()); - return actor.As(); + return actor; } - public Actor CreateActor(uint? id = null, T1? component1 = null, T2? component2 = null) + public Actor CreateActor(uint? id = null, T1? component1 = null, T2? component2 = null) where T1 : struct, IActorComponent where T2 : struct, IActorComponent { @@ -46,10 +46,10 @@ public Actor CreateActor(uint? id = null, T1? component1 = null, T2? actor.Add(component1 ?? CreateComponent()); actor.Add(component2 ?? CreateComponent()); - return actor.As(); + return actor; } - public Actor CreateActor(uint? id = null, T1? component1 = null, T2? component2 = null, + public Actor CreateActor(uint? id = null, T1? component1 = null, T2? component2 = null, T3? component3 = null) where T1 : struct, IActorComponent where T2 : struct, IActorComponent @@ -60,7 +60,7 @@ public Actor CreateActor(uint? id = null, T1? component1 = null, actor.Add(component2 ?? CreateComponent()); actor.Add(component3 ?? CreateComponent()); - return actor.As(); + return actor; } public Actor[] CreateActors(int? length = null) diff --git a/tests/Hexecs.Tests/Assets/AssetContextShould.cs b/tests/Hexecs.Tests/Assets/AssetContextShould.cs index 5c211b2..87dbb97 100644 --- a/tests/Hexecs.Tests/Assets/AssetContextShould.cs +++ b/tests/Hexecs.Tests/Assets/AssetContextShould.cs @@ -1,4 +1,6 @@ -namespace Hexecs.Tests.Assets; +using Hexecs.Assets; + +namespace Hexecs.Tests.Assets; public sealed class AssetContextShould(AssetTestFixture fixture) : IClassFixture { @@ -8,7 +10,7 @@ public void GetAssetByAlias() // arrange var alias = fixture.RandomString(); - uint? assetId = null; + AssetId assetId = AssetId.Empty; fixture.CreateAssetContext(loader => { var asset = loader.CreateAsset(alias); diff --git a/tests/Hexecs.Tests/Assets/AssetFilter1Should.cs b/tests/Hexecs.Tests/Assets/AssetFilter1Should.cs index e452589..da45f86 100644 --- a/tests/Hexecs.Tests/Assets/AssetFilter1Should.cs +++ b/tests/Hexecs.Tests/Assets/AssetFilter1Should.cs @@ -1,4 +1,5 @@ -using Hexecs.Tests.Mocks.Assets; +using Hexecs.Assets; +using Hexecs.Tests.Mocks.Assets; namespace Hexecs.Tests.Assets; @@ -8,18 +9,21 @@ public sealed class AssetFilter1Should(AssetTestFixture fixture) : IClassFixture public void ContainsAllAssets() { // arrange - var assetIds = new List(); + + var assetIds = new List(); var context = fixture.CreateAssetContext(loader => { - for (int i = 1; i < 100; i++) + for (var i = 1; i < 100; i++) { var asset = loader.CreateAsset(new CarAsset(i, i)); assetIds.Add(asset.Id); } }); - var expectedAssets = assetIds.Select(id => context.GetAsset(id)).ToArray(); + var expectedAssets = assetIds + .Select(context.GetAsset) + .ToArray(); // act @@ -37,7 +41,8 @@ public void ContainsAllAssets() public void AssetFilterShouldEnumerable() { // arrange - var expectedIds = new Dictionary(); + + var expectedIds = new Dictionary(); var context = fixture.CreateAssetContext(loader => { @@ -56,7 +61,7 @@ public void AssetFilterShouldEnumerable() // assert - var actualIds = new List(); + var actualIds = new List(); foreach (var asset in filter) { actualIds.Add(asset.Id); @@ -95,8 +100,8 @@ public void EmptyFilterWhenNoComponentsExist() [Fact(DisplayName = "Фильтр должен учитывать constraint")] public void FilterWithConstraint() { - var notExpectedIds = new List(); - uint expectedId = 0; + var notExpectedIds = new List(); + var expectedId = AssetId.Empty; // arrange var context = fixture.CreateAssetContext(loader => @@ -146,7 +151,7 @@ public void GetThrowsExceptionWhenNotFound() // act - Action act = () => filter.Get(999); // Несуществующий ID + Action act = () => filter.Get(new AssetId(999)); // Несуществующий ID // assert act @@ -158,7 +163,8 @@ public void GetThrowsExceptionWhenNotFound() public void ContainsReturnsCorrectStatus() { // arrange - uint existingId = 0; + + var existingId = AssetId.Empty; var context = fixture.CreateAssetContext(loader => { var asset = loader.CreateAsset(new CarAsset(1, 1)); @@ -174,7 +180,7 @@ public void ContainsReturnsCorrectStatus() .BeTrue(); filter - .Contains(existingId + 100) + .Contains(new AssetId(existingId.Value + 100)) .Should() .BeFalse(); } diff --git a/tests/Hexecs.Tests/Assets/AssetFilter2Should.cs b/tests/Hexecs.Tests/Assets/AssetFilter2Should.cs index 9008d8f..515ad06 100644 --- a/tests/Hexecs.Tests/Assets/AssetFilter2Should.cs +++ b/tests/Hexecs.Tests/Assets/AssetFilter2Should.cs @@ -1,4 +1,5 @@ -using Hexecs.Tests.Mocks.Assets; +using Hexecs.Assets; +using Hexecs.Tests.Mocks.Assets; namespace Hexecs.Tests.Assets; @@ -8,7 +9,8 @@ public sealed class AssetFilter2Should(AssetTestFixture fixture) : IClassFixture public void ContainsAllAssets() { // arrange - var assetIds = new List(); + + var assetIds = new List(); var context = fixture.CreateAssetContext(loader => { @@ -21,7 +23,9 @@ public void ContainsAllAssets() } }); - var expectedAssets = assetIds.Select(id => context.GetAsset(id)).ToArray(); + var expectedAssets = assetIds + .Select(context.GetAsset) + .ToArray(); // act @@ -39,7 +43,8 @@ public void ContainsAllAssets() public void AssetFilterShouldEnumerable() { // arrange - var expectedIds = new Dictionary(); + + var expectedIds = new Dictionary(); var context = fixture.CreateAssetContext(loader => { @@ -59,7 +64,7 @@ public void AssetFilterShouldEnumerable() // assert - var actualIds = new List(); + var actualIds = new List(); foreach (var asset in filter) { actualIds.Add(asset.Id); @@ -102,8 +107,8 @@ public void EmptyFilterWhenNoComponentsExist() [Fact(DisplayName = "Фильтр должен учитывать constraint")] public void FilterWithConstraint() { - var notExpectedIds = new List(); - uint expectedId = 0; + var notExpectedIds = new List(); + AssetId expectedId = AssetId.Empty; // arrange var context = fixture.CreateAssetContext(loader => @@ -112,7 +117,7 @@ public void FilterWithConstraint() new CarAsset(10, 10), new UnitAsset(), new BuildingAsset()).Id); - + notExpectedIds.Add(loader.CreateAsset( new CarAsset(10, 10), new UnitAsset(), @@ -158,7 +163,7 @@ public void GetThrowsExceptionWhenNotFound() // act - Action act = () => filter.Get(999); // Несуществующий ID + Action act = () => filter.Get(new AssetId(999)); // Несуществующий ID // assert act @@ -170,7 +175,9 @@ public void GetThrowsExceptionWhenNotFound() public void ContainsReturnsCorrectStatus() { // arrange - uint existingId = 0; + + var existingId = AssetId.Empty; + var context = fixture.CreateAssetContext(loader => { var asset = loader.CreateAsset(new CarAsset(1, 1), new UnitAsset()); @@ -186,7 +193,7 @@ public void ContainsReturnsCorrectStatus() .BeTrue(); filter - .Contains(existingId + 100) + .Contains(new AssetId(existingId.Value + 100)) .Should() .BeFalse(); } diff --git a/tests/Hexecs.Tests/Assets/AssetFilter3Should.cs b/tests/Hexecs.Tests/Assets/AssetFilter3Should.cs index fe6b906..f24b01e 100644 --- a/tests/Hexecs.Tests/Assets/AssetFilter3Should.cs +++ b/tests/Hexecs.Tests/Assets/AssetFilter3Should.cs @@ -1,4 +1,5 @@ -using Hexecs.Tests.Mocks.Assets; +using Hexecs.Assets; +using Hexecs.Tests.Mocks.Assets; namespace Hexecs.Tests.Assets; @@ -8,7 +9,7 @@ public sealed class AssetFilter3Should(AssetTestFixture fixture) : IClassFixture public void ContainsAllAssets() { // arrange - var assetIds = new List(); + var assetIds = new List(); var context = fixture.CreateAssetContext(loader => { @@ -40,7 +41,7 @@ public void ContainsAllAssets() public void AssetFilterShouldEnumerable() { // arrange - var expectedIds = new Dictionary(); + var expectedIds = new Dictionary(); var context = fixture.CreateAssetContext(loader => { @@ -61,7 +62,7 @@ public void AssetFilterShouldEnumerable() // assert - var actualIds = new List(); + var actualIds = new List(); foreach (var asset in filter) { actualIds.Add(asset.Id); @@ -108,8 +109,8 @@ public void EmptyFilterWhenNoComponentsExist() [Fact(DisplayName = "Фильтр должен учитывать constraint")] public void FilterWithConstraint() { - var notExpectedIds = new List(); - uint expectedId = 0; + var notExpectedIds = new List(); + var expectedId = AssetId.Empty; // arrange var context = fixture.CreateAssetContext(loader => @@ -161,7 +162,7 @@ public void GetThrowsExceptionWhenNotFound() // act - Action act = () => filter.Get(999); // Несуществующий ID + Action act = () => filter.Get(new AssetId(999)); // Несуществующий ID // assert act @@ -173,7 +174,8 @@ public void GetThrowsExceptionWhenNotFound() public void ContainsReturnsCorrectStatus() { // arrange - uint existingId = 0; + + var existingId = AssetId.Empty; var context = fixture.CreateAssetContext(loader => { var asset = loader.CreateAsset(new CarAsset(1, 1), new DecisionAsset(), new UnitAsset()); @@ -183,13 +185,14 @@ public void ContainsReturnsCorrectStatus() var filter = context.Filter(); // act & assert + filter .Contains(existingId) .Should() .BeTrue(); filter - .Contains(existingId + 100) + .Contains(new AssetId(existingId.Value + 100)) .Should() .BeFalse(); } diff --git a/tests/Hexecs.Tests/Assets/AssetMethodsConsistencyTests.cs b/tests/Hexecs.Tests/Assets/AssetMethodsConsistencyTests.cs new file mode 100644 index 0000000..0722d49 --- /dev/null +++ b/tests/Hexecs.Tests/Assets/AssetMethodsConsistencyTests.cs @@ -0,0 +1,163 @@ +using System.Reflection; +using Hexecs.Assets; + +namespace Hexecs.Tests.Assets; + +public class AssetMethodsConsistencyTests +{ + /// + /// Все типы, которые должны иметь общие методы + /// + private static readonly Type[] AssetTypes = + [ + typeof(Asset), + typeof(AssetRef<>), + typeof(AssetRef<,>), + typeof(AssetRef<,,>) + ]; + + /// + /// Эталонный тип — источник правды для списка методов + /// + private static readonly Type ReferenceType = typeof(Asset); + + /// + /// Методы, которые исключаем из проверки (специфичные для типа или системные) + /// + private static readonly HashSet ExcludedMethods = + [ + "AsRef", + "GetType", + "ToString", + "Equals", + "GetHashCode" + ]; + + private static IEnumerable CommonMethodNames => + ReferenceType + .GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly) + .Select(m => m.Name) + .Where(name => !ExcludedMethods.Contains(name)) + .Distinct(); + + [Fact(DisplayName = "Все типы акторов должны иметь общие методы")] + public void AllActorTypes_ShouldHaveCommonMethods() + { + var expectedMethods = CommonMethodNames.ToList(); + + foreach (var type in AssetTypes.Where(t => t != ReferenceType)) + { + var methods = type.GetMethods(BindingFlags.Public | BindingFlags.Instance); + var methodNames = methods.Select(m => m.Name).Distinct().ToHashSet(); + + foreach (var expectedMethod in expectedMethods) + { + methodNames.Should().Contain(expectedMethod, + because: $"тип {type.Name} должен содержать метод {expectedMethod} (как в {ReferenceType.Name})"); + } + } + } + + [Fact(DisplayName = "Все общие методы должны иметь одинаковые сигнатуры")] + public void CommonMethods_ShouldHaveIdenticalSignatures() + { + foreach (var methodName in CommonMethodNames) + { + var referenceMethods = GetMethodSignatures(ReferenceType, methodName); + + foreach (var type in AssetTypes.Where(t => t != ReferenceType)) + { + var typeMethods = GetMethodSignatures(type, methodName); + + typeMethods.Should().BeEquivalentTo(referenceMethods, + because: + $"метод {methodName} в {type.Name} должен иметь такую же сигнатуру как в {ReferenceType.Name}"); + } + } + } + + [Fact(DisplayName = "Все общие методы должны иметь AggressiveInlining-атрибут")] + public void CommonMethods_ShouldHaveAggressiveInlining() + { + foreach (var type in AssetTypes) + { + var methods = type + .GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly) + .Where(m => CommonMethodNames.Contains(m.Name)); + + foreach (var method in methods) + { + var implFlags = method.MethodImplementationFlags; + + implFlags.Should().HaveFlag(MethodImplAttributes.AggressiveInlining, + because: $"метод {type.Name}.{method.Name} должен иметь атрибут AggressiveInlining"); + } + } + } + + private static List GetMethodSignatures(Type type, string methodName) + { + return type + .GetMethods(BindingFlags.Public | BindingFlags.Instance) + .Where(m => m.Name == methodName) + .Select(m => new MethodSignature(m)) + .ToList(); + } + + private sealed class MethodSignature + { + public string Name { get; } + public string ReturnType { get; } + public string[] ParameterTypes { get; } + public string[] GenericConstraints { get; } + public int GenericArgumentCount { get; } + + public MethodSignature(MethodInfo method) + { + Name = method.Name; + ReturnType = NormalizeTypeName(method.ReturnType); + ParameterTypes = method.GetParameters() + .Select(p => NormalizeTypeName(p.ParameterType)) + .ToArray(); + GenericArgumentCount = method.GetGenericArguments().Length; + GenericConstraints = method.GetGenericArguments() + .SelectMany(g => g.GetGenericParameterConstraints()) + .Select(NormalizeTypeName) + .OrderBy(x => x) + .ToArray(); + } + + private static string NormalizeTypeName(Type type) + { + if (type.IsGenericParameter) + return "T"; + + if (type.IsGenericType) + { + var baseName = type.GetGenericTypeDefinition().Name; + var args = string.Join(",", type.GetGenericArguments().Select(NormalizeTypeName)); + return $"{baseName}[{args}]"; + } + + if (type.IsByRef) + return $"ref {NormalizeTypeName(type.GetElementType()!)}"; + + return type.Name; + } + + public override bool Equals(object? obj) + { + if (obj is not MethodSignature other) return false; + return Name == other.Name + && ReturnType == other.ReturnType + && GenericArgumentCount == other.GenericArgumentCount + && ParameterTypes.SequenceEqual(other.ParameterTypes) + && GenericConstraints.SequenceEqual(other.GenericConstraints); + } + + public override int GetHashCode() => HashCode.Combine(Name, ReturnType, GenericArgumentCount); + + public override string ToString() => + $"{ReturnType} {Name}<{GenericArgumentCount}>({string.Join(", ", ParameterTypes)})"; + } +} \ No newline at end of file diff --git a/tests/Hexecs.Tests/Assets/AssetTestFixture.cs b/tests/Hexecs.Tests/Assets/AssetTestFixture.cs index 87098d2..d674119 100644 --- a/tests/Hexecs.Tests/Assets/AssetTestFixture.cs +++ b/tests/Hexecs.Tests/Assets/AssetTestFixture.cs @@ -27,23 +27,25 @@ public World World private AssetContext? _assets; private World? _world; - public Asset CreateAsset() where T : struct, IAssetComponent + public Asset CreateAsset() where T : struct, IAssetComponent { - var assetId = Asset.EmptyId; + var assetId = AssetId.Empty; + _world = new WorldBuilder() .CreateAssetData(CreateAssets) .CreateAssetData(loader => { assetId = loader.CreateAsset(CreateComponent()).Id; }) .Build(); _assets = _world.Assets; - return Assets.GetAsset(assetId); + return Assets.GetAsset(assetId); } - public Asset CreateAsset() + public Asset CreateAsset() where T1 : struct, IAssetComponent where T2 : struct, IAssetComponent { - var assetId = Asset.EmptyId; + var assetId = AssetId.Empty; + _world = new WorldBuilder() .CreateAssetData(CreateAssets) .CreateAssetData(loader => @@ -55,7 +57,7 @@ public Asset CreateAsset() .Build(); _assets = _world.Assets; - return Assets.GetAsset(assetId); + return Assets.GetAssetRef(assetId); } public AssetContext CreateAssetContext(Action? assets = null) From 65bba57c8388e96f78e5be9bca87189645fddbf9 Mon Sep 17 00:00:00 2001 From: Kirill Bazhaikin Date: Wed, 26 Aug 2026 23:39:53 +0300 Subject: [PATCH 02/11] Fix parallel worker --- ...UpdateSystemWithParallelWorkerBenchmark.cs | 14 +-- benchmarks/Hexecs.Benchmarks/Program.cs | 2 +- src/Hexecs/Threading/DefaultParallelWorker.cs | 113 +++++++++++------- 3 files changed, 78 insertions(+), 51 deletions(-) diff --git a/benchmarks/Hexecs.Benchmarks/Actors/UpdateSystemWithParallelWorkerBenchmark.cs b/benchmarks/Hexecs.Benchmarks/Actors/UpdateSystemWithParallelWorkerBenchmark.cs index b426bc0..afe613d 100644 --- a/benchmarks/Hexecs.Benchmarks/Actors/UpdateSystemWithParallelWorkerBenchmark.cs +++ b/benchmarks/Hexecs.Benchmarks/Actors/UpdateSystemWithParallelWorkerBenchmark.cs @@ -27,7 +27,7 @@ namespace Hexecs.Benchmarks.Actors; // // ------------------------------------------------------------------------------------ // -// BenchmarkDotNet v0.15.8, macOS Tahoe 26.2 (25C56) [Darwin 25.2.0] +// BenchmarkDotNet v0.15.8, macOS Tahoe 26.6.2 (25G83) [Darwin 25.6.0] // Apple M3 Max, 1 CPU, 16 logical and 16 physical cores // .NET SDK 10.0.102 // [Host] : .NET 10.0.1 (10.0.1, 10.0.125.57005), Arm64 RyuJIT armv8.0-a @@ -37,13 +37,13 @@ namespace Hexecs.Benchmarks.Actors; // // | Method | Count | Mean | Ratio | Allocated | Alloc Ratio | // |-------------------- |-------- |----------:|------:|----------:|------------:| -// | FriFlo_Parallel | 100000 | 30.08 us | 0.33 | - | NA | -// | DefaultEcs_Parallel | 100000 | 86.19 us | 0.94 | - | NA | -// | Hexecs_Parallel | 100000 | 92.12 us | 1.00 | - | NA | +// | FriFlo_Parallel | 100000 | 30.15 us | 0.61 | - | NA | +// | Hexecs_Parallel | 100000 | 49.46 us | 1.00 | - | NA | +// | DefaultEcs_Parallel | 100000 | 89.68 us | 1.81 | - | NA | // | | | | | | | -// | FriFlo_Parallel | 1000000 | 294.42 us | 0.38 | - | NA | -// | Hexecs_Parallel | 1000000 | 783.70 us | 1.00 | - | NA | -// | DefaultEcs_Parallel | 1000000 | 916.69 us | 1.17 | - | NA | +// | FriFlo_Parallel | 1000000 | 295.67 us | 0.78 | - | NA | +// | Hexecs_Parallel | 1000000 | 378.41 us | 1.00 | - | NA | +// | DefaultEcs_Parallel | 1000000 | 906.10 us | 2.39 | - | NA | [SimpleJob(RuntimeMoniker.Net10_0)] [Orderer(SummaryOrderPolicy.FastestToSlowest)] diff --git a/benchmarks/Hexecs.Benchmarks/Program.cs b/benchmarks/Hexecs.Benchmarks/Program.cs index 903dae0..005f12a 100644 --- a/benchmarks/Hexecs.Benchmarks/Program.cs +++ b/benchmarks/Hexecs.Benchmarks/Program.cs @@ -2,5 +2,5 @@ using Hexecs.Benchmarks.Actors; using Hexecs.Benchmarks.Collections; -BenchmarkRunner.Run(); +BenchmarkRunner.Run(); //BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args); diff --git a/src/Hexecs/Threading/DefaultParallelWorker.cs b/src/Hexecs/Threading/DefaultParallelWorker.cs index 530cfba..e6fe8b0 100644 --- a/src/Hexecs/Threading/DefaultParallelWorker.cs +++ b/src/Hexecs/Threading/DefaultParallelWorker.cs @@ -1,4 +1,4 @@ -namespace Hexecs.Threading; +namespace Hexecs.Threading; public sealed class DefaultParallelWorker : IParallelWorker { @@ -6,6 +6,8 @@ public sealed class DefaultParallelWorker : IParallelWorker private readonly Barrier _barrier; private readonly Thread[] _workers; + private readonly CancellationTokenSource _cts; + private readonly CancellationToken _cancellationToken; private IParallelJob? _job; private volatile bool _disposed; @@ -14,19 +16,29 @@ public DefaultParallelWorker( int degreeOfParallelism, ThreadPriority priority = ThreadPriority.AboveNormal) { - if (degreeOfParallelism < 2) ThreadingError.WrongDegreeOfParallelism(); + if (degreeOfParallelism < 2) + throw new ArgumentOutOfRangeException(nameof(degreeOfParallelism), + "Degree of parallelism must be at least 2."); DegreeOfParallelism = degreeOfParallelism; - _barrier = new Barrier(participantCount: degreeOfParallelism + 1); // +1 — основной поток + _cts = new CancellationTokenSource(); + _cancellationToken = _cts.Token; + + // +1 для управляющего потока + _barrier = new Barrier(participantCount: degreeOfParallelism + 1); _workers = new Thread[degreeOfParallelism]; + // Используем countdown, чтобы главный поток не вышел из конструктора, + // пока все воркеры гарантированно не дойдут до первого барьера. + using var startupLatch = new CountdownEvent(degreeOfParallelism); + for (var i = 0; i < degreeOfParallelism; i++) { var workerIndex = i; - var thread = new Thread(() => ExecuteWorker(workerIndex)) + var thread = new Thread(() => ExecuteWorker(workerIndex, startupLatch)) { - IsBackground = false, + IsBackground = false, // Потоки foreground, удерживают приложение Priority = priority, Name = $"ParallelRunner {workerIndex} of {degreeOfParallelism}" }; @@ -34,70 +46,85 @@ public DefaultParallelWorker( _workers[i] = thread; thread.Start(); } + + // Ждем, пока все потоки инициализируются и встанут у барьера + startupLatch.Wait(); } - public void Dispose() + public void Run(IParallelJob job) { - if (_disposed) return; - _disposed = true; + ObjectDisposedException.ThrowIf(_disposed, nameof(DefaultParallelWorker)); + + _job = job; - // Сигналим барьер, чтобы разбудить воркеров — они увидят _disposed и выйдут try { - _barrier.SignalAndWait(); + // Фаза 1: Разрешаем воркерам начать выполнение задачи + _barrier.SignalAndWait(_cancellationToken); + + // Фаза 2: Ожидаем, пока все воркеры завершат задачу + _barrier.SignalAndWait(_cancellationToken); } - catch (ObjectDisposedException) + catch (OperationCanceledException) { - // Уже disposed + // Происходит утилизация воркера во время работы } - - // Ждём завершения воркеров - foreach (var thread in _workers) + finally { - thread.Join(); + _job = null; } - - ArrayUtils.Clear(_workers); - _barrier.Dispose(); } - public void Run(IParallelJob job) - { - ObjectDisposedException.ThrowIf(_disposed, typeof(DefaultParallelWorker)); - - _job = job; - - // Фаза старта: отпускаем всех воркеров - _barrier.SignalAndWait(); - - // Фаза завершения: ждём всех воркеров - _barrier.SignalAndWait(); - - _job = null; - } - - private void ExecuteWorker(int workerIndex) + private void ExecuteWorker(int workerIndex, CountdownEvent startupLatch) { var lastWorkerIndex = _workers.Length - 1; + // Сигнализируем конструктору, что данный поток готов + startupLatch.Signal(); + try { - while (true) + while (!_cancellationToken.IsCancellationRequested) { - // Ждём старт сигнала от основного потока - _barrier.SignalAndWait(); - - if (_disposed) return; + // Точка ожидания 1: Ждем команду "Старт" от метода Run + _barrier.SignalAndWait(_cancellationToken); + // Выполняем работу (проверяем job на null на случай отмены) _job?.Execute(workerIndex, lastWorkerIndex); - // Сообщаем о завершении фазы - _barrier.SignalAndWait(); + // Точка ожидания 2: Сигнализируем о завершении и ждем остальных воркеров + Главный поток + _barrier.SignalAndWait(_cancellationToken); } } + catch (OperationCanceledException) + { + // Нормальный выход при отмене через CTS + } catch (ObjectDisposedException) { - // Барьер уже утилизирован — нормальный выход + // Нормальный выход, если барьер уничтожен } } + + public void Dispose() + { + if (_disposed) return; + _disposed = true; + + // Отменяем токен — это заставит методы SignalAndWait выкинуть OperationCanceledException + // и мгновенно разблокирует все потоки, где бы они ни находились + _cts.Cancel(); + + // Теперь спокойно дожидаемся завершения потоков + foreach (var thread in _workers) + { + if (thread.IsAlive) + { + thread.Join(); + } + } + + _barrier.Dispose(); + _cts.Dispose(); + } } \ No newline at end of file From d3965e8f82bfcc1b1de5f668bcdd623549685f11 Mon Sep 17 00:00:00 2001 From: Kirill Bazhaikin Date: Thu, 27 Aug 2026 00:44:57 +0300 Subject: [PATCH 03/11] Fix parallel worker --- src/Hexecs/Threading/DefaultParallelWorker.cs | 9 ++++++--- .../Threading/DefaultParallelWorkerShould.cs | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/Hexecs/Threading/DefaultParallelWorker.cs b/src/Hexecs/Threading/DefaultParallelWorker.cs index e6fe8b0..dc63624 100644 --- a/src/Hexecs/Threading/DefaultParallelWorker.cs +++ b/src/Hexecs/Threading/DefaultParallelWorker.cs @@ -17,9 +17,12 @@ public DefaultParallelWorker( ThreadPriority priority = ThreadPriority.AboveNormal) { if (degreeOfParallelism < 2) - throw new ArgumentOutOfRangeException(nameof(degreeOfParallelism), - "Degree of parallelism must be at least 2."); - + { + throw new ArgumentOutOfRangeException( + paramName: nameof(degreeOfParallelism), + message: "Degree of parallelism must be at least 2."); + } + DegreeOfParallelism = degreeOfParallelism; _cts = new CancellationTokenSource(); diff --git a/tests/Hexecs.Tests/Threading/DefaultParallelWorkerShould.cs b/tests/Hexecs.Tests/Threading/DefaultParallelWorkerShould.cs index 3078ec3..18dc7de 100644 --- a/tests/Hexecs.Tests/Threading/DefaultParallelWorkerShould.cs +++ b/tests/Hexecs.Tests/Threading/DefaultParallelWorkerShould.cs @@ -179,7 +179,7 @@ public void WorkCorrectlyInGameLoop() [Fact(DisplayName = "НЕ должен работать с DegreeOfParallelism < 2")] public void ThrowIfDegreeOfParallelismIsOne() { - Assert.Throws(() => new DefaultParallelWorker(1)); + Assert.Throws(() => new DefaultParallelWorker(1)); } private sealed class TestParallelJob : IParallelJob From 6d10ac06f02185c32888301120d3e1cf876c8d83 Mon Sep 17 00:00:00 2001 From: Kirill Bazhaikin Date: Thu, 27 Aug 2026 01:20:24 +0300 Subject: [PATCH 04/11] Update benchmarks --- .../ActorFilter2EnumerationBenchmark.cs | 26 +++++++++---------- .../ActorFilter3EnumerationBenchmark.cs | 26 +++++++++---------- benchmarks/Hexecs.Benchmarks/Program.cs | 3 +-- 3 files changed, 27 insertions(+), 28 deletions(-) diff --git a/benchmarks/Hexecs.Benchmarks/Actors/ActorFilter2EnumerationBenchmark.cs b/benchmarks/Hexecs.Benchmarks/Actors/ActorFilter2EnumerationBenchmark.cs index 5243d5e..2a3bd3f 100644 --- a/benchmarks/Hexecs.Benchmarks/Actors/ActorFilter2EnumerationBenchmark.cs +++ b/benchmarks/Hexecs.Benchmarks/Actors/ActorFilter2EnumerationBenchmark.cs @@ -28,27 +28,27 @@ namespace Hexecs.Benchmarks.Actors; // // ------------------------------------------------------------------------------------ // -// BenchmarkDotNet v0.15.8, macOS Tahoe 26.2 (25C56) [Darwin 25.2.0] +// BenchmarkDotNet v0.15.8, macOS Tahoe 26.6.2 (25G83) [Darwin 25.6.0] // Apple M3 Max, 1 CPU, 16 logical and 16 physical cores -// .NET SDK 10.0.102 +// .NET SDK 10.0.400 // [Host] : .NET 10.0.1 (10.0.1, 10.0.125.57005), Arm64 RyuJIT armv8.0-a -// .NET 10.0 : .NET 10.0.2 (10.0.2, 10.0.225.61305), Arm64 RyuJIT armv8.0-a +// .NET 10.0 : .NET 10.0.11 (10.0.11, 10.0.1126.37416), Arm64 RyuJIT armv8.0-a // // Job=.NET 10.0 Runtime=.NET 10.0 // // | Method | Count | Mean | Ratio | Gen0 | Allocated | Alloc Ratio | // |----------------------- |------- |----------:|------:|-------:|----------:|------------:| -// | FriFlo | 10000 | 6.614 us | 0.66 | 0.0076 | 88 B | NA | -// | FriFlo_Chunks | 10000 | 6.716 us | 0.67 | - | - | NA | -// | Hexecs_ComponentAccess | 10000 | 8.878 us | 0.88 | - | - | NA | -// | DefaultEcs | 10000 | 9.770 us | 0.97 | - | - | NA | -// | Hexecs | 10000 | 10.078 us | 1.00 | - | - | NA | +// | FriFlo | 10000 | 5.864 us | 0.57 | 0.0076 | 88 B | NA | +// | FriFlo_Chunks | 10000 | 6.740 us | 0.65 | - | - | NA | +// | Hexecs_ComponentAccess | 10000 | 9.124 us | 0.88 | - | - | NA | +// | DefaultEcs | 10000 | 9.672 us | 0.93 | - | - | NA | +// | Hexecs | 10000 | 10.357 us | 1.00 | - | - | NA | // | | | | | | | | -// | FriFlo | 100000 | 65.792 us | 0.70 | - | 88 B | NA | -// | FriFlo_Chunks | 100000 | 67.258 us | 0.72 | - | - | NA | -// | Hexecs_ComponentAccess | 100000 | 84.009 us | 0.90 | - | - | NA | -// | DefaultEcs | 100000 | 92.408 us | 0.98 | - | - | NA | -// | Hexecs | 100000 | 93.853 us | 1.00 | - | - | NA | +// | FriFlo | 100000 | 56.446 us | 0.60 | - | 88 B | NA | +// | FriFlo_Chunks | 100000 | 67.383 us | 0.72 | - | - | NA | +// | Hexecs_ComponentAccess | 100000 | 83.895 us | 0.89 | - | - | NA | +// | DefaultEcs | 100000 | 92.942 us | 0.99 | - | - | NA | +// | Hexecs | 100000 | 93.962 us | 1.00 | - | - | NA | [SimpleJob(RuntimeMoniker.Net10_0)] [Orderer(SummaryOrderPolicy.FastestToSlowest)] diff --git a/benchmarks/Hexecs.Benchmarks/Actors/ActorFilter3EnumerationBenchmark.cs b/benchmarks/Hexecs.Benchmarks/Actors/ActorFilter3EnumerationBenchmark.cs index 0d66d63..85c2d50 100644 --- a/benchmarks/Hexecs.Benchmarks/Actors/ActorFilter3EnumerationBenchmark.cs +++ b/benchmarks/Hexecs.Benchmarks/Actors/ActorFilter3EnumerationBenchmark.cs @@ -29,27 +29,27 @@ namespace Hexecs.Benchmarks.Actors; // // ------------------------------------------------------------------------------------ // -// BenchmarkDotNet v0.15.8, macOS Tahoe 26.2 (25C56) [Darwin 25.2.0] +// BenchmarkDotNet v0.15.8, macOS Tahoe 26.6.2 (25G83) [Darwin 25.6.0] // Apple M3 Max, 1 CPU, 16 logical and 16 physical cores -// .NET SDK 10.0.102 +// .NET SDK 10.0.400 // [Host] : .NET 10.0.1 (10.0.1, 10.0.125.57005), Arm64 RyuJIT armv8.0-a -// .NET 10.0 : .NET 10.0.2 (10.0.2, 10.0.225.61305), Arm64 RyuJIT armv8.0-a +// .NET 10.0 : .NET 10.0.11 (10.0.11, 10.0.1126.37416), Arm64 RyuJIT armv8.0-a // // Job=.NET 10.0 Runtime=.NET 10.0 // // | Method | Count | Mean | Ratio | Allocated | Alloc Ratio | // |----------------------- |------- |-----------:|------:|----------:|------------:| -// | FriFlo | 10000 | 9.383 us | 0.69 | 88 B | NA | -// | FriFlo_Chunks | 10000 | 9.538 us | 0.70 | - | NA | -// | Hexecs_ComponentAccess | 10000 | 12.621 us | 0.93 | - | NA | -// | DefaultEcs | 10000 | 13.351 us | 0.99 | - | NA | -// | Hexecs | 10000 | 13.534 us | 1.00 | - | NA | +// | FriFlo | 10000 | 8.304 us | 0.59 | 88 B | NA | +// | FriFlo_Chunks | 10000 | 9.552 us | 0.68 | - | NA | +// | Hexecs_ComponentAccess | 10000 | 12.520 us | 0.90 | - | NA | +// | DefaultEcs | 10000 | 13.495 us | 0.96 | - | NA | +// | Hexecs | 10000 | 13.987 us | 1.00 | - | NA | // | | | | | | | -// | FriFlo | 100000 | 91.925 us | 0.65 | 88 B | NA | -// | FriFlo_Chunks | 100000 | 94.962 us | 0.67 | - | NA | -// | Hexecs_ComponentAccess | 100000 | 131.812 us | 0.93 | - | NA | -// | Hexecs | 100000 | 142.264 us | 1.00 | - | NA | -// | DefaultEcs | 100000 | 158.585 us | 1.11 | - | NA | +// | FriFlo | 100000 | 82.093 us | 0.58 | 88 B | NA | +// | FriFlo_Chunks | 100000 | 95.106 us | 0.67 | - | NA | +// | Hexecs_ComponentAccess | 100000 | 132.204 us | 0.93 | - | NA | +// | Hexecs | 100000 | 142.729 us | 1.00 | - | NA | +// | DefaultEcs | 100000 | 158.741 us | 1.11 | - | NA | [SimpleJob(RuntimeMoniker.Net10_0)] [Orderer(SummaryOrderPolicy.FastestToSlowest)] diff --git a/benchmarks/Hexecs.Benchmarks/Program.cs b/benchmarks/Hexecs.Benchmarks/Program.cs index 005f12a..ba0951a 100644 --- a/benchmarks/Hexecs.Benchmarks/Program.cs +++ b/benchmarks/Hexecs.Benchmarks/Program.cs @@ -1,6 +1,5 @@ using BenchmarkDotNet.Running; using Hexecs.Benchmarks.Actors; -using Hexecs.Benchmarks.Collections; -BenchmarkRunner.Run(); +BenchmarkRunner.Run(); //BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args); From 7e4b3341c658d18dfdaadc076f591d9b8303b020 Mon Sep 17 00:00:00 2001 From: Kirill Bazhaikin Date: Thu, 27 Aug 2026 01:55:02 +0300 Subject: [PATCH 05/11] Update benchmarks --- .../ActorFilter2EnumerationBenchmark.cs | 20 +++++++------- .../ActorFilter3EnumerationBenchmark.cs | 20 +++++++------- ...UpdateSystemWithParallelWorkerBenchmark.cs | 16 +++++------ .../Collections/SparsePageDictionary.cs | 1 - benchmarks/Hexecs.Benchmarks/Program.cs | 2 +- src/Hexecs/Assets/Delegates/AssetPredicate.cs | 2 -- src/Hexecs/Utils/ComponentsAccess.cs | 27 +++++++++++++------ src/Hexecs/Utils/ValueStringBuilder.cs | 2 -- 8 files changed, 48 insertions(+), 42 deletions(-) diff --git a/benchmarks/Hexecs.Benchmarks/Actors/ActorFilter2EnumerationBenchmark.cs b/benchmarks/Hexecs.Benchmarks/Actors/ActorFilter2EnumerationBenchmark.cs index 2a3bd3f..7d96f22 100644 --- a/benchmarks/Hexecs.Benchmarks/Actors/ActorFilter2EnumerationBenchmark.cs +++ b/benchmarks/Hexecs.Benchmarks/Actors/ActorFilter2EnumerationBenchmark.cs @@ -38,17 +38,17 @@ namespace Hexecs.Benchmarks.Actors; // // | Method | Count | Mean | Ratio | Gen0 | Allocated | Alloc Ratio | // |----------------------- |------- |----------:|------:|-------:|----------:|------------:| -// | FriFlo | 10000 | 5.864 us | 0.57 | 0.0076 | 88 B | NA | -// | FriFlo_Chunks | 10000 | 6.740 us | 0.65 | - | - | NA | -// | Hexecs_ComponentAccess | 10000 | 9.124 us | 0.88 | - | - | NA | -// | DefaultEcs | 10000 | 9.672 us | 0.93 | - | - | NA | -// | Hexecs | 10000 | 10.357 us | 1.00 | - | - | NA | +// | FriFlo | 10000 | 6.061 us | 0.71 | 0.0076 | 88 B | NA | +// | Hexecs_ComponentAccess | 10000 | 6.241 us | 0.73 | - | - | NA | +// | FriFlo_Chunks | 10000 | 6.732 us | 0.79 | - | - | NA | +// | Hexecs | 10000 | 8.534 us | 1.00 | - | - | NA | +// | DefaultEcs | 10000 | 9.906 us | 1.16 | - | - | NA | // | | | | | | | | -// | FriFlo | 100000 | 56.446 us | 0.60 | - | 88 B | NA | -// | FriFlo_Chunks | 100000 | 67.383 us | 0.72 | - | - | NA | -// | Hexecs_ComponentAccess | 100000 | 83.895 us | 0.89 | - | - | NA | -// | DefaultEcs | 100000 | 92.942 us | 0.99 | - | - | NA | -// | Hexecs | 100000 | 93.962 us | 1.00 | - | - | NA | +// | FriFlo | 100000 | 56.486 us | 0.77 | - | 88 B | NA | +// | Hexecs_ComponentAccess | 100000 | 56.937 us | 0.77 | - | - | NA | +// | FriFlo_Chunks | 100000 | 67.463 us | 0.92 | - | - | NA | +// | Hexecs | 100000 | 73.653 us | 1.00 | - | - | NA | +// | DefaultEcs | 100000 | 93.593 us | 1.27 | - | - | NA | [SimpleJob(RuntimeMoniker.Net10_0)] [Orderer(SummaryOrderPolicy.FastestToSlowest)] diff --git a/benchmarks/Hexecs.Benchmarks/Actors/ActorFilter3EnumerationBenchmark.cs b/benchmarks/Hexecs.Benchmarks/Actors/ActorFilter3EnumerationBenchmark.cs index 85c2d50..bca3bf0 100644 --- a/benchmarks/Hexecs.Benchmarks/Actors/ActorFilter3EnumerationBenchmark.cs +++ b/benchmarks/Hexecs.Benchmarks/Actors/ActorFilter3EnumerationBenchmark.cs @@ -39,17 +39,17 @@ namespace Hexecs.Benchmarks.Actors; // // | Method | Count | Mean | Ratio | Allocated | Alloc Ratio | // |----------------------- |------- |-----------:|------:|----------:|------------:| -// | FriFlo | 10000 | 8.304 us | 0.59 | 88 B | NA | -// | FriFlo_Chunks | 10000 | 9.552 us | 0.68 | - | NA | -// | Hexecs_ComponentAccess | 10000 | 12.520 us | 0.90 | - | NA | -// | DefaultEcs | 10000 | 13.495 us | 0.96 | - | NA | -// | Hexecs | 10000 | 13.987 us | 1.00 | - | NA | +// | Hexecs_ComponentAccess | 10000 | 8.256 us | 0.81 | - | NA | +// | FriFlo | 10000 | 8.398 us | 0.82 | 88 B | NA | +// | FriFlo_Chunks | 10000 | 9.560 us | 0.93 | - | NA | +// | Hexecs | 10000 | 10.240 us | 1.00 | - | NA | +// | DefaultEcs | 10000 | 13.360 us | 1.30 | - | NA | // | | | | | | | -// | FriFlo | 100000 | 82.093 us | 0.58 | 88 B | NA | -// | FriFlo_Chunks | 100000 | 95.106 us | 0.67 | - | NA | -// | Hexecs_ComponentAccess | 100000 | 132.204 us | 0.93 | - | NA | -// | Hexecs | 100000 | 142.729 us | 1.00 | - | NA | -// | DefaultEcs | 100000 | 158.741 us | 1.11 | - | NA | +// | FriFlo | 100000 | 83.226 us | 0.79 | 88 B | NA | +// | Hexecs_ComponentAccess | 100000 | 84.102 us | 0.80 | - | NA | +// | FriFlo_Chunks | 100000 | 95.161 us | 0.91 | - | NA | +// | Hexecs | 100000 | 104.746 us | 1.00 | - | NA | +// | DefaultEcs | 100000 | 162.182 us | 1.55 | - | NA | [SimpleJob(RuntimeMoniker.Net10_0)] [Orderer(SummaryOrderPolicy.FastestToSlowest)] diff --git a/benchmarks/Hexecs.Benchmarks/Actors/UpdateSystemWithParallelWorkerBenchmark.cs b/benchmarks/Hexecs.Benchmarks/Actors/UpdateSystemWithParallelWorkerBenchmark.cs index afe613d..9c8ee55 100644 --- a/benchmarks/Hexecs.Benchmarks/Actors/UpdateSystemWithParallelWorkerBenchmark.cs +++ b/benchmarks/Hexecs.Benchmarks/Actors/UpdateSystemWithParallelWorkerBenchmark.cs @@ -29,21 +29,21 @@ namespace Hexecs.Benchmarks.Actors; // // BenchmarkDotNet v0.15.8, macOS Tahoe 26.6.2 (25G83) [Darwin 25.6.0] // Apple M3 Max, 1 CPU, 16 logical and 16 physical cores -// .NET SDK 10.0.102 +// .NET SDK 10.0.400 // [Host] : .NET 10.0.1 (10.0.1, 10.0.125.57005), Arm64 RyuJIT armv8.0-a -// .NET 10.0 : .NET 10.0.2 (10.0.2, 10.0.225.61305), Arm64 RyuJIT armv8.0-a +// .NET 10.0 : .NET 10.0.11 (10.0.11, 10.0.1126.37416), Arm64 RyuJIT armv8.0-a // // Job=.NET 10.0 Runtime=.NET 10.0 // // | Method | Count | Mean | Ratio | Allocated | Alloc Ratio | // |-------------------- |-------- |----------:|------:|----------:|------------:| -// | FriFlo_Parallel | 100000 | 30.15 us | 0.61 | - | NA | -// | Hexecs_Parallel | 100000 | 49.46 us | 1.00 | - | NA | -// | DefaultEcs_Parallel | 100000 | 89.68 us | 1.81 | - | NA | +// | FriFlo_Parallel | 100000 | 30.01 us | 0.66 | - | NA | +// | Hexecs_Parallel | 100000 | 45.29 us | 1.00 | - | NA | +// | DefaultEcs_Parallel | 100000 | 87.11 us | 1.92 | - | NA | // | | | | | | | -// | FriFlo_Parallel | 1000000 | 295.67 us | 0.78 | - | NA | -// | Hexecs_Parallel | 1000000 | 378.41 us | 1.00 | - | NA | -// | DefaultEcs_Parallel | 1000000 | 906.10 us | 2.39 | - | NA | +// | FriFlo_Parallel | 1000000 | 294.72 us | 0.88 | - | NA | +// | Hexecs_Parallel | 1000000 | 334.05 us | 1.00 | - | NA | +// | DefaultEcs_Parallel | 1000000 | 796.86 us | 2.39 | - | NA | [SimpleJob(RuntimeMoniker.Net10_0)] [Orderer(SummaryOrderPolicy.FastestToSlowest)] diff --git a/benchmarks/Hexecs.Benchmarks/Collections/SparsePageDictionary.cs b/benchmarks/Hexecs.Benchmarks/Collections/SparsePageDictionary.cs index 1109bd0..d75469d 100644 --- a/benchmarks/Hexecs.Benchmarks/Collections/SparsePageDictionary.cs +++ b/benchmarks/Hexecs.Benchmarks/Collections/SparsePageDictionary.cs @@ -1,5 +1,4 @@ using System.Runtime.InteropServices; -using Hexecs.Utils; namespace Hexecs.Benchmarks.Collections; diff --git a/benchmarks/Hexecs.Benchmarks/Program.cs b/benchmarks/Hexecs.Benchmarks/Program.cs index ba0951a..3a5c65d 100644 --- a/benchmarks/Hexecs.Benchmarks/Program.cs +++ b/benchmarks/Hexecs.Benchmarks/Program.cs @@ -1,5 +1,5 @@ using BenchmarkDotNet.Running; using Hexecs.Benchmarks.Actors; -BenchmarkRunner.Run(); +BenchmarkRunner.Run(); //BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args); diff --git a/src/Hexecs/Assets/Delegates/AssetPredicate.cs b/src/Hexecs/Assets/Delegates/AssetPredicate.cs index 4e481c5..94d8074 100644 --- a/src/Hexecs/Assets/Delegates/AssetPredicate.cs +++ b/src/Hexecs/Assets/Delegates/AssetPredicate.cs @@ -1,5 +1,3 @@ -using Hexecs.Actors; - namespace Hexecs.Assets.Delegates; public delegate bool AssetPredicate(in AssetRef component) diff --git a/src/Hexecs/Utils/ComponentsAccess.cs b/src/Hexecs/Utils/ComponentsAccess.cs index f405985..92f1708 100644 --- a/src/Hexecs/Utils/ComponentsAccess.cs +++ b/src/Hexecs/Utils/ComponentsAccess.cs @@ -2,16 +2,22 @@ public readonly ref struct ComponentsAccess { - private readonly uint[] _sparse; - private readonly T[] _values; + public static ComponentsAccess Empty + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => new(); + } + + private readonly ReadOnlySpan _sparse; + private readonly Span _values; [MethodImpl(MethodImplOptions.AggressiveInlining)] public ComponentsAccess() { - _sparse = []; - _values = []; + _sparse = ReadOnlySpan.Empty; + _values = Span.Empty; } - + [MethodImpl(MethodImplOptions.AggressiveInlining)] internal ComponentsAccess(uint[] sparse, T[] values) { @@ -22,8 +28,13 @@ internal ComponentsAccess(uint[] sparse, T[] values) public ref T this[uint id] { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => ref Unsafe.Add( - ref MemoryMarshal.GetArrayDataReference(_values), - (int)Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(_sparse), (int)id) - 1); + get + { + ref var sparseStart = ref MemoryMarshal.GetReference(_sparse); + ref var valuesStart = ref MemoryMarshal.GetReference(_values); + + var denseIndex = (int)Unsafe.Add(ref sparseStart, (nint)id) - 1; + return ref Unsafe.Add(ref valuesStart, (nint)denseIndex); + } } } \ No newline at end of file diff --git a/src/Hexecs/Utils/ValueStringBuilder.cs b/src/Hexecs/Utils/ValueStringBuilder.cs index 03fb7bd..1d2eea6 100644 --- a/src/Hexecs/Utils/ValueStringBuilder.cs +++ b/src/Hexecs/Utils/ValueStringBuilder.cs @@ -1,6 +1,4 @@ using System.Globalization; -using Hexecs.Actors; -using Hexecs.Assets; namespace Hexecs.Utils; From 862c9c34062152fffec8468c92fb7a591d468313 Mon Sep 17 00:00:00 2001 From: Kirill Bazhaikin Date: Thu, 27 Aug 2026 02:21:08 +0300 Subject: [PATCH 06/11] Update benchmarks --- .../ActorCheckComponentExistsBenchmark.cs | 32 +++++++++---------- ...ctorCreateAddComponentsDestroyBenchmark.cs | 26 +++++++-------- benchmarks/Hexecs.Benchmarks/Program.cs | 2 +- 3 files changed, 30 insertions(+), 30 deletions(-) diff --git a/benchmarks/Hexecs.Benchmarks/Actors/ActorCheckComponentExistsBenchmark.cs b/benchmarks/Hexecs.Benchmarks/Actors/ActorCheckComponentExistsBenchmark.cs index c95130d..6aa79c8 100644 --- a/benchmarks/Hexecs.Benchmarks/Actors/ActorCheckComponentExistsBenchmark.cs +++ b/benchmarks/Hexecs.Benchmarks/Actors/ActorCheckComponentExistsBenchmark.cs @@ -29,27 +29,27 @@ namespace Hexecs.Benchmarks.Actors; // // ------------------------------------------------------------------------------------ // -// BenchmarkDotNet v0.15.8, macOS Tahoe 26.2 (25C56) [Darwin 25.2.0] +// BenchmarkDotNet v0.15.8, macOS Tahoe 26.6.2 (25G83) [Darwin 25.6.0] // Apple M3 Max, 1 CPU, 16 logical and 16 physical cores -// .NET SDK 10.0.102 +// .NET SDK 10.0.400 // [Host] : .NET 10.0.1 (10.0.1, 10.0.125.57005), Arm64 RyuJIT armv8.0-a -// .NET 10.0 : .NET 10.0.2 (10.0.2, 10.0.225.61305), Arm64 RyuJIT armv8.0-a +// .NET 10.0 : .NET 10.0.11 (10.0.11, 10.0.1126.37416), Arm64 RyuJIT armv8.0-a // // Job=.NET 10.0 Runtime=.NET 10.0 // -// | Method | Count | Mean | Ratio | Allocated | Alloc Ratio | -// |----------------- |------- |-----------:|------:|----------:|------------:| -// | Hexecs_Is | 10000 | 9.916 us | 0.90 | - | NA | -// | Hexecs_Has | 10000 | 10.960 us | 1.00 | - | NA | -// | Hexecs_Reference | 10000 | 11.301 us | 1.03 | - | NA | -// | FriFlo_Has | 10000 | 16.540 us | 1.51 | - | NA | -// | DefaultEcs_Has | 10000 | 25.877 us | 2.36 | - | NA | -// | | | | | | | -// | Hexecs_Is | 100000 | 98.966 us | 0.90 | - | NA | -// | Hexecs_Has | 100000 | 110.039 us | 1.00 | - | NA | -// | Hexecs_Reference | 100000 | 112.981 us | 1.03 | - | NA | -// | FriFlo_Has | 100000 | 159.346 us | 1.45 | - | NA | -// | DefaultEcs_Has | 100000 | 256.135 us | 2.33 | - | NA | +// | Method | Count | Mean | Ratio | Allocated | Alloc Ratio | +// |----------------- |------- |----------:|------:|----------:|------------:| +// | Hexecs_Has | 10000 | 10.95 us | 1.00 | - | NA | +// | Hexecs_Is | 10000 | 11.30 us | 1.03 | - | NA | +// | Hexecs_Reference | 10000 | 11.30 us | 1.03 | - | NA | +// | FriFlo_Has | 10000 | 16.38 us | 1.50 | - | NA | +// | DefaultEcs_Has | 10000 | 25.62 us | 2.34 | - | NA | +// | | | | | | | +// | Hexecs_Has | 100000 | 110.84 us | 1.00 | - | NA | +// | Hexecs_Reference | 100000 | 113.48 us | 1.02 | - | NA | +// | Hexecs_Is | 100000 | 113.51 us | 1.02 | - | NA | +// | FriFlo_Has | 100000 | 159.75 us | 1.44 | - | NA | +// | DefaultEcs_Has | 100000 | 254.32 us | 2.29 | - | NA | [SimpleJob(RuntimeMoniker.Net10_0)] [Orderer(SummaryOrderPolicy.FastestToSlowest)] diff --git a/benchmarks/Hexecs.Benchmarks/Actors/ActorCreateAddComponentsDestroyBenchmark.cs b/benchmarks/Hexecs.Benchmarks/Actors/ActorCreateAddComponentsDestroyBenchmark.cs index 76ee82f..93ebbe2 100644 --- a/benchmarks/Hexecs.Benchmarks/Actors/ActorCreateAddComponentsDestroyBenchmark.cs +++ b/benchmarks/Hexecs.Benchmarks/Actors/ActorCreateAddComponentsDestroyBenchmark.cs @@ -30,27 +30,27 @@ namespace Hexecs.Benchmarks.Actors; // // --------------------------------------------------------------------------------------------------------- // -// BenchmarkDotNet v0.15.8, macOS Tahoe 26.2 (25C56) [Darwin 25.2.0] +// BenchmarkDotNet v0.15.8, macOS Tahoe 26.6.2 (25G83) [Darwin 25.6.0] // Apple M3 Max, 1 CPU, 16 logical and 16 physical cores -// .NET SDK 10.0.102 +// .NET SDK 10.0.400 // [Host] : .NET 10.0.1 (10.0.1, 10.0.125.57005), Arm64 RyuJIT armv8.0-a -// .NET 10.0 : .NET 10.0.2 (10.0.2, 10.0.225.61305), Arm64 RyuJIT armv8.0-a +// .NET 10.0 : .NET 10.0.11 (10.0.11, 10.0.1126.37416), Arm64 RyuJIT armv8.0-a // // Job=.NET 10.0 Runtime=.NET 10.0 // // | Method | Count | Mean | Ratio | Gen0 | Gen1 | Allocated | Alloc Ratio | // |---------------------------- |------- |--------------:|------:|----------:|---------:|-----------:|------------:| -// | FriFlo_CreateAddDestroy | 1000 | 70.04 us | 0.45 | - | - | - | NA | -// | Hexecs_CreateAddDestroy | 1000 | 156.05 us | 1.00 | - | - | - | NA | -// | DefaultEcs_CreateAddDestroy | 1000 | 206.26 us | 1.32 | 3.6621 | - | 32000 B | NA | +// | FriFlo_CreateAddDestroy | 1000 | 64.36 us | 0.40 | - | - | - | NA | +// | Hexecs_CreateAddDestroy | 1000 | 162.46 us | 1.00 | - | - | - | NA | +// | DefaultEcs_CreateAddDestroy | 1000 | 207.01 us | 1.27 | 3.6621 | - | 32000 B | NA | // | | | | | | | | | -// | FriFlo_CreateAddDestroy | 100000 | 7,036.37 us | 0.41 | - | - | 40 B | 1.00 | -// | Hexecs_CreateAddDestroy | 100000 | 16,996.78 us | 1.00 | - | - | 40 B | 1.00 | -// | DefaultEcs_CreateAddDestroy | 100000 | 22,336.53 us | 1.31 | 375.0000 | 156.2500 | 3200040 B | 80,001.00 | +// | FriFlo_CreateAddDestroy | 100000 | 7,036.00 us | 0.40 | - | - | 40 B | 1.00 | +// | Hexecs_CreateAddDestroy | 100000 | 17,473.30 us | 1.00 | - | - | 40 B | 1.00 | +// | DefaultEcs_CreateAddDestroy | 100000 | 22,755.83 us | 1.30 | 375.0000 | 156.2500 | 3200040 B | 80,001.00 | // | | | | | | | | | -// | FriFlo_CreateAddDestroy | 500000 | 33,983.08 us | 0.36 | - | - | 40 B | 1.00 | -// | Hexecs_CreateAddDestroy | 500000 | 93,505.58 us | 1.00 | - | - | 40 B | 1.00 | -// | DefaultEcs_CreateAddDestroy | 500000 | 122,641.64 us | 1.31 | 1800.0000 | 800.0000 | 16000040 B | 400,001.00 | +// | FriFlo_CreateAddDestroy | 500000 | 35,389.70 us | 0.37 | - | - | 40 B | 1.00 | +// | Hexecs_CreateAddDestroy | 500000 | 95,996.62 us | 1.00 | - | - | 40 B | 1.00 | +// | DefaultEcs_CreateAddDestroy | 500000 | 121,362.58 us | 1.26 | 1800.0000 | 800.0000 | 16000040 B | 400,001.00 | [SimpleJob(RuntimeMoniker.Net10_0)] [Orderer(SummaryOrderPolicy.FastestToSlowest)] @@ -247,7 +247,7 @@ public void Setup() { actor.Destroy(); } - + _defaultEntities.Clear(); _frifloEntities.Clear(); _hexecsActors.Clear(); diff --git a/benchmarks/Hexecs.Benchmarks/Program.cs b/benchmarks/Hexecs.Benchmarks/Program.cs index 3a5c65d..4fb1ede 100644 --- a/benchmarks/Hexecs.Benchmarks/Program.cs +++ b/benchmarks/Hexecs.Benchmarks/Program.cs @@ -1,5 +1,5 @@ using BenchmarkDotNet.Running; using Hexecs.Benchmarks.Actors; -BenchmarkRunner.Run(); +BenchmarkRunner.Run(); //BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args); From 824e6e040dc2f66e32c18ef31e86099ca616c962 Mon Sep 17 00:00:00 2001 From: Kirill Bazhaikin Date: Thu, 27 Aug 2026 02:23:07 +0300 Subject: [PATCH 07/11] Bump version --- src/Hexecs/Hexecs.csproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Hexecs/Hexecs.csproj b/src/Hexecs/Hexecs.csproj index bd57d4b..6efd237 100644 --- a/src/Hexecs/Hexecs.csproj +++ b/src/Hexecs/Hexecs.csproj @@ -14,8 +14,8 @@ Hexecs Simple Entity Component System framework - 0.4.4 - 0.4.4 + 0.4.5 + 0.4.5 git git://github.com/teoadal/Hexecs Hexecs From 223b281346eb0f65f58395ff0d3d8d9a0eebbe2a Mon Sep 17 00:00:00 2001 From: Kirill Bazhaikin Date: Thu, 27 Aug 2026 02:25:23 +0300 Subject: [PATCH 08/11] Cleanup --- tests/Hexecs.Tests/Actors/ActorListShould.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/Hexecs.Tests/Actors/ActorListShould.cs b/tests/Hexecs.Tests/Actors/ActorListShould.cs index 7143703..11c8696 100644 --- a/tests/Hexecs.Tests/Actors/ActorListShould.cs +++ b/tests/Hexecs.Tests/Actors/ActorListShould.cs @@ -135,7 +135,6 @@ public void Should_Add_Using_Different_References(bool useActorRef) list.Add(actor); } - // Assert list .Contains(actor.Id) From 5022a3f3d1d9b776219b9829a407c72062a8f1d0 Mon Sep 17 00:00:00 2001 From: Kirill Bazhaikin Date: Thu, 27 Aug 2026 02:36:00 +0300 Subject: [PATCH 09/11] Added editorconfig --- .editorconfig | 130 +++++++++ .../Hexecs.Tests/Actors/ActorFilter1Should.cs | 28 +- tests/Hexecs.Tests/Actors/ActorListShould.cs | 20 +- .../Assets/AssetConstraintShould.cs | 24 +- .../Hexecs.Tests/Assets/AssetContextShould.cs | 13 +- .../Hexecs.Tests/Assets/AssetFilter1Should.cs | 68 ++--- .../Hexecs.Tests/Assets/AssetFilter2Should.cs | 92 +++--- .../Hexecs.Tests/Assets/AssetFilter3Should.cs | 62 +++-- .../Assets/AssetMethodsConsistencyTests.cs | 98 ++++--- .../Collections/ArrayEnumeratorShould.cs | 29 +- tests/Hexecs.Tests/Collections/BlockShould.cs | 61 ++-- .../Hexecs.Tests/Collections/BucketShould.cs | 76 ++--- .../Collections/InlineBucketShould.cs | 263 +++++++++--------- .../Collections/ThreadLocalStackShould.cs | 95 ++++--- .../ConfigurationserviceShould.cs | 29 +- .../Threading/DefaultParallelWorkerShould.cs | 46 +-- .../Utils/ValueStringBuilderShould.cs | 164 +++++------ 17 files changed, 765 insertions(+), 533 deletions(-) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..df41990 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,130 @@ +[*] +charset = utf-8 +end_of_line = lf +trim_trailing_whitespace = true +insert_final_newline = true +indent_style = space +indent_size = 4 + +# Microsoft .NET properties +csharp_new_line_before_members_in_object_initializers = false +csharp_preferred_modifier_order = public, private, protected, internal, new, static, abstract, virtual, sealed, readonly, override, extern, unsafe, volatile, async, required:suggestion +csharp_prefer_braces = true:error +csharp_style_namespace_declarations = file_scoped:warning +dotnet_naming_rule.private_constants_rule.severity = warning +dotnet_naming_rule.private_constants_rule.style = upper_camel_case_style +dotnet_naming_rule.private_constants_rule.symbols = private_constants_symbols +dotnet_naming_rule.private_static_fields_rule.severity = warning +dotnet_naming_rule.private_static_fields_rule.style = upper_camel_case_style +dotnet_naming_rule.private_static_fields_rule.symbols = private_static_fields_symbols +dotnet_naming_rule.private_static_readonly_rule.severity = warning +dotnet_naming_rule.private_static_readonly_rule.style = upper_camel_case_style +dotnet_naming_rule.private_static_readonly_rule.symbols = private_static_readonly_symbols +dotnet_naming_style.lower_camel_case_style.capitalization = camel_case +dotnet_naming_style.upper_camel_case_style.capitalization = pascal_case +dotnet_naming_symbols.private_constants_symbols.applicable_accessibilities = private +dotnet_naming_symbols.private_constants_symbols.applicable_kinds = field +dotnet_naming_symbols.private_constants_symbols.required_modifiers = const +dotnet_naming_symbols.private_static_fields_symbols.applicable_accessibilities = private +dotnet_naming_symbols.private_static_fields_symbols.applicable_kinds = field +dotnet_naming_symbols.private_static_fields_symbols.required_modifiers = static +dotnet_naming_symbols.private_static_readonly_symbols.applicable_accessibilities = private +dotnet_naming_symbols.private_static_readonly_symbols.applicable_kinds = field +dotnet_naming_symbols.private_static_readonly_symbols.required_modifiers = static, readonly +dotnet_separate_import_directive_groups = true +dotnet_style_parentheses_in_arithmetic_binary_operators = never_if_unnecessary:warning +dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:warning +dotnet_style_parentheses_in_relational_binary_operators = never_if_unnecessary:warning +dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion +dotnet_style_predefined_type_for_member_access = true:suggestion +dotnet_style_qualification_for_event = false:warning +dotnet_style_qualification_for_field = false:warning +dotnet_style_qualification_for_method = false:warning +dotnet_style_qualification_for_property = false:warning +dotnet_style_require_accessibility_modifiers = for_non_interface_members:warning + +# ReSharper properties +resharper_align_multiline_binary_expressions_chain = false +resharper_autodetect_indent_settings = true +resharper_blank_lines_around_single_line_local_method = 1 +resharper_blank_lines_before_block_statements = 1 +resharper_blank_lines_before_control_transfer_statements = 1 +resharper_blank_lines_before_single_line_comment = 1 +resharper_blank_lines_around_property = 1 +resharper_blank_lines_around_single_line_auto_property = 1 +resharper_blank_lines_around_single_line_property = 1 +resharper_blank_lines_around_auto_property = 1 +resharper_braces_redundant = true +resharper_csharp_keep_blank_lines_in_code = 1 +resharper_csharp_keep_blank_lines_in_declarations = 1 +resharper_csharp_max_line_length = 170 +resharper_csharp_stick_comment = false +resharper_csharp_wrap_after_declaration_lpar = true +resharper_csharp_wrap_after_invocation_lpar = true +resharper_csharp_wrap_arguments_style = chop_if_long +resharper_csharp_wrap_before_first_type_parameter_constraint = true +resharper_csharp_wrap_extends_list_style = chop_if_long +resharper_csharp_wrap_parameters_style = chop_if_long +resharper_csharp_space_within_single_line_array_initializer_braces = true +resharper_enforce_line_ending_style = true +resharper_for_built_in_types = use_var_when_evident +resharper_for_simple_types = use_var_when_evident +resharper_for_other_types = use_var_when_evident +resharper_keep_existing_declaration_parens_arrangement = false +resharper_keep_existing_embedded_arrangement = false +resharper_keep_existing_expr_member_arrangement = false +resharper_keep_existing_invocation_parens_arrangement = false +resharper_local_function_body = expression_body +resharper_new_line_before_while = true +resharper_object_creation_when_type_evident = explicitly_typed +resharper_place_accessorholder_attribute_on_same_line = false +resharper_place_expr_method_on_single_line = true +resharper_place_expr_property_on_single_line = true +resharper_place_field_attribute_on_same_line = false +resharper_place_simple_embedded_statement_on_same_line = false +resharper_use_indent_from_vs = false +resharper_wrap_before_extends_colon = true +resharper_wrap_before_linq_expression = true +resharper_wrap_chained_method_calls = chop_if_long +resharper_wrap_linq_expressions = chop_always +resharper_xmldoc_max_line_length = 180 + +# ReSharper inspection severities +resharper_arrange_accessor_owner_body_highlighting = error +resharper_arrange_attributes_highlighting = error +resharper_arrange_constructor_or_destructor_body_highlighting = error +resharper_arrange_method_or_operator_body_highlighting = error +resharper_arrange_object_creation_when_type_evident_highlighting = error +resharper_arrange_redundant_parentheses_highlighting = hint +resharper_arrange_this_qualifier_highlighting = error +resharper_arrange_type_member_modifiers_highlighting = error +resharper_auto_property_can_be_made_get_only_global_highlighting = none +resharper_auto_property_can_be_made_get_only_local_highlighting = none +resharper_bad_braces_spaces_highlighting = warning +resharper_bad_control_braces_indent_highlighting = warning +resharper_bad_control_braces_line_breaks_highlighting = warning +resharper_bad_declaration_braces_indent_highlighting = warning +resharper_bad_declaration_braces_line_breaks_highlighting = warning +resharper_bad_empty_braces_line_breaks_highlighting = warning +resharper_bad_expression_braces_indent_highlighting = warning +resharper_bad_expression_braces_line_breaks_highlighting = warning +resharper_bad_namespace_braces_indent_highlighting = warning +resharper_built_in_type_reference_style_for_member_access_highlighting = hint +resharper_built_in_type_reference_style_highlighting = hint +resharper_class_can_be_sealed_global_highlighting = warning +resharper_class_can_be_sealed_local_highlighting = warning +resharper_incorrect_blank_lines_near_braces_highlighting = warning +resharper_suggest_var_or_type_deconstruction_declarations_highlighting = warning +resharper_suggest_var_or_type_built_in_types_highlighting = error +resharper_suggest_var_or_type_simple_types_highlighting = error +resharper_suggest_var_or_type_elsewhere_highlighting = error +resharper_tabs_are_disallowed_highlighting = warning +resharper_unnecessary_whitespace_highlighting = none +resharper_web_config_module_not_resolved_highlighting = warning +resharper_web_config_type_not_resolved_highlighting = warning +resharper_web_config_wrong_module_highlighting = warning +resharper_parameter_type_can_be_enumerable_global_highlighting = none +resharper_parameter_type_can_be_enumerable_local_highlighting = none + +[*.md] +trim_trailing_whitespace = false \ No newline at end of file diff --git a/tests/Hexecs.Tests/Actors/ActorFilter1Should.cs b/tests/Hexecs.Tests/Actors/ActorFilter1Should.cs index e09ef39..cb3dbb4 100644 --- a/tests/Hexecs.Tests/Actors/ActorFilter1Should.cs +++ b/tests/Hexecs.Tests/Actors/ActorFilter1Should.cs @@ -12,10 +12,10 @@ public void ContainsActorCreatedBeforeFilter() var component = fixture.CreateComponent(); Actor actor = fixture.CreateActor(component1: component); - + // act - var filter = fixture + ActorFilter filter = fixture .Actors .Filter(); @@ -39,13 +39,13 @@ public void ContainsActorCreatedAfterFilter() // arrange var component = fixture.CreateComponent(); - var filter = fixture + ActorFilter filter = fixture .Actors .Filter(); // act - var actor = fixture.CreateActor(component1: component); + Actor actor = fixture.CreateActor(component1: component); // assert @@ -66,9 +66,9 @@ public void ContainsAllActors() { // arrange - var actors = fixture.CreateActors(); + Actor[] actors = fixture.CreateActors(); - var filter = fixture + ActorFilter filter = fixture .Actors .Filter(); @@ -76,11 +76,11 @@ public void ContainsAllActors() .Where(actor => actor.Id.Value % 2 == 0) .Do(actor => actor.Destroy()); - var expectedActors = actors.Where(actor => actor.Id.Value % 2 != 0); + IEnumerable expectedActors = actors.Where(actor => actor.Id.Value % 2 != 0); // act - var actualActors = filter.ToArray(); + Actor[] actualActors = filter.ToArray(); // assert @@ -94,8 +94,8 @@ public void RemoveDestroyedActor() { // arrange - var actor = fixture.CreateActor(); - var filter = fixture + Actor actor = fixture.CreateActor(); + ActorFilter filter = fixture .Actors .Filter(); @@ -116,8 +116,8 @@ public void RemoveActorAfterRemoveComponent() { // arrange - var actor = fixture.CreateActor(); - var filter = fixture + Actor actor = fixture.CreateActor(); + ActorFilter filter = fixture .Actors .Filter(); @@ -133,5 +133,5 @@ public void RemoveActorAfterRemoveComponent() .BeFalse(); } - -} \ No newline at end of file + +} diff --git a/tests/Hexecs.Tests/Actors/ActorListShould.cs b/tests/Hexecs.Tests/Actors/ActorListShould.cs index 11c8696..aa41a11 100644 --- a/tests/Hexecs.Tests/Actors/ActorListShould.cs +++ b/tests/Hexecs.Tests/Actors/ActorListShould.cs @@ -9,7 +9,7 @@ public void Should_Add_Actors_And_Increase_Length() { // Arrange using var list = new ActorList(fixture.Actors); - var actor = fixture.CreateActor(); + Actor actor = fixture.CreateActor(); // Act list.Add(actor); @@ -27,7 +27,7 @@ public void Should_Return_False_When_Removing_Non_Existent_Actor() var fakeId = new ActorId(999); // Act - var result = list.Remove(fakeId); + bool result = list.Remove(fakeId); // Assert result.Should().BeFalse(); @@ -54,7 +54,7 @@ public void Should_Automatically_Remove_Actor_When_Component_Is_Removed() { // Arrange using var list = new ActorList(fixture.Actors); - var actor = fixture.CreateActor(); + Actor actor = fixture.CreateActor(); list.Add(actor); // Act @@ -76,14 +76,14 @@ public void Should_Enumerate_Added_Actors() { // Arrange using var list = new ActorList(fixture.Actors); - var actor1 = fixture.CreateActor(); - var actor2 = fixture.CreateActor(); + Actor actor1 = fixture.CreateActor(); + Actor actor2 = fixture.CreateActor(); list.Add(actor1); list.Add(actor2); // Act var resultIds = new List(); - foreach (var actor in list) + foreach (ActorRef actor in list) { resultIds.Add(actor.Id); } @@ -101,11 +101,11 @@ public void Should_Throw_When_Adding_To_Disposed_List() // Arrange var list = new ActorList(fixture.Actors); list.Dispose(); - var actor = fixture.CreateActor(); + Actor actor = fixture.CreateActor(); // Act - var action = () => list.Add(actor); + Action action = () => list.Add(actor); // Assert @@ -122,7 +122,7 @@ public void Should_Add_Using_Different_References(bool useActorRef) { // Arrange using var list = new ActorList(fixture.Actors); - var actor = fixture.CreateActor(); + Actor actor = fixture.CreateActor(); // Act @@ -141,4 +141,4 @@ public void Should_Add_Using_Different_References(bool useActorRef) .Should() .BeTrue(); } -} \ No newline at end of file +} diff --git a/tests/Hexecs.Tests/Assets/AssetConstraintShould.cs b/tests/Hexecs.Tests/Assets/AssetConstraintShould.cs index 3198019..52e88d2 100644 --- a/tests/Hexecs.Tests/Assets/AssetConstraintShould.cs +++ b/tests/Hexecs.Tests/Assets/AssetConstraintShould.cs @@ -10,8 +10,8 @@ public void Should_Be_Applicable_When_Conditions_Met() { // Arrange - var asset = fixture.CreateAsset(); - var constraint = AssetConstraint + Asset asset = fixture.CreateAsset(); + AssetConstraint constraint = AssetConstraint .Include(fixture.Assets) .Build(); @@ -26,8 +26,8 @@ public void Should_Be_Applicable_When_Conditions_Met() public void Should_Not_Be_Applicable_When_Excluded_Component_Exists() { // Arrange - var asset = fixture.CreateAsset(); - var constraint = AssetConstraint + Asset asset = fixture.CreateAsset(); + AssetConstraint constraint = AssetConstraint .Exclude(fixture.Assets) .Build(); @@ -42,10 +42,10 @@ public void Should_Not_Be_Applicable_When_Excluded_Component_Exists() public void Builder_Should_Throw_On_Duplicate_Component() { // Arrange - var builder = AssetConstraint.Include(fixture.Assets); + AssetConstraint.Builder builder = AssetConstraint.Include(fixture.Assets); // Act - var action = () => builder.Include(); + Func action = () => builder.Include(); // Assert action @@ -57,12 +57,12 @@ public void Builder_Should_Throw_On_Duplicate_Component() public void Should_Implement_Equality_Correctly() { // Arrange - var context = fixture.Assets; - var constraint1 = AssetConstraint.Include(context) + AssetContext context = fixture.Assets; + AssetConstraint constraint1 = AssetConstraint.Include(context) .Exclude() .Build(); - var constraint2 = AssetConstraint.Include(context) + AssetConstraint constraint2 = AssetConstraint.Include(context) .Exclude() .Build(); @@ -80,8 +80,8 @@ public void Should_Implement_Equality_Correctly() public void Should_Work_With_Multiple_Includes() { // Arrange - var actor = fixture.CreateAsset(); - var constraint = AssetConstraint + Asset actor = fixture.CreateAsset(); + AssetConstraint constraint = AssetConstraint .Include(fixture.Assets) .Build(); @@ -90,4 +90,4 @@ public void Should_Work_With_Multiple_Includes() .Should() .BeTrue(); } -} \ No newline at end of file +} diff --git a/tests/Hexecs.Tests/Assets/AssetContextShould.cs b/tests/Hexecs.Tests/Assets/AssetContextShould.cs index 87dbb97..c4f4258 100644 --- a/tests/Hexecs.Tests/Assets/AssetContextShould.cs +++ b/tests/Hexecs.Tests/Assets/AssetContextShould.cs @@ -1,4 +1,5 @@ using Hexecs.Assets; +using Hexecs.Assets.Sources; namespace Hexecs.Tests.Assets; @@ -9,17 +10,17 @@ public void GetAssetByAlias() { // arrange - var alias = fixture.RandomString(); - AssetId assetId = AssetId.Empty; + string alias = fixture.RandomString(); + var assetId = AssetId.Empty; fixture.CreateAssetContext(loader => { - var asset = loader.CreateAsset(alias); + AssetConfigurator asset = loader.CreateAsset(alias); assetId = asset.Id; }); // act - var actual = fixture.Assets.Invoking(ctx => ctx.GetAsset(alias)) + Asset actual = fixture.Assets.Invoking(ctx => ctx.GetAsset(alias)) .Should() .NotThrow() .Which; @@ -36,9 +37,9 @@ public void Throw_IfAssetByAlias_NotFound() { // act && assert - var context = fixture.CreateAssetContext(); + AssetContext context = fixture.CreateAssetContext(); context.Invoking(ctx => ctx.GetAsset(fixture.RandomString())) .Should() .Throw(); } -} \ No newline at end of file +} diff --git a/tests/Hexecs.Tests/Assets/AssetFilter1Should.cs b/tests/Hexecs.Tests/Assets/AssetFilter1Should.cs index da45f86..4097381 100644 --- a/tests/Hexecs.Tests/Assets/AssetFilter1Should.cs +++ b/tests/Hexecs.Tests/Assets/AssetFilter1Should.cs @@ -1,4 +1,5 @@ using Hexecs.Assets; +using Hexecs.Assets.Sources; using Hexecs.Tests.Mocks.Assets; namespace Hexecs.Tests.Assets; @@ -8,27 +9,27 @@ public sealed class AssetFilter1Should(AssetTestFixture fixture) : IClassFixture [Fact(DisplayName = "Фильтр ассетов должен содержать все созданные ассеты")] public void ContainsAllAssets() { - // arrange + // arrange var assetIds = new List(); - var context = fixture.CreateAssetContext(loader => + AssetContext context = fixture.CreateAssetContext(loader => { for (var i = 1; i < 100; i++) { - var asset = loader.CreateAsset(new CarAsset(i, i)); + AssetConfigurator asset = loader.CreateAsset(new CarAsset(i, i)); assetIds.Add(asset.Id); } }); - var expectedAssets = assetIds + Asset[] expectedAssets = assetIds .Select(context.GetAsset) .ToArray(); // act - var filter = context.Filter(); - var actualActors = filter.ToArray(); + AssetFilter filter = context.Filter(); + Asset[] actualActors = filter.ToArray(); // assert @@ -40,16 +41,16 @@ public void ContainsAllAssets() [Fact(DisplayName = "Фильтр ассетов можно перебирать как AssetRef")] public void AssetFilterShouldEnumerable() { - // arrange + // arrange var expectedIds = new Dictionary(); - var context = fixture.CreateAssetContext(loader => + AssetContext context = fixture.CreateAssetContext(loader => { for (var i = 0; i < 100; i++) { var component = new CarAsset(i, i); - var asset = loader.CreateAsset(component); + AssetConfigurator asset = loader.CreateAsset(component); expectedIds.Add(asset.Id, component); } @@ -57,21 +58,24 @@ public void AssetFilterShouldEnumerable() // act - var filter = context.Filter(); + AssetFilter filter = context.Filter(); // assert var actualIds = new List(); - foreach (var asset in filter) + + foreach (AssetRef asset in filter) { actualIds.Add(asset.Id); asset .Component1 - .Should().Be(expectedIds[asset.Id]); + .Should() + .Be(expectedIds[asset.Id]); } filter.Length - .Should().Be(expectedIds.Count); + .Should() + .Be(expectedIds.Count); actualIds .Should() @@ -86,10 +90,10 @@ public void AssetFilterShouldEnumerable() public void EmptyFilterWhenNoComponentsExist() { // arrange - var context = fixture.CreateAssetContext(); + AssetContext context = fixture.CreateAssetContext(); // act - var filter = context.Filter(); + AssetFilter filter = context.Filter(); // assert filter.Length @@ -104,23 +108,25 @@ public void FilterWithConstraint() var expectedId = AssetId.Empty; // arrange - var context = fixture.CreateAssetContext(loader => + AssetContext context = fixture.CreateAssetContext(loader => { - notExpectedIds.Add(loader.CreateAsset( - new CarAsset(10, 10), - new UnitAsset()).Id); + notExpectedIds.Add( + loader.CreateAsset( + new CarAsset(10, 10), + new UnitAsset()) + .Id); - notExpectedIds.Add(loader.CreateAsset( - new CarAsset(30, 30)).Id); + notExpectedIds.Add(loader.CreateAsset(new CarAsset(30, 30)).Id); expectedId = loader.CreateAsset( - new CarAsset(20, 20), - new BuildingAsset()).Id; + new CarAsset(20, 20), + new BuildingAsset()) + .Id; }); // act - var filter = context.Filter(constraint => constraint + AssetFilter filter = context.Filter(constraint => constraint .Exclude() .Include()); @@ -133,7 +139,7 @@ public void FilterWithConstraint() .Should() .BeTrue(); - foreach (var notExpectedId in notExpectedIds) + foreach (AssetId notExpectedId in notExpectedIds) { filter.Contains(notExpectedId) .Should() @@ -145,9 +151,9 @@ public void FilterWithConstraint() public void GetThrowsExceptionWhenNotFound() { // arrange - var context = fixture.CreateAssetContext(loader => { loader.CreateAsset(new CarAsset(1, 1)); }); + AssetContext context = fixture.CreateAssetContext(loader => { loader.CreateAsset(new CarAsset(1, 1)); }); - var filter = context.Filter(); + AssetFilter filter = context.Filter(); // act @@ -165,13 +171,13 @@ public void ContainsReturnsCorrectStatus() // arrange var existingId = AssetId.Empty; - var context = fixture.CreateAssetContext(loader => + AssetContext context = fixture.CreateAssetContext(loader => { - var asset = loader.CreateAsset(new CarAsset(1, 1)); + AssetConfigurator asset = loader.CreateAsset(new CarAsset(1, 1)); existingId = asset.Id; }); - var filter = context.Filter(); + AssetFilter filter = context.Filter(); // act & assert filter @@ -184,4 +190,4 @@ public void ContainsReturnsCorrectStatus() .Should() .BeFalse(); } -} \ No newline at end of file +} diff --git a/tests/Hexecs.Tests/Assets/AssetFilter2Should.cs b/tests/Hexecs.Tests/Assets/AssetFilter2Should.cs index 515ad06..839a18c 100644 --- a/tests/Hexecs.Tests/Assets/AssetFilter2Should.cs +++ b/tests/Hexecs.Tests/Assets/AssetFilter2Should.cs @@ -1,4 +1,5 @@ using Hexecs.Assets; +using Hexecs.Assets.Sources; using Hexecs.Tests.Mocks.Assets; namespace Hexecs.Tests.Assets; @@ -8,29 +9,29 @@ public sealed class AssetFilter2Should(AssetTestFixture fixture) : IClassFixture [Fact(DisplayName = "Фильтр ассетов должен содержать все созданные ассеты")] public void ContainsAllAssets() { - // arrange + // arrange var assetIds = new List(); - var context = fixture.CreateAssetContext(loader => + AssetContext context = fixture.CreateAssetContext(loader => { - for (int i = 1; i < 100; i++) + for (var i = 1; i < 100; i++) { - var asset = loader.CreateAsset( + AssetConfigurator asset = loader.CreateAsset( new CarAsset(i, i), new UnitAsset(i, i)); assetIds.Add(asset.Id); } }); - var expectedAssets = assetIds + Asset[] expectedAssets = assetIds .Select(context.GetAsset) .ToArray(); // act - var filter = context.Filter(); - var actualActors = filter.ToArray(); + AssetFilter filter = context.Filter(); + Asset[] actualActors = filter.ToArray(); // assert @@ -42,17 +43,17 @@ public void ContainsAllAssets() [Fact(DisplayName = "Фильтр ассетов можно перебирать как AssetRef")] public void AssetFilterShouldEnumerable() { - // arrange + // arrange var expectedIds = new Dictionary(); - var context = fixture.CreateAssetContext(loader => + AssetContext context = fixture.CreateAssetContext(loader => { for (var i = 1; i < 100; i++) { var component1 = new CarAsset(i, i); var component2 = new UnitAsset(i, i); - var asset = loader.CreateAsset(component1, component2); + AssetConfigurator asset = loader.CreateAsset(component1, component2); expectedIds.Add(asset.Id, (component1, component2)); } @@ -60,25 +61,29 @@ public void AssetFilterShouldEnumerable() // act - var filter = context.Filter(); + AssetFilter filter = context.Filter(); // assert var actualIds = new List(); - foreach (var asset in filter) + + foreach (AssetRef asset in filter) { actualIds.Add(asset.Id); asset .Component1 - .Should().Be(expectedIds[asset.Id].Item1); + .Should() + .Be(expectedIds[asset.Id].Item1); asset .Component2 - .Should().Be(expectedIds[asset.Id].Item2); + .Should() + .Be(expectedIds[asset.Id].Item2); } filter.Length - .Should().Be(expectedIds.Count); + .Should() + .Be(expectedIds.Count); actualIds .Should() @@ -93,10 +98,10 @@ public void AssetFilterShouldEnumerable() public void EmptyFilterWhenNoComponentsExist() { // arrange - var context = fixture.CreateAssetContext(); + AssetContext context = fixture.CreateAssetContext(); // act - var filter = context.Filter(); + AssetFilter filter = context.Filter(); // assert filter.Length @@ -108,30 +113,35 @@ public void EmptyFilterWhenNoComponentsExist() public void FilterWithConstraint() { var notExpectedIds = new List(); - AssetId expectedId = AssetId.Empty; + var expectedId = AssetId.Empty; // arrange - var context = fixture.CreateAssetContext(loader => + AssetContext context = fixture.CreateAssetContext(loader => { - notExpectedIds.Add(loader.CreateAsset( - new CarAsset(10, 10), - new UnitAsset(), - new BuildingAsset()).Id); - - notExpectedIds.Add(loader.CreateAsset( - new CarAsset(10, 10), - new UnitAsset(), - new NonExistentAsset()).Id); + notExpectedIds.Add( + loader.CreateAsset( + new CarAsset(10, 10), + new UnitAsset(), + new BuildingAsset()) + .Id); + + notExpectedIds.Add( + loader.CreateAsset( + new CarAsset(10, 10), + new UnitAsset(), + new NonExistentAsset()) + .Id); expectedId = loader.CreateAsset( - new CarAsset(20, 20), - new UnitAsset(), - new SubjectAsset()).Id; + new CarAsset(20, 20), + new UnitAsset(), + new SubjectAsset()) + .Id; }); // act - var filter = context.Filter(constraint => constraint + AssetFilter filter = context.Filter(constraint => constraint .Exclude() .Include()); @@ -144,7 +154,7 @@ public void FilterWithConstraint() .Should() .BeTrue(); - foreach (var notExpectedId in notExpectedIds) + foreach (AssetId notExpectedId in notExpectedIds) { filter.Contains(notExpectedId) .Should() @@ -156,10 +166,10 @@ public void FilterWithConstraint() public void GetThrowsExceptionWhenNotFound() { // arrange - var context = fixture.CreateAssetContext(loader => loader + AssetContext context = fixture.CreateAssetContext(loader => loader .CreateAsset(new CarAsset(1, 1), new UnitAsset())); - var filter = context.Filter(); + AssetFilter filter = context.Filter(); // act @@ -175,16 +185,16 @@ public void GetThrowsExceptionWhenNotFound() public void ContainsReturnsCorrectStatus() { // arrange - + var existingId = AssetId.Empty; - - var context = fixture.CreateAssetContext(loader => + + AssetContext context = fixture.CreateAssetContext(loader => { - var asset = loader.CreateAsset(new CarAsset(1, 1), new UnitAsset()); + AssetConfigurator asset = loader.CreateAsset(new CarAsset(1, 1), new UnitAsset()); existingId = asset.Id; }); - var filter = context.Filter(); + AssetFilter filter = context.Filter(); // act & assert filter @@ -197,4 +207,4 @@ public void ContainsReturnsCorrectStatus() .Should() .BeFalse(); } -} \ No newline at end of file +} diff --git a/tests/Hexecs.Tests/Assets/AssetFilter3Should.cs b/tests/Hexecs.Tests/Assets/AssetFilter3Should.cs index f24b01e..ea3aa02 100644 --- a/tests/Hexecs.Tests/Assets/AssetFilter3Should.cs +++ b/tests/Hexecs.Tests/Assets/AssetFilter3Should.cs @@ -1,4 +1,5 @@ using Hexecs.Assets; +using Hexecs.Assets.Sources; using Hexecs.Tests.Mocks.Assets; namespace Hexecs.Tests.Assets; @@ -8,14 +9,14 @@ public sealed class AssetFilter3Should(AssetTestFixture fixture) : IClassFixture [Fact(DisplayName = "Фильтр ассетов должен содержать все созданные ассеты")] public void ContainsAllAssets() { - // arrange + // arrange var assetIds = new List(); - var context = fixture.CreateAssetContext(loader => + AssetContext context = fixture.CreateAssetContext(loader => { - for (int i = 1; i < 100; i++) + for (var i = 1; i < 100; i++) { - var asset = loader.CreateAsset( + AssetConfigurator asset = loader.CreateAsset( new CarAsset(i, i), new DecisionAsset(i, i), new UnitAsset(i, i)); @@ -23,12 +24,12 @@ public void ContainsAllAssets() } }); - var expectedAssets = assetIds.Select(id => context.GetAsset(id)).ToArray(); + Asset[] expectedAssets = assetIds.Select(id => context.GetAsset(id)).ToArray(); // act - var filter = context.Filter(); - var actualActors = filter.ToArray(); + AssetFilter filter = context.Filter(); + Asset[] actualActors = filter.ToArray(); // assert @@ -40,17 +41,17 @@ public void ContainsAllAssets() [Fact(DisplayName = "Фильтр ассетов можно перебирать как AssetRef")] public void AssetFilterShouldEnumerable() { - // arrange + // arrange var expectedIds = new Dictionary(); - var context = fixture.CreateAssetContext(loader => + AssetContext context = fixture.CreateAssetContext(loader => { for (var i = 1; i < 100; i++) { var component1 = new CarAsset(i, i); var component2 = new DecisionAsset(i, i); var component3 = new UnitAsset(i, i); - var asset = loader.CreateAsset(component1, component2, component3); + AssetConfigurator asset = loader.CreateAsset(component1, component2, component3); expectedIds.Add(asset.Id, (component1, component2, component3)); } @@ -58,29 +59,34 @@ public void AssetFilterShouldEnumerable() // act - var filter = context.Filter(); + AssetFilter filter = context.Filter(); // assert var actualIds = new List(); - foreach (var asset in filter) + + foreach (AssetRef asset in filter) { actualIds.Add(asset.Id); asset .Component1 - .Should().Be(expectedIds[asset.Id].Item1); + .Should() + .Be(expectedIds[asset.Id].Item1); asset .Component2 - .Should().Be(expectedIds[asset.Id].Item2); + .Should() + .Be(expectedIds[asset.Id].Item2); asset .Component3 - .Should().Be(expectedIds[asset.Id].Item3); + .Should() + .Be(expectedIds[asset.Id].Item3); } filter.Length - .Should().Be(expectedIds.Count); + .Should() + .Be(expectedIds.Count); actualIds .Should() @@ -95,10 +101,10 @@ public void AssetFilterShouldEnumerable() public void EmptyFilterWhenNoComponentsExist() { // arrange - var context = fixture.CreateAssetContext(); + AssetContext context = fixture.CreateAssetContext(); // act - var filter = context.Filter(); + AssetFilter filter = context.Filter(); // assert filter.Length @@ -113,9 +119,9 @@ public void FilterWithConstraint() var expectedId = AssetId.Empty; // arrange - var context = fixture.CreateAssetContext(loader => + AssetContext context = fixture.CreateAssetContext(loader => { - var asset = loader.CreateAsset(new CarAsset(10, 10), new DecisionAsset(), new UnitAsset()); + AssetConfigurator asset = loader.CreateAsset(new CarAsset(10, 10), new DecisionAsset(), new UnitAsset()); asset.Set(new BuildingAsset()); notExpectedIds.Add(asset.Id); @@ -130,7 +136,7 @@ public void FilterWithConstraint() // act - var filter = context.Filter(constraint => constraint + AssetFilter filter = context.Filter(constraint => constraint .Exclude() .Include()); @@ -143,7 +149,7 @@ public void FilterWithConstraint() .Should() .BeTrue(); - foreach (var notExpectedId in notExpectedIds) + foreach (AssetId notExpectedId in notExpectedIds) { filter.Contains(notExpectedId) .Should() @@ -155,10 +161,10 @@ public void FilterWithConstraint() public void GetThrowsExceptionWhenNotFound() { // arrange - var context = fixture.CreateAssetContext(loader => loader + AssetContext context = fixture.CreateAssetContext(loader => loader .CreateAsset(new CarAsset(1, 1), new DecisionAsset(), new UnitAsset())); - var filter = context.Filter(); + AssetFilter filter = context.Filter(); // act @@ -176,13 +182,13 @@ public void ContainsReturnsCorrectStatus() // arrange var existingId = AssetId.Empty; - var context = fixture.CreateAssetContext(loader => + AssetContext context = fixture.CreateAssetContext(loader => { - var asset = loader.CreateAsset(new CarAsset(1, 1), new DecisionAsset(), new UnitAsset()); + AssetConfigurator asset = loader.CreateAsset(new CarAsset(1, 1), new DecisionAsset(), new UnitAsset()); existingId = asset.Id; }); - var filter = context.Filter(); + AssetFilter filter = context.Filter(); // act & assert @@ -196,4 +202,4 @@ public void ContainsReturnsCorrectStatus() .Should() .BeFalse(); } -} \ No newline at end of file +} diff --git a/tests/Hexecs.Tests/Assets/AssetMethodsConsistencyTests.cs b/tests/Hexecs.Tests/Assets/AssetMethodsConsistencyTests.cs index 0722d49..3b9fb52 100644 --- a/tests/Hexecs.Tests/Assets/AssetMethodsConsistencyTests.cs +++ b/tests/Hexecs.Tests/Assets/AssetMethodsConsistencyTests.cs @@ -1,4 +1,5 @@ using System.Reflection; + using Hexecs.Assets; namespace Hexecs.Tests.Assets; @@ -33,27 +34,28 @@ public class AssetMethodsConsistencyTests "GetHashCode" ]; - private static IEnumerable CommonMethodNames => - ReferenceType - .GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly) - .Select(m => m.Name) - .Where(name => !ExcludedMethods.Contains(name)) - .Distinct(); + private static IEnumerable CommonMethodNames => ReferenceType + .GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly) + .Select(m => m.Name) + .Where(name => !ExcludedMethods.Contains(name)) + .Distinct(); [Fact(DisplayName = "Все типы акторов должны иметь общие методы")] public void AllActorTypes_ShouldHaveCommonMethods() { - var expectedMethods = CommonMethodNames.ToList(); + List expectedMethods = CommonMethodNames.ToList(); - foreach (var type in AssetTypes.Where(t => t != ReferenceType)) + foreach (Type type in AssetTypes.Where(t => t != ReferenceType)) { - var methods = type.GetMethods(BindingFlags.Public | BindingFlags.Instance); - var methodNames = methods.Select(m => m.Name).Distinct().ToHashSet(); + MethodInfo[] methods = type.GetMethods(BindingFlags.Public | BindingFlags.Instance); + HashSet methodNames = methods.Select(m => m.Name).Distinct().ToHashSet(); - foreach (var expectedMethod in expectedMethods) + foreach (string expectedMethod in expectedMethods) { - methodNames.Should().Contain(expectedMethod, - because: $"тип {type.Name} должен содержать метод {expectedMethod} (как в {ReferenceType.Name})"); + methodNames.Should() + .Contain( + expectedMethod, + because: $"тип {type.Name} должен содержать метод {expectedMethod} (как в {ReferenceType.Name})"); } } } @@ -61,17 +63,19 @@ public void AllActorTypes_ShouldHaveCommonMethods() [Fact(DisplayName = "Все общие методы должны иметь одинаковые сигнатуры")] public void CommonMethods_ShouldHaveIdenticalSignatures() { - foreach (var methodName in CommonMethodNames) + foreach (string methodName in CommonMethodNames) { - var referenceMethods = GetMethodSignatures(ReferenceType, methodName); + List referenceMethods = GetMethodSignatures(ReferenceType, methodName); - foreach (var type in AssetTypes.Where(t => t != ReferenceType)) + foreach (Type type in AssetTypes.Where(t => t != ReferenceType)) { - var typeMethods = GetMethodSignatures(type, methodName); + List typeMethods = GetMethodSignatures(type, methodName); - typeMethods.Should().BeEquivalentTo(referenceMethods, - because: - $"метод {methodName} в {type.Name} должен иметь такую же сигнатуру как в {ReferenceType.Name}"); + typeMethods.Should() + .BeEquivalentTo( + referenceMethods, + because: + $"метод {methodName} в {type.Name} должен иметь такую же сигнатуру как в {ReferenceType.Name}"); } } } @@ -79,18 +83,20 @@ public void CommonMethods_ShouldHaveIdenticalSignatures() [Fact(DisplayName = "Все общие методы должны иметь AggressiveInlining-атрибут")] public void CommonMethods_ShouldHaveAggressiveInlining() { - foreach (var type in AssetTypes) + foreach (Type type in AssetTypes) { - var methods = type + IEnumerable methods = type .GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly) .Where(m => CommonMethodNames.Contains(m.Name)); - foreach (var method in methods) + foreach (MethodInfo method in methods) { - var implFlags = method.MethodImplementationFlags; + MethodImplAttributes implFlags = method.MethodImplementationFlags; - implFlags.Should().HaveFlag(MethodImplAttributes.AggressiveInlining, - because: $"метод {type.Name}.{method.Name} должен иметь атрибут AggressiveInlining"); + implFlags.Should() + .HaveFlag( + MethodImplAttributes.AggressiveInlining, + because: $"метод {type.Name}.{method.Name} должен иметь атрибут AggressiveInlining"); } } } @@ -107,9 +113,13 @@ private static List GetMethodSignatures(Type type, string metho private sealed class MethodSignature { public string Name { get; } + public string ReturnType { get; } + public string[] ParameterTypes { get; } + public string[] GenericConstraints { get; } + public int GenericArgumentCount { get; } public MethodSignature(MethodInfo method) @@ -130,34 +140,48 @@ public MethodSignature(MethodInfo method) private static string NormalizeTypeName(Type type) { if (type.IsGenericParameter) + { return "T"; + } if (type.IsGenericType) { - var baseName = type.GetGenericTypeDefinition().Name; - var args = string.Join(",", type.GetGenericArguments().Select(NormalizeTypeName)); + string baseName = type.GetGenericTypeDefinition().Name; + string args = string.Join(",", type.GetGenericArguments().Select(NormalizeTypeName)); + return $"{baseName}[{args}]"; } if (type.IsByRef) + { return $"ref {NormalizeTypeName(type.GetElementType()!)}"; + } return type.Name; } public override bool Equals(object? obj) { - if (obj is not MethodSignature other) return false; + if (obj is not MethodSignature other) + { + return false; + } + return Name == other.Name - && ReturnType == other.ReturnType - && GenericArgumentCount == other.GenericArgumentCount - && ParameterTypes.SequenceEqual(other.ParameterTypes) - && GenericConstraints.SequenceEqual(other.GenericConstraints); + && ReturnType == other.ReturnType + && GenericArgumentCount == other.GenericArgumentCount + && ParameterTypes.SequenceEqual(other.ParameterTypes) + && GenericConstraints.SequenceEqual(other.GenericConstraints); } - public override int GetHashCode() => HashCode.Combine(Name, ReturnType, GenericArgumentCount); + public override int GetHashCode() + { + return HashCode.Combine(Name, ReturnType, GenericArgumentCount); + } - public override string ToString() => - $"{ReturnType} {Name}<{GenericArgumentCount}>({string.Join(", ", ParameterTypes)})"; + public override string ToString() + { + return $"{ReturnType} {Name}<{GenericArgumentCount}>({string.Join(", ", ParameterTypes)})"; + } } -} \ No newline at end of file +} diff --git a/tests/Hexecs.Tests/Collections/ArrayEnumeratorShould.cs b/tests/Hexecs.Tests/Collections/ArrayEnumeratorShould.cs index b3c8658..695c0b0 100644 --- a/tests/Hexecs.Tests/Collections/ArrayEnumeratorShould.cs +++ b/tests/Hexecs.Tests/Collections/ArrayEnumeratorShould.cs @@ -1,4 +1,5 @@ using System.Collections; + using Hexecs.Collections; namespace Hexecs.Tests.Collections; @@ -12,7 +13,7 @@ public void Empty_Enumerator_Should_Not_MoveNext() var enumerator = ArrayEnumerator.Empty; // Act - var result = enumerator.MoveNext(); + bool result = enumerator.MoveNext(); // Assert result.Should().BeFalse(); @@ -41,7 +42,7 @@ public void Enumerator_Should_Enumerate_All_Array_Elements(int[] testArray) public void Enumerator_Should_Respect_Specified_Length(int[] testArray) { // Arrange - var specifiedLength = testArray.Length / 2; + int specifiedLength = testArray.Length / 2; var enumerator = new ArrayEnumerator(testArray, specifiedLength); var resultList = new List(); @@ -65,7 +66,7 @@ public void Reset_Should_Set_Index_To_Initial_Position(int[] testArray) // Act - первый проход enumerator.MoveNext(); - var firstElement = enumerator.Current; + int firstElement = enumerator.Current; // Полный проход while (enumerator.MoveNext()) @@ -74,8 +75,8 @@ public void Reset_Should_Set_Index_To_Initial_Position(int[] testArray) // Reset и снова первый элемент enumerator.Reset(); - var hasMoved = enumerator.MoveNext(); - var firstElementAfterReset = enumerator.Current; + bool hasMoved = enumerator.MoveNext(); + int firstElementAfterReset = enumerator.Current; // Assert hasMoved.Should().BeTrue(); @@ -103,10 +104,10 @@ public void IEnumerator_Current_Should_Return_Same_Value_As_Current(int[] testAr IEnumerator genericEnumerator = enumerator; enumerator.MoveNext(); genericEnumerator.MoveNext(); - + // Act - var current = enumerator.Current; - var genericCurrent = genericEnumerator.Current; + int current = enumerator.Current; + object? genericCurrent = genericEnumerator.Current; // Assert genericCurrent @@ -135,8 +136,8 @@ public void Current_Should_Return_Reference_To_Current_Element(int[] testArray) // Act enumerator.MoveNext(); - var originalValue = enumerator.Current; - var newValue = originalValue + 1; + int originalValue = enumerator.Current; + int newValue = originalValue + 1; // Изменяем значение в массиве через ссылку testArray[0] = newValue; @@ -164,15 +165,15 @@ public void IEnumeratorT_Current_Should_Return_Same_Value_As_Current(int[] testA IEnumerator genericEnumerator = enumerator; enumerator.MoveNext(); genericEnumerator.MoveNext(); - + // Act - var current = enumerator.Current; - var genericCurrent = genericEnumerator.Current; + int current = enumerator.Current; + int genericCurrent = genericEnumerator.Current; // Assert genericCurrent .Should() .Be(current); } -} \ No newline at end of file +} diff --git a/tests/Hexecs.Tests/Collections/BlockShould.cs b/tests/Hexecs.Tests/Collections/BlockShould.cs index c3c5492..77ba691 100644 --- a/tests/Hexecs.Tests/Collections/BlockShould.cs +++ b/tests/Hexecs.Tests/Collections/BlockShould.cs @@ -100,7 +100,7 @@ public void ArrayAndLengthConstructor_WithNegativeLength_ShouldCreateEmptyBlock( { // Arrange var array = new[] { 1, 2, 3 }; - var length = -1; + int length = -1; // Act var block = new Block(array, length); @@ -188,7 +188,7 @@ public void ListConstructor_WithEmptyList_ShouldCreateEmptyBlock() public void EnumerableConstructor_ShouldCreateBlockWithEnumerableElements() { // Arrange - var enumerable = Enumerable.Range(1, 3); + IEnumerable enumerable = Enumerable.Range(1, 3); // Act var block = new Block(enumerable); @@ -202,7 +202,7 @@ public void EnumerableConstructor_ShouldCreateBlockWithEnumerableElements() public void EnumerableConstructor_WithEmptyEnumerable_ShouldCreateEmptyBlock() { // Arrange - var enumerable = Enumerable.Empty(); + IEnumerable enumerable = Enumerable.Empty(); // Act var block = new Block(enumerable); @@ -216,7 +216,7 @@ public void EnumerableConstructor_WithEmptyEnumerable_ShouldCreateEmptyBlock() public void EnumerableAndLengthConstructor_ShouldCreateBlockWithSpecifiedLength() { // Arrange - var enumerable = Enumerable.Range(1, 5); // 1, 2, 3, 4, 5 + IEnumerable enumerable = Enumerable.Range(1, 5); // 1, 2, 3, 4, 5 var length = 3; // Act @@ -231,7 +231,7 @@ public void EnumerableAndLengthConstructor_ShouldCreateBlockWithSpecifiedLength( public void EnumerableAndLengthConstructor_WithZeroLength_ShouldCreateEmptyBlock() { // Arrange - var enumerable = Enumerable.Range(1, 5); + IEnumerable enumerable = Enumerable.Range(1, 5); var length = 0; // Act @@ -273,7 +273,7 @@ public void AsMemory_ForEmptyBlock_ShouldReturnEmptyMemory() var block = new Block(); // Act - var memory = block.AsMemory(); + Memory memory = block.AsMemory(); // Assert memory.IsEmpty.Should().BeTrue(); @@ -287,7 +287,7 @@ public void AsMemory_ForNonEmptyBlock_ShouldReturnMemoryWithElements() var block = new Block(array); // Act - var memory = block.AsMemory(); + Memory memory = block.AsMemory(); // Assert memory.Length.Should().Be(array.Length); @@ -301,7 +301,7 @@ public void AsSpan_ForEmptyBlock_ShouldReturnEmptySpan() var block = new Block(); // Act - var span = block.AsSpan(); + Span span = block.AsSpan(); // Assert span.IsEmpty.Should().BeTrue(); @@ -315,7 +315,7 @@ public void AsSpan_ForNonEmptyBlock_ShouldReturnSpanWithElements() var block = new Block(array); // Act - var span = block.AsSpan(); + Span span = block.AsSpan(); // Assert span.Length.Should().Be(array.Length); @@ -343,10 +343,17 @@ public void Contains_ForEmptyBlock_ShouldReturnFalse() block.Contains("a").Should().BeFalse(); } - private class CaseInsensitiveComparer : IEqualityComparer + private sealed class CaseInsensitiveComparer : IEqualityComparer { - public bool Equals(string? x, string? y) => string.Equals(x, y, StringComparison.OrdinalIgnoreCase); - public int GetHashCode(string obj) => obj.ToLowerInvariant().GetHashCode(); + public bool Equals(string? x, string? y) + { + return string.Equals(x, y, StringComparison.OrdinalIgnoreCase); + } + + public int GetHashCode(string obj) + { + return obj.ToLowerInvariant().GetHashCode(); + } } [Fact(DisplayName = "Contains с пользовательским компаратором должен использовать компаратор")] @@ -365,7 +372,7 @@ public void GetRef_ShouldReturnRefToElement() var block = new Block(array); // Block uses this array instance // Act - ref var itemRef = ref block.GetRef(1); + ref int itemRef = ref block.GetRef(1); // Assert itemRef.Should().Be(20); @@ -399,10 +406,10 @@ public void GetRef_OnBlockFromDefaultConstructor_ShouldReturnNullRef_AndNotThrow // If index is 0 for an empty array, it will throw IndexOutOfRangeException. // Let's test with _array explicitly null using the constructor that takes T[] - Block blockWithNullArray = new Block((int[]?)null!); + var blockWithNullArray = new Block((int[]?)null!); Action act = () => { - ref var _ = ref blockWithNullArray.GetRef(0); + ref int _ = ref blockWithNullArray.GetRef(0); // Попытка использования ref Unsafe.NullRef() приведет к NullReferenceException // Console.WriteLine(_); // Это вызовет исключение }; @@ -433,7 +440,7 @@ public void GetRef_OnBlockFromDefaultConstructor_ShouldReturnNullRef_AndNotThrow var defaultBlock = new Block(); Action actDefault = () => { - ref var _ = ref defaultBlock.GetRef(0); + ref int _ = ref defaultBlock.GetRef(0); }; actDefault.Should().Throw(); } @@ -444,13 +451,13 @@ public void GetRef_IndexOutOfRange_ShouldThrow() var block = new Block(new[] { 1 }); Action act = () => { - ref var _ = ref block.GetRef(1); + ref int _ = ref block.GetRef(1); }; act.Should().Throw(); Action actNegative = () => { - ref var _ = ref block.GetRef(-1); + ref int _ = ref block.GetRef(-1); }; actNegative.Should().Throw(); } @@ -461,7 +468,7 @@ public void GetEnumerator_ForEmptyBlock_ShouldNotYieldAnyItems() { var block = new Block(); var count = 0; - foreach (var _ in block) + foreach (decimal _ in block) { count++; } @@ -476,7 +483,7 @@ public void GetEnumerator_ShouldIterateOverAllItems() var block = new Block(array); var iteratedItems = new List(); - foreach (var item in block) + foreach (string item in block) { iteratedItems.Add(item); } @@ -504,7 +511,7 @@ public void GetUnderlyingArray_ShouldReturnInternalArray() { var array = new[] { 1, 2 }; var block = new Block(array); // This constructor assigns the reference - var underlyingArray = block.GetUnderlyingArray(); + int[] underlyingArray = block.GetUnderlyingArray(); underlyingArray.Should().BeSameAs(array); // Checks if it's the exact same instance } @@ -516,7 +523,7 @@ public void GetUnderlyingArray_FromIEnumerableConstructor_MayReturnDifferentArra IEnumerable enumerable = sourceArray; var block = new Block(enumerable); // Uses CollectionUtils.ToArray - var underlyingArray = block.GetUnderlyingArray(); + int[] underlyingArray = block.GetUnderlyingArray(); underlyingArray.Should().NotBeSameAs(sourceArray); // CollectionUtils.ToArray likely creates a new array underlyingArray.Should().Equal(sourceArray); } @@ -570,7 +577,7 @@ public void Indexer_Get_IndexOutOfRange_ShouldThrow() var block = new Block(new[] { 'a' }); Action act = () => { - var _ = block[1]; + char _ = block[1]; }; act.Should().Throw(); } @@ -601,7 +608,7 @@ public void Indexer_Set_OnCopy_ShouldNotAffectOriginalStructsArrayIfCopied() // This test demonstrates behavior of value types (structs) var array = new[] { 1, 2, 3 }; var block1 = new Block(array); - var block2 = block1; // Value type copy + Block block2 = block1; // Value type copy block2[0] = 100; // Modifies the array referenced by block2._array @@ -629,7 +636,7 @@ public void IEnumerable_T_GetEnumerator_ShouldWorkCorrectly() IEnumerable enumerable = block; // Explicitly use IEnumerable var iteratedItems = new List(); - foreach (var item in enumerable) + foreach (int item in enumerable) { iteratedItems.Add(item); } @@ -645,7 +652,7 @@ public void IEnumerable_GetEnumerator_ShouldWorkCorrectly() System.Collections.IEnumerable enumerable = block; // Explicitly use IEnumerable var iteratedItems = new List(); // IEnumerator returns object - foreach (var item in enumerable) + foreach (object item in enumerable) { iteratedItems.Add(item); } @@ -653,4 +660,4 @@ public void IEnumerable_GetEnumerator_ShouldWorkCorrectly() // Convert object list to int list for comparison iteratedItems.Cast().Should().Equal(array); } -} \ No newline at end of file +} diff --git a/tests/Hexecs.Tests/Collections/BucketShould.cs b/tests/Hexecs.Tests/Collections/BucketShould.cs index dba5a37..3e6475a 100644 --- a/tests/Hexecs.Tests/Collections/BucketShould.cs +++ b/tests/Hexecs.Tests/Collections/BucketShould.cs @@ -2,7 +2,7 @@ namespace Hexecs.Tests.Collections; -public class BucketShould +public sealed class BucketShould { [Fact(DisplayName = "Конструктор: должен создать пустой Bucket, если capacity = 0")] public void Constructor_WithZeroCapacity_ShouldCreateEmptyBucket() @@ -76,7 +76,7 @@ public void AsMemory_WhenEmpty_ShouldReturnEmptyMemory() var bucket = new Bucket(0); // Act - var memory = bucket.AsMemory(); + Memory memory = bucket.AsMemory(); // Assert memory.IsEmpty.Should().BeTrue(); @@ -91,7 +91,7 @@ public void AsMemory_WhenNotEmpty_ShouldReturnMemoryWithItems() bucket.Add(2); // Act - var memory = bucket.AsMemory(); + Memory memory = bucket.AsMemory(); // Assert memory.Length.Should().BeGreaterThanOrEqualTo(bucket.Length); // ArrayPool может вернуть больший массив @@ -105,7 +105,7 @@ public void AsSpan_WhenEmpty_ShouldReturnEmptySpan() var bucket = new Bucket(0); // Act - var span = bucket.AsSpan(); + Span span = bucket.AsSpan(); // Assert span.IsEmpty.Should().BeTrue(); @@ -120,7 +120,7 @@ public void AsSpan_WhenNotEmpty_ShouldReturnSpanWithItems() bucket.Add("world"); // Act - var span = bucket.AsSpan(); + Span span = bucket.AsSpan(); // Assert span.Length.Should().Be(2); @@ -134,7 +134,7 @@ public void AsReadOnlySpan_WhenEmpty_ShouldReturnEmptyReadOnlySpan() var bucket = new Bucket(0); // Act - var span = bucket.AsReadOnlySpan(); + ReadOnlySpan span = bucket.AsReadOnlySpan(); // Assert span.IsEmpty.Should().BeTrue(); @@ -149,7 +149,7 @@ public void AsReadOnlySpan_WhenNotEmpty_ShouldReturnReadOnlySpanWithItems() bucket.Add('b'); // Act - var span = bucket.AsReadOnlySpan(); + ReadOnlySpan span = bucket.AsReadOnlySpan(); // Assert span.Length.Should().Be(2); @@ -202,7 +202,7 @@ public void GetEnumerator_ShouldEnumerateItemsCorrectly() var actualItems = new List(); // Act - foreach (var item in bucket) + foreach (int item in bucket) { actualItems.Add(item); } @@ -219,7 +219,7 @@ public void GetEnumerator_WhenEmpty_ShouldEnumerateNothing() var count = 0; // Act - foreach (var _ in bucket) + foreach (string _ in bucket) { count++; } @@ -238,8 +238,8 @@ public void IndexOf_ItemExists_ShouldReturnCorrectIndex() bucket.Add("c"); // Act - var indexB = bucket.IndexOf("b"); - var indexC = bucket.IndexOf("c"); + int indexB = bucket.IndexOf("b"); + int indexC = bucket.IndexOf("c"); // Assert indexB.Should().Be(1); @@ -255,7 +255,7 @@ public void IndexOf_ItemDoesNotExist_ShouldReturnMinusOne() bucket.Add("b"); // Act - var index = bucket.IndexOf("z"); + int index = bucket.IndexOf("z"); // Assert index.Should().Be(-1); @@ -268,7 +268,7 @@ public void IndexOf_WhenEmpty_ShouldReturnMinusOne() var bucket = new Bucket(0); // Act - var index = bucket.IndexOf(123); + int index = bucket.IndexOf(123); // Assert index.Should().Be(-1); @@ -281,11 +281,11 @@ public void IndexOf_WithCustomComparer_ShouldUseComparer() var bucket = new Bucket(2); bucket.Add("apple"); bucket.Add("APPLE"); - var comparer = StringComparer.OrdinalIgnoreCase; + StringComparer comparer = StringComparer.OrdinalIgnoreCase; // Act - var index = bucket.IndexOf("apple", comparer); // Должен найти "apple" - var indexIgnoreCase = bucket.IndexOf("Apple", comparer); // Должен найти "APPLE" на позиции 1 + int index = bucket.IndexOf("apple", comparer); // Должен найти "apple" + int indexIgnoreCase = bucket.IndexOf("Apple", comparer); // Должен найти "APPLE" на позиции 1 // Assert index.Should().Be(0); @@ -301,7 +301,7 @@ public void Has_ItemExists_ShouldReturnTrue() bucket.Add(200); // Act - var has = bucket.Has(200); + bool has = bucket.Has(200); // Assert has.Should().BeTrue(); @@ -315,7 +315,7 @@ public void Has_ItemDoesNotExist_ShouldReturnFalse() bucket.Add(100); // Act - var has = bucket.Has(300); + bool has = bucket.Has(300); // Assert has.Should().BeFalse(); @@ -328,7 +328,7 @@ public void Has_WhenEmpty_ShouldReturnFalse() var bucket = new Bucket(0); // Act - var has = bucket.Has("any"); + bool has = bucket.Has("any"); // Assert has.Should().BeFalse(); @@ -340,11 +340,11 @@ public void Has_WithCustomComparer_ShouldUseComparer() // Arrange var bucket = new Bucket(1); bucket.Add("TestData"); - var comparer = StringComparer.OrdinalIgnoreCase; + StringComparer comparer = StringComparer.OrdinalIgnoreCase; // Act - var hasLower = bucket.Has("testdata", comparer); - var hasUpper = bucket.Has("TESTDATA", comparer); + bool hasLower = bucket.Has("testdata", comparer); + bool hasUpper = bucket.Has("TESTDATA", comparer); // Assert hasLower.Should().BeTrue(); @@ -361,7 +361,7 @@ public void Remove_ItemExists_ShouldRemoveItemAndReturnTrue() bucket.Add(3); // Act - var result = bucket.Remove(2); + bool result = bucket.Remove(2); // Assert result.Should().BeTrue(); @@ -379,7 +379,7 @@ public void Remove_ItemDoesNotExist_ShouldReturnFalse() bucket.Add(2); // Act - var result = bucket.Remove(3); + bool result = bucket.Remove(3); // Assert result.Should().BeFalse(); @@ -394,7 +394,7 @@ public void Remove_WhenEmpty_ShouldReturnFalse() var bucket = new Bucket(0); // Act - var result = bucket.Remove("any"); + bool result = bucket.Remove("any"); // Assert result.Should().BeFalse(); @@ -408,10 +408,10 @@ public void Remove_WithCustomComparer_ShouldUseComparerAndRemoveItem() var bucket = new Bucket(2); bucket.Add("ItemOne"); bucket.Add("ItemTwo"); - var comparer = StringComparer.OrdinalIgnoreCase; + StringComparer comparer = StringComparer.OrdinalIgnoreCase; // Act - var result = bucket.Remove("itemone", comparer); + bool result = bucket.Remove("itemone", comparer); // Assert result.Should().BeTrue(); @@ -427,7 +427,7 @@ public void ToArray_WhenEmpty_ShouldReturnEmptyArray() var bucket = new Bucket(0); // Act - var array = bucket.ToArray(); + int[] array = bucket.ToArray(); // Assert array.Should().BeEmpty(); @@ -443,7 +443,7 @@ public void ToArray_WhenNotEmpty_ShouldReturnArrayWithItems() bucket.Add("z"); // Act - var array = bucket.ToArray(); + string[] array = bucket.ToArray(); // Assert array.Should().Equal("x", "y", "z"); @@ -459,11 +459,11 @@ public void ToBlock_ShouldConvertCorrectly() bucket.Add(9); // Act - // Так как Block не определен в контексте, мы можем проверить, + // Так как Block не определен в контексте, мы можем проверить, // что ReadOnlySpan, используемый для его создания, корректен. // Если бы Block имел метод ToArray() или свойство, мы бы использовали его. // В данном случае, проверим содержимое AsReadOnlySpan(), которое передается в конструктор Block. - var blockEquivalentContent = bucket.AsReadOnlySpan().ToArray(); + int[] blockEquivalentContent = bucket.AsReadOnlySpan().ToArray(); // Assert blockEquivalentContent.Should().Equal(7, 8, 9); @@ -479,7 +479,7 @@ public void ToBlock_WhenEmpty_ShouldReturnEmptyBlockContent() var bucket = new Bucket(0); // Act - var blockEquivalentContent = bucket.AsReadOnlySpan().ToArray(); + char[] blockEquivalentContent = bucket.AsReadOnlySpan().ToArray(); // Assert blockEquivalentContent.Should().BeEmpty(); @@ -493,7 +493,7 @@ public void TryAdd_NewItem_ShouldAddAndReturnTrue() var bucket = new Bucket(1); // Act - var result = bucket.TryAdd(10); + bool result = bucket.TryAdd(10); // Assert result.Should().BeTrue(); @@ -509,7 +509,7 @@ public void TryAdd_ExistingItem_ShouldNotAddAndReturnFalse() bucket.Add(10); // Act - var result = bucket.TryAdd(10); + bool result = bucket.TryAdd(10); // Assert result.Should().BeFalse(); @@ -521,14 +521,14 @@ public void TryAdd_WithCustomComparer_ShouldRespectComparer() { // Arrange var bucket = new Bucket(2); - var comparer = StringComparer.OrdinalIgnoreCase; + StringComparer comparer = StringComparer.OrdinalIgnoreCase; bucket.Add("Example"); // Act // Не должен добавить, т.к. уже есть без учета регистра - var resultAddDifferentCase = bucket.TryAdd("example", comparer); - var resultAddNew = bucket.TryAdd("NewItem", comparer); // Должен добавить + bool resultAddDifferentCase = bucket.TryAdd("example", comparer); + bool resultAddNew = bucket.TryAdd("NewItem", comparer); // Должен добавить // Assert resultAddDifferentCase.Should().BeFalse(); @@ -576,4 +576,4 @@ public void IEnumerableT_GetEnumerator_ShouldWork() // Assert items.Should().Equal(1, 2); } -} \ No newline at end of file +} diff --git a/tests/Hexecs.Tests/Collections/InlineBucketShould.cs b/tests/Hexecs.Tests/Collections/InlineBucketShould.cs index 60f92be..007c8e3 100644 --- a/tests/Hexecs.Tests/Collections/InlineBucketShould.cs +++ b/tests/Hexecs.Tests/Collections/InlineBucketShould.cs @@ -10,15 +10,15 @@ public void Add_ToEmptyBucket_ShouldIncreaseLength() // Arrange var bucket = new InlineBucket(); var item = 42; - + // Act bucket.Add(item); - + // Assert bucket.Length.Should().Be(1); bucket[0].Should().Be(item); } - + [Theory(DisplayName = "Добавление элемента в непустую коллекцию должно увеличивать длину")] [AutoData] public void Add_ToNonEmptyBucket_ShouldIncreaseLength(int item1, int item2) @@ -26,36 +26,36 @@ public void Add_ToNonEmptyBucket_ShouldIncreaseLength(int item1, int item2) // Arrange var bucket = new InlineBucket(); bucket.Add(item1); - + // Act bucket.Add(item2); - + // Assert bucket.Length.Should().Be(2); bucket[0].Should().Be(item1); bucket[1].Should().Be(item2); } - + [Fact(DisplayName = "Добавление элементов сверх размера встроенного массива должно работать корректно")] public void Add_MoreItemsThanInlineArraySize_ShouldWorkCorrectly() { // Arrange var bucket = new InlineBucket(); - var items = Enumerable + int[] items = Enumerable .Range(0, InlineBucket.InlineArraySize + 1) .ToArray(); - + // Act - foreach (var item in items) + foreach (int item in items) { bucket.Add(item); } - + // Assert bucket.Length .Should() .Be(items.Length); - + for (var i = 0; i < items.Length; i++) { bucket[i] @@ -63,7 +63,7 @@ public void Add_MoreItemsThanInlineArraySize_ShouldWorkCorrectly() .Be(items[i]); } } - + [Fact(DisplayName = "Contains должен возвращать true для существующего элемента")] public void Contains_ExistingItem_ShouldReturnTrue() { @@ -72,14 +72,14 @@ public void Contains_ExistingItem_ShouldReturnTrue() bucket.Add(1); bucket.Add(2); bucket.Add(3); - + // Act - var result = bucket.Contains(2); - + bool result = bucket.Contains(2); + // Assert result.Should().BeTrue(); } - + [Fact(DisplayName = "Contains должен возвращать false для несуществующего элемента")] public void Contains_NonExistingItem_ShouldReturnFalse() { @@ -88,14 +88,14 @@ public void Contains_NonExistingItem_ShouldReturnFalse() bucket.Add(1); bucket.Add(2); bucket.Add(3); - + // Act - var result = bucket.Contains(4); - + bool result = bucket.Contains(4); + // Assert result.Should().BeFalse(); } - + [Fact(DisplayName = "Contains должен использовать переданный компаратор")] public void Contains_WithCustomEqualityComparer_ShouldUseIt() { @@ -105,17 +105,17 @@ public void Contains_WithCustomEqualityComparer_ShouldUseIt() var item2 = new TestStruct { Value = 20 }; bucket.Add(item1); bucket.Add(item2); - - var comparer = EqualityComparer.Create((x, y) => x.Value == y.Value, x => x.Value.GetHashCode()); + + EqualityComparer comparer = EqualityComparer.Create((x, y) => x.Value == y.Value, x => x.Value.GetHashCode()); var searchItem = new TestStruct { Value = 10 }; // Не та же ссылка, но то же значение - + // Act - var result = bucket.Contains(searchItem, comparer); - + bool result = bucket.Contains(searchItem, comparer); + // Assert result.Should().BeTrue(); } - + [Fact(DisplayName = "CopyTo должен копировать элементы в буфер")] public void CopyTo_ShouldCopyItemsToBuffer() { @@ -124,19 +124,19 @@ public void CopyTo_ShouldCopyItemsToBuffer() bucket.Add(1); bucket.Add(2); bucket.Add(3); - + var buffer = new int[5]; var span = new Span(buffer); - + // Act bucket.CopyTo(ref span); - + // Assert buffer[0].Should().Be(1); buffer[1].Should().Be(2); buffer[2].Should().Be(3); } - + [Fact(DisplayName = "CopyTo не должен изменять буфер при пустой коллекции")] public void CopyTo_EmptyBucket_ShouldNotModifyBuffer() { @@ -145,54 +145,56 @@ public void CopyTo_EmptyBucket_ShouldNotModifyBuffer() var buffer = new int[] { 1, 2, 3 }; var expectedBuffer = new int[] { 1, 2, 3 }; var span = new Span(buffer); - + // Act bucket.CopyTo(ref span); - + // Assert buffer.Should().BeEquivalentTo(expectedBuffer); } - + [Fact(DisplayName = "Dispose должен очищать внутренние структуры")] public void Dispose_ShouldClearInternalStructures() { // Arrange var bucket = new InlineBucket(); + for (var i = 0; i < 15; i++) // Добавляем больше, чем InlineArraySize { bucket.Add(i); } - + // Act bucket.Dispose(); - + // Assert bucket.Length.Should().Be(0); } - + [Fact(DisplayName = "GetEnumerator должен позволять перебирать элементы")] public void GetEnumerator_ShouldEnumerateItems() { // Arrange var bucket = new InlineBucket(); var expectedItems = new[] { 1, 2, 3, 4, 5 }; - - foreach (var item in expectedItems) + + foreach (int item in expectedItems) { bucket.Add(item); } - + // Act var actualItems = new List(); - foreach (var item in bucket) + + foreach (int item in bucket) { actualItems.Add(item); } - + // Assert actualItems.Should().BeEquivalentTo(expectedItems); } - + [Theory(DisplayName = "GetRef должен возвращать ссылку на элемент по индексу")] [InlineData(0)] [InlineData(5)] @@ -203,23 +205,24 @@ public void GetRef_ShouldReturnReferenceToItem(int index) { // Arrange var bucket = new InlineBucket(); + for (var i = 0; i < 20; i++) { bucket.Add(i); } - + // Act - ref var itemRef = ref bucket.GetRef(index); - var originalValue = itemRef; + ref int itemRef = ref bucket.GetRef(index); + int originalValue = itemRef; itemRef = 100; - + // Assert bucket[index].Should().Be(100); - + // Cleanup itemRef = originalValue; } - + [Fact(DisplayName = "IndexOf должен возвращать индекс существующего элемента")] public void IndexOf_ExistingItem_ShouldReturnCorrectIndex() { @@ -228,14 +231,14 @@ public void IndexOf_ExistingItem_ShouldReturnCorrectIndex() bucket.Add(10); bucket.Add(20); bucket.Add(30); - + // Act - var index = bucket.IndexOf(20); - + int index = bucket.IndexOf(20); + // Assert index.Should().Be(1); } - + [Fact(DisplayName = "IndexOf должен возвращать -1 для несуществующего элемента")] public void IndexOf_NonExistingItem_ShouldReturnMinusOne() { @@ -244,27 +247,27 @@ public void IndexOf_NonExistingItem_ShouldReturnMinusOne() bucket.Add(10); bucket.Add(20); bucket.Add(30); - + // Act - var index = bucket.IndexOf(40); - + int index = bucket.IndexOf(40); + // Assert index.Should().Be(-1); } - + [Fact(DisplayName = "IndexOf должен возвращать -1 для пустой коллекции")] public void IndexOf_EmptyBucket_ShouldReturnMinusOne() { // Arrange var bucket = new InlineBucket(); - + // Act - var index = bucket.IndexOf(10); - + int index = bucket.IndexOf(10); + // Assert index.Should().Be(-1); } - + [Fact(DisplayName = "IndexOf должен использовать переданный компаратор")] public void IndexOf_WithCustomEqualityComparer_ShouldUseIt() { @@ -272,18 +275,18 @@ public void IndexOf_WithCustomEqualityComparer_ShouldUseIt() var bucket = new InlineBucket(); bucket.Add(new TestStruct { Value = 10 }); bucket.Add(new TestStruct { Value = 20 }); - - var comparer = EqualityComparer.Create( - (x, y) => x.Value == y.Value, + + EqualityComparer comparer = EqualityComparer.Create( + (x, y) => x.Value == y.Value, x => x.Value.GetHashCode()); - + // Act - var index = bucket.IndexOf(new TestStruct { Value = 20 }, comparer); - + int index = bucket.IndexOf(new TestStruct { Value = 20 }, comparer); + // Assert index.Should().Be(1); } - + [Fact(DisplayName = "Remove должен удалять существующий элемент из начала коллекции")] public void Remove_ExistingItemFromBeginning_ShouldRemoveAndReturnTrue() { @@ -292,18 +295,18 @@ public void Remove_ExistingItemFromBeginning_ShouldRemoveAndReturnTrue() bucket.Add(10); bucket.Add(20); bucket.Add(30); - var initialLength = bucket.Length; - + int initialLength = bucket.Length; + // Act - var result = bucket.Remove(10); - + bool result = bucket.Remove(10); + // Assert result.Should().BeTrue(); bucket.Length.Should().Be(initialLength - 1); bucket[0].Should().Be(20); bucket[1].Should().Be(30); } - + [Fact(DisplayName = "Remove должен удалять существующий элемент из середины коллекции")] public void Remove_ExistingItemFromMiddle_ShouldRemoveAndReturnTrue() { @@ -312,18 +315,18 @@ public void Remove_ExistingItemFromMiddle_ShouldRemoveAndReturnTrue() bucket.Add(10); bucket.Add(20); bucket.Add(30); - var initialLength = bucket.Length; - + int initialLength = bucket.Length; + // Act - var result = bucket.Remove(20); - + bool result = bucket.Remove(20); + // Assert result.Should().BeTrue(); bucket.Length.Should().Be(initialLength - 1); bucket[0].Should().Be(10); bucket[1].Should().Be(30); } - + [Fact(DisplayName = "Remove должен удалять существующий элемент из конца коллекции")] public void Remove_ExistingItemFromEnd_ShouldRemoveAndReturnTrue() { @@ -332,18 +335,18 @@ public void Remove_ExistingItemFromEnd_ShouldRemoveAndReturnTrue() bucket.Add(10); bucket.Add(20); bucket.Add(30); - var initialLength = bucket.Length; - + int initialLength = bucket.Length; + // Act - var result = bucket.Remove(30); - + bool result = bucket.Remove(30); + // Assert result.Should().BeTrue(); bucket.Length.Should().Be(initialLength - 1); bucket[0].Should().Be(10); bucket[1].Should().Be(20); } - + [Fact(DisplayName = "Remove должен возвращать false для несуществующего элемента")] public void Remove_NonExistingItem_ShouldReturnFalse() { @@ -352,29 +355,29 @@ public void Remove_NonExistingItem_ShouldReturnFalse() bucket.Add(10); bucket.Add(20); bucket.Add(30); - var initialLength = bucket.Length; - + int initialLength = bucket.Length; + // Act - var result = bucket.Remove(40); - + bool result = bucket.Remove(40); + // Assert result.Should().BeFalse(); bucket.Length.Should().Be(initialLength); } - + [Fact(DisplayName = "Remove должен возвращать false для пустой коллекции")] public void Remove_EmptyBucket_ShouldReturnFalse() { // Arrange var bucket = new InlineBucket(); - + // Act - var result = bucket.Remove(10); - + bool result = bucket.Remove(10); + // Assert result.Should().BeFalse(); } - + [Fact(DisplayName = "Remove должен использовать переданный компаратор")] public void Remove_WithCustomEqualityComparer_ShouldUseIt() { @@ -382,48 +385,48 @@ public void Remove_WithCustomEqualityComparer_ShouldUseIt() var bucket = new InlineBucket(); bucket.Add(new TestStruct { Value = 10 }); bucket.Add(new TestStruct { Value = 20 }); - - var comparer = EqualityComparer.Create( - (x, y) => x.Value == y.Value, + + EqualityComparer comparer = EqualityComparer.Create( + (x, y) => x.Value == y.Value, x => x.Value.GetHashCode()); - + // Act - var result = bucket.Remove(new TestStruct { Value = 20 }, comparer); - + bool result = bucket.Remove(new TestStruct { Value = 20 }, comparer); + // Assert result.Should().BeTrue(); bucket.Length.Should().Be(1); } - + [Fact(DisplayName = "Remove должен корректно обрабатывать элементы за пределами встроенного массива")] public void Remove_ItemFromBeyondInlineArray_ShouldWorkCorrectly() { // Arrange var bucket = new InlineBucket(); - + // Заполняем больше элементов, чем размер встроенного массива for (var i = 0; i < 15; i++) { bucket.Add(i); } - + // Act - var result = bucket.Remove(12); - + bool result = bucket.Remove(12); + // Assert result.Should().BeTrue(); bucket.Length.Should().Be(14); - + // Проверяем, что все элементы на своих местах for (var i = 0; i < 12; i++) { bucket[i].Should().Be(i); } - + bucket[12].Should().Be(13); bucket[13].Should().Be(14); } - + [Fact(DisplayName = "ToArray должен возвращать массив со всеми элементами")] public void ToArray_ShouldReturnArrayWithAllItems() { @@ -432,27 +435,27 @@ public void ToArray_ShouldReturnArrayWithAllItems() bucket.Add(10); bucket.Add(20); bucket.Add(30); - + // Act - var array = bucket.ToArray(); - + int[] array = bucket.ToArray(); + // Assert array.Should().BeEquivalentTo(new[] { 10, 20, 30 }); } - + [Fact(DisplayName = "ToArray должен возвращать пустой массив для пустой коллекции")] public void ToArray_EmptyBucket_ShouldReturnEmptyArray() { // Arrange var bucket = new InlineBucket(); - + // Act - var array = bucket.ToArray(); - + int[] array = bucket.ToArray(); + // Assert array.Should().BeEmpty(); } - + [Fact(DisplayName = "TryAdd должен добавлять элемент, если его нет в коллекции")] public void TryAdd_NonExistingItem_ShouldAddAndReturnTrue() { @@ -460,16 +463,16 @@ public void TryAdd_NonExistingItem_ShouldAddAndReturnTrue() var bucket = new InlineBucket(); bucket.Add(10); bucket.Add(20); - + // Act - var result = bucket.TryAdd(30); - + bool result = bucket.TryAdd(30); + // Assert result.Should().BeTrue(); bucket.Length.Should().Be(3); bucket[2].Should().Be(30); } - + [Fact(DisplayName = "Индексатор должен правильно получать элементы из встроенного массива")] public void Indexer_Get_ShouldRetrieveItemsFromInlineArray() { @@ -478,32 +481,32 @@ public void Indexer_Get_ShouldRetrieveItemsFromInlineArray() bucket.Add(10); bucket.Add(20); bucket.Add(30); - + // Act & Assert bucket[0].Should().Be(10); bucket[1].Should().Be(20); bucket[2].Should().Be(30); } - + [Fact(DisplayName = "Индексатор должен правильно получать элементы за пределами встроенного массива")] public void Indexer_Get_ShouldRetrieveItemsBeyondInlineArray() { // Arrange var bucket = new InlineBucket(); - + // Добавляем больше элементов, чем размер встроенного массива for (var i = 0; i < 15; i++) { bucket.Add(i); } - + // Act & Assert for (var i = 0; i < 15; i++) { bucket[i].Should().Be(i); } } - + [Fact(DisplayName = "Индексатор должен правильно устанавливать элементы во встроенном массиве")] public void Indexer_Set_ShouldSetItemsInInlineArray() { @@ -512,37 +515,37 @@ public void Indexer_Set_ShouldSetItemsInInlineArray() bucket.Add(10); bucket.Add(20); bucket.Add(30); - + // Act bucket[1] = 25; - + // Assert bucket[0].Should().Be(10); bucket[1].Should().Be(25); bucket[2].Should().Be(30); } - + [Fact(DisplayName = "Индексатор должен правильно устанавливать элементы за пределами встроенного массива")] public void Indexer_Set_ShouldSetItemsBeyondInlineArray() { // Arrange var bucket = new InlineBucket(); - + // Добавляем больше элементов, чем размер встроенного массива for (var i = 0; i < 15; i++) { bucket.Add(i); } - + // Act bucket[12] = 120; - + // Assert bucket[12].Should().Be(120); } - + public struct TestStruct { public int Value; } -} \ No newline at end of file +} diff --git a/tests/Hexecs.Tests/Collections/ThreadLocalStackShould.cs b/tests/Hexecs.Tests/Collections/ThreadLocalStackShould.cs index 4079bfa..7441d4f 100644 --- a/tests/Hexecs.Tests/Collections/ThreadLocalStackShould.cs +++ b/tests/Hexecs.Tests/Collections/ThreadLocalStackShould.cs @@ -4,7 +4,8 @@ namespace Hexecs.Tests.Collections; public sealed class ThreadLocalStackShould { - [Theory, AutoData] + [Theory] + [AutoData] [Trait("Category", "Unit")] public void Store_And_Retrieve_Single_Element(uint value) { @@ -13,7 +14,7 @@ public void Store_And_Retrieve_Single_Element(uint value) // Act stack.Push(value); - var success = stack.TryPop(out var result); + bool success = stack.TryPop(out uint result); // Assert success.Should().BeTrue(); @@ -29,11 +30,18 @@ public void Handle_Push_And_Pop_Of_Multiple_Elements_In_LIFO_Order() var values = new uint[] { 10, 20, 30, 40 }; // Act - foreach (var v in values) stack.Push(v); + foreach (uint v in values) + { + stack.Push(v); + } // Assert var results = new List(); - while (stack.TryPop(out var r)) results.Add(r); + + while (stack.TryPop(out uint r)) + { + results.Add(r); + } results.Should().Equal(40, 30, 20, 10); } @@ -46,13 +54,14 @@ public void Return_False_On_Empty_Stack() using var stack = new ThreadLocalStack(); // Act - var success = stack.TryPop(out _); + bool success = stack.TryPop(out _); // Assert success.Should().BeFalse(); } - [Fact(DisplayName = "Стек должен корректно работать с большим объемом данных в однопоточном режиме, гарантируя отсутствие потерь при миграции данных в глобальный пул")] + [Fact( + DisplayName = "Стек должен корректно работать с большим объемом данных в однопоточном режиме, гарантируя отсутствие потерь при миграции данных в глобальный пул")] [Trait("Category", "Unit")] public void Correctly_Handle_Large_Volume_In_Single_Thread() { @@ -62,20 +71,27 @@ public void Correctly_Handle_Large_Volume_In_Single_Thread() var results = new List(count); // Act - for (uint i = 0; i < count; i++) stack.Push(i); - - while (stack.TryPop(out var result)) + for (uint i = 0; i < count; i++) + { + stack.Push(i); + } + + while (stack.TryPop(out uint result)) { results.Add(result); } // Assert results.Should().HaveCount(count); - + // Вместо тяжелого BeEquivalentTo используем быструю проверку набора данных - var resultHash = results.Aggregate(0u, (s, v) => s ^ v); + uint resultHash = results.Aggregate(0u, (s, v) => s ^ v); var expectedHash = 0u; - for (uint i = 0; i < count; i++) expectedHash ^= i; + + for (uint i = 0; i < count; i++) + { + expectedHash ^= i; + } resultHash.Should().Be(expectedHash, "контрольная сумма всех ID должна совпадать"); results.Should().OnlyHaveUniqueItems("ID не должны дублироваться"); @@ -89,31 +105,36 @@ public void Ensure_No_Data_Loss_Under_Parallel_Load() const int threadsCount = 4; const int opsPerThread = 25_000; const int totalCount = threadsCount * opsPerThread; - - using var stack = new ThreadLocalStack(totalCount); + + var stack = new ThreadLocalStack(totalCount); var counts = new int[totalCount]; // Act - Parallel.For(0, threadsCount, t => - { - for (var i = 0; i < opsPerThread; i++) + Parallel.For( + 0, + threadsCount, + t => { - var val = (uint)(t * opsPerThread + i); - stack.Push(val); - - if (stack.TryPop(out var popped)) + for (var i = 0; i < opsPerThread; i++) { - Interlocked.Increment(ref counts[popped]); + var val = (uint)(t * opsPerThread + i); + stack.Push(val); + + if (stack.TryPop(out uint popped)) + { + Interlocked.Increment(ref counts[popped]); + } } - } - }); + }); // Добираем "осадок" из локальных буферов, чтобы убедиться, что всё на месте - while (stack.TryPop(out var remaining)) + while (stack.TryPop(out uint remaining)) { Interlocked.Increment(ref counts[remaining]); } + stack.Dispose(); + // Assert counts.Should().OnlyContain(x => x == 1, "каждый вставленный ID должен быть обработан ровно один раз"); } @@ -130,20 +151,32 @@ public async Task Allow_Threads_To_Exchange_Data_Through_Global_Pool() // Поток A: Заполняет и завершается await Task.Run(() => { - for (uint i = 0; i < elementCount; i++) stack.Push(i); + for (uint i = 0; i < elementCount; i++) + { + stack.Push(i); + } + stack.Flush(); }); // Поток B: Пытается выкачать всё - var results = await Task.Run(() => + List results = await Task.Run(() => { var list = new List(); - var timeout = DateTime.Now.AddSeconds(5); + DateTime timeout = DateTime.Now.AddSeconds(5); + while (list.Count < elementCount && DateTime.Now < timeout) { - if (stack.TryPop(out var val)) list.Add(val); - else Thread.Yield(); + if (stack.TryPop(out uint val)) + { + list.Add(val); + } + else + { + Thread.Yield(); + } } + return list; }); @@ -151,4 +184,4 @@ await Task.Run(() => results.Should().HaveCount((int)elementCount, "все элементы должны быть переданы между потоками"); results.Should().OnlyHaveUniqueItems(); } -} \ No newline at end of file +} diff --git a/tests/Hexecs.Tests/Configurations/ConfigurationserviceShould.cs b/tests/Hexecs.Tests/Configurations/ConfigurationserviceShould.cs index e0b8c9f..cc272ff 100644 --- a/tests/Hexecs.Tests/Configurations/ConfigurationserviceShould.cs +++ b/tests/Hexecs.Tests/Configurations/ConfigurationserviceShould.cs @@ -1,4 +1,5 @@ using System.Collections.Concurrent; + using Hexecs.Configurations; namespace Hexecs.Tests.Configurations; @@ -14,7 +15,7 @@ public void GetValue_ShouldReturnValueFromSource() mockSource.Setup(s => s.TryGetValue(It.Is(k => k == "test-key"), out outValue!)) .Returns(true); - var sources = new[] { mockSource.Object }; + IConfigurationSource[] sources = new[] { mockSource.Object }; var values = new ConcurrentDictionary(); var service = new ConfigurationService(sources, values); @@ -34,7 +35,7 @@ public void GetValue_ShouldCacheValueAfterFirstAccess() mockSource.Setup(s => s.TryGetValue(It.Is(k => k == "test-key"), out outValue!)) .Returns(true); - var sources = new[] { mockSource.Object }; + IConfigurationSource[] sources = new[] { mockSource.Object }; var values = new ConcurrentDictionary(); var service = new ConfigurationService(sources, values); @@ -57,7 +58,7 @@ public void GetValue_ShouldReturnNull_WhenValueNotFound() mockSource.Setup(s => s.TryGetValue(It.IsAny(), out outValue)) .Returns(false); - var sources = new[] { mockSource.Object }; + IConfigurationSource[] sources = new[] { mockSource.Object }; var values = new ConcurrentDictionary(); var service = new ConfigurationService(sources, values); @@ -84,7 +85,7 @@ public void GetValue_ShouldCheckAllSourcesInOrder() .Setup(s => s.TryGetValue(It.Is(k => k == "test-key"), out outValue2!)) .Returns(true); - var sources = new[] { mockSource1.Object, mockSource2.Object }; + IConfigurationSource[] sources = new[] { mockSource1.Object, mockSource2.Object }; var values = new ConcurrentDictionary(); var service = new ConfigurationService(sources, values); @@ -102,11 +103,11 @@ public void GetRequiredValue_ShouldReturnValue_WhenFound() { // Arrange var mockSource = new Mock(); - int outValue = 42; + var outValue = 42; mockSource.Setup(s => s.TryGetValue(It.Is(k => k == "test-key"), out outValue)) .Returns(true); - var sources = new[] { mockSource.Object }; + IConfigurationSource[] sources = new[] { mockSource.Object }; var values = new ConcurrentDictionary(); var service = new ConfigurationService(sources, values); @@ -122,16 +123,16 @@ public void GetRequiredValue_ShouldThrowException_WhenValueNotFound() { // Arrange var mockSource = new Mock(); - int outValue = 0; + var outValue = 0; mockSource.Setup(s => s.TryGetValue(It.IsAny(), out outValue)) .Returns(false); - var sources = new[] { mockSource.Object }; + IConfigurationSource[] sources = new[] { mockSource.Object }; var values = new ConcurrentDictionary(); var service = new ConfigurationService(sources, values); // Act & Assert - var act = () => service.GetRequiredValue("non-existent-key"); + Func act = () => service.GetRequiredValue("non-existent-key"); act.Should().Throw(); } @@ -154,10 +155,10 @@ public void GetValue_ShouldHandleDifferentTypes(T expectedValue) { // Arrange var mockSource = new Mock(); - + // Используем CallBase и создаем тестовый источник var testSource = new TestConfigurationSource(expectedValue); - + var sources = new IConfigurationSource[] { testSource }; var values = new ConcurrentDictionary(); var service = new ConfigurationService(sources, values); @@ -189,10 +190,12 @@ public bool TryGetValue(string key, out TValue value) if (typeof(TValue) == typeof(T)) { value = (TValue)(object)_value!; + return true; } - + value = default!; + return false; } -} \ No newline at end of file +} diff --git a/tests/Hexecs.Tests/Threading/DefaultParallelWorkerShould.cs b/tests/Hexecs.Tests/Threading/DefaultParallelWorkerShould.cs index 18dc7de..7da77f4 100644 --- a/tests/Hexecs.Tests/Threading/DefaultParallelWorkerShould.cs +++ b/tests/Hexecs.Tests/Threading/DefaultParallelWorkerShould.cs @@ -1,5 +1,6 @@ using System.Collections.Concurrent; using System.Diagnostics; + using Hexecs.Threading; using Hexecs.Worlds; @@ -40,12 +41,13 @@ public void CallEachWorkerExactlyOnce() using var worker = new DefaultParallelWorker(degreeOfParallelism); var executionCounts = new int[degreeOfParallelism]; - var job = new TestParallelJob(_context, + var job = new TestParallelJob( + _context, (workerIndex, _) => { Interlocked.Increment(ref executionCounts[workerIndex]); }); worker.Run(job); - foreach (var count in executionCounts) + foreach (int count in executionCounts) { Assert.Equal(1, count); } @@ -78,11 +80,13 @@ public void ExecuteWorkInParallel() using var worker = new DefaultParallelWorker(degreeOfParallelism); var threadIds = new ConcurrentBag(); - var job = new TestParallelJob(_context, (_, _) => - { - threadIds.Add(Environment.CurrentManagedThreadId); - Thread.Sleep(10); // simulate work - }); + var job = new TestParallelJob( + _context, + (_, _) => + { + threadIds.Add(Environment.CurrentManagedThreadId); + Thread.Sleep(10); // simulate work + }); worker.Run(job); @@ -118,11 +122,13 @@ public void PassCorrectWorkerIndexAndCount() var indices = new ConcurrentBag(); var counts = new ConcurrentBag(); - var job = new TestParallelJob(_context, (workerIndex, workerCount) => - { - indices.Add(workerIndex); - counts.Add(workerCount); - }); + var job = new TestParallelJob( + _context, + (workerIndex, workerCount) => + { + indices.Add(workerIndex); + counts.Add(workerCount); + }); worker.Run(job); @@ -158,14 +164,16 @@ public void WorkCorrectlyInGameLoop() const int frameCount = 60; // 60 кадров var totalExecutions = 0; - for (int frame = 0; frame < frameCount; frame++) + for (var frame = 0; frame < frameCount; frame++) { var frameExecutions = 0; - var job = new TestParallelJob(_context, (_, _) => - { - Interlocked.Increment(ref frameExecutions); - Thread.SpinWait(100); // simulate work - }); + var job = new TestParallelJob( + _context, + (_, _) => + { + Interlocked.Increment(ref frameExecutions); + Thread.SpinWait(100); // simulate work + }); worker.Run(job); @@ -204,4 +212,4 @@ public void Dispose() { _world.Dispose(); } -} \ No newline at end of file +} diff --git a/tests/Hexecs.Tests/Utils/ValueStringBuilderShould.cs b/tests/Hexecs.Tests/Utils/ValueStringBuilderShould.cs index 09ec629..657452c 100644 --- a/tests/Hexecs.Tests/Utils/ValueStringBuilderShould.cs +++ b/tests/Hexecs.Tests/Utils/ValueStringBuilderShould.cs @@ -3,67 +3,67 @@ namespace Hexecs.Tests.Utils; -public class ValueStringBuilderShould +public sealed class ValueStringBuilderShould { [Fact(DisplayName = "Создание пустого билдера через конструктор с буфером")] public void EmptyConstructor_CreatesEmptyBuilder() { // Arrange Span buffer = stackalloc char[16]; - + // Act var builder = new ValueStringBuilder(buffer); - + // Assert builder.Length.Should().Be(0); builder.ToString().Should().BeEmpty(); } - + [Fact(DisplayName = "Создание пустого билдера через конструктор с ёмкостью")] public void CapacityConstructor_CreatesEmptyBuilder() { // Arrange & Act using var builder = new ValueStringBuilder(16); - + // Assert builder.Length.Should().Be(0); builder.ToString().Should().BeEmpty(); } - + [Fact(DisplayName = "Добавление символов добавляет их в билдер")] public void Append_Char_AppendsToBuilder() { // Arrange Span buffer = stackalloc char[16]; var builder = new ValueStringBuilder(buffer); - + // Act builder.Append('a'); builder.Append('b'); builder.Append('c'); - + // Assert builder.Length.Should().Be(3); builder.ToString().Should().Be("abc"); } - + [Fact(DisplayName = "Добавление строк корректно добавляется в билдер")] public void Append_String_AppendsToBuilder() { // Arrange Span buffer = stackalloc char[16]; var builder = new ValueStringBuilder(buffer); - + // Act builder.Append("Hello"); builder.Append(" "); builder.Append("World"); - + // Assert builder.Length.Should().Be(11); builder.ToString().Should().Be("Hello World"); } - + [Theory(DisplayName = "Добавление пустой или null строки не изменяет билдер")] [InlineData("")] [InlineData(null)] @@ -72,15 +72,15 @@ public void Append_EmptyOrNullString_NoEffect(string? input) // Arrange Span buffer = stackalloc char[16]; var builder = new ValueStringBuilder(buffer); - + // Act builder.Append(input); - + // Assert builder.Length.Should().Be(0); builder.ToString().Should().BeEmpty(); } - + [Theory(DisplayName = "Добавление булевых значений добавляет 'True' или 'False'")] [InlineData(true, "True")] [InlineData(false, "False")] @@ -89,14 +89,14 @@ public void Append_Bool_AppendsCorrectString(bool value, string expected) // Arrange Span buffer = stackalloc char[16]; var builder = new ValueStringBuilder(buffer); - + // Act builder.Append(value); - + // Assert builder.ToString().Should().Be(expected); } - + [Theory(DisplayName = "Добавление целых чисел преобразует их в строки")] [InlineData(42, "42")] [InlineData(-123, "-123")] @@ -108,14 +108,14 @@ public void Append_Int_AppendsCorrectString(int value, string expected) // Arrange Span buffer = stackalloc char[16]; var builder = new ValueStringBuilder(buffer); - + // Act builder.Append(value); - + // Assert builder.ToString().Should().Be(expected); } - + [Theory(DisplayName = "Добавление целых чисел с форматом применяет указанный формат")] [InlineData(42, "X4", "002A")] [InlineData(255, "D8", "00000255")] @@ -125,14 +125,14 @@ public void Append_Int_WithFormat_AppendsCorrectString(int value, string format, // Arrange Span buffer = stackalloc char[32]; var builder = new ValueStringBuilder(buffer); - + // Act builder.Append(value, format); - + // Assert builder.ToString().Should().Be(expected); } - + [Theory(DisplayName = "Добавление чисел с плавающей точкой преобразует их в строки")] [InlineData(3.14159, "3.14159")] [InlineData(-0.5, "-0.5")] @@ -142,14 +142,14 @@ public void Append_Double_AppendsCorrectString(double value, string expected) // Arrange Span buffer = stackalloc char[32]; var builder = new ValueStringBuilder(buffer); - + // Act builder.Append(value, culture: CultureInfo.InvariantCulture); - + // Assert builder.ToString().Should().Be(expected); } - + [Theory(DisplayName = "Добавление чисел с плавающей точкой с форматом применяет формат")] [InlineData(3.14159, "F2", "3.14")] [InlineData(1234.5678, "E2", "1.23E+003")] @@ -159,14 +159,14 @@ public void Append_Double_WithFormat_AppendsCorrectString(double value, string f // Arrange Span buffer = stackalloc char[32]; var builder = new ValueStringBuilder(buffer); - + // Act builder.Append(value, format, CultureInfo.InvariantCulture); - + // Assert builder.ToString().Should().Be(expected); } - + [Fact(DisplayName = "Добавление GUID преобразует его в строку со стандартным форматом")] public void Append_Guid_AppendsCorrectString() { @@ -174,14 +174,14 @@ public void Append_Guid_AppendsCorrectString() Span buffer = stackalloc char[64]; var builder = new ValueStringBuilder(buffer); var guid = new Guid("12345678-1234-1234-1234-123456789abc"); - + // Act builder.Append(guid); - + // Assert builder.ToString().Should().Be("12345678-1234-1234-1234-123456789abc"); } - + [Theory(DisplayName = "Добавление GUID с форматом применяет указанный формат")] [InlineData("D", "12345678-1234-1234-1234-123456789abc")] [InlineData("B", "{12345678-1234-1234-1234-123456789abc}")] @@ -192,14 +192,14 @@ public void Append_Guid_WithFormat_AppendsCorrectString(string format, string ex Span buffer = stackalloc char[64]; var builder = new ValueStringBuilder(buffer); var guid = new Guid("12345678-1234-1234-1234-123456789abc"); - + // Act builder.Append(guid, format); - + // Assert builder.ToString().Should().Be(expected); } - + [Fact(DisplayName = "Добавление DateTime с форматом применяет указанный формат")] public void Append_DateTime_WithFormat_AppendsCorrectString() { @@ -207,14 +207,14 @@ public void Append_DateTime_WithFormat_AppendsCorrectString() Span buffer = stackalloc char[64]; var builder = new ValueStringBuilder(buffer); var date = new DateTime(2023, 10, 15, 14, 30, 45); - + // Act builder.Append(date, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture); - + // Assert builder.ToString().Should().Be("2023-10-15 14:30:45"); } - + [Theory(DisplayName = "Добавление TimeSpan с разными форматами применяет форматы")] [InlineData("c", "01:02:03")] [InlineData("g", "1:02:03")] @@ -224,14 +224,14 @@ public void Append_TimeSpan_WithFormat_AppendsCorrectString(string format, strin Span buffer = stackalloc char[64]; var builder = new ValueStringBuilder(buffer); var timeSpan = new TimeSpan(0, 1, 2, 3); - + // Act builder.Append(timeSpan, format, CultureInfo.InvariantCulture); - + // Assert builder.ToString().Should().Be(expected); } - + [Fact(DisplayName = "Добавление Span добавляет все символы в билдер")] public void Append_CharSpan_AppendsCorrectString() { @@ -239,14 +239,14 @@ public void Append_CharSpan_AppendsCorrectString() Span buffer = stackalloc char[32]; var builder = new ValueStringBuilder(buffer); Span value = stackalloc char[] { 'T', 'e', 's', 't' }; - + // Act builder.Append(value); - + // Assert builder.ToString().Should().Be("Test"); } - + [Fact(DisplayName = "Добавление ReadOnlySpan добавляет все символы в билдер")] public void Append_ReadOnlyCharSpan_AppendsCorrectString() { @@ -254,14 +254,14 @@ public void Append_ReadOnlyCharSpan_AppendsCorrectString() Span buffer = stackalloc char[32]; var builder = new ValueStringBuilder(buffer); ReadOnlySpan value = "Hello"; - + // Act builder.Append(value); - + // Assert builder.ToString().Should().Be("Hello"); } - + [Fact(DisplayName = "Clear сбрасывает длину билдера без изменения буфера")] public void Clear_ResetsLength() { @@ -269,19 +269,19 @@ public void Clear_ResetsLength() Span buffer = stackalloc char[32]; var builder = new ValueStringBuilder(buffer); builder.Append("Test"); - + // Act builder.Clear(); - + // Assert builder.Length.Should().Be(0); builder.ToString().Should().BeEmpty(); - + // Проверяем, что можно снова добавлять данные builder.Append("New"); builder.ToString().Should().Be("New"); } - + [Fact(DisplayName = "Whitespace добавляет пробел в билдер")] public void Whitespace_AddsSpace() { @@ -289,15 +289,15 @@ public void Whitespace_AddsSpace() Span buffer = stackalloc char[32]; var builder = new ValueStringBuilder(buffer); builder.Append("Hello"); - + // Act builder.Whitespace(); builder.Append("World"); - + // Assert builder.ToString().Should().Be("Hello World"); } - + [Theory(DisplayName = "TrimEnd удаляет различные пробельные символы в конце")] [InlineData("Hello ", "Hello")] [InlineData("Hello\t\n ", "Hello")] @@ -309,14 +309,14 @@ public void TrimEnd_RemovesTrailingWhitespace(string input, string expected) Span buffer = stackalloc char[32]; var builder = new ValueStringBuilder(buffer); builder.Append(input); - + // Act builder.TrimEnd(); - + // Assert builder.ToString().Should().Be(expected); } - + [Fact(DisplayName = "EnsureCapacity увеличивает буфер для требуемой ёмкости")] public void EnsureCapacity_GrowsBuffer() { @@ -324,20 +324,20 @@ public void EnsureCapacity_GrowsBuffer() Span buffer = stackalloc char[4]; var builder = new ValueStringBuilder(buffer); builder.Append("AB"); - + // Act builder.EnsureCapacity(10); - + // Проверяем, что существующее содержимое сохранилось builder.ToString().Should().Be("AB"); - + // Проверяем, что можем добавить больше символов builder.Append("CDEFGHIJ"); - + // Assert builder.ToString().Should().Be("ABCDEFGHIJ"); } - + [Fact(DisplayName = "EnsureCapacity не изменяет буфер, если текущей ёмкости достаточно")] public void EnsureCapacity_DoesNotGrowBufferWhenCapacityIsSufficient() { @@ -345,14 +345,14 @@ public void EnsureCapacity_DoesNotGrowBufferWhenCapacityIsSufficient() Span buffer = stackalloc char[16]; var builder = new ValueStringBuilder(buffer); builder.Append("AB"); - + // Act builder.EnsureCapacity(5); // Меньше текущей ёмкости 16 - + // Assert builder.ToString().Should().Be("AB"); } - + [Fact(DisplayName = "ToReadonlySpan возвращает корректный ReadOnlySpan с содержимым")] public void ToReadonlySpan_ReturnsCorrectSpan() { @@ -360,65 +360,65 @@ public void ToReadonlySpan_ReturnsCorrectSpan() Span buffer = stackalloc char[32]; var builder = new ValueStringBuilder(buffer); builder.Append("Test"); - + // Act ReadOnlySpan span = builder.AsReadonlySpan(); - + // Assert span.Length.Should().Be(4); span[0].Should().Be('T'); span[1].Should().Be('e'); span[2].Should().Be('s'); span[3].Should().Be('t'); - + // Проверка всего span целиком span.ToString().Should().Be("Test"); } - + [Fact(DisplayName = "Автоматическое увеличение буфера при превышении ёмкости")] public void AutomaticBufferGrowth_WhenAppendingBeyondCapacity() { // Arrange Span buffer = stackalloc char[4]; var builder = new ValueStringBuilder(buffer); - + // Act builder.Append("1234"); // Заполняем исходный буфер builder.Append("5678"); // Должно вызвать увеличение буфера - + // Assert builder.ToString().Should().Be("12345678"); builder.Length.Should().Be(8); } - + [Fact(DisplayName = "Добавление uint значений преобразует их в строки")] public void Append_UInt_AppendsCorrectString() { // Arrange Span buffer = stackalloc char[32]; var builder = new ValueStringBuilder(buffer); - + // Act builder.Append(uint.MaxValue); - + // Assert builder.ToString().Should().Be("4294967295"); } - + [Fact(DisplayName = "Добавление long значений преобразует их в строки")] public void Append_Long_AppendsCorrectString() { // Arrange Span buffer = stackalloc char[32]; var builder = new ValueStringBuilder(buffer); - + // Act builder.Append(long.MaxValue); - + // Assert builder.ToString().Should().Be("9223372036854775807"); } - + [Theory(DisplayName = "Добавление одиночного символа оптимизировано для строк длины 1")] [InlineData("A")] [InlineData("1")] @@ -428,12 +428,12 @@ public void Append_SingleCharacterString_UsesOptimizedPath(string singleChar) // Arrange Span buffer = stackalloc char[16]; var builder = new ValueStringBuilder(buffer); - + // Act builder.Append(singleChar); - + // Assert builder.Length.Should().Be(1); builder.ToString().Should().Be(singleChar); } -} \ No newline at end of file +} From c5f10e9ba4072ff43fb14a53635eea279ceddef9 Mon Sep 17 00:00:00 2001 From: Kirill Bazhaikin Date: Thu, 27 Aug 2026 02:55:40 +0300 Subject: [PATCH 10/11] Added editorconfig --- .../ActorCheckComponentExistsBenchmark.cs | 44 +++-- ...ctorCreateAddComponentsDestroyBenchmark.cs | 42 ++-- .../ActorFilter2EnumerationBenchmark.cs | 60 +++--- .../ActorFilter3EnumerationBenchmark.cs | 75 +++++--- .../Actors/ActorHierarchyBenchmark.cs | 42 ++-- .../Actors/ActorRelationBenchmark.cs | 58 +++--- ...UpdateSystemWithParallelWorkerBenchmark.cs | 38 ++-- .../Collections/SparseDictionary.cs | 104 +++++++--- .../Collections/SparsePageDictionary.cs | 114 ++++++++--- .../SparsePageDictionaryBenchmark.cs | 86 ++++++--- .../Collections/ThreadLocalStackBenchmark.cs | 83 ++++---- .../Mocks/ActorComponents/Attack.cs | 2 +- .../Mocks/ActorComponents/AttackBuilder.cs | 2 +- .../Mocks/ActorComponents/Defence.cs | 2 +- .../Mocks/ActorComponents/DefenceBuilder.cs | 2 +- .../Mocks/ActorComponents/Employee.cs | 2 +- .../ActorComponents/EmployeeAgreement.cs | 7 +- .../Mocks/ActorComponents/Employer.cs | 2 +- .../Mocks/ActorComponents/Speed.cs | 2 +- src/Hexecs/Actors/Actor.cs | 39 +++- src/Hexecs/Actors/ActorConstraint.cs | 44 +++-- src/Hexecs/Attributes/OrderAttribute.cs | 3 +- src/Hexecs/Collections/ArrayEnumerator.cs | 9 +- src/Hexecs/Collections/Block.cs | 86 +++++++-- src/Hexecs/Collections/Bucket.cs | 111 ++++++++--- src/Hexecs/Collections/InlineBucket.cs | 132 +++++++++---- src/Hexecs/Collections/ThreadLocalStack.cs | 36 ++-- .../Configurations/ConfigurationBuilder.cs | 8 +- .../Configurations/ConfigurationError.cs | 2 +- .../Configurations/ConfigurationService.cs | 35 ++-- .../Configurations/IConfigurationSource.cs | 2 +- src/Hexecs/Dependencies/Dependency.cs | 14 +- src/Hexecs/Dependencies/DependencyError.cs | 11 +- src/Hexecs/Dependencies/DependencyKey.cs | 24 ++- src/Hexecs/Dependencies/DependencyProvider.cs | 94 ++++++--- .../DependencyProviderExtensions.cs | 31 ++- src/Hexecs/Dependencies/DependencyUtils.cs | 18 +- .../Dependencies/IDependencyCollection.cs | 2 +- .../Dependencies/IDependencyProvider.cs | 2 +- .../Dependencies/IDependencyRegistrar.cs | 2 +- src/Hexecs/Loggers/ContextLogger.cs | 13 +- src/Hexecs/Loggers/ILogSink.cs | 21 +- src/Hexecs/Loggers/ILogValueWriter.cs | 2 +- src/Hexecs/Loggers/ILogValueWriterFactory.cs | 2 +- src/Hexecs/Loggers/LogBuilder.cs | 41 ++-- src/Hexecs/Loggers/LogLevel.cs | 4 +- src/Hexecs/Loggers/LogService.cs | 57 ++++-- .../Serializations/JsonWriterExtensions.cs | 29 ++- src/Hexecs/Threading/DefaultParallelWorker.cs | 18 +- src/Hexecs/Threading/IParallelJob.cs | 2 +- src/Hexecs/Threading/IParallelWorker.cs | 4 +- src/Hexecs/Threading/ThreadingError.cs | 2 +- src/Hexecs/Utils/Args.cs | 58 ++++-- src/Hexecs/Utils/ArrayUtils.cs | 82 ++++++-- src/Hexecs/Utils/CollectionUtils.cs | 62 ++++-- src/Hexecs/Utils/ComponentsAccess.cs | 13 +- src/Hexecs/Utils/DelegateUtils.cs | 6 +- src/Hexecs/Utils/Error.cs | 12 +- src/Hexecs/Utils/HashHelper.cs | 21 +- src/Hexecs/Utils/IArray.cs | 2 +- src/Hexecs/Utils/ICloneable.cs | 4 +- src/Hexecs/Utils/IHaveOrder.cs | 2 +- src/Hexecs/Utils/OrderComparer.cs | 28 ++- src/Hexecs/Utils/ReferenceComparer.cs | 12 +- src/Hexecs/Utils/ServiceProviderExtensions.cs | 4 +- src/Hexecs/Utils/StringUtils.cs | 22 ++- src/Hexecs/Utils/TypeOf.cs | 39 ++-- src/Hexecs/Utils/ValueStringBuilder.cs | 155 ++++++++++----- .../Actors/ActorComponentShould.cs | 2 +- .../Actors/ActorConstraintShould.cs | 46 ++--- .../Hexecs.Tests/Actors/ActorContextShould.cs | 182 +++++++++--------- .../Hexecs.Tests/Actors/ActorFilter1Should.cs | 2 - .../Hexecs.Tests/Actors/ActorFilter2Should.cs | 28 +-- .../Hexecs.Tests/Actors/ActorFilter3Should.cs | 45 +++-- tests/Hexecs.Tests/Actors/ActorListShould.cs | 1 + .../Hexecs.Tests/Actors/ActorMarshalShould.cs | 16 +- .../Actors/ActorMethodsConsistencyTests.cs | 97 ++++++---- tests/Hexecs.Tests/Actors/ActorNodeShould.cs | 76 ++++---- .../Actors/ActorRelationShould.cs | 55 +++--- tests/Hexecs.Tests/Actors/ActorShould.cs | 130 +++++++------ .../Hexecs.Tests/Actors/ActorSystemShould1.cs | 14 +- .../Hexecs.Tests/Actors/ActorSystemShould2.cs | 14 +- .../Hexecs.Tests/Actors/ActorSystemShould3.cs | 14 +- tests/Hexecs.Tests/Actors/ActorTestFixture.cs | 69 +++++-- tests/Hexecs.Tests/Assets/AssetTestFixture.cs | 28 ++- tests/Hexecs.Tests/BaseFixture.cs | 44 +++-- .../Collections/InlineBucketShould.cs | 10 +- .../ConfigurationserviceShould.cs | 12 +- .../Dependencies/DependencyShould.cs | 19 +- .../Hexecs.Tests/Loggers/LogServiceShould.cs | 164 +++++++++------- tests/Hexecs.Tests/Loggers/TextSinkShould.cs | 39 ++-- .../ActorComponents/DisposableComponent.cs | 5 +- tests/Hexecs.Tests/Mocks/CommandMock.cs | 2 +- tests/Hexecs.Tests/Pipelines/CommandShould.cs | 16 +- tests/Hexecs.Tests/Pipelines/MessageShould.cs | 6 +- .../Pipelines/NotificationShould.cs | 12 +- .../Pipelines/PipelineTestFixture.cs | 15 +- tests/Hexecs.Tests/Pipelines/QueryShould.cs | 8 +- tests/Hexecs.Tests/Utils/ArgsShould.cs | 56 +++--- tests/Hexecs.Tests/Utils/ArrayUtilsShould.cs | 60 +++--- tests/Hexecs.Tests/Utils/TypeOfShould.cs | 20 +- .../Utils/ValueStringBuilderShould.cs | 3 +- .../Hexecs.Tests/Values/ValueServiceShould.cs | 34 ++-- tests/Hexecs.Tests/Worlds/DiceShould.cs | 24 ++- .../Worlds/WordDependencyShould.cs | 33 ++-- 105 files changed, 2261 insertions(+), 1329 deletions(-) diff --git a/benchmarks/Hexecs.Benchmarks/Actors/ActorCheckComponentExistsBenchmark.cs b/benchmarks/Hexecs.Benchmarks/Actors/ActorCheckComponentExistsBenchmark.cs index 6aa79c8..4a7fccf 100644 --- a/benchmarks/Hexecs.Benchmarks/Actors/ActorCheckComponentExistsBenchmark.cs +++ b/benchmarks/Hexecs.Benchmarks/Actors/ActorCheckComponentExistsBenchmark.cs @@ -1,6 +1,9 @@ using Friflo.Engine.ECS; + using Hexecs.Benchmarks.Mocks.ActorComponents; using Hexecs.Worlds; + +using Entity = DefaultEcs.Entity; using World = Hexecs.Worlds.World; namespace Hexecs.Benchmarks.Actors; @@ -11,7 +14,7 @@ namespace Hexecs.Benchmarks.Actors; // [Host] : .NET 10.0.2 (10.0.2, 10.0.225.61305), X64 RyuJIT x86-64-v3 // .NET 10.0 : .NET 10.0.2 (10.0.2, 10.0.225.61305), X64 RyuJIT x86-64-v3 // -// Job=.NET 10.0 Runtime=.NET 10.0 +// Job=.NET 10.0 Runtime=.NET 10.0 // // | Method | Count | Mean | Ratio | Allocated | Alloc Ratio | // |----------------- |------- |----------:|------:|----------:|------------:| @@ -35,7 +38,7 @@ namespace Hexecs.Benchmarks.Actors; // [Host] : .NET 10.0.1 (10.0.1, 10.0.125.57005), Arm64 RyuJIT armv8.0-a // .NET 10.0 : .NET 10.0.11 (10.0.11, 10.0.1126.37416), Arm64 RyuJIT armv8.0-a // -// Job=.NET 10.0 Runtime=.NET 10.0 +// Job=.NET 10.0 Runtime=.NET 10.0 // // | Method | Count | Mean | Ratio | Allocated | Alloc Ratio | // |----------------- |------- |----------:|------:|----------:|------------:| @@ -53,14 +56,16 @@ namespace Hexecs.Benchmarks.Actors; [SimpleJob(RuntimeMoniker.Net10_0)] [Orderer(SummaryOrderPolicy.FastestToSlowest)] -[MeanColumn, MemoryDiagnoser] +[MeanColumn] +[MemoryDiagnoser] [HideColumns("Job", "Error", "StdDev", "Median", "RatioSD")] [JsonExporterAttribute.Full] [JsonExporterAttribute.FullCompressed] [BenchmarkCategory("Actors")] public class ActorCheckComponentExistsBenchmark { - [Params(10_000, 100_000)] public int Count; + [Params(10_000, 100_000)] + public int Count; private ActorContext _context = null!; private DefaultEcs.World _defaultWorld = null!; @@ -74,9 +79,12 @@ public int Hexecs_Has() var result = 0; // ReSharper disable once ForeachCanBeConvertedToQueryUsingAnotherGetEnumerator - foreach (var actor in _context) + foreach (Actor actor in _context) { - if (actor.Has()) result++; + if (actor.Has()) + { + result++; + } } return result; @@ -88,7 +96,7 @@ public int DefaultEcs_Has() var result = 0; // ReSharper disable once ForeachCanBeConvertedToQueryUsingAnotherGetEnumerator - foreach (var entity in _defaultWorld) + foreach (Entity entity in _defaultWorld) { if (entity.Has()) { @@ -105,7 +113,7 @@ public int FriFlo_Has() var result = 0; // ReSharper disable once ForeachCanBeConvertedToQueryUsingAnotherGetEnumerator - foreach (var entity in _frifloAllEntitiesQuery.Entities) + foreach (Friflo.Engine.ECS.Entity entity in _frifloAllEntitiesQuery.Entities) { if (entity.HasComponent()) { @@ -122,7 +130,7 @@ public int Hexecs_Is() var result = 0; // ReSharper disable once ForeachCanBeConvertedToQueryUsingAnotherGetEnumerator - foreach (var actor in _context) + foreach (Actor actor in _context) { if (actor.IsRef(out _)) { @@ -139,9 +147,10 @@ public int Hexecs_Reference() var result = 0; // ReSharper disable once ForeachCanBeConvertedToQueryUsingAnotherGetEnumerator - foreach (var actor in _context) + foreach (Actor actor in _context) { - ref var reference = ref actor.TryGetRef(); + ref Speed reference = ref actor.TryGetRef(); + if (!Unsafe.IsNullRef(ref reference)) { result++; @@ -174,17 +183,20 @@ public void Setup() for (var i = 0; i < Count; i++) { - var actor = _context.CreateActor(); + Actor actor = _context.CreateActor(); actor.Add(new Attack()); actor.Add(new Defence()); - var defaultEntity = _defaultWorld.CreateEntity(); + Entity defaultEntity = _defaultWorld.CreateEntity(); defaultEntity.Set(); defaultEntity.Set(); - var frifloEntity = _frifloWorld.CreateEntity(new Attack(), new Defence()); + Friflo.Engine.ECS.Entity frifloEntity = _frifloWorld.CreateEntity(new Attack(), new Defence()); - if (i % 10 != 0) continue; + if (i % 10 != 0) + { + continue; + } actor.Add(new Speed()); @@ -192,4 +204,4 @@ public void Setup() frifloEntity.Add(new Speed()); } } -} \ No newline at end of file +} diff --git a/benchmarks/Hexecs.Benchmarks/Actors/ActorCreateAddComponentsDestroyBenchmark.cs b/benchmarks/Hexecs.Benchmarks/Actors/ActorCreateAddComponentsDestroyBenchmark.cs index 93ebbe2..8b9facd 100644 --- a/benchmarks/Hexecs.Benchmarks/Actors/ActorCreateAddComponentsDestroyBenchmark.cs +++ b/benchmarks/Hexecs.Benchmarks/Actors/ActorCreateAddComponentsDestroyBenchmark.cs @@ -1,7 +1,11 @@ using DefaultEcs; + using Friflo.Engine.ECS; + using Hexecs.Benchmarks.Mocks.ActorComponents; using Hexecs.Worlds; + +using Entity = DefaultEcs.Entity; using World = Hexecs.Worlds.World; namespace Hexecs.Benchmarks.Actors; @@ -12,7 +16,7 @@ namespace Hexecs.Benchmarks.Actors; // [Host] : .NET 10.0.2 (10.0.2, 10.0.225.61305), X64 RyuJIT x86-64-v3 // .NET 10.0 : .NET 10.0.2 (10.0.2, 10.0.225.61305), X64 RyuJIT x86-64-v3 // -// Job=.NET 10.0 Runtime=.NET 10.0 +// Job=.NET 10.0 Runtime=.NET 10.0 // // | Method | Count | Mean | Ratio | Gen0 | Allocated | Alloc Ratio | // |---------------------------- |------- |-------------:|------:|---------:|-----------:|------------:| @@ -36,7 +40,7 @@ namespace Hexecs.Benchmarks.Actors; // [Host] : .NET 10.0.1 (10.0.1, 10.0.125.57005), Arm64 RyuJIT armv8.0-a // .NET 10.0 : .NET 10.0.11 (10.0.11, 10.0.1126.37416), Arm64 RyuJIT armv8.0-a // -// Job=.NET 10.0 Runtime=.NET 10.0 +// Job=.NET 10.0 Runtime=.NET 10.0 // // | Method | Count | Mean | Ratio | Gen0 | Gen1 | Allocated | Alloc Ratio | // |---------------------------- |------- |--------------:|------:|----------:|---------:|-----------:|------------:| @@ -54,14 +58,16 @@ namespace Hexecs.Benchmarks.Actors; [SimpleJob(RuntimeMoniker.Net10_0)] [Orderer(SummaryOrderPolicy.FastestToSlowest)] -[MeanColumn, MemoryDiagnoser] +[MeanColumn] +[MemoryDiagnoser] [HideColumns("Job", "Error", "StdDev", "Median", "RatioSD")] [JsonExporterAttribute.Full] [JsonExporterAttribute.FullCompressed] [BenchmarkCategory("Actors")] public class ActorCreateAddComponentsDestroyBenchmark { - [Params(1_000, 100_000, 500_000)] public int Count; + [Params(1_000, 100_000, 500_000)] + public int Count; private List _defaultEntities = null!; private List _defaultSets = null!; @@ -83,7 +89,7 @@ public int Hexecs_CreateAddDestroy() for (var i = 0; i < Count; i++) { - var actor = _hexecsContext.CreateActor(); + Actor actor = _hexecsContext.CreateActor(); actor.Add(new Attack { Value = i }); actor.Add(new Defence()); actor.Add(new Speed()); @@ -91,7 +97,7 @@ public int Hexecs_CreateAddDestroy() _hexecsActors.Add(actor); } - foreach (var actor in _hexecsActors) + foreach (Actor actor in _hexecsActors) { actor.Remove(); actor.Remove(); @@ -110,7 +116,7 @@ public int DefaultEcs_CreateAddDestroy() for (var i = 0; i < Count; i++) { - var entity = _defaultWorld.CreateEntity(); + Entity entity = _defaultWorld.CreateEntity(); entity.Set(new Attack { Value = i }); entity.Set(new Defence()); entity.Set(new Speed()); @@ -118,7 +124,7 @@ public int DefaultEcs_CreateAddDestroy() _defaultEntities.Add(entity); } - foreach (var entity in _defaultEntities) + foreach (Entity entity in _defaultEntities) { entity.Remove(); entity.Remove(); @@ -137,7 +143,7 @@ public int FriFlo_CreateAddDestroy() for (var i = 0; i < Count; i++) { - var entity = _frifloWorld.CreateEntity(); + Friflo.Engine.ECS.Entity entity = _frifloWorld.CreateEntity(); entity.AddComponent(new Attack { Value = i }); entity.AddComponent(new Defence()); entity.AddComponent(new Speed()); @@ -145,7 +151,7 @@ public int FriFlo_CreateAddDestroy() _frifloEntities.Add(entity); } - foreach (var entity in _frifloEntities) + foreach (Friflo.Engine.ECS.Entity entity in _frifloEntities) { entity.RemoveComponent(); entity.RemoveComponent(); @@ -172,7 +178,7 @@ public void Cleanup() [GlobalSetup] public void Setup() { - _defaultEntities = new List(Count); + _defaultEntities = new List(Count); _defaultWorld = new DefaultEcs.World(); _defaultSets = [ @@ -215,17 +221,17 @@ public void Setup() // warmup for (var i = 0; i < Count; i++) { - var defaultEntity = _defaultWorld.CreateEntity(); + Entity defaultEntity = _defaultWorld.CreateEntity(); defaultEntity.Set(); defaultEntity.Set(); defaultEntity.Set(); _defaultEntities.Add(defaultEntity); - var frifloEntity = _frifloWorld.CreateEntity(new Attack(), new Defence(), new Speed()); + Friflo.Engine.ECS.Entity frifloEntity = _frifloWorld.CreateEntity(new Attack(), new Defence(), new Speed()); _frifloEntities.Add(frifloEntity); - var actor = _hexecsContext.CreateActor(); + Actor actor = _hexecsContext.CreateActor(); actor.Add(new Attack()); actor.Add(new Defence()); actor.Add(new Speed()); @@ -233,17 +239,17 @@ public void Setup() _hexecsActors.Add(actor); } - foreach (var entity in _defaultEntities) + foreach (Entity entity in _defaultEntities) { entity.Dispose(); } - foreach (var entity in _frifloEntities) + foreach (Friflo.Engine.ECS.Entity entity in _frifloEntities) { entity.DeleteEntity(); } - foreach (var actor in _hexecsActors) + foreach (Actor actor in _hexecsActors) { actor.Destroy(); } @@ -252,4 +258,4 @@ public void Setup() _frifloEntities.Clear(); _hexecsActors.Clear(); } -} \ No newline at end of file +} diff --git a/benchmarks/Hexecs.Benchmarks/Actors/ActorFilter2EnumerationBenchmark.cs b/benchmarks/Hexecs.Benchmarks/Actors/ActorFilter2EnumerationBenchmark.cs index 7d96f22..11dc592 100644 --- a/benchmarks/Hexecs.Benchmarks/Actors/ActorFilter2EnumerationBenchmark.cs +++ b/benchmarks/Hexecs.Benchmarks/Actors/ActorFilter2EnumerationBenchmark.cs @@ -1,7 +1,14 @@ -using Friflo.Engine.ECS; +using DefaultEcs; + +using Friflo.Engine.ECS; + using Hexecs.Benchmarks.Mocks.ActorComponents; +using Hexecs.Utils; using Hexecs.Worlds; +using Entity = DefaultEcs.Entity; +using World = Hexecs.Worlds.World; + namespace Hexecs.Benchmarks.Actors; // BenchmarkDotNet v0.15.8, Windows 11 (10.0.22621.4317/22H2/2022Update/SunValley2) @@ -10,7 +17,7 @@ namespace Hexecs.Benchmarks.Actors; // [Host] : .NET 10.0.2 (10.0.2, 10.0.225.61305), X64 RyuJIT x86-64-v3 // .NET 10.0 : .NET 10.0.2 (10.0.2, 10.0.225.61305), X64 RyuJIT x86-64-v3 // -// Job=.NET 10.0 Runtime=.NET 10.0 +// Job=.NET 10.0 Runtime=.NET 10.0 // // | Method | Count | Mean | Ratio | Allocated | Alloc Ratio | // |----------------------- |------- |----------:|------:|----------:|------------:| @@ -34,7 +41,7 @@ namespace Hexecs.Benchmarks.Actors; // [Host] : .NET 10.0.1 (10.0.1, 10.0.125.57005), Arm64 RyuJIT armv8.0-a // .NET 10.0 : .NET 10.0.11 (10.0.11, 10.0.1126.37416), Arm64 RyuJIT armv8.0-a // -// Job=.NET 10.0 Runtime=.NET 10.0 +// Job=.NET 10.0 Runtime=.NET 10.0 // // | Method | Count | Mean | Ratio | Gen0 | Allocated | Alloc Ratio | // |----------------------- |------- |----------:|------:|-------:|----------:|------------:| @@ -52,14 +59,16 @@ namespace Hexecs.Benchmarks.Actors; [SimpleJob(RuntimeMoniker.Net10_0)] [Orderer(SummaryOrderPolicy.FastestToSlowest)] -[MeanColumn, MemoryDiagnoser] +[MeanColumn] +[MemoryDiagnoser] [HideColumns("Job", "Error", "StdDev", "Median", "RatioSD")] [JsonExporterAttribute.Full] [JsonExporterAttribute.FullCompressed] [BenchmarkCategory("Actors")] public class ActorFilter2EnumerationBenchmark { - [Params(10_000, 100_000)] public int Count; + [Params(10_000, 100_000)] + public int Count; private ActorContext _context = null!; private ActorFilter _filter = null!; @@ -75,10 +84,11 @@ public class ActorFilter2EnumerationBenchmark public int Hexecs() { var result = 0; - foreach (var actor in _filter) + + foreach (ActorRef actor in _filter) { result += actor.Component1.Value + - actor.Component2.Value; + actor.Component2.Value; } return result; @@ -89,13 +99,13 @@ public int Hexecs_ComponentAccess() { var result = 0; - var attacks = _context.GetComponents(); - var defences = _context.GetComponents(); + ComponentsAccess attacks = _context.GetComponents(); + ComponentsAccess defences = _context.GetComponents(); - foreach (var actorId in _filter.Keys) + foreach (uint actorId in _filter.Keys) { result += attacks[actorId].Value + - defences[actorId].Value; + defences[actorId].Value; } return result; @@ -104,14 +114,15 @@ public int Hexecs_ComponentAccess() [Benchmark] public int DefaultEcs() { - var attacks = _defaultWorld.GetComponents(); - var defences = _defaultWorld.GetComponents(); + Components attacks = _defaultWorld.GetComponents(); + Components defences = _defaultWorld.GetComponents(); var result = 0; - foreach (var entity in _defaultEntitySet.GetEntities()) + + foreach (Entity entity in _defaultEntitySet.GetEntities()) { result += attacks[entity].Value + - defences[entity].Value; + defences[entity].Value; } return result; @@ -125,7 +136,7 @@ public int FriFlo() _frifloQuery.ForEachEntity((ref attack, ref defence, _) => { result += attack.Value + - defence.Value; + defence.Value; }); return result; @@ -136,15 +147,15 @@ public int FriFlo_Chunks() { var result = 0; - foreach (var queryChunk in _frifloQuery.Chunks) + foreach (Chunks queryChunk in _frifloQuery.Chunks) { - var attacks = queryChunk.Chunk1; - var defences = queryChunk.Chunk2; + Chunk attacks = queryChunk.Chunk1; + Chunk defences = queryChunk.Chunk2; for (var i = 0; i < queryChunk.Length; i++) { result += attacks[i].Value + - defences[i].Value; + defences[i].Value; } } @@ -173,20 +184,21 @@ public void Setup() _filter = _world.Actors.Filter(); _frifloQuery = _frifloWorld.Query(); - var context = _world.Actors; + ActorContext context = _world.Actors; + for (var i = 0; i < Count; i++) { var attack = new Attack { Value = i }; - var actor = context.CreateActor(); + Actor actor = context.CreateActor(); actor.Add(in attack); actor.Add(new Defence()); - var defaultEntity = _defaultWorld.CreateEntity(); + Entity defaultEntity = _defaultWorld.CreateEntity(); defaultEntity.Set(in attack); defaultEntity.Set(); _frifloWorld.CreateEntity(attack, new Defence(), new Speed()); } } -} \ No newline at end of file +} diff --git a/benchmarks/Hexecs.Benchmarks/Actors/ActorFilter3EnumerationBenchmark.cs b/benchmarks/Hexecs.Benchmarks/Actors/ActorFilter3EnumerationBenchmark.cs index bca3bf0..b6e6e86 100644 --- a/benchmarks/Hexecs.Benchmarks/Actors/ActorFilter3EnumerationBenchmark.cs +++ b/benchmarks/Hexecs.Benchmarks/Actors/ActorFilter3EnumerationBenchmark.cs @@ -1,6 +1,12 @@ -using Friflo.Engine.ECS; +using DefaultEcs; + +using Friflo.Engine.ECS; + using Hexecs.Benchmarks.Mocks.ActorComponents; +using Hexecs.Utils; using Hexecs.Worlds; + +using Entity = DefaultEcs.Entity; using World = Hexecs.Worlds.World; namespace Hexecs.Benchmarks.Actors; @@ -11,7 +17,7 @@ namespace Hexecs.Benchmarks.Actors; // [Host] : .NET 10.0.2 (10.0.2, 10.0.225.61305), X64 RyuJIT x86-64-v3 // .NET 10.0 : .NET 10.0.2 (10.0.2, 10.0.225.61305), X64 RyuJIT x86-64-v3 // -// Job=.NET 10.0 Runtime=.NET 10.0 +// Job=.NET 10.0 Runtime=.NET 10.0 // // | Method | Count | Mean | Ratio | Allocated | Alloc Ratio | // |----------------------- |------- |----------:|------:|----------:|------------:| @@ -35,7 +41,7 @@ namespace Hexecs.Benchmarks.Actors; // [Host] : .NET 10.0.1 (10.0.1, 10.0.125.57005), Arm64 RyuJIT armv8.0-a // .NET 10.0 : .NET 10.0.11 (10.0.11, 10.0.1126.37416), Arm64 RyuJIT armv8.0-a // -// Job=.NET 10.0 Runtime=.NET 10.0 +// Job=.NET 10.0 Runtime=.NET 10.0 // // | Method | Count | Mean | Ratio | Allocated | Alloc Ratio | // |----------------------- |------- |-----------:|------:|----------:|------------:| @@ -53,14 +59,16 @@ namespace Hexecs.Benchmarks.Actors; [SimpleJob(RuntimeMoniker.Net10_0)] [Orderer(SummaryOrderPolicy.FastestToSlowest)] -[MeanColumn, MemoryDiagnoser] +[MeanColumn] +[MemoryDiagnoser] [HideColumns("Job", "Error", "StdDev", "Median", "RatioSD")] [JsonExporterAttribute.Full] [JsonExporterAttribute.FullCompressed] [BenchmarkCategory("Actors")] public class ActorFilter3EnumerationBenchmark { - [Params(10_000, 100_000)] public int Count; + [Params(10_000, 100_000)] + public int Count; private ActorContext _context = null!; private ActorFilter _filter = null!; @@ -76,11 +84,12 @@ public class ActorFilter3EnumerationBenchmark public int Hexecs() { var result = 0; - foreach (var actor in _filter) + + foreach (ActorRef actor in _filter) { result += actor.Component1.Value + - actor.Component2.Value + - actor.Component3.Value; + actor.Component2.Value + + actor.Component3.Value; } return result; @@ -91,15 +100,15 @@ public int Hexecs_ComponentAccess() { var result = 0; - var attacks = _context.GetComponents(); - var defences = _context.GetComponents(); - var speeds = _context.GetComponents(); + ComponentsAccess attacks = _context.GetComponents(); + ComponentsAccess defences = _context.GetComponents(); + ComponentsAccess speeds = _context.GetComponents(); - foreach (var actorId in _filter.Keys) + foreach (uint actorId in _filter.Keys) { result += attacks[actorId].Value + - defences[actorId].Value + - speeds[actorId].Value; + defences[actorId].Value + + speeds[actorId].Value; } return result; @@ -108,16 +117,17 @@ public int Hexecs_ComponentAccess() [Benchmark] public int DefaultEcs() { - var attacks = _defaultWorld.GetComponents(); - var defences = _defaultWorld.GetComponents(); - var speeds = _defaultWorld.GetComponents(); + Components attacks = _defaultWorld.GetComponents(); + Components defences = _defaultWorld.GetComponents(); + Components speeds = _defaultWorld.GetComponents(); var result = 0; - foreach (var entity in _defaultEntitySet.GetEntities()) + + foreach (Entity entity in _defaultEntitySet.GetEntities()) { result += attacks[entity].Value + - defences[entity].Value + - speeds[entity].Value; + defences[entity].Value + + speeds[entity].Value; } return result; @@ -131,8 +141,8 @@ public int FriFlo() _frifloQuery.ForEachEntity((ref attack, ref defence, ref speed, _) => { result += attack.Value + - defence.Value + - speed.Value; + defence.Value + + speed.Value; }); return result; @@ -143,17 +153,17 @@ public int FriFlo_Chunks() { var result = 0; - foreach (var queryChunk in _frifloQuery.Chunks) + foreach (Chunks queryChunk in _frifloQuery.Chunks) { - var attacks = queryChunk.Chunk1; - var defences = queryChunk.Chunk2; - var speeds = queryChunk.Chunk3; + Chunk attacks = queryChunk.Chunk1; + Chunk defences = queryChunk.Chunk2; + Chunk speeds = queryChunk.Chunk3; for (var i = 0; i < queryChunk.Length; i++) { result += attacks[i].Value + - defences[i].Value + - speeds[i].Value; + defences[i].Value + + speeds[i].Value; } } @@ -182,17 +192,18 @@ public void Setup() _filter = _world.Actors.Filter(); _frifloQuery = _frifloWorld.Query(); - var context = _world.Actors; + ActorContext context = _world.Actors; + for (var i = 0; i < Count; i++) { var attack = new Attack { Value = i }; - var actor = context.CreateActor(); + Actor actor = context.CreateActor(); actor.Add(in attack); actor.Add(new Defence()); actor.Add(new Speed()); - var defaultEntity = _defaultWorld.CreateEntity(); + Entity defaultEntity = _defaultWorld.CreateEntity(); defaultEntity.Set(in attack); defaultEntity.Set(); defaultEntity.Set(); @@ -200,4 +211,4 @@ public void Setup() _frifloWorld.CreateEntity(attack, new Defence(), new Speed()); } } -} \ No newline at end of file +} diff --git a/benchmarks/Hexecs.Benchmarks/Actors/ActorHierarchyBenchmark.cs b/benchmarks/Hexecs.Benchmarks/Actors/ActorHierarchyBenchmark.cs index 9494530..bc78f91 100644 --- a/benchmarks/Hexecs.Benchmarks/Actors/ActorHierarchyBenchmark.cs +++ b/benchmarks/Hexecs.Benchmarks/Actors/ActorHierarchyBenchmark.cs @@ -1,4 +1,5 @@ using Hexecs.Worlds; + using Friflo.Engine.ECS; namespace Hexecs.Benchmarks.Actors; @@ -9,7 +10,7 @@ namespace Hexecs.Benchmarks.Actors; // [Host] : .NET 10.0.2 (10.0.2, 10.0.225.61305), X64 RyuJIT x86-64-v3 // .NET 10.0 : .NET 10.0.2 (10.0.2, 10.0.225.61305), X64 RyuJIT x86-64-v3 // -// Job=.NET 10.0 Runtime=.NET 10.0 +// Job=.NET 10.0 Runtime=.NET 10.0 // // | Method | Count | Mean | Ratio | Allocated | Alloc Ratio | // |----------------- |------ |-------------:|------:|----------:|------------:| @@ -27,7 +28,7 @@ namespace Hexecs.Benchmarks.Actors; // [Host] : .NET 10.0.1 (10.0.1, 10.0.125.57005), Arm64 RyuJIT armv8.0-a // .NET 10.0 : .NET 10.0.2 (10.0.2, 10.0.225.61305), Arm64 RyuJIT armv8.0-a // -// Job=.NET 10.0 Runtime=.NET 10.0 +// Job=.NET 10.0 Runtime=.NET 10.0 // // | Method | Count | Mean | Ratio | Allocated | Alloc Ratio | // |----------------- |------ |------------:|------:|----------:|------------:| @@ -39,14 +40,16 @@ namespace Hexecs.Benchmarks.Actors; [SimpleJob(RuntimeMoniker.Net10_0)] [Orderer(SummaryOrderPolicy.FastestToSlowest)] -[MeanColumn, MemoryDiagnoser] +[MeanColumn] +[MemoryDiagnoser] [HideColumns("Job", "Error", "StdDev", "Median", "RatioSD")] [JsonExporterAttribute.Full] [JsonExporterAttribute.FullCompressed] [BenchmarkCategory("Actors")] public class ActorHierarchyBenchmark { - [Params(100, 1_000)] public int Count; + [Params(100, 1_000)] + public int Count; private ActorContext _actorContext = null!; private Actor[] _buffer = null!; @@ -64,7 +67,8 @@ public class ActorHierarchyBenchmark public int Hexecs_Hierarchy() { var childIdx = 0; - foreach (var parent in _parents) + + foreach (Actor parent in _parents) { for (var j = 0; j < Count; j++) { @@ -73,14 +77,14 @@ public int Hexecs_Hierarchy() } var result = 0; - var buffer = _buffer; + Actor[] buffer = _buffer; - foreach (var parent in _parents) + foreach (Actor parent in _parents) { - var children = parent.Children(); + ActorContext.ChildrenEnumerator children = parent.Children(); var k = 0; - foreach (var child in children) + foreach (Actor child in children) { buffer[k++] = child; result++; @@ -99,7 +103,8 @@ public int Hexecs_Hierarchy() public int Friflo_Hierarchy() { var childIdx = 0; - foreach (var parent in _friParents) + + foreach (Entity parent in _friParents) { for (var j = 0; j < Count; j++) { @@ -108,15 +113,15 @@ public int Friflo_Hierarchy() } var result = 0; - var buffer = _friBuffer; + Entity[] buffer = _friBuffer; for (var i = 0; i < _friParents.Length; i++) { - var parent = _friParents[i]; - var children = parent.ChildEntities; + Entity parent = _friParents[i]; + ChildEntities children = parent.ChildEntities; var k = 0; - foreach (var child in children) + foreach (Entity child in children) { buffer[k++] = child; result++; @@ -154,7 +159,7 @@ public void Setup() for (var j = 0; j < Count; j++) { - var index = (i * Count) + j; + int index = (i * Count) + j; _children[index] = _actorContext.CreateActor(); _friChildren[index] = _friStore.CreateEntity(); } @@ -162,5 +167,8 @@ public void Setup() } [GlobalCleanup] - public void Cleanup() => _world.Dispose(); -} \ No newline at end of file + public void Cleanup() + { + _world.Dispose(); + } +} diff --git a/benchmarks/Hexecs.Benchmarks/Actors/ActorRelationBenchmark.cs b/benchmarks/Hexecs.Benchmarks/Actors/ActorRelationBenchmark.cs index cc71f40..df4c991 100644 --- a/benchmarks/Hexecs.Benchmarks/Actors/ActorRelationBenchmark.cs +++ b/benchmarks/Hexecs.Benchmarks/Actors/ActorRelationBenchmark.cs @@ -1,4 +1,6 @@ using Friflo.Engine.ECS; + +using Hexecs.Actors.Relations; using Hexecs.Benchmarks.Mocks.ActorComponents; using Hexecs.Worlds; @@ -10,7 +12,7 @@ namespace Hexecs.Benchmarks.Actors; // [Host] : .NET 10.0.2 (10.0.2, 10.0.225.61305), X64 RyuJIT x86-64-v3 // .NET 10.0 : .NET 10.0.2 (10.0.2, 10.0.225.61305), X64 RyuJIT x86-64-v3 // -// Job=.NET 10.0 Runtime=.NET 10.0 +// Job=.NET 10.0 Runtime=.NET 10.0 // // | Method | Count | Mean | Ratio | Allocated | Alloc Ratio | // |------- |------ |--------------:|------:|----------:|------------:| @@ -31,7 +33,7 @@ namespace Hexecs.Benchmarks.Actors; // [Host] : .NET 10.0.1 (10.0.1, 10.0.125.57005), Arm64 RyuJIT armv8.0-a // .NET 10.0 : .NET 10.0.2 (10.0.2, 10.0.225.61305), Arm64 RyuJIT armv8.0-a // -// Job=.NET 10.0 Runtime=.NET 10.0 +// Job=.NET 10.0 Runtime=.NET 10.0 // // | Method | Count | Mean | Ratio | Allocated | Alloc Ratio | // |------- |------ |---------------:|------:|----------:|------------:| @@ -46,14 +48,16 @@ namespace Hexecs.Benchmarks.Actors; [SimpleJob(RuntimeMoniker.Net10_0)] [Orderer(SummaryOrderPolicy.FastestToSlowest)] -[MeanColumn, MemoryDiagnoser] +[MeanColumn] +[MemoryDiagnoser] [HideColumns("Job", "Error", "StdDev", "Median", "RatioSD")] [JsonExporterAttribute.Full] [JsonExporterAttribute.FullCompressed] [BenchmarkCategory("Actors")] public class ActorRelationBenchmark { - [Params(10, 100, 1_000)] public int Count; + [Params(10, 100, 1_000)] + public int Count; private ActorContext _actorContext = null!; private Actor[] _actorBuffer = null!; @@ -70,29 +74,33 @@ public class ActorRelationBenchmark public int Hexecs() { // Часть 1: Наполнение - using (var employeeEnumerator = _employeeFilter.GetEnumerator()) + using (ActorFilter.Enumerator employeeEnumerator = _employeeFilter.GetEnumerator()) { - foreach (var employer in _employerFilter) + foreach (ActorRef employer in _employerFilter) { for (var i = 0; i < Count; i++) { - if (!employeeEnumerator.MoveNext()) break; - var employee = employeeEnumerator.Current; + if (!employeeEnumerator.MoveNext()) + { + break; + } + + ActorRef employee = employeeEnumerator.Current; employer.AddRelation(employee, new EmployeeAgreement { Salary = i }); } } } var result = 0; - var buffer = _actorBuffer; + Actor[] buffer = _actorBuffer; // Часть 2: Удаление - foreach (var employer in _employerFilter) + foreach (ActorRef employer in _employerFilter) { - var relations = employer.Relations(); + ActorRelationEnumerator relations = employer.Relations(); var i = 0; - foreach (var relation in relations) + foreach (ActorRelation relation in relations) { buffer[i++] = relation; } @@ -113,30 +121,34 @@ public int Hexecs() public int FriFlo() { // Часть 1: Наполнение - using (var employeeEnumerator = _frifloEmployees.Entities.GetEnumerator()) + using (EntitiesEnumerator employeeEnumerator = _frifloEmployees.Entities.GetEnumerator()) { - foreach (var employer in _frifloEmployers.Entities) + foreach (Entity employer in _frifloEmployers.Entities) { for (var i = 0; i < Count; i++) { - if (!employeeEnumerator.MoveNext()) break; - var employee = employeeEnumerator.Current; + if (!employeeEnumerator.MoveNext()) + { + break; + } + + Entity employee = employeeEnumerator.Current; employer.AddRelation(new EmployeeAgreement { Salary = i, Target = employee }); } } } var result = 0; - var buffer = _frifloBuffer; + Entity[] buffer = _frifloBuffer; // Часть 2: Удаление - foreach (var employer in _frifloEmployers.Entities) + foreach (Entity employer in _frifloEmployers.Entities) { // Получаем все связи данного типа у сущности - var relations = employer.GetRelations(); + Relations relations = employer.GetRelations(); var i = 0; - foreach (var relation in relations) + foreach (EmployeeAgreement relation in relations) { buffer[i++] = relation.Target; } @@ -176,18 +188,18 @@ public void Setup() for (var i = 0; i < Count; i++) { - var employer = _actorContext.CreateActor(); + Actor employer = _actorContext.CreateActor(); employer.Add(new Employer()); _frifloWorld.CreateEntity(new Employer()); for (var y = 0; y < Count; y++) { - var employee = _actorContext.CreateActor(); + Actor employee = _actorContext.CreateActor(); employee.Add(new Employee()); _frifloWorld.CreateEntity(new Employee()); } } } -} \ No newline at end of file +} diff --git a/benchmarks/Hexecs.Benchmarks/Actors/UpdateSystemWithParallelWorkerBenchmark.cs b/benchmarks/Hexecs.Benchmarks/Actors/UpdateSystemWithParallelWorkerBenchmark.cs index 9c8ee55..25adc4e 100644 --- a/benchmarks/Hexecs.Benchmarks/Actors/UpdateSystemWithParallelWorkerBenchmark.cs +++ b/benchmarks/Hexecs.Benchmarks/Actors/UpdateSystemWithParallelWorkerBenchmark.cs @@ -1,10 +1,14 @@ using DefaultEcs.System; + using Friflo.Engine.ECS; + using Hexecs.Actors.Systems; using Hexecs.Benchmarks.Mocks.ActorComponents; using Hexecs.Threading; using Hexecs.Worlds; +using Entity = DefaultEcs.Entity; + namespace Hexecs.Benchmarks.Actors; // BenchmarkDotNet v0.15.8, Windows 11 (10.0.22621.4317/22H2/2022Update/SunValley2) @@ -13,7 +17,7 @@ namespace Hexecs.Benchmarks.Actors; // [Host] : .NET 10.0.2 (10.0.2, 10.0.225.61305), X64 RyuJIT x86-64-v3 // .NET 10.0 : .NET 10.0.2 (10.0.2, 10.0.225.61305), X64 RyuJIT x86-64-v3 // -// Job=.NET 10.0 Runtime=.NET 10.0 +// Job=.NET 10.0 Runtime=.NET 10.0 // // | Method | Count | Mean | Ratio | Allocated | Alloc Ratio | // |-------------------- |-------- |------------:|------:|----------:|------------:| @@ -33,7 +37,7 @@ namespace Hexecs.Benchmarks.Actors; // [Host] : .NET 10.0.1 (10.0.1, 10.0.125.57005), Arm64 RyuJIT armv8.0-a // .NET 10.0 : .NET 10.0.11 (10.0.11, 10.0.1126.37416), Arm64 RyuJIT armv8.0-a // -// Job=.NET 10.0 Runtime=.NET 10.0 +// Job=.NET 10.0 Runtime=.NET 10.0 // // | Method | Count | Mean | Ratio | Allocated | Alloc Ratio | // |-------------------- |-------- |----------:|------:|----------:|------------:| @@ -47,14 +51,16 @@ namespace Hexecs.Benchmarks.Actors; [SimpleJob(RuntimeMoniker.Net10_0)] [Orderer(SummaryOrderPolicy.FastestToSlowest)] -[MeanColumn, MemoryDiagnoser] +[MeanColumn] +[MemoryDiagnoser] [HideColumns("Job", "Error", "StdDev", "Median", "RatioSD")] [JsonExporterAttribute.Full] [JsonExporterAttribute.FullCompressed] [BenchmarkCategory("Actors")] public class UpdateSystemWithParallelWorkerBenchmark { - [Params(100_000, 1_000_000)] public int Count; + [Params(100_000, 1_000_000)] + public int Count; private DefaultEcs.World _defaultWorld = null!; private DefaultEcsParallelSystem _defaultSystem = null!; @@ -72,6 +78,7 @@ public class UpdateSystemWithParallelWorkerBenchmark public int Hexecs_Parallel() { _hexecsSystem.Update(_state); + return _hexecsSystem.Filter.Length; } @@ -79,6 +86,7 @@ public int Hexecs_Parallel() public int DefaultEcs_Parallel() { _defaultSystem.Update(_state); + return _defaultSystem.Set.Count; } @@ -86,6 +94,7 @@ public int DefaultEcs_Parallel() public int FriFlo_Parallel() { _frifloJob.RunParallel(); + return _frifloQuery.Count; } @@ -127,15 +136,16 @@ public void Setup() _state = new WorldTime(); - var context = _hexecsWorld.Actors; + ActorContext context = _hexecsWorld.Actors; + for (var i = 0; i < Count; i++) { - var actor = context.CreateActor(); + Actor actor = context.CreateActor(); actor.Add(new Attack()); actor.Add(new Defence()); actor.Add(new Speed()); - var defaultEntity = _defaultWorld.CreateEntity(); + Entity defaultEntity = _defaultWorld.CreateEntity(); defaultEntity.Set(); defaultEntity.Set(); defaultEntity.Set(); @@ -154,9 +164,9 @@ public HexecsUpdateParallelSystem( protected override void Update(in ActorRef actor, in WorldTime time) { - ref var attack = ref actor.Component1; - ref var defence = ref actor.Component2; - ref var speed = ref actor.Component3; + ref Attack attack = ref actor.Component1; + ref Defence defence = ref actor.Component2; + ref Speed speed = ref actor.Component3; attack.Value++; defence.Value++; @@ -175,13 +185,13 @@ public DefaultEcsParallelSystem(DefaultEcs.World world, DefaultEcs.Threading.IPa protected override void Update(WorldTime state, in DefaultEcs.Entity entity) { - ref var attack = ref entity.Get(); - ref var defence = ref entity.Get(); - ref var speed = ref entity.Get(); + ref Attack attack = ref entity.Get(); + ref Defence defence = ref entity.Get(); + ref Speed speed = ref entity.Get(); attack.Value++; defence.Value++; speed.Value++; } } -} \ No newline at end of file +} diff --git a/benchmarks/Hexecs.Benchmarks/Collections/SparseDictionary.cs b/benchmarks/Hexecs.Benchmarks/Collections/SparseDictionary.cs index 540a630..1606214 100644 --- a/benchmarks/Hexecs.Benchmarks/Collections/SparseDictionary.cs +++ b/benchmarks/Hexecs.Benchmarks/Collections/SparseDictionary.cs @@ -37,46 +37,59 @@ public ReadOnlySpan Values [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Contains(uint key) { - var sparse = _sparse; + uint[] sparse = _sparse; + if ((uint)key < (uint)sparse.Length) { return sparse[key] != 0; } + return false; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool TryGetValue(uint key, out TValue value) { - var sparse = _sparse; + uint[] sparse = _sparse; + if ((uint)key < (uint)sparse.Length) { - var denseIndexPlusOne = sparse[key]; + uint denseIndexPlusOne = sparse[key]; + if (denseIndexPlusOne != 0) { value = _values[denseIndexPlusOne - 1]; + return true; } } + value = default; + return false; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Add(uint key, TValue value) { - if (TryAdd(key, value)) return; + if (TryAdd(key, value)) + { + return; + } + Throw("Key already exists"); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool TryAdd(uint key, TValue value) { - var sparse = _sparse; + uint[] sparse = _sparse; + // Проверка на наличие места и ключа в массиве if ((uint)key < (uint)sparse.Length && (uint)_count < (uint)_dense.Length) { - ref var slot = ref sparse[key]; + ref uint slot = ref sparse[key]; + if (slot == 0) { var idx = (uint)_count; @@ -84,10 +97,14 @@ public bool TryAdd(uint key, TValue value) _dense[idx] = key; _values[idx] = value; _count++; + return true; } - if (_dense[slot - 1] == key) return false; + if (_dense[slot - 1] == key) + { + return false; + } } return TryAddSlow(key, value); @@ -95,19 +112,32 @@ public bool TryAdd(uint key, TValue value) public bool Remove(uint key) { - var sparse = _sparse; - if ((uint)key >= (uint)sparse.Length) return false; + uint[] sparse = _sparse; + + if ((uint)key >= (uint)sparse.Length) + { + return false; + } + + uint denseIndexPlusOne = sparse[key]; - var denseIndexPlusOne = sparse[key]; - if (denseIndexPlusOne == 0) return false; + if (denseIndexPlusOne == 0) + { + return false; + } - var denseIndex = (int)denseIndexPlusOne - 1; - if (_dense[denseIndex] != key) return false; + int denseIndex = (int)denseIndexPlusOne - 1; + + if (_dense[denseIndex] != key) + { + return false; + } + + int lastIndex = _count - 1; - var lastIndex = _count - 1; if (denseIndex != lastIndex) { - var lastKey = _dense[lastIndex]; + uint lastKey = _dense[lastIndex]; _dense[denseIndex] = lastKey; _values[denseIndex] = _values[lastIndex]; _sparse[lastKey] = (uint)denseIndex + 1; @@ -115,13 +145,14 @@ public bool Remove(uint key) sparse[key] = 0; _count = lastIndex; + return true; } public void Clear() { - var dense = _dense; - var sparse = _sparse; + uint[] dense = _dense; + uint[] sparse = _sparse; for (var i = 0; i < _count; i++) { @@ -136,21 +167,25 @@ private bool TryAddSlow(uint key, TValue value) { if ((uint)key >= (uint)_sparse.Length) { - var newSize = Math.Max(_sparse.Length * 2, (int)key + 1); + int newSize = Math.Max(_sparse.Length * 2, (int)key + 1); Array.Resize(ref _sparse, newSize); } if ((uint)_count >= (uint)_dense.Length) { - var newSize = _dense.Length * 2; + int newSize = _dense.Length * 2; Array.Resize(ref _dense, newSize); Array.Resize(ref _values, newSize); } - ref var denseIndexPlusOne = ref _sparse[key]; + ref uint denseIndexPlusOne = ref _sparse[key]; + if (denseIndexPlusOne != 0) { - if (_dense[denseIndexPlusOne - 1] == key) return false; + if (_dense[denseIndexPlusOne - 1] == key) + { + return false; + } } var denseIndex = (uint)_count; @@ -158,11 +193,15 @@ private bool TryAddSlow(uint key, TValue value) _dense[denseIndex] = key; _values[denseIndex] = value; _count++; + return true; } - + [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Enumerator GetEnumerator() => new(_values.AsSpan(0, _count)); + public Enumerator GetEnumerator() + { + return new Enumerator(_values.AsSpan(0, _count)); + } public ref struct Enumerator { @@ -177,10 +216,11 @@ internal Enumerator(Span values) if (_remaining == 0) { _current = ref Unsafe.NullRef(); + return; } - ref var first = ref MemoryMarshal.GetReference(values); + ref TValue first = ref MemoryMarshal.GetReference(values); _current = ref Unsafe.Subtract(ref first, 1); } @@ -193,13 +233,21 @@ public ref TValue Current [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool MoveNext() { - if (--_remaining < 0) return false; + if (--_remaining < 0) + { + return false; + } + _current = ref Unsafe.Add(ref _current, 1); + return true; } } - + [DoesNotReturn] [MethodImpl(MethodImplOptions.NoInlining)] - private static void Throw(string message) => throw new InvalidOperationException(message); -} \ No newline at end of file + private static void Throw(string message) + { + throw new InvalidOperationException(message); + } +} diff --git a/benchmarks/Hexecs.Benchmarks/Collections/SparsePageDictionary.cs b/benchmarks/Hexecs.Benchmarks/Collections/SparsePageDictionary.cs index d75469d..e88c5df 100644 --- a/benchmarks/Hexecs.Benchmarks/Collections/SparsePageDictionary.cs +++ b/benchmarks/Hexecs.Benchmarks/Collections/SparsePageDictionary.cs @@ -43,11 +43,12 @@ public ReadOnlySpan Values public bool Contains(uint key) { var pageIndex = (int)(key >> PageBits); - var pages = _sparsePages; + uint[]?[] pages = _sparsePages; if ((uint)pageIndex < (uint)pages.Length) { - var page = pages[pageIndex]; + uint[]? page = pages[pageIndex]; + if (page != null) { return page[key & PageMask] != 0; @@ -61,28 +62,37 @@ public bool Contains(uint key) public bool TryGetValue(uint key, out TValue value) { var pageIndex = (int)(key >> PageBits); + if ((uint)pageIndex < (uint)_sparsePages.Length) { - var page = _sparsePages[pageIndex]; + uint[]? page = _sparsePages[pageIndex]; + if (page != null) { - var denseIndexPlusOne = page[key & PageMask]; + uint denseIndexPlusOne = page[key & PageMask]; + if (denseIndexPlusOne != 0) { value = _values[denseIndexPlusOne - 1]; + return true; } } } value = default; + return false; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Add(uint key, TValue value) { - if (TryAdd(key, value)) return; + if (TryAdd(key, value)) + { + return; + } + Throw("Key already exists"); } @@ -90,15 +100,17 @@ public void Add(uint key, TValue value) public bool TryAdd(uint key, TValue value) { var pageIndex = (int)(key >> PageBits); - var pages = _sparsePages; + uint[]?[] pages = _sparsePages; // Максимально компактная проверка на готовность страницы и места if ((uint)pageIndex < (uint)pages.Length) { - var page = pages[pageIndex]; + uint[]? page = pages[pageIndex]; + if (page != null && (uint)_count < (uint)_dense.Length) { - ref var slot = ref page[key & PageMask]; + ref uint slot = ref page[key & PageMask]; + if (slot == 0) // Чистая вставка (самый частый случай в ECS) { var idx = (uint)_count; @@ -106,11 +118,15 @@ public bool TryAdd(uint key, TValue value) _dense[idx] = key; _values[idx] = value; _count++; + return true; } // Если не 0, проверяем на дубликат (чуть медленнее) - if (_dense[slot - 1] == key) return false; + if (_dense[slot - 1] == key) + { + return false; + } } } @@ -120,23 +136,40 @@ public bool TryAdd(uint key, TValue value) public bool Remove(uint key) { var pageIndex = (int)(key >> PageBits); + // Используем вашу оригинальную "плоскую" логику из коммита - if ((uint)pageIndex >= (uint)_sparsePages.Length) return false; + if ((uint)pageIndex >= (uint)_sparsePages.Length) + { + return false; + } - var page = _sparsePages[pageIndex]; - if (page == null) return false; + uint[]? page = _sparsePages[pageIndex]; + + if (page == null) + { + return false; + } var offset = (int)(key & PageMask); - var denseIndexPlusOne = page[offset]; - if (denseIndexPlusOne == 0) return false; + uint denseIndexPlusOne = page[offset]; - var denseIndex = (int)denseIndexPlusOne - 1; - if (_dense[denseIndex] != key) return false; + if (denseIndexPlusOne == 0) + { + return false; + } + + int denseIndex = (int)denseIndexPlusOne - 1; + + if (_dense[denseIndex] != key) + { + return false; + } + + int lastIndex = _count - 1; - var lastIndex = _count - 1; if (denseIndex != lastIndex) { - var lastKey = _dense[lastIndex]; + uint lastKey = _dense[lastIndex]; _dense[denseIndex] = lastKey; _values[denseIndex] = _values[lastIndex]; @@ -146,18 +179,19 @@ public bool Remove(uint key) page[offset] = 0; _count = lastIndex; // Используем вычисленный lastIndex + return true; } public void Clear() { - var dense = _dense; - var sparsePages = _sparsePages; + uint[] dense = _dense; + uint[]?[] sparsePages = _sparsePages; // Очищаем только занятые ячейки в разреженных страницах за O(Count) for (var i = 0; i < _count; i++) { - var key = dense[i]; + uint key = dense[i]; var pageIndex = (int)(key >> PageBits); sparsePages[pageIndex]![key & PageMask] = 0; } @@ -169,7 +203,7 @@ private void EnsurePageArraySize(int pageIndex) { if (pageIndex >= _sparsePages.Length) { - var newSize = Math.Max(_sparsePages.Length * 2, pageIndex + 1); + int newSize = Math.Max(_sparsePages.Length * 2, pageIndex + 1); Array.Resize(ref _sparsePages, newSize); } } @@ -178,7 +212,7 @@ private void EnsureDenseCapacity() { if (_count >= _dense.Length) { - var newSize = _dense.Length * 2; + int newSize = _dense.Length * 2; Array.Resize(ref _dense, newSize); Array.Resize(ref _values, newSize); } @@ -191,16 +225,21 @@ private bool TryAddSlow(uint key, TValue value) var pageIndex = (int)(key >> PageBits); EnsurePageArraySize(pageIndex); - ref var page = ref _sparsePages[pageIndex]; + ref uint[]? page = ref _sparsePages[pageIndex]; + if (page == null) { page = new uint[PageSize]; } - ref var denseIndexPlusOne = ref page[key & PageMask]; + ref uint denseIndexPlusOne = ref page[key & PageMask]; + if (denseIndexPlusOne != 0) { - if (_dense[denseIndexPlusOne - 1] == key) return false; + if (_dense[denseIndexPlusOne - 1] == key) + { + return false; + } } var denseIndex = (uint)_count; @@ -208,11 +247,15 @@ private bool TryAddSlow(uint key, TValue value) _dense[denseIndex] = key; _values[denseIndex] = value; _count++; + return true; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Enumerator GetEnumerator() => new(_values.AsSpan(0, _count)); + public Enumerator GetEnumerator() + { + return new Enumerator(_values.AsSpan(0, _count)); + } public ref struct Enumerator { @@ -227,10 +270,11 @@ internal Enumerator(Span values) if (_remaining == 0) { _current = ref Unsafe.NullRef(); + return; } - ref var first = ref MemoryMarshal.GetReference(values); + ref TValue first = ref MemoryMarshal.GetReference(values); _current = ref Unsafe.Subtract(ref first, 1); } @@ -243,13 +287,21 @@ public ref TValue Current [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool MoveNext() { - if (--_remaining < 0) return false; + if (--_remaining < 0) + { + return false; + } + _current = ref Unsafe.Add(ref _current, 1); + return true; } } [DoesNotReturn] [MethodImpl(MethodImplOptions.NoInlining)] - private static void Throw(string message) => throw new InvalidOperationException(message); -} \ No newline at end of file + private static void Throw(string message) + { + throw new InvalidOperationException(message); + } +} diff --git a/benchmarks/Hexecs.Benchmarks/Collections/SparsePageDictionaryBenchmark.cs b/benchmarks/Hexecs.Benchmarks/Collections/SparsePageDictionaryBenchmark.cs index 84ae8dc..1347244 100644 --- a/benchmarks/Hexecs.Benchmarks/Collections/SparsePageDictionaryBenchmark.cs +++ b/benchmarks/Hexecs.Benchmarks/Collections/SparsePageDictionaryBenchmark.cs @@ -6,7 +6,7 @@ // [Host] : .NET 10.0.2 (10.0.2, 10.0.225.61305), X64 RyuJIT x86-64-v3 // .NET 10.0 : .NET 10.0.2 (10.0.2, 10.0.225.61305), X64 RyuJIT x86-64-v3 // -// Job=.NET 10.0 Runtime=.NET 10.0 +// Job=.NET 10.0 Runtime=.NET 10.0 // // | Method | N | Mean | Allocated | // |-------------------------- |--------- |------------------:|----------:| @@ -102,7 +102,8 @@ // | AddRemoveCycle_Dict | 10000000 | 201,447.264 ns | - | [SimpleJob(RuntimeMoniker.Net10_0)] -[MeanColumn, MemoryDiagnoser] +[MeanColumn] +[MemoryDiagnoser] [HideColumns("Job", "Error", "StdDev", "Median", "RatioSD", "Count")] [JsonExporterAttribute.Full] [JsonExporterAttribute.FullCompressed] @@ -128,7 +129,7 @@ public class SparsePageDictionaryBenchmark [GlobalSetup] public void Setup() { - var keyRange = Math.Max(N * 10, 1_000); + int keyRange = Math.Max(N * 10, 1_000); _keys = Enumerable.Range(0, N * 2) .Select(_ => (uint)Random.Shared.Next(0, keyRange)) .Distinct() @@ -141,8 +142,11 @@ public void Setup() .ToArray(); var present = new bool[keyRange]; + for (var i = 0; i < _keys.Length; i++) + { present[_keys[i]] = true; + } var missCount = 1000; var missing = new uint[missCount]; @@ -150,10 +154,17 @@ public void Setup() for (var k = 0; k < keyRange && written < missCount; k++) { - if (!present[k]) missing[written++] = (uint)k; + if (!present[k]) + { + missing[written++] = (uint)k; + } + } + + if (written < missCount) + { + Array.Resize(ref missing, written); } - if (written < missCount) Array.Resize(ref missing, written); _missingKeys = missing; _sparsePage = new SparsePageDictionary(denseCapacity: N); @@ -166,7 +177,8 @@ public void Setup() _dictCycle = new Dictionary(capacity: N); const int value = 42; - foreach (var key in _keys) + + foreach (uint key in _keys) { _sparsePage.Add(key, value); _sparsePageCycle.Add(key, value); @@ -189,7 +201,8 @@ public void Setup() public int Iterate_Sparse() { var sum = 0; - foreach (var entry in _sparse) + + foreach (int entry in _sparse) { sum += entry; } @@ -201,7 +214,8 @@ public int Iterate_Sparse() public int Iterate_SparsePage() { var sum = 0; - foreach (var entry in _sparsePage) + + foreach (int entry in _sparsePage) { sum += entry; } @@ -213,7 +227,8 @@ public int Iterate_SparsePage() public int Iterate_Dict() { var sum = 0; - foreach (var kv in _dict) + + foreach (KeyValuePair kv in _dict) { sum += kv.Value; } @@ -227,7 +242,8 @@ public int Iterate_Dict() public bool Contains_Sparse_Hit() { var found = false; - foreach (var key in _lookupKeys) + + foreach (uint key in _lookupKeys) { found = _sparse.Contains(key); } @@ -239,7 +255,8 @@ public bool Contains_Sparse_Hit() public bool Contains_SparsePage_Hit() { var found = false; - foreach (var key in _lookupKeys) + + foreach (uint key in _lookupKeys) { found = _sparsePage.Contains(key); } @@ -251,7 +268,8 @@ public bool Contains_SparsePage_Hit() public bool Contains_Dict_Hit() { var found = false; - foreach (var key in _lookupKeys) + + foreach (uint key in _lookupKeys) { found = _dict.ContainsKey(key); } @@ -265,7 +283,8 @@ public bool Contains_Dict_Hit() public bool Contains_Sparse_Miss() { var found = false; - foreach (var key in _missingKeys) + + foreach (uint key in _missingKeys) { found = _sparse.Contains(key); } @@ -277,7 +296,8 @@ public bool Contains_Sparse_Miss() public bool Contains_SparsePage_Miss() { var found = false; - foreach (var key in _missingKeys) + + foreach (uint key in _missingKeys) { found = _sparsePage.Contains(key); } @@ -289,7 +309,8 @@ public bool Contains_SparsePage_Miss() public bool Contains_Dict_Miss() { var found = false; - foreach (var key in _missingKeys) + + foreach (uint key in _missingKeys) { found = _dict.ContainsKey(key); } @@ -303,9 +324,10 @@ public bool Contains_Dict_Miss() public int TryGetValue_Sparse() { var sum = 0; - foreach (var key in _lookupKeys) + + foreach (uint key in _lookupKeys) { - if (_sparse.TryGetValue(key, out var value)) + if (_sparse.TryGetValue(key, out int value)) { sum += value; } @@ -318,9 +340,10 @@ public int TryGetValue_Sparse() public int TryGetValue_SparsePage() { var sum = 0; - foreach (var key in _lookupKeys) + + foreach (uint key in _lookupKeys) { - if (_sparsePage.TryGetValue(key, out var value)) + if (_sparsePage.TryGetValue(key, out int value)) { sum += value; } @@ -333,9 +356,10 @@ public int TryGetValue_SparsePage() public int TryGetValue_Dict() { var sum = 0; - foreach (var key in _lookupKeys) + + foreach (uint key in _lookupKeys) { - if (_dict.TryGetValue(key, out var value)) + if (_dict.TryGetValue(key, out int value)) { sum += value; } @@ -349,20 +373,20 @@ public int TryGetValue_Dict() [Benchmark] public int AddRemoveCycle_Sparse() { - var dict = _sparseCycle; + SparseDictionary dict = _sparseCycle; var count = 0; // Симуляция ECS: добавляем/удаляем entity из фильтра for (var i = 0; i < 10; i++) { - foreach (var key in _lookupKeys) + foreach (uint key in _lookupKeys) { dict.Add(key, 42); } count += dict.Count; - foreach (var key in _lookupKeys) + foreach (uint key in _lookupKeys) { dict.Remove(key); } @@ -374,20 +398,20 @@ public int AddRemoveCycle_Sparse() [Benchmark] public int AddRemoveCycle_SparsePage() { - var dict = _sparsePageCycle; + SparsePageDictionary dict = _sparsePageCycle; var count = 0; // Симуляция ECS: добавляем/удаляем entity из фильтра for (var i = 0; i < 10; i++) { - foreach (var key in _lookupKeys) + foreach (uint key in _lookupKeys) { dict.Add(key, 42); } count += dict.Count; - foreach (var key in _lookupKeys) + foreach (uint key in _lookupKeys) { dict.Remove(key); } @@ -399,19 +423,19 @@ public int AddRemoveCycle_SparsePage() [Benchmark] public int AddRemoveCycle_Dict() { - var dict = _dictCycle; + Dictionary dict = _dictCycle; var count = 0; for (var i = 0; i < 10; i++) { - foreach (var key in _lookupKeys) + foreach (uint key in _lookupKeys) { dict[key] = 42; } count += dict.Count; - foreach (var key in _lookupKeys) + foreach (uint key in _lookupKeys) { dict.Remove(key); } @@ -419,4 +443,4 @@ public int AddRemoveCycle_Dict() return count; } -} \ No newline at end of file +} diff --git a/benchmarks/Hexecs.Benchmarks/Collections/ThreadLocalStackBenchmark.cs b/benchmarks/Hexecs.Benchmarks/Collections/ThreadLocalStackBenchmark.cs index 3458161..f223203 100644 --- a/benchmarks/Hexecs.Benchmarks/Collections/ThreadLocalStackBenchmark.cs +++ b/benchmarks/Hexecs.Benchmarks/Collections/ThreadLocalStackBenchmark.cs @@ -1,4 +1,5 @@ using System.Collections.Concurrent; + using Hexecs.Collections; namespace Hexecs.Benchmarks.Collections; @@ -9,7 +10,7 @@ namespace Hexecs.Benchmarks.Collections; // [Host] : .NET 10.0.1 (10.0.1, 10.0.125.57005), Arm64 RyuJIT armv8.0-a // .NET 10.0 : .NET 10.0.1 (10.0.1, 10.0.125.57005), Arm64 RyuJIT armv8.0-a // -// Job=.NET 10.0 Runtime=.NET 10.0 +// Job=.NET 10.0 Runtime=.NET 10.0 // // | Method | Mean | Ratio | Gen0 | Allocated | Alloc Ratio | // |-------------------------- |---------:|------:|---------:|----------:|------------:| @@ -19,14 +20,15 @@ namespace Hexecs.Benchmarks.Collections; [SimpleJob(RuntimeMoniker.Net10_0)] [Orderer(SummaryOrderPolicy.FastestToSlowest)] -[MeanColumn, MemoryDiagnoser] +[MeanColumn] +[MemoryDiagnoser] [HideColumns("Job", "Error", "StdDev", "Median", "RatioSD", "Count")] [JsonExporterAttribute.Full] [JsonExporterAttribute.FullCompressed] [BenchmarkCategory("Collections")] public class ThreadLocalStackBenchmark { - [Params(10_000)] + [Params(10_000)] public int Count = 10_000; private const int ThreadCount = 4; @@ -34,62 +36,74 @@ public class ThreadLocalStackBenchmark private ConcurrentStack _concurrentStack = null!; private Stack _lockedStack = null!; private ThreadLocalStack _threadLocalStack = null!; - private readonly Lock _stackLock = new(); + private readonly Lock _stackLock = new Lock(); [Benchmark(Baseline = true)] public int ThreadLocalStack_Parallel() { - var opsPerThread = Count / ThreadCount; + int opsPerThread = Count / ThreadCount; var result = 0; - Parallel.For(0, ThreadCount, _ => - { - for (var i = 0; i < opsPerThread; i++) + Parallel.For( + 0, + ThreadCount, + _ => { - if (_threadLocalStack.TryPop(out var id)) + for (var i = 0; i < opsPerThread; i++) { - Interlocked.Increment(ref result); - _threadLocalStack.Push(id); + if (_threadLocalStack.TryPop(out uint id)) + { + Interlocked.Increment(ref result); + _threadLocalStack.Push(id); + } } - } - }); + }); + return result; } [Benchmark] public int ConcurrentStack_Parallel() { - var opsPerThread = Count / ThreadCount; + int opsPerThread = Count / ThreadCount; var result = 0; - Parallel.For(0, ThreadCount, _ => - { - for (var i = 0; i < opsPerThread; i++) + Parallel.For( + 0, + ThreadCount, + _ => { - if (_concurrentStack.TryPop(out var id)) + for (var i = 0; i < opsPerThread; i++) { - Interlocked.Increment(ref result); - _concurrentStack.Push(id); + if (_concurrentStack.TryPop(out uint id)) + { + Interlocked.Increment(ref result); + _concurrentStack.Push(id); + } } - } - }); + }); + return result; } [Benchmark] public int LockedStack_Parallel() { - var opsPerThread = Count / ThreadCount; + int opsPerThread = Count / ThreadCount; var result = 0; - Parallel.For(0, ThreadCount, _ => - { - for (var i = 0; i < opsPerThread; i++) + Parallel.For( + 0, + ThreadCount, + _ => { - if (TryPopLocked(out var id)) + for (var i = 0; i < opsPerThread; i++) { - Interlocked.Increment(ref result); - PushLocked(id); + if (TryPopLocked(out uint id)) + { + Interlocked.Increment(ref result); + PushLocked(id); + } } - } - }); + }); + return result; } @@ -119,13 +133,14 @@ public void Cleanup() private bool TryPopLocked(out uint id) { - using var locker = _stackLock.EnterScope(); + using Lock.Scope locker = _stackLock.EnterScope(); + return _lockedStack.TryPop(out id); } private void PushLocked(uint id) { - using var locker = _stackLock.EnterScope(); + using Lock.Scope locker = _stackLock.EnterScope(); _lockedStack.Push(id); } -} \ No newline at end of file +} diff --git a/benchmarks/Hexecs.Benchmarks/Mocks/ActorComponents/Attack.cs b/benchmarks/Hexecs.Benchmarks/Mocks/ActorComponents/Attack.cs index 8479b55..a590b2b 100644 --- a/benchmarks/Hexecs.Benchmarks/Mocks/ActorComponents/Attack.cs +++ b/benchmarks/Hexecs.Benchmarks/Mocks/ActorComponents/Attack.cs @@ -5,4 +5,4 @@ namespace Hexecs.Benchmarks.Mocks.ActorComponents; public struct Attack : IActorComponent, IComponent { public int Value; -} \ No newline at end of file +} diff --git a/benchmarks/Hexecs.Benchmarks/Mocks/ActorComponents/AttackBuilder.cs b/benchmarks/Hexecs.Benchmarks/Mocks/ActorComponents/AttackBuilder.cs index d2d58c6..0e7034f 100644 --- a/benchmarks/Hexecs.Benchmarks/Mocks/ActorComponents/AttackBuilder.cs +++ b/benchmarks/Hexecs.Benchmarks/Mocks/ActorComponents/AttackBuilder.cs @@ -9,4 +9,4 @@ public void Build(in Actor actor, in AssetRef asset, Args args) { actor.Add(new Attack { Value = asset.Component1.Attack }); } -} \ No newline at end of file +} diff --git a/benchmarks/Hexecs.Benchmarks/Mocks/ActorComponents/Defence.cs b/benchmarks/Hexecs.Benchmarks/Mocks/ActorComponents/Defence.cs index 62c521a..1fe493f 100644 --- a/benchmarks/Hexecs.Benchmarks/Mocks/ActorComponents/Defence.cs +++ b/benchmarks/Hexecs.Benchmarks/Mocks/ActorComponents/Defence.cs @@ -5,4 +5,4 @@ namespace Hexecs.Benchmarks.Mocks.ActorComponents; public struct Defence : IActorComponent, IComponent { public int Value; -} \ No newline at end of file +} diff --git a/benchmarks/Hexecs.Benchmarks/Mocks/ActorComponents/DefenceBuilder.cs b/benchmarks/Hexecs.Benchmarks/Mocks/ActorComponents/DefenceBuilder.cs index 3e63e2d..1f168d9 100644 --- a/benchmarks/Hexecs.Benchmarks/Mocks/ActorComponents/DefenceBuilder.cs +++ b/benchmarks/Hexecs.Benchmarks/Mocks/ActorComponents/DefenceBuilder.cs @@ -9,4 +9,4 @@ public void Build(in Actor actor, in AssetRef asset, Args args) { actor.Add(new Defence { Value = asset.Component1.Defence }); } -} \ No newline at end of file +} diff --git a/benchmarks/Hexecs.Benchmarks/Mocks/ActorComponents/Employee.cs b/benchmarks/Hexecs.Benchmarks/Mocks/ActorComponents/Employee.cs index 55e9ce9..63d8d7f 100644 --- a/benchmarks/Hexecs.Benchmarks/Mocks/ActorComponents/Employee.cs +++ b/benchmarks/Hexecs.Benchmarks/Mocks/ActorComponents/Employee.cs @@ -2,4 +2,4 @@ namespace Hexecs.Benchmarks.Mocks.ActorComponents; -public struct Employee : IActorComponent, IComponent; \ No newline at end of file +public struct Employee : IActorComponent, IComponent; diff --git a/benchmarks/Hexecs.Benchmarks/Mocks/ActorComponents/EmployeeAgreement.cs b/benchmarks/Hexecs.Benchmarks/Mocks/ActorComponents/EmployeeAgreement.cs index 6f153a8..53a4dc5 100644 --- a/benchmarks/Hexecs.Benchmarks/Mocks/ActorComponents/EmployeeAgreement.cs +++ b/benchmarks/Hexecs.Benchmarks/Mocks/ActorComponents/EmployeeAgreement.cs @@ -7,5 +7,8 @@ public struct EmployeeAgreement : ILinkRelation public Entity Target; public int Salary; - public Entity GetRelationKey() => Target; -} \ No newline at end of file + public Entity GetRelationKey() + { + return Target; + } +} diff --git a/benchmarks/Hexecs.Benchmarks/Mocks/ActorComponents/Employer.cs b/benchmarks/Hexecs.Benchmarks/Mocks/ActorComponents/Employer.cs index fe32ae2..d461e8e 100644 --- a/benchmarks/Hexecs.Benchmarks/Mocks/ActorComponents/Employer.cs +++ b/benchmarks/Hexecs.Benchmarks/Mocks/ActorComponents/Employer.cs @@ -2,4 +2,4 @@ namespace Hexecs.Benchmarks.Mocks.ActorComponents; -public struct Employer : IActorComponent, IComponent; \ No newline at end of file +public struct Employer : IActorComponent, IComponent; diff --git a/benchmarks/Hexecs.Benchmarks/Mocks/ActorComponents/Speed.cs b/benchmarks/Hexecs.Benchmarks/Mocks/ActorComponents/Speed.cs index 7483cdf..9f92e64 100644 --- a/benchmarks/Hexecs.Benchmarks/Mocks/ActorComponents/Speed.cs +++ b/benchmarks/Hexecs.Benchmarks/Mocks/ActorComponents/Speed.cs @@ -5,4 +5,4 @@ namespace Hexecs.Benchmarks.Mocks.ActorComponents; public struct Speed : IActorComponent, IComponent { public int Value; -} \ No newline at end of file +} diff --git a/src/Hexecs/Actors/Actor.cs b/src/Hexecs/Actors/Actor.cs index 34d6ff0..4bf8c6a 100644 --- a/src/Hexecs/Actors/Actor.cs +++ b/src/Hexecs/Actors/Actor.cs @@ -21,7 +21,7 @@ namespace Hexecs.Actors; public static Actor Empty { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => new(null!, ActorId.Empty); + get => new Actor(null!, ActorId.Empty); } /// @@ -386,20 +386,29 @@ public bool Update(in T component, bool createIfNotExists = true) /// Актёр для сравнения. /// Возвращает true, если актёры равны; иначе false. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(Actor other) => Id == other.Id && ReferenceEquals(Context, other.Context); + public bool Equals(Actor other) + { + return Id == other.Id && ReferenceEquals(Context, other.Context); + } /// /// Проверяет равенство с другим объектом. /// /// Объект для сравнения. /// Возвращает true, если объекты равны; иначе false. - public override bool Equals(object? obj) => obj is Actor other && Equals(other); + public override bool Equals(object? obj) + { + return obj is Actor other && Equals(other); + } /// /// Возвращает хеш-код для актёра. /// /// Хеш-код актёра. - public override int GetHashCode() => HashCode.Combine(Id); + public override int GetHashCode() + { + return HashCode.Combine(Id); + } /// /// Сравнивает двух актёров на равенство. @@ -408,7 +417,10 @@ public bool Update(in T component, bool createIfNotExists = true) /// Правый актёр. /// Возвращает true, если актёры равны; иначе false. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(in Actor left, in Actor right) => left.Equals(right); + public static bool operator ==(in Actor left, in Actor right) + { + return left.Equals(right); + } /// /// Сравнивает двух актёров на неравенство. @@ -417,7 +429,10 @@ public bool Update(in T component, bool createIfNotExists = true) /// Правый актёр. /// Возвращает true, если актёры не равны; иначе false. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(in Actor left, in Actor right) => !left.Equals(right); + public static bool operator !=(in Actor left, in Actor right) + { + return !left.Equals(right); + } #endregion @@ -429,7 +444,10 @@ public bool Update(in T component, bool createIfNotExists = true) /// Актёр для преобразования. /// Возвращает true, если актёр не пустой; иначе false. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator bool(in Actor actor) => !actor.IsEmpty; + public static implicit operator bool(in Actor actor) + { + return !actor.IsEmpty; + } /// /// Неявное преобразование актёра в ActorId. @@ -437,7 +455,10 @@ public bool Update(in T component, bool createIfNotExists = true) /// Актёр для преобразования. /// Идентификатор актёра. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator ActorId(in Actor actor) => actor.Id; + public static implicit operator ActorId(in Actor actor) + { + return actor.Id; + } #endregion -} \ No newline at end of file +} diff --git a/src/Hexecs/Actors/ActorConstraint.cs b/src/Hexecs/Actors/ActorConstraint.cs index c770a3c..434e9be 100644 --- a/src/Hexecs/Actors/ActorConstraint.cs +++ b/src/Hexecs/Actors/ActorConstraint.cs @@ -1,7 +1,7 @@ namespace Hexecs.Actors; /// -/// Класс, представляющий ограничения для актёров, позволяющий фильтровать актёры +/// Класс, представляющий ограничения для актёров, позволяющий фильтровать актёры /// на основе наличия или отсутствия определенных компонентов. /// public sealed partial class ActorConstraint : IEquatable, IDisposable @@ -79,7 +79,7 @@ public static Builder Include(ActorContext context) private ActorConstraint(int contextId, int hash, Subscription[] subscriptions) { - foreach (var subscription in subscriptions) + foreach (Subscription subscription in subscriptions) { subscription.Subscribe(this); } @@ -97,22 +97,31 @@ private ActorConstraint(int contextId, int hash, Subscription[] subscriptions) public bool Applicable(ActorId actorId) { // ReSharper disable once LoopCanBeConvertedToQuery - foreach (var subscription in _subscriptions) + foreach (Subscription subscription in _subscriptions) { - if (!subscription.Check(actorId)) return false; + if (!subscription.Check(actorId)) + { + return false; + } } return true; } - private void OnExclude(ActorId actorId) => Removing?.Invoke(actorId); + private void OnExclude(ActorId actorId) + { + Removing?.Invoke(actorId); + } private void OnInclude(ActorId actorId) { // ReSharper disable once LoopCanBeConvertedToQuery - foreach (var subscription in _subscriptions) + foreach (Subscription subscription in _subscriptions) { - if (!subscription.Check(actorId)) return; + if (!subscription.Check(actorId)) + { + return; + } } Added?.Invoke(actorId); @@ -127,14 +136,20 @@ private void OnInclude(ActorId actorId) /// Возвращает true, если указанный объект равен текущему объекту; иначе false public bool Equals(ActorConstraint? other) { - if (other == null || _contextId != other._contextId) return false; + if (other == null || _contextId != other._contextId) + { + return false; + } - var otherSubscriptions = other._subscriptions; + Subscription[] otherSubscriptions = other._subscriptions; // ReSharper disable once LoopCanBeConvertedToQuery for (var i = 0; i < _subscriptions.Length; i++) { - if (!_subscriptions[i].Equals(otherSubscriptions[i])) return false; + if (!_subscriptions[i].Equals(otherSubscriptions[i])) + { + return false; + } } return true; @@ -154,7 +169,10 @@ public override bool Equals(object? obj) /// Возвращает хеш-код для текущего объекта. /// /// Хеш-код для текущего объекта - public override int GetHashCode() => _hash; + public override int GetHashCode() + { + return _hash; + } #endregion @@ -163,9 +181,9 @@ public override bool Equals(object? obj) /// void IDisposable.Dispose() { - foreach (var subscription in _subscriptions) + foreach (Subscription subscription in _subscriptions) { subscription.Unsubscribe(this); } } -} \ No newline at end of file +} diff --git a/src/Hexecs/Attributes/OrderAttribute.cs b/src/Hexecs/Attributes/OrderAttribute.cs index 7e02026..569b892 100644 --- a/src/Hexecs/Attributes/OrderAttribute.cs +++ b/src/Hexecs/Attributes/OrderAttribute.cs @@ -9,8 +9,9 @@ public sealed class OrderAttribute(int value) : Attribute public static int TryGetValue(Type type, int defaultValue = int.MaxValue) { var attribute = type.GetCustomAttribute(); + return attribute?.Value ?? defaultValue; } public readonly int Value = value; -} \ No newline at end of file +} diff --git a/src/Hexecs/Collections/ArrayEnumerator.cs b/src/Hexecs/Collections/ArrayEnumerator.cs index e293b8b..c9d5fb0 100644 --- a/src/Hexecs/Collections/ArrayEnumerator.cs +++ b/src/Hexecs/Collections/ArrayEnumerator.cs @@ -12,7 +12,7 @@ public struct ArrayEnumerator : IEnumerator public static ArrayEnumerator Empty { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => new(); + get => new ArrayEnumerator(); } /// @@ -73,7 +73,10 @@ public ArrayEnumerator(T[] array, int length) /// /// Возвращает true, если перечислитель успешно перемещен к следующему элементу; false, если перечислитель достиг конца последовательности. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool MoveNext() => ++_index < _length; + public bool MoveNext() + { + return ++_index < _length; + } /// /// Устанавливает перечислитель в его начальное положение. @@ -98,4 +101,4 @@ readonly void IDisposable.Dispose() object IEnumerator.Current => Current!; #endregion -} \ No newline at end of file +} diff --git a/src/Hexecs/Collections/Block.cs b/src/Hexecs/Collections/Block.cs index 84cf0ea..89cdb0d 100644 --- a/src/Hexecs/Collections/Block.cs +++ b/src/Hexecs/Collections/Block.cs @@ -38,7 +38,10 @@ public Block(T item) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Block(T[] array) => _array = array; + public Block(T[] array) + { + _array = array; + } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Block(T[] array, int length) @@ -49,28 +52,46 @@ public Block(T[] array, int length) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Block(ReadOnlySpan span) => _array = span.ToArray(); + public Block(ReadOnlySpan span) + { + _array = span.ToArray(); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Block(List collection) => _array = collection.ToArray(); + public Block(List collection) + { + _array = collection.ToArray(); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Block(IEnumerable collection) => _array = CollectionUtils.ToArray(collection); + public Block(IEnumerable collection) + { + _array = CollectionUtils.ToArray(collection); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Block(IEnumerable collection, int length) => _array = CollectionUtils.ToArray(collection, length); + public Block(IEnumerable collection, int length) + { + _array = CollectionUtils.ToArray(collection, length); + } #endregion [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Memory AsMemory() => _array == null || _array.Length == 0 - ? Memory.Empty - : new Memory(_array); + public Memory AsMemory() + { + return _array == null || _array.Length == 0 + ? Memory.Empty + : new Memory(_array); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Span AsSpan() => _array == null || _array.Length == 0 - ? Span.Empty - : new Span(_array); + public Span AsSpan() + { + return _array == null || _array.Length == 0 + ? Span.Empty + : new Span(_array); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Contains(T value, IEqualityComparer? equalityComparer = null) @@ -81,26 +102,43 @@ public bool Contains(T value, IEqualityComparer? equalityComparer = null) [MethodImpl(MethodImplOptions.AggressiveInlining)] public ref T GetRef(int index) { - if (_array == null) return ref Unsafe.NullRef(); + if (_array == null) + { + return ref Unsafe.NullRef(); + } + return ref _array[index]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ArrayEnumerator GetEnumerator() => _array == null || _array.Length == 0 - ? ArrayEnumerator.Empty - : new ArrayEnumerator(_array); + public ArrayEnumerator GetEnumerator() + { + return _array == null || _array.Length == 0 + ? ArrayEnumerator.Empty + : new ArrayEnumerator(_array); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public T[] GetUnderlyingArray() => _array ?? []; + public T[] GetUnderlyingArray() + { + return _array ?? []; + } public int IndexOf(T value, IEqualityComparer? equalityComparer = null) { - if (_array == null || _array.Length == 0) return -1; + if (_array == null || _array.Length == 0) + { + return -1; + } equalityComparer ??= EqualityComparer.Default; + for (var i = 0; i < _array.Length; i++) { - if (equalityComparer.Equals(_array[i], value)) return i; + if (equalityComparer.Equals(_array[i], value)) + { + return i; + } } return -1; @@ -114,7 +152,13 @@ public T this[int index] set => _array![index] = value; } - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); -} \ No newline at end of file + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } +} diff --git a/src/Hexecs/Collections/Bucket.cs b/src/Hexecs/Collections/Bucket.cs index f69f0f9..3f69988 100644 --- a/src/Hexecs/Collections/Bucket.cs +++ b/src/Hexecs/Collections/Bucket.cs @@ -36,43 +36,65 @@ public void Add(T item) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public readonly Memory AsMemory() => _array == null || _array.Length == 0 - ? Memory.Empty - : new Memory(_array); + public readonly Memory AsMemory() + { + return _array == null || _array.Length == 0 + ? Memory.Empty + : new Memory(_array); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public readonly Span AsSpan() => _length == 0 - ? Span.Empty - : _array.AsSpan(0, _length); + public readonly Span AsSpan() + { + return _length == 0 + ? Span.Empty + : _array.AsSpan(0, _length); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public readonly ReadOnlySpan AsReadOnlySpan() => _length == 0 - ? ReadOnlySpan.Empty - : new ReadOnlySpan(_array, 0, _length); + public readonly ReadOnlySpan AsReadOnlySpan() + { + return _length == 0 + ? ReadOnlySpan.Empty + : new ReadOnlySpan(_array, 0, _length); + } public void Dispose() { - if (_array is { Length: > 0 }) ArrayPool.Shared.Return(_array); + if (_array is { Length: > 0 }) + { + ArrayPool.Shared.Return(_array); + } _array = []; _length = 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public readonly ArrayEnumerator GetEnumerator() => _array == null - ? ArrayEnumerator.Empty - : new ArrayEnumerator(_array, _length); + public readonly ArrayEnumerator GetEnumerator() + { + return _array == null + ? ArrayEnumerator.Empty + : new ArrayEnumerator(_array, _length); + } public readonly int IndexOf(T item, IEqualityComparer? equalityComparer = null) { - if (_length == 0) return -1; + if (_length == 0) + { + return -1; + } equalityComparer ??= EqualityComparer.Default; - var span = AsReadOnlySpan(); + ReadOnlySpan span = AsReadOnlySpan(); + for (var i = 0; i < span.Length; i++) { - if (equalityComparer.Equals(span[i], item)) return i; + if (equalityComparer.Equals(span[i], item)) + { + return i; + } } return -1; @@ -80,13 +102,19 @@ public readonly int IndexOf(T item, IEqualityComparer? equalityComparer = nul public readonly bool Has(T item, IEqualityComparer? equalityComparer = null) { - if (_length == 0) return false; + if (_length == 0) + { + return false; + } equalityComparer ??= EqualityComparer.Default; - foreach (var exists in AsReadOnlySpan()) + foreach (T exists in AsReadOnlySpan()) { - if (equalityComparer.Equals(exists, item)) return true; + if (equalityComparer.Equals(exists, item)) + { + return true; + } } return false; @@ -94,17 +122,23 @@ public readonly bool Has(T item, IEqualityComparer? equalityComparer = null) public bool Remove(T item, IEqualityComparer? equalityComparer = null) { - var index = IndexOf(item, equalityComparer); - if (index == -1) return false; + int index = IndexOf(item, equalityComparer); + + if (index == -1) + { + return false; + } RemoveAtSwapBack(index); + return true; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void RemoveAtSwapBack(int index) { - var lastIndex = _length - 1; + int lastIndex = _length - 1; + if (index < lastIndex) { _array![index] = _array[lastIndex]; @@ -117,23 +151,40 @@ public void RemoveAtSwapBack(int index) _length--; } - + [MethodImpl(MethodImplOptions.AggressiveInlining)] - public readonly T[] ToArray() => AsReadOnlySpan().ToArray(); + public readonly T[] ToArray() + { + return AsReadOnlySpan().ToArray(); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public readonly Block ToBlock() => new(AsReadOnlySpan()); + public readonly Block ToBlock() + { + return new Block(AsReadOnlySpan()); + } public bool TryAdd(T item, IEqualityComparer? equalityComparer = null) { - var has = Has(item, equalityComparer); - if (has) return false; + bool has = Has(item, equalityComparer); + + if (has) + { + return false; + } Add(item); + return true; } - readonly IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + readonly IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } - readonly IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); -} \ No newline at end of file + readonly IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } +} diff --git a/src/Hexecs/Collections/InlineBucket.cs b/src/Hexecs/Collections/InlineBucket.cs index 62beba7..d559a30 100644 --- a/src/Hexecs/Collections/InlineBucket.cs +++ b/src/Hexecs/Collections/InlineBucket.cs @@ -20,8 +20,14 @@ public int Length public void Add(T item) { - if (_length < InlineArraySize) _inlineArray[_length] = item; - else ArrayUtils.Insert(ref _array, ArrayPool.Shared, _length - InlineArraySize, item); + if (_length < InlineArraySize) + { + _inlineArray[_length] = item; + } + else + { + ArrayUtils.Insert(ref _array, ArrayPool.Shared, _length - InlineArraySize, item); + } _length++; } @@ -34,7 +40,10 @@ public readonly bool Contains(T item, EqualityComparer? equalityComparer = nu public readonly void CopyTo(ref Span buffer) { - if (_length == 0) return; + if (_length == 0) + { + return; + } for (var i = 0; i < _length; i++) { @@ -44,34 +53,47 @@ public readonly void CopyTo(ref Span buffer) public void Dispose() { - if (_array is { Length: > 0 }) ArrayPool.Shared.Return(_array); + if (_array is { Length: > 0 }) + { + ArrayPool.Shared.Return(_array); + } + _array = []; _length = 0; } public Enumerator GetEnumerator() { - ref var reference = ref Unsafe.As(ref _inlineArray); - var span = MemoryMarshal.CreateSpan(ref reference, InlineArraySize); + ref T reference = ref Unsafe.As(ref _inlineArray); + Span span = MemoryMarshal.CreateSpan(ref reference, InlineArraySize); + return new Enumerator(span, _array, _length); } public ref T GetRef(int index) { - if (index >= InlineArraySize) return ref _array[index - InlineArraySize]; + if (index >= InlineArraySize) + { + return ref _array[index - InlineArraySize]; + } + + ref T reference = ref Unsafe.As(ref _inlineArray); + Span span = MemoryMarshal.CreateSpan(ref reference, InlineArraySize); - ref var reference = ref Unsafe.As(ref _inlineArray); - var span = MemoryMarshal.CreateSpan(ref reference, InlineArraySize); return ref span[index]; } public readonly int IndexOf(T item, EqualityComparer? equalityComparer = null) { - if (_length == 0) return -1; + if (_length == 0) + { + return -1; + } equalityComparer ??= EqualityComparer.Default; - var inlineLength = Math.Min(_length, InlineArraySize); + int inlineLength = Math.Min(_length, InlineArraySize); + for (var i = 0; i < inlineLength; i++) { if (equalityComparer.Equals(_inlineArray[i], item)) @@ -80,12 +102,19 @@ public readonly int IndexOf(T item, EqualityComparer? equalityComparer = null } } - if (_array == null || _array.Length == 0) return -1; + if (_array == null || _array.Length == 0) + { + return -1; + } + + Span span = _array.AsSpan(0, _length - InlineArraySize); - var span = _array.AsSpan(0, _length - InlineArraySize); for (var i = 0; i < span.Length; i++) { - if (equalityComparer.Equals(span[i], item)) return InlineArraySize + i; + if (equalityComparer.Equals(span[i], item)) + { + return InlineArraySize + i; + } } return -1; @@ -93,19 +122,26 @@ public readonly int IndexOf(T item, EqualityComparer? equalityComparer = null public bool Remove(T item, EqualityComparer? equalityComparer = null) { - if (_length == 0) return false; + if (_length == 0) + { + return false; + } equalityComparer ??= EqualityComparer.Default; - var arraySize = _length - InlineArraySize; - var inlineLength = Math.Min(_length, InlineArraySize); + int arraySize = _length - InlineArraySize; + int inlineLength = Math.Min(_length, InlineArraySize); for (var index = 0; index < inlineLength; index++) { - if (!equalityComparer.Equals(_inlineArray[index], item)) continue; + if (!equalityComparer.Equals(_inlineArray[index], item)) + { + continue; + } + + int inlineEnd = inlineLength - 1; - var inlineEnd = inlineLength - 1; - for (var i = index; i < inlineEnd; i++) + for (int i = index; i < inlineEnd; i++) { _inlineArray[i] = _inlineArray[i + 1]; } @@ -118,15 +154,24 @@ public bool Remove(T item, EqualityComparer? equalityComparer = null) } _length--; + return true; } - if (_array.Length == 0 || arraySize <= 0) return false; + if (_array.Length == 0 || arraySize <= 0) + { + return false; + } + + Span span = _array.AsSpan(0, arraySize); - var span = _array.AsSpan(0, arraySize); for (var i = 0; i < span.Length; i++) { - if (!equalityComparer.Equals(span[i], item)) continue; + if (!equalityComparer.Equals(span[i], item)) + { + continue; + } + ArrayUtils.Cut(_array, i, arraySize); _length--; @@ -142,16 +187,26 @@ public T this[int index] readonly get => index < InlineArraySize ? _inlineArray[index] : _array[index - InlineArraySize]; set { - if (index < InlineArraySize) _inlineArray[index] = value; - else _array[index - InlineArraySize] = value; + if (index < InlineArraySize) + { + _inlineArray[index] = value; + } + else + { + _array[index - InlineArraySize] = value; + } } } public readonly T[] ToArray() { - if (_length == 0) return []; + if (_length == 0) + { + return []; + } + + T[] result = ArrayUtils.Create(_length); - var result = ArrayUtils.Create(_length); for (var i = 0; i < _length; i++) { result[i] = this[i]; @@ -162,10 +217,15 @@ public readonly T[] ToArray() public bool TryAdd(T item, EqualityComparer? equalityComparer = null) { - var has = Contains(item, equalityComparer); - if (has) return false; + bool has = Contains(item, equalityComparer); + + if (has) + { + return false; + } Add(item); + return true; } @@ -174,9 +234,10 @@ public ref struct Enumerator public readonly ref T Current { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => ref _index < InlineArraySize - ? ref _inlineArray[_index] - : ref _array[_index - InlineArraySize]; + get => + ref _index < InlineArraySize + ? ref _inlineArray[_index] + : ref _array[_index - InlineArraySize]; } private readonly Span _inlineArray; @@ -194,7 +255,10 @@ internal Enumerator(Span inlineArray, T[] array, int length) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool MoveNext() => ++_index < _length; + public bool MoveNext() + { + return ++_index < _length; + } } [InlineArray(InlineArraySize)] @@ -208,4 +272,4 @@ private sealed class InlineBucketDebugProxy(InlineBucket bucket) [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] public readonly T[] Elements = bucket.ToArray(); } -} \ No newline at end of file +} diff --git a/src/Hexecs/Collections/ThreadLocalStack.cs b/src/Hexecs/Collections/ThreadLocalStack.cs index 1ca8fd9..38277e2 100644 --- a/src/Hexecs/Collections/ThreadLocalStack.cs +++ b/src/Hexecs/Collections/ThreadLocalStack.cs @@ -12,9 +12,9 @@ internal sealed class ThreadLocalStack : IDisposable where T : struct private readonly ThreadLocal _localStack; private readonly Stack _globalStack; #if NET9_0_OR_GREATER - private readonly Lock _globalLock = new(); + private readonly Lock _globalLock = new Lock(); #else - private readonly object _globalLock = new(); + private readonly object _globalLock = new object(); #endif private bool _isDisposed; @@ -35,7 +35,7 @@ public void Clear() _globalStack.Clear(); } - foreach (var local in _localStack.Values) + foreach (LocalBuffer local in _localStack.Values) { local.Count = 0; } @@ -43,7 +43,10 @@ public void Clear() public void Dispose() { - if (_isDisposed) return; + if (_isDisposed) + { + return; + } // Сначала ставим флаг, чтобы другие потоки перестали работать со стеком _isDisposed = true; @@ -54,7 +57,7 @@ public void Dispose() // Проверяем буферы только если ThreadLocal еще жив try { - foreach (var local in _localStack.Values) + foreach (LocalBuffer local in _localStack.Values) { while (local.Count > 0) { @@ -75,10 +78,12 @@ public void Dispose() [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Push(T item) { - var local = _localStack.Value!; + LocalBuffer local = _localStack.Value!; + if (local.Count < LocalCapacity) { local.Data[local.Count++] = item; + return; } @@ -89,20 +94,24 @@ public void Push(T item) [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool TryPop(out T result) { - var local = _localStack.Value!; + LocalBuffer local = _localStack.Value!; + if (local.Count > 0) { result = local.Data[--local.Count]; + return true; } if (TryPopFromGlobal(local) && local.Count > 0) { result = local.Data[--local.Count]; + return true; } result = default; + return false; } @@ -114,7 +123,8 @@ public void Flush() { if (_localStack.IsValueCreated) { - var local = _localStack.Value!; + LocalBuffer local = _localStack.Value!; + if (local.Count > 0) { #if NET9_0_OR_GREATER @@ -157,9 +167,13 @@ private bool TryPopFromGlobal(LocalBuffer local) lock (_globalLock) #endif { - if (_globalStack.Count == 0) return false; + if (_globalStack.Count == 0) + { + return false; + } + + int toFetch = Math.Min(_globalStack.Count, BatchSize); - var toFetch = Math.Min(_globalStack.Count, BatchSize); // Проверяем свободное место (на всякий случай) toFetch = Math.Min(toFetch, LocalCapacity - local.Count); @@ -177,4 +191,4 @@ private sealed class LocalBuffer public readonly T[] Data = ArrayUtils.Create(LocalCapacity); public int Count; } -} \ No newline at end of file +} diff --git a/src/Hexecs/Configurations/ConfigurationBuilder.cs b/src/Hexecs/Configurations/ConfigurationBuilder.cs index 44e8787..37f5881 100644 --- a/src/Hexecs/Configurations/ConfigurationBuilder.cs +++ b/src/Hexecs/Configurations/ConfigurationBuilder.cs @@ -5,7 +5,7 @@ namespace Hexecs.Configurations; public sealed class ConfigurationBuilder { private readonly List _sources = []; - private readonly ConcurrentDictionary _values = new(); + private readonly ConcurrentDictionary _values = new ConcurrentDictionary(); internal ConfigurationBuilder() { @@ -13,7 +13,7 @@ internal ConfigurationBuilder() internal ConfigurationService Build() { - foreach (var source in _sources) + foreach (IConfigurationSource source in _sources) { source.Load(); } @@ -24,12 +24,14 @@ internal ConfigurationService Build() public ConfigurationBuilder UseSource(IConfigurationSource source) { _sources.Add(source); + return this; } public ConfigurationBuilder UseValue(string key, T? value) { _values[key] = value; + return this; } -} \ No newline at end of file +} diff --git a/src/Hexecs/Configurations/ConfigurationError.cs b/src/Hexecs/Configurations/ConfigurationError.cs index 0373a37..97d44ed 100644 --- a/src/Hexecs/Configurations/ConfigurationError.cs +++ b/src/Hexecs/Configurations/ConfigurationError.cs @@ -7,4 +7,4 @@ public static void KeyNotFound(string key) { throw new KeyNotFoundException($"Configuration key '{key}' isn't found"); } -} \ No newline at end of file +} diff --git a/src/Hexecs/Configurations/ConfigurationService.cs b/src/Hexecs/Configurations/ConfigurationService.cs index 2a57254..ce1140a 100644 --- a/src/Hexecs/Configurations/ConfigurationService.cs +++ b/src/Hexecs/Configurations/ConfigurationService.cs @@ -4,7 +4,7 @@ namespace Hexecs.Configurations; public sealed class ConfigurationService { - public static ConfigurationService Empty => new([], []); + public static ConfigurationService Empty => new ConfigurationService([], []); private readonly IConfigurationSource[] _sources; private readonly ConcurrentDictionary _values; @@ -20,18 +20,31 @@ internal ConfigurationService( public T GetRequiredValue(string key) { var result = GetValue(key); - if (result == null) ConfigurationError.KeyNotFound(key); + + if (result == null) + { + ConfigurationError.KeyNotFound(key); + } return result; } - public T? GetValue(string key) => (T?)_values.GetOrAdd(key, static (k, sources) => + public T? GetValue(string key) { - foreach (var source in sources) - { - if (source.TryGetValue(k, out var exists)) return exists; - } - - return null; - }, _sources); -} \ No newline at end of file + return (T?)_values.GetOrAdd( + key, + static (k, sources) => + { + foreach (IConfigurationSource source in sources) + { + if (source.TryGetValue(k, out T? exists)) + { + return exists; + } + } + + return null; + }, + _sources); + } +} diff --git a/src/Hexecs/Configurations/IConfigurationSource.cs b/src/Hexecs/Configurations/IConfigurationSource.cs index 6befbed..5f3f47d 100644 --- a/src/Hexecs/Configurations/IConfigurationSource.cs +++ b/src/Hexecs/Configurations/IConfigurationSource.cs @@ -5,4 +5,4 @@ public interface IConfigurationSource void Load(); bool TryGetValue(string key, out T? value); -} \ No newline at end of file +} diff --git a/src/Hexecs/Dependencies/Dependency.cs b/src/Hexecs/Dependencies/Dependency.cs index 4b8d8b0..b6661a2 100644 --- a/src/Hexecs/Dependencies/Dependency.cs +++ b/src/Hexecs/Dependencies/Dependency.cs @@ -59,8 +59,16 @@ public Dependency(DependencyLifetime lifetime, Type contract, Func progress) { - var path = string.Join(" -> ", progress.Reverse().Select(TypeOf.GetTypeName)); + string path = string.Join(" -> ", progress.Reverse().Select(TypeOf.GetTypeName)); + throw new Exception($"Detected circular dependency of service '{TypeOf.GetTypeName(request)}' ({path})"); } @@ -30,7 +31,8 @@ public static T NotSupportedLifetime(DependencyLifetime lifetime) [DoesNotReturn] public static object ServiceNotRegistered(Type required, Type? request = null) { - var service = TypeOf.GetTypeName(required); + string service = TypeOf.GetTypeName(required); + throw request == null ? new Exception($"Service '{service}' isn't registered") : new Exception($"Service '{service}' isn't registered for resolve {TypeOf.GetTypeName(request)}"); @@ -39,7 +41,8 @@ public static object ServiceNotRegistered(Type required, Type? request = null) [DoesNotReturn] public static void ResolverNotFound(Type contract, DependencyLifetime lifetime) { - var service = TypeOf.GetTypeName(contract); + string service = TypeOf.GetTypeName(contract); + throw new Exception($"Service resolver for '{service}' with lifetime {lifetime} isn't registered"); } -} \ No newline at end of file +} diff --git a/src/Hexecs/Dependencies/DependencyKey.cs b/src/Hexecs/Dependencies/DependencyKey.cs index 192179e..6dd8332 100644 --- a/src/Hexecs/Dependencies/DependencyKey.cs +++ b/src/Hexecs/Dependencies/DependencyKey.cs @@ -7,14 +7,26 @@ internal readonly struct DependencyKey(Type serviceType, int index) : IEquatable public const int DefaultSlot = 0; [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static DependencyKey First(Type serviceType) => new(serviceType, DefaultSlot); - + public static DependencyKey First(Type serviceType) + { + return new DependencyKey(serviceType, DefaultSlot); + } + public readonly int Index = index; public readonly Type ServiceType = serviceType; - public bool Equals(DependencyKey other) => Index == other.Index && ServiceType == other.ServiceType; + public bool Equals(DependencyKey other) + { + return Index == other.Index && ServiceType == other.ServiceType; + } - public override bool Equals(object? obj) => obj is DependencyKey key && Equals(key); + public override bool Equals(object? obj) + { + return obj is DependencyKey key && Equals(key); + } - public override int GetHashCode() => HashCode.Combine(Index, ServiceType); -} \ No newline at end of file + public override int GetHashCode() + { + return HashCode.Combine(Index, ServiceType); + } +} diff --git a/src/Hexecs/Dependencies/DependencyProvider.cs b/src/Hexecs/Dependencies/DependencyProvider.cs index 8557b12..02d5103 100644 --- a/src/Hexecs/Dependencies/DependencyProvider.cs +++ b/src/Hexecs/Dependencies/DependencyProvider.cs @@ -24,11 +24,14 @@ public DependencyProvider( public void Dispose() { - if (_disposed) return; + if (_disposed) + { + return; + } _disposed = true; // self-disposing protection - foreach (var disposable in _disposables) + foreach (IDisposable disposable in _disposables) { disposable.Dispose(); } @@ -48,56 +51,75 @@ public TService[] GetServices() where TService : class { EnsureNotDisposed(); - var collectionType = typeof(TService[]); - var serviceType = typeof(TService); + Type collectionType = typeof(TService[]); + Type serviceType = typeof(TService); - var collectionKey = DependencyKey.First(collectionType); - if (TryGetValue(collectionKey, out var exists)) + DependencyKey collectionKey = DependencyKey.First(collectionType); + + if (TryGetValue(collectionKey, out object? exists)) { return exists == null ? [] : (TService[])exists; } - if (!_progress.Add(collectionType)) DependencyError.CircularDependency(serviceType, _progress); + if (!_progress.Add(collectionType)) + { + DependencyError.CircularDependency(serviceType, _progress); + } - var buffer = RentArrayBuffer(); + List buffer = RentArrayBuffer(); var storeArray = true; - if (_dependencies.TryGetValue(serviceType, out var dependencies)) + if (_dependencies.TryGetValue(serviceType, out Dependency[]? dependencies)) { for (var i = 0; i < dependencies.Length; i++) { var key = new DependencyKey(serviceType, i); - if (TryGetValue(key, out var resolved) && resolved != null) + + if (TryGetValue(key, out object? resolved) && resolved != null) { buffer.Add(resolved); + continue; } - var dependency = dependencies[i]; - var instance = ResolveInstance(in dependency); + Dependency dependency = dependencies[i]; + object? instance = ResolveInstance(in dependency); - if (instance == null) TryAdd(key, null); + if (instance == null) + { + TryAdd(key, null); + } else { - var isCached = TryCache(dependency.Lifetime, in key, instance); - if (storeArray) storeArray = isCached; + bool isCached = TryCache(dependency.Lifetime, in key, instance); + + if (storeArray) + { + storeArray = isCached; + } } } } - var array = buffer.Cast().ToArray(); + TService[] array = buffer.Cast().ToArray(); ReturnArrayBuffer(buffer); - if (storeArray) TryAdd(collectionKey, array); + if (storeArray) + { + TryAdd(collectionKey, array); + } return array; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public object? GetService(Type contract) => GetService(DependencyKey.First(contract)); + public object? GetService(Type contract) + { + return GetService(DependencyKey.First(contract)); + } public DependencyProvider GetScopeProvider() { @@ -105,6 +127,7 @@ public DependencyProvider GetScopeProvider() var provider = new DependencyProvider(_dependencies, _root ?? this); provider.Add(DependencyKey.First(typeof(IDependencyProvider)), provider); + return provider; } @@ -137,27 +160,43 @@ private static void ReturnArrayBuffer(List buffer) [MethodImpl(MethodImplOptions.AggressiveInlining)] private void EnsureNotDisposed() { - if (_disposed) DependencyError.Disposed(); + if (_disposed) + { + DependencyError.Disposed(); + } } private object? GetService(in DependencyKey key) { EnsureNotDisposed(); - var contract = key.ServiceType; + Type contract = key.ServiceType; - if (TryGetValue(key, out var exists)) return exists; - if (!_progress.Add(contract)) DependencyError.CircularDependency(contract, _progress); + if (TryGetValue(key, out object? exists)) + { + return exists; + } + + if (!_progress.Add(contract)) + { + DependencyError.CircularDependency(contract, _progress); + } object? instance; - if (_dependencies.TryGetValue(contract, out var dependencies)) + if (_dependencies.TryGetValue(contract, out Dependency[]? dependencies)) { - var dependency = dependencies[key.Index]; + Dependency dependency = dependencies[key.Index]; instance = ResolveInstance(in dependency); - if (instance == null) TryAdd(key, null); - else TryCache(dependency.Lifetime, in key, instance); + if (instance == null) + { + TryAdd(key, null); + } + else + { + TryCache(dependency.Lifetime, in key, instance); + } } else { @@ -173,6 +212,7 @@ private void EnsureNotDisposed() private bool TryCache(DependencyLifetime lifetime, in DependencyKey key, object instance) { var isCached = false; + if (lifetime != DependencyLifetime.Transient) { TryAdd(key, instance); @@ -186,4 +226,4 @@ private bool TryCache(DependencyLifetime lifetime, in DependencyKey key, object return isCached; } -} \ No newline at end of file +} diff --git a/src/Hexecs/Dependencies/DependencyProviderExtensions.cs b/src/Hexecs/Dependencies/DependencyProviderExtensions.cs index 362b64f..0c4b7ba 100644 --- a/src/Hexecs/Dependencies/DependencyProviderExtensions.cs +++ b/src/Hexecs/Dependencies/DependencyProviderExtensions.cs @@ -1,3 +1,5 @@ +using System.Reflection; + namespace Hexecs.Dependencies; public static class DependencyProviderExtensions @@ -7,9 +9,9 @@ public static object Activate( [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] Type implementation) { - var constructor = DependencyUtils.GetInjectableConstructor(implementation); - var parameters = constructor.GetParameters(); - var parametersLength = parameters.Length; + ConstructorInfo constructor = DependencyUtils.GetInjectableConstructor(implementation); + ParameterInfo[] parameters = constructor.GetParameters(); + int parametersLength = parameters.Length; if (parametersLength == 0) { @@ -17,13 +19,18 @@ public static object Activate( } var dependencies = new object?[parametersLength]; - for (var i = parametersLength - 1; i >= 0; i--) + + for (int i = parametersLength - 1; i >= 0; i--) { - var parameter = parameters[i]; - var parameterType = parameter.ParameterType; + ParameterInfo parameter = parameters[i]; + Type parameterType = parameter.ParameterType; - var dependency = provider.GetService(parameterType); - if (dependency != null) dependencies[i] = dependency; + object? dependency = provider.GetService(parameterType); + + if (dependency != null) + { + dependencies[i] = dependency; + } else { dependencies[i] = parameter.HasDefaultValue @@ -39,8 +46,12 @@ public static TService GetRequiredService(this IDependencyProvider pro where TService : class { var service = provider.GetService(); - if (service == null) DependencyError.ServiceNotRegistered(typeof(TService)); + + if (service == null) + { + DependencyError.ServiceNotRegistered(typeof(TService)); + } return service; } -} \ No newline at end of file +} diff --git a/src/Hexecs/Dependencies/DependencyUtils.cs b/src/Hexecs/Dependencies/DependencyUtils.cs index 3cc9e36..6a1999b 100644 --- a/src/Hexecs/Dependencies/DependencyUtils.cs +++ b/src/Hexecs/Dependencies/DependencyUtils.cs @@ -4,18 +4,22 @@ namespace Hexecs.Dependencies; internal static class DependencyUtils { - public static ConstructorInfo GetInjectableConstructor( - [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] - Type type) + public static ConstructorInfo GetInjectableConstructor([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] Type type) { - var constructors = type.GetConstructors(); - foreach (var constructor in constructors) + ConstructorInfo[] constructors = type.GetConstructors(); + + foreach (ConstructorInfo constructor in constructors) { - if (constructor.IsPrivate || constructor.IsStatic) continue; + if (constructor.IsPrivate || constructor.IsStatic) + { + continue; + } + return constructor; } DependencyError.InjectableConstructorNotFound(type); + return null; } -} \ No newline at end of file +} diff --git a/src/Hexecs/Dependencies/IDependencyCollection.cs b/src/Hexecs/Dependencies/IDependencyCollection.cs index e06a1c2..881974b 100644 --- a/src/Hexecs/Dependencies/IDependencyCollection.cs +++ b/src/Hexecs/Dependencies/IDependencyCollection.cs @@ -17,4 +17,4 @@ public interface IDependencyCollection IDependencyCollection UseTransient(Type contract, Func resolver); IDependencyCollection UseTransient(Func resolver) where T : class; -} \ No newline at end of file +} diff --git a/src/Hexecs/Dependencies/IDependencyProvider.cs b/src/Hexecs/Dependencies/IDependencyProvider.cs index cf47e74..9b22c4e 100644 --- a/src/Hexecs/Dependencies/IDependencyProvider.cs +++ b/src/Hexecs/Dependencies/IDependencyProvider.cs @@ -26,4 +26,4 @@ public interface IDependencyProvider /// Тип запрашиваемых сервисов. /// Массив экземпляров сервисов указанного типа. TService[] GetServices() where TService : class; -} \ No newline at end of file +} diff --git a/src/Hexecs/Dependencies/IDependencyRegistrar.cs b/src/Hexecs/Dependencies/IDependencyRegistrar.cs index 87837c1..fe8cf6d 100644 --- a/src/Hexecs/Dependencies/IDependencyRegistrar.cs +++ b/src/Hexecs/Dependencies/IDependencyRegistrar.cs @@ -3,4 +3,4 @@ public interface IDependencyRegistrar { void TryRegister(IDependencyCollection services); -} \ No newline at end of file +} diff --git a/src/Hexecs/Loggers/ContextLogger.cs b/src/Hexecs/Loggers/ContextLogger.cs index b9f7e5f..c322c26 100644 --- a/src/Hexecs/Loggers/ContextLogger.cs +++ b/src/Hexecs/Loggers/ContextLogger.cs @@ -112,7 +112,10 @@ public void Write(LogLevel level, string template, T1 arg1, T2 arg2, public void Write( LogLevel level, string template, - T1 arg1, T2 arg2, T3 arg3, T4 arg4) + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4) { logService.Write(level, context, template, arg1, arg2, arg3, arg4); } @@ -121,10 +124,14 @@ public void Write( public void Write( LogLevel level, string template, - T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5) + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5) { logService.Write(level, context, template, arg1, arg2, arg3, arg4, arg5); } #endregion -} \ No newline at end of file +} diff --git a/src/Hexecs/Loggers/ILogSink.cs b/src/Hexecs/Loggers/ILogSink.cs index 7edba00..1dcb98e 100644 --- a/src/Hexecs/Loggers/ILogSink.cs +++ b/src/Hexecs/Loggers/ILogSink.cs @@ -11,7 +11,7 @@ public interface ILogSink : IDisposable /// Уровень логирования /// Возвращает true, если доступен;false если нет bool IsEnabled(LogLevel level); - + /// /// Записать лог в подсистему вывода. /// @@ -28,11 +28,20 @@ public interface ILogSink : IDisposable void Write( LogLevel level, - string context, string template, - T1 arg1, T2 arg2, T3 arg3, T4 arg4); + string context, + string template, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4); void Write( LogLevel level, - string context, string template, - T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5); -} \ No newline at end of file + string context, + string template, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5); +} diff --git a/src/Hexecs/Loggers/ILogValueWriter.cs b/src/Hexecs/Loggers/ILogValueWriter.cs index 5aa99d9..02e1965 100644 --- a/src/Hexecs/Loggers/ILogValueWriter.cs +++ b/src/Hexecs/Loggers/ILogValueWriter.cs @@ -5,4 +5,4 @@ public interface ILogValueWriter; public interface ILogValueWriter : ILogValueWriter { void Write(ref ValueStringBuilder stringBuilder, T arg); -} \ No newline at end of file +} diff --git a/src/Hexecs/Loggers/ILogValueWriterFactory.cs b/src/Hexecs/Loggers/ILogValueWriterFactory.cs index f2db532..8512e28 100644 --- a/src/Hexecs/Loggers/ILogValueWriterFactory.cs +++ b/src/Hexecs/Loggers/ILogValueWriterFactory.cs @@ -3,4 +3,4 @@ public interface ILogValueWriterFactory { bool TryCreateWriter(out ILogValueWriter writer); -} \ No newline at end of file +} diff --git a/src/Hexecs/Loggers/LogBuilder.cs b/src/Hexecs/Loggers/LogBuilder.cs index 3fca481..7336805 100644 --- a/src/Hexecs/Loggers/LogBuilder.cs +++ b/src/Hexecs/Loggers/LogBuilder.cs @@ -1,5 +1,6 @@ using System.Collections.Concurrent; using System.Text; + using Hexecs.Actors; using Hexecs.Actors.Loggers; using Hexecs.Assets; @@ -19,21 +20,23 @@ public sealed class LogBuilder internal LogBuilder() { - _valueWriters = new ConcurrentDictionary([ - new KeyValuePair(typeof(DateTime), new DefaultDateTimeWriter()), - new KeyValuePair(typeof(double), new DefaultDoubleWriter()), - new KeyValuePair(typeof(float), new DefaultFloatWriter()), - new KeyValuePair(typeof(Guid), new DefaultGuidWriter()), - new KeyValuePair(typeof(int), new DefaultIntWriter()), - new KeyValuePair(typeof(uint), new DefaultUIntWriter()), - new KeyValuePair(typeof(long), new DefaultLongWriter()), - new KeyValuePair(typeof(string), new DefaultStringWriter()), - new KeyValuePair(typeof(TimeSpan), new DefaultTimeSpanWriter()), - new KeyValuePair(typeof(Actor), ActorLogWriter.Instance), - new KeyValuePair(typeof(Asset), AssetLogWriter.Instance), - new KeyValuePair(typeof(ActorId), ActorIdLogWriter.Instance), - new KeyValuePair(typeof(AssetId), AssetIdLogWriter.Instance) - ], ReferenceComparer.Instance); + _valueWriters = new ConcurrentDictionary( + [ + new KeyValuePair(typeof(DateTime), new DefaultDateTimeWriter()), + new KeyValuePair(typeof(double), new DefaultDoubleWriter()), + new KeyValuePair(typeof(float), new DefaultFloatWriter()), + new KeyValuePair(typeof(Guid), new DefaultGuidWriter()), + new KeyValuePair(typeof(int), new DefaultIntWriter()), + new KeyValuePair(typeof(uint), new DefaultUIntWriter()), + new KeyValuePair(typeof(long), new DefaultLongWriter()), + new KeyValuePair(typeof(string), new DefaultStringWriter()), + new KeyValuePair(typeof(TimeSpan), new DefaultTimeSpanWriter()), + new KeyValuePair(typeof(Actor), ActorLogWriter.Instance), + new KeyValuePair(typeof(Asset), AssetLogWriter.Instance), + new KeyValuePair(typeof(ActorId), ActorIdLogWriter.Instance), + new KeyValuePair(typeof(AssetId), AssetIdLogWriter.Instance) + ], + ReferenceComparer.Instance); _valueFactories = new Queue(4); } @@ -46,6 +49,7 @@ internal LogService Build() public LogBuilder MinimalLevel(LogLevel level) { _level = level; + return this; } @@ -53,12 +57,14 @@ public LogBuilder SetValueWriter(ILogValueWriter writer) { // for replace exists writer _valueWriters[typeof(T)] = writer; + return this; } public LogBuilder SetValueWriterFactory(ILogValueWriterFactory writerFactory) { _valueFactories.Enqueue(writerFactory); + return this; } @@ -74,7 +80,7 @@ public LogBuilder UseConsoleSink(int bufferSize = 16384, Encoding? encoding = nu public LogBuilder UseTextSink(StreamWriter writer) { - var factories = _valueFactories.ToArray(); + ILogValueWriterFactory[] factories = _valueFactories.ToArray(); var sink = new TextSink(_level, factories, _valueWriters, writer); return UseSink(sink); @@ -83,6 +89,7 @@ public LogBuilder UseTextSink(StreamWriter writer) public LogBuilder UseSink(ILogSink sink) { _writers.Add(sink); + return this; } -} \ No newline at end of file +} diff --git a/src/Hexecs/Loggers/LogLevel.cs b/src/Hexecs/Loggers/LogLevel.cs index 0794a8c..d288dd3 100644 --- a/src/Hexecs/Loggers/LogLevel.cs +++ b/src/Hexecs/Loggers/LogLevel.cs @@ -3,7 +3,7 @@ /// /// Определяет различные уровни серьезности логирования. /// -public enum LogLevel: byte +public enum LogLevel : byte { /// /// Логи, содержащие наиболее подробные сообщения. @@ -41,4 +41,4 @@ public enum LogLevel: byte /// Эти логи должны указывать на сбой в текущей активности, а не на сбой всей приложения. /// Error = 4 -} \ No newline at end of file +} diff --git a/src/Hexecs/Loggers/LogService.cs b/src/Hexecs/Loggers/LogService.cs index 6d7ce17..ff94c39 100644 --- a/src/Hexecs/Loggers/LogService.cs +++ b/src/Hexecs/Loggers/LogService.cs @@ -2,7 +2,7 @@ public sealed class LogService : ILogSink { - public static LogService Empty => new([]); + public static LogService Empty => new LogService([]); private readonly ILogSink[] _writers; @@ -12,19 +12,31 @@ internal LogService(ILogSink[] writers) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ContextLogger CreateContext(string context) => new(this, context); + public ContextLogger CreateContext(string context) + { + return new ContextLogger(this, context); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ContextLogger CreateContext(Type context) => new(this, TypeOf.GetTypeName(context)); + public ContextLogger CreateContext(Type context) + { + return new ContextLogger(this, TypeOf.GetTypeName(context)); + } public bool IsEnabled(LogLevel level) { - if (_writers.Length == 0) return false; + if (_writers.Length == 0) + { + return false; + } // ReSharper disable once LoopCanBeConvertedToQuery - foreach (var writer in _writers) + foreach (ILogSink writer in _writers) { - if (writer.IsEnabled(level)) return true; + if (writer.IsEnabled(level)) + { + return true; + } } return false; @@ -32,7 +44,7 @@ public bool IsEnabled(LogLevel level) public void Write(LogLevel level, string context, string template) { - foreach (var writer in _writers) + foreach (ILogSink writer in _writers) { writer.Write(level, context, template); } @@ -40,7 +52,7 @@ public void Write(LogLevel level, string context, string template) public void Write(LogLevel level, string context, string template, T1 arg1) { - foreach (var writer in _writers) + foreach (ILogSink writer in _writers) { writer.Write(level, context, template, arg1); } @@ -48,7 +60,7 @@ public void Write(LogLevel level, string context, string template, T1 arg1) public void Write(LogLevel level, string context, string template, T1 arg1, T2 arg2) { - foreach (var writer in _writers) + foreach (ILogSink writer in _writers) { writer.Write(level, context, template, arg1, arg2); } @@ -56,7 +68,7 @@ public void Write(LogLevel level, string context, string template, T1 ar public void Write(LogLevel level, string context, string template, T1 arg1, T2 arg2, T3 arg3) { - foreach (var writer in _writers) + foreach (ILogSink writer in _writers) { writer.Write(level, context, template, arg1, arg2, arg3); } @@ -64,10 +76,14 @@ public void Write(LogLevel level, string context, string template, T public void Write( LogLevel level, - string context, string template, - T1 arg1, T2 arg2, T3 arg3, T4 arg4) + string context, + string template, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4) { - foreach (var writer in _writers) + foreach (ILogSink writer in _writers) { writer.Write(level, context, template, arg1, arg2, arg3, arg4); } @@ -75,10 +91,15 @@ public void Write( public void Write( LogLevel level, - string context, string template, - T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5) + string context, + string template, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5) { - foreach (var writer in _writers) + foreach (ILogSink writer in _writers) { writer.Write(level, context, template, arg1, arg2, arg3, arg4, arg5); } @@ -86,9 +107,9 @@ public void Write( public void Dispose() { - foreach (var writer in _writers) + foreach (ILogSink writer in _writers) { writer.Dispose(); } } -} \ No newline at end of file +} diff --git a/src/Hexecs/Serializations/JsonWriterExtensions.cs b/src/Hexecs/Serializations/JsonWriterExtensions.cs index efe570c..0328e99 100644 --- a/src/Hexecs/Serializations/JsonWriterExtensions.cs +++ b/src/Hexecs/Serializations/JsonWriterExtensions.cs @@ -1,4 +1,5 @@ using System.Text.Json; + using Hexecs.Actors; using Hexecs.Assets; using Hexecs.Collections; @@ -9,18 +10,21 @@ public static class JsonWriterExtensions { extension(Utf8JsonWriter writer) { - public Utf8JsonWriter WriteProperty(string propertyName, + public Utf8JsonWriter WriteProperty( + string propertyName, Action value) { writer.WritePropertyName(propertyName); value(writer); + return writer; } - public Utf8JsonWriter WriteProperty(string propertyName, + public Utf8JsonWriter WriteProperty( + string propertyName, in TArray array, Action value) - where TArray: struct, IArray + where TArray : struct, IArray { writer.WritePropertyName(propertyName); writer.WriteStartArray(); @@ -39,6 +43,7 @@ public Utf8JsonWriter WriteProperty(string propertyName, public Utf8JsonWriter WriteProperty(string propertyName, ActorId value) { writer.WriteNumber(propertyName, value.Value); + return writer; } @@ -46,6 +51,7 @@ public Utf8JsonWriter WriteProperty(string propertyName, ActorId value) public Utf8JsonWriter WriteProperty(string propertyName, AssetId value) { writer.WriteNumber(propertyName, value.Value); + return writer; } @@ -53,6 +59,7 @@ public Utf8JsonWriter WriteProperty(string propertyName, AssetId value) public Utf8JsonWriter WriteProperty(string propertyName, bool value) { writer.WriteBoolean(propertyName, value); + return writer; } @@ -62,7 +69,8 @@ public Utf8JsonWriter WriteProperty(string propertyName, DateOnly value) writer.WritePropertyName(propertyName); Span buffer = stackalloc char[68]; - if (value.TryFormat(buffer, out var charsWritten)) + + if (value.TryFormat(buffer, out int charsWritten)) { writer.WriteStringValue(buffer[..charsWritten]); } @@ -78,6 +86,7 @@ public Utf8JsonWriter WriteProperty(string propertyName, DateOnly value) public Utf8JsonWriter WriteProperty(string propertyName, int value) { writer.WriteNumber(propertyName, value); + return writer; } @@ -85,6 +94,7 @@ public Utf8JsonWriter WriteProperty(string propertyName, int value) public Utf8JsonWriter WriteProperty(string propertyName, long value) { writer.WriteNumber(propertyName, value); + return writer; } @@ -92,6 +102,7 @@ public Utf8JsonWriter WriteProperty(string propertyName, long value) public Utf8JsonWriter WriteProperty(string propertyName, string value) { writer.WriteString(propertyName, value); + return writer; } @@ -99,6 +110,7 @@ public Utf8JsonWriter WriteProperty(string propertyName, string value) public Utf8JsonWriter WriteProperty(string propertyName, Type value) { writer.WriteString(propertyName, value.FullName); + return writer; } @@ -106,16 +118,19 @@ public Utf8JsonWriter WriteProperty(string propertyName, Type value) public Utf8JsonWriter WriteProperty(string propertyName, uint value) { writer.WriteNumber(propertyName, value); + return writer; } - internal Utf8JsonWriter WriteProperty(string propertyName, + internal Utf8JsonWriter WriteProperty( + string propertyName, ref readonly InlineBucket value) { writer.WritePropertyName(propertyName); writer.WriteStartArray(); - foreach (var element in value) + + foreach (ushort element in value) { writer.WriteNumberValue(element); } @@ -125,4 +140,4 @@ internal Utf8JsonWriter WriteProperty(string propertyName, return writer; } } -} \ No newline at end of file +} diff --git a/src/Hexecs/Threading/DefaultParallelWorker.cs b/src/Hexecs/Threading/DefaultParallelWorker.cs index dc63624..835bd09 100644 --- a/src/Hexecs/Threading/DefaultParallelWorker.cs +++ b/src/Hexecs/Threading/DefaultParallelWorker.cs @@ -19,10 +19,10 @@ public DefaultParallelWorker( if (degreeOfParallelism < 2) { throw new ArgumentOutOfRangeException( - paramName: nameof(degreeOfParallelism), + paramName: nameof(degreeOfParallelism), message: "Degree of parallelism must be at least 2."); } - + DegreeOfParallelism = degreeOfParallelism; _cts = new CancellationTokenSource(); @@ -38,7 +38,7 @@ public DefaultParallelWorker( for (var i = 0; i < degreeOfParallelism; i++) { - var workerIndex = i; + int workerIndex = i; var thread = new Thread(() => ExecuteWorker(workerIndex, startupLatch)) { IsBackground = false, // Потоки foreground, удерживают приложение @@ -80,7 +80,7 @@ public void Run(IParallelJob job) private void ExecuteWorker(int workerIndex, CountdownEvent startupLatch) { - var lastWorkerIndex = _workers.Length - 1; + int lastWorkerIndex = _workers.Length - 1; // Сигнализируем конструктору, что данный поток готов startupLatch.Signal(); @@ -111,7 +111,11 @@ private void ExecuteWorker(int workerIndex, CountdownEvent startupLatch) public void Dispose() { - if (_disposed) return; + if (_disposed) + { + return; + } + _disposed = true; // Отменяем токен — это заставит методы SignalAndWait выкинуть OperationCanceledException @@ -119,7 +123,7 @@ public void Dispose() _cts.Cancel(); // Теперь спокойно дожидаемся завершения потоков - foreach (var thread in _workers) + foreach (Thread thread in _workers) { if (thread.IsAlive) { @@ -130,4 +134,4 @@ public void Dispose() _barrier.Dispose(); _cts.Dispose(); } -} \ No newline at end of file +} diff --git a/src/Hexecs/Threading/IParallelJob.cs b/src/Hexecs/Threading/IParallelJob.cs index cfd4551..6f56145 100644 --- a/src/Hexecs/Threading/IParallelJob.cs +++ b/src/Hexecs/Threading/IParallelJob.cs @@ -7,4 +7,4 @@ public interface IParallelJob ActorContext Context { get; } void Execute(int workerIndex, int workersCount); -} \ No newline at end of file +} diff --git a/src/Hexecs/Threading/IParallelWorker.cs b/src/Hexecs/Threading/IParallelWorker.cs index f268ae0..0e079ad 100644 --- a/src/Hexecs/Threading/IParallelWorker.cs +++ b/src/Hexecs/Threading/IParallelWorker.cs @@ -3,6 +3,6 @@ public interface IParallelWorker : IDisposable { int DegreeOfParallelism { get; } - + void Run(IParallelJob job); -} \ No newline at end of file +} diff --git a/src/Hexecs/Threading/ThreadingError.cs b/src/Hexecs/Threading/ThreadingError.cs index 68d249c..eb8ddb3 100644 --- a/src/Hexecs/Threading/ThreadingError.cs +++ b/src/Hexecs/Threading/ThreadingError.cs @@ -7,4 +7,4 @@ public static void WrongDegreeOfParallelism() { throw new ArgumentException("Degree of parallelism must be greater or equal than two"); } -} \ No newline at end of file +} diff --git a/src/Hexecs/Utils/Args.cs b/src/Hexecs/Utils/Args.cs index d0c0d15..a0bb9ed 100644 --- a/src/Hexecs/Utils/Args.cs +++ b/src/Hexecs/Utils/Args.cs @@ -7,12 +7,16 @@ namespace Hexecs.Utils; /// public sealed class Args : IEnumerable> { - [ThreadStatic] private static Args? _instance; + [ThreadStatic] + private static Args? Instance; /// /// Получает экземпляр Args из пула или создает новый, если пул пуст. /// - public static Args Rent() => Interlocked.Exchange(ref _instance, null) ?? new Args(); + public static Args Rent() + { + return Interlocked.Exchange(ref Instance, null) ?? new Args(); + } /// /// Получает экземпляр Args из пула и устанавливает одно значение. @@ -20,7 +24,10 @@ public sealed class Args : IEnumerable> /// Тип значения. /// Имя аргумента. /// Значение аргумента. - public static Args Rent(string name, TValue value) => Rent().Set(name, value); + public static Args Rent(string name, TValue value) + { + return Rent().Set(name, value); + } private readonly Dictionary _values; @@ -37,7 +44,7 @@ private Args() /// Имя аргумента. public TValue Get(string name) { - if (!TryGet(name, out var value)) + if (!TryGet(name, out TValue value)) { ActorError.ValueNotFound(name, typeof(TValue)); } @@ -53,7 +60,7 @@ public TValue Get(string name) /// Имя аргумента. public TValue GetOrDefault(string name) { - return TryGet(name, out var value) ? value : default!; + return TryGet(name, out TValue value) ? value : default!; } /// @@ -65,7 +72,7 @@ public TValue GetOrDefault(string name) /// Значение по умолчанию public TValue GetOrDefault(string name, TValue defaultValue) { - return TryGet(name, out var value) ? value : defaultValue; + return TryGet(name, out TValue value) ? value : defaultValue; } /// @@ -74,13 +81,13 @@ public TValue GetOrDefault(string name, TValue defaultValue) /// public void Return() { - foreach (var storage in _values.Values) + foreach (IValueStorage storage in _values.Values) { storage.Return(); } _values.Clear(); - Interlocked.Exchange(ref _instance, this); + Interlocked.Exchange(ref Instance, this); } /// @@ -92,20 +99,24 @@ public void Return() /// Возвращает true, если значение найдено; в противном случае — false. public bool TryGet(string name, out TValue value) { - if (!_values.TryGetValue(typeof(TValue), out var storage)) + if (!_values.TryGetValue(typeof(TValue), out IValueStorage? storage)) { value = default!; + return false; } var expectedValues = Unsafe.As>(storage); - if (expectedValues.TryGetValue(name, out var existsValue)) + + if (expectedValues.TryGetValue(name, out TValue? existsValue)) { value = existsValue; + return true; } value = default!; + return false; } @@ -117,9 +128,9 @@ public bool TryGet(string name, out TValue value) /// Значение аргумента. public Args Set(string name, TValue value) { - var key = typeof(TValue); + Type key = typeof(TValue); - if (!_values.TryGetValue(key, out var storage)) + if (!_values.TryGetValue(key, out IValueStorage? storage)) { storage = ValueStorage.RentStorage(); _values.Add(key, storage); @@ -131,11 +142,17 @@ public Args Set(string name, TValue value) return this; } - public IEnumerator> GetEnumerator() => _values.Values - .SelectMany(static storage => storage.Enumerate()) - .GetEnumerator(); + public IEnumerator> GetEnumerator() + { + return _values.Values + .SelectMany(static storage => storage.Enumerate()) + .GetEnumerator(); + } - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } /// /// Интерфейс для хранилища значений определенного типа. @@ -150,11 +167,12 @@ private interface IValueStorage [DebuggerDisplay("Type {typeof(TValue).Name}, Count = {Count}")] private sealed class ValueStorage : Dictionary, IValueStorage { - [ThreadStatic] private static ValueStorage? _storageInstance; + [ThreadStatic] + private static ValueStorage? StorageInstance; public static ValueStorage RentStorage() { - return Interlocked.Exchange(ref _storageInstance, null) ?? new ValueStorage(); + return Interlocked.Exchange(ref StorageInstance, null) ?? new ValueStorage(); } public IEnumerable> Enumerate() @@ -165,7 +183,7 @@ public IEnumerable> Enumerate() public void Return() { Clear(); - Interlocked.Exchange(ref _storageInstance, this); + Interlocked.Exchange(ref StorageInstance, this); } } -} \ No newline at end of file +} diff --git a/src/Hexecs/Utils/ArrayUtils.cs b/src/Hexecs/Utils/ArrayUtils.cs index d473a9a..078fcf2 100644 --- a/src/Hexecs/Utils/ArrayUtils.cs +++ b/src/Hexecs/Utils/ArrayUtils.cs @@ -24,13 +24,16 @@ public static class ArrayUtils [MethodImpl(MethodImplOptions.AggressiveInlining)] public static T[] Create(int length) { - if (length == 0) return []; + if (length == 0) + { + return []; + } // ReSharper disable once InvertIf if (Environment.Is64BitProcess && typeof(T).IsPrimitive && length > 100) { // На 64-битной платформе для примитивных типов выравниваем размер по 16 байт - var alignedLength = (length + 1) & ~1; // Выравнивание по границе 16 байт + int alignedLength = (length + 1) & ~1; // Выравнивание по границе 16 байт return GC.AllocateUninitializedArray(alignedLength); } @@ -47,7 +50,11 @@ public static T[] Create(int length) /// public static void Clear(T[] array) { - if (array.Length == 0) return; + if (array.Length == 0) + { + return; + } + Array.Clear(array); } @@ -62,7 +69,11 @@ public static void Clear(T[] array) /// public static void Clear(T[] array, int length) { - if (array.Length == 0 || length == 0) return; + if (array.Length == 0 || length == 0) + { + return; + } + Array.Clear(array, 0, length); } @@ -78,7 +89,7 @@ public static void Clear(T[] array, int length) /// public static void Cut(T[] array, int index) { - var length = array.Length - 1; + int length = array.Length - 1; if (index < length) { @@ -122,7 +133,10 @@ public static void Cut(T[] array, int index, int length) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void EnsureCapacity(ref T[] array, int capacity, bool clear = false) { - if (array.Length < capacity) Resize(ref array, capacity, clear); + if (array.Length < capacity) + { + Resize(ref array, capacity, clear); + } } /// @@ -139,7 +153,10 @@ public static void EnsureCapacity(ref T[] array, int capacity, bool clear = f [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void EnsureCapacity(ref T[] array, ArrayPool pool, int capacity, bool clear = false) { - if (array.Length < capacity) Resize(ref array, pool, capacity, clear); + if (array.Length < capacity) + { + Resize(ref array, pool, capacity, clear); + } } /// @@ -155,8 +172,12 @@ public static void EnsureCapacity(ref T[] array, ArrayPool pool, int capac [MethodImpl(MethodImplOptions.NoInlining)] public static void Insert(ref T[] array, int index, in T element) { - var arrayLength = array.Length; - if (index >= arrayLength) Resize(ref array, arrayLength * 2); + int arrayLength = array.Length; + if (index >= arrayLength) + { + Resize(ref array, arrayLength * 2); + } + array[index] = element; } @@ -175,8 +196,12 @@ public static void Insert(ref T[] array, int index, in T element) [MethodImpl(MethodImplOptions.NoInlining)] public static void Insert(ref T[] array, ArrayPool pool, int index, in T element) { - var arrayLength = array.Length; - if (index >= arrayLength) Resize(ref array, pool, arrayLength * 2); + int arrayLength = array.Length; + if (index >= arrayLength) + { + Resize(ref array, pool, arrayLength * 2); + } + array[index] = element; } @@ -230,10 +255,16 @@ public static void InsertOrCreate(ref T[]? array, ArrayPool pool, int inde [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Remove(T[]? array, T item) { - if (array == null) return false; + if (array == null) + { + return false; + } - var index = Array.IndexOf(array, item); - if (index == -1) return false; + int index = Array.IndexOf(array, item); + if (index == -1) + { + return false; + } if (RuntimeHelpers.IsReferenceOrContainsReferences()) { @@ -241,7 +272,7 @@ public static bool Remove(T[]? array, T item) } else { - var lastElementIndex = array.Length - 1; + int lastElementIndex = array.Length - 1; Buffer.BlockCopy(array, (index + 1) * Unsafe.SizeOf(), array, index * Unsafe.SizeOf(), (lastElementIndex - index) * Unsafe.SizeOf()); @@ -265,14 +296,20 @@ public static bool Remove(T[]? array, T item) /// public static void Resize(ref T[] array, int newLength, bool clear = false) { - if (newLength == 0) newLength = 2; + if (newLength == 0) + { + newLength = 2; + } - var newArray = Create(newLength); + T[] newArray = Create(newLength); if (array.Length > 0) { Array.Copy(array, newArray, array.Length); - if (clear) Array.Clear(array, 0, array.Length); + if (clear) + { + Array.Clear(array, 0, array.Length); + } } array = newArray; @@ -292,9 +329,12 @@ public static void Resize(ref T[] array, int newLength, bool clear = false) /// public static void Resize(ref T[] array, ArrayPool pool, int newLength, bool clear = false) { - if (newLength == 0) newLength = 2; + if (newLength == 0) + { + newLength = 2; + } - var newArray = pool.Rent(newLength); + T[] newArray = pool.Rent(newLength); if (array.Length > 0) { @@ -304,4 +344,4 @@ public static void Resize(ref T[] array, ArrayPool pool, int newLength, bo array = newArray; } -} \ No newline at end of file +} diff --git a/src/Hexecs/Utils/CollectionUtils.cs b/src/Hexecs/Utils/CollectionUtils.cs index 9a21339..f0e6f60 100644 --- a/src/Hexecs/Utils/CollectionUtils.cs +++ b/src/Hexecs/Utils/CollectionUtils.cs @@ -19,7 +19,7 @@ public static class CollectionUtils /// Действие , которое нужно выполнить для каждого элемента. public static void Do(this IEnumerable collection, Action action) { - foreach (var element in collection) + foreach (T element in collection) { action(element); } @@ -34,7 +34,7 @@ public static void Do(this IEnumerable collection, Action action) /// Действие , которое нужно выполнить для каждого элемента. public static void Do(this T[] collection, Action action) { - foreach (var element in collection) + foreach (T element in collection) { action(element); } @@ -65,9 +65,13 @@ public static TValue[] ToArray( Func selector, TContext context) { - if (collection.Count == 0) return []; + if (collection.Count == 0) + { + return []; + } + + TValue[] result = ArrayUtils.Create(collection.Count); - var result = ArrayUtils.Create(collection.Count); for (var i = 0; i < collection.Count; i++) { result[i] = selector(collection[i], context); @@ -86,16 +90,20 @@ public static TValue[] ToArray( /// Новый массив [], содержащий элементы из коллекции. Возвращает пустой массив, если исходная коллекция пуста. public static T[] ToArray(IEnumerable collection) { - if (!collection.TryGetNonEnumeratedCount(out var count)) + if (!collection.TryGetNonEnumeratedCount(out int count)) { return collection.ToArray(); } - if (count == 0) return []; + if (count == 0) + { + return []; + } - var array = ArrayUtils.Create(count); + T[] array = ArrayUtils.Create(count); var index = 0; - foreach (var element in collection) + + foreach (T element in collection) { array[index++] = element; } @@ -117,13 +125,21 @@ public static T[] ToArray(IEnumerable collection) /// public static T[] ToArray(IEnumerable collection, int length) { - if (length == 0) return []; + if (length == 0) + { + return []; + } - var array = ArrayUtils.Create(length); + T[] array = ArrayUtils.Create(length); var index = 0; - foreach (var element in collection) + + foreach (T element in collection) { - if (index == length) break; + if (index == length) + { + break; + } + array[index++] = element; } @@ -159,15 +175,27 @@ public void Dispose() } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public IEnumerator GetEnumerator() => this; + public IEnumerator GetEnumerator() + { + return this; + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool MoveNext() => _collection.MoveNext(); + public bool MoveNext() + { + return _collection.MoveNext(); + } - public void Reset() => _collection.Reset(); + public void Reset() + { + _collection.Reset(); + } - IEnumerator IEnumerable.GetEnumerator() => this; + IEnumerator IEnumerable.GetEnumerator() + { + return this; + } object? IEnumerator.Current => Current; } -} \ No newline at end of file +} diff --git a/src/Hexecs/Utils/ComponentsAccess.cs b/src/Hexecs/Utils/ComponentsAccess.cs index 92f1708..e595957 100644 --- a/src/Hexecs/Utils/ComponentsAccess.cs +++ b/src/Hexecs/Utils/ComponentsAccess.cs @@ -5,9 +5,9 @@ public readonly ref struct ComponentsAccess public static ComponentsAccess Empty { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => new(); + get => new ComponentsAccess(); } - + private readonly ReadOnlySpan _sparse; private readonly Span _values; @@ -30,11 +30,12 @@ public ref T this[uint id] [MethodImpl(MethodImplOptions.AggressiveInlining)] get { - ref var sparseStart = ref MemoryMarshal.GetReference(_sparse); - ref var valuesStart = ref MemoryMarshal.GetReference(_values); + ref uint sparseStart = ref MemoryMarshal.GetReference(_sparse); + ref T valuesStart = ref MemoryMarshal.GetReference(_values); + + int denseIndex = (int)Unsafe.Add(ref sparseStart, (nint)id) - 1; - var denseIndex = (int)Unsafe.Add(ref sparseStart, (nint)id) - 1; return ref Unsafe.Add(ref valuesStart, (nint)denseIndex); } } -} \ No newline at end of file +} diff --git a/src/Hexecs/Utils/DelegateUtils.cs b/src/Hexecs/Utils/DelegateUtils.cs index a066438..119fb49 100644 --- a/src/Hexecs/Utils/DelegateUtils.cs +++ b/src/Hexecs/Utils/DelegateUtils.cs @@ -3,6 +3,6 @@ namespace Hexecs.Utils; internal static class DelegateUtils { public static readonly Func AlwaysTrue = static _ => true; - - public static readonly Action EmptyAction = static _ => {}; -} \ No newline at end of file + + public static readonly Action EmptyAction = static _ => { }; +} diff --git a/src/Hexecs/Utils/Error.cs b/src/Hexecs/Utils/Error.cs index 362dbe1..507c196 100644 --- a/src/Hexecs/Utils/Error.cs +++ b/src/Hexecs/Utils/Error.cs @@ -3,8 +3,14 @@ namespace Hexecs.Utils; public static class Error { [DoesNotReturn] - public static void Raise(string message) => throw new Exception(message); + public static void Raise(string message) + { + throw new Exception(message); + } [DoesNotReturn] - public static T Raise(string message) => throw new Exception(message); -} \ No newline at end of file + public static T Raise(string message) + { + throw new Exception(message); + } +} diff --git a/src/Hexecs/Utils/HashHelper.cs b/src/Hexecs/Utils/HashHelper.cs index 2f8aa55..852770a 100644 --- a/src/Hexecs/Utils/HashHelper.cs +++ b/src/Hexecs/Utils/HashHelper.cs @@ -15,15 +15,20 @@ internal static class HashHelper public static int GetPrime(int min) { - foreach (var prime in Primes) + foreach (int prime in Primes) { if (prime >= min) + { return prime; + } } - for (var i = min | 1; i < int.MaxValue; i += 2) + for (int i = min | 1; i < int.MaxValue; i += 2) { - if (IsPrime(i) && (i - 1) % HashPrime != 0) return i; + if (IsPrime(i) && (i - 1) % HashPrime != 0) + { + return i; + } } return min; @@ -31,15 +36,21 @@ public static int GetPrime(int min) private static bool IsPrime(int candidate) { - if ((candidate & 1) == 0) return candidate == 2; + if ((candidate & 1) == 0) + { + return candidate == 2; + } var limit = (int)Math.Sqrt(candidate); + for (var divisor = 3; divisor <= limit; divisor += 2) { if ((candidate % divisor) == 0) + { return false; + } } return true; } -} \ No newline at end of file +} diff --git a/src/Hexecs/Utils/IArray.cs b/src/Hexecs/Utils/IArray.cs index b08a38a..745b8cf 100644 --- a/src/Hexecs/Utils/IArray.cs +++ b/src/Hexecs/Utils/IArray.cs @@ -7,4 +7,4 @@ public interface IArray Span AsSpan(); T this[int index] { get; set; } -} \ No newline at end of file +} diff --git a/src/Hexecs/Utils/ICloneable.cs b/src/Hexecs/Utils/ICloneable.cs index d83856d..35c93cf 100644 --- a/src/Hexecs/Utils/ICloneable.cs +++ b/src/Hexecs/Utils/ICloneable.cs @@ -6,7 +6,7 @@ namespace Hexecs.Utils; /// Обобщенный интерфейс для клонирования структурных типов. /// Позволяет создавать копии структур, реализующих данный интерфейс. /// -/// Тип структуры, которая может быть клонирована. +/// Тип структуры, которая может быть клонирована. /// Должен реализовывать и быть структурой. public interface ICloneable where T : struct, ICloneable @@ -17,4 +17,4 @@ public interface ICloneable /// Копия текущего экземпляра структуры типа T. [Pure] T Clone(); -} \ No newline at end of file +} diff --git a/src/Hexecs/Utils/IHaveOrder.cs b/src/Hexecs/Utils/IHaveOrder.cs index 632c51c..80f809d 100644 --- a/src/Hexecs/Utils/IHaveOrder.cs +++ b/src/Hexecs/Utils/IHaveOrder.cs @@ -17,4 +17,4 @@ public interface IHaveOrder /// Целое число, представляющее позицию объекта в последовательности упорядоченных элементов. /// int Order { get; } -} \ No newline at end of file +} diff --git a/src/Hexecs/Utils/OrderComparer.cs b/src/Hexecs/Utils/OrderComparer.cs index 435c7b5..d74b129 100644 --- a/src/Hexecs/Utils/OrderComparer.cs +++ b/src/Hexecs/Utils/OrderComparer.cs @@ -5,23 +5,37 @@ namespace Hexecs.Utils; public sealed class OrderComparer : IComparer where T : class { - public static IComparer CreateInstance() => new OrderComparer(); + public static IComparer CreateInstance() + { + return new OrderComparer(); + } public int Compare(T? x, T? y) { // ReSharper disable once ConvertIfStatementToSwitchStatement - if (x == null && y == null) return 0; - if (x == null) return -1; - if (y == null) return 1; + if (x == null && y == null) + { + return 0; + } + + if (x == null) + { + return -1; + } + + if (y == null) + { + return 1; + } - var xOrder = x is IHaveOrder xHasOrder + int xOrder = x is IHaveOrder xHasOrder ? xHasOrder.Order : OrderAttribute.TryGetValue(x.GetType()); - var yOrder = y is IHaveOrder yHasOrder + int yOrder = y is IHaveOrder yHasOrder ? yHasOrder.Order : OrderAttribute.TryGetValue(y.GetType()); return xOrder.CompareTo(yOrder); } -} \ No newline at end of file +} diff --git a/src/Hexecs/Utils/ReferenceComparer.cs b/src/Hexecs/Utils/ReferenceComparer.cs index d7989bb..ac53215 100644 --- a/src/Hexecs/Utils/ReferenceComparer.cs +++ b/src/Hexecs/Utils/ReferenceComparer.cs @@ -29,12 +29,18 @@ private ReferenceComparer() /// Первый сравниваемый объект. /// Второй сравниваемый объект. /// Возвращает true, если объекты ссылаются на один и тот же экземпляр; в противном случае — false. - public bool Equals(T? x, T? y) => ReferenceEquals(x, y); + public bool Equals(T? x, T? y) + { + return ReferenceEquals(x, y); + } /// /// Возвращает хеш-код для указанного объекта, используя /// /// Объект, для которого требуется получить хеш-код. /// Хеш-код, соответствующий идентичности объекта. - public int GetHashCode([DisallowNull] T obj) => RuntimeHelpers.GetHashCode(obj); -} \ No newline at end of file + public int GetHashCode([DisallowNull] T obj) + { + return RuntimeHelpers.GetHashCode(obj); + } +} diff --git a/src/Hexecs/Utils/ServiceProviderExtensions.cs b/src/Hexecs/Utils/ServiceProviderExtensions.cs index 31ed032..8ebf495 100644 --- a/src/Hexecs/Utils/ServiceProviderExtensions.cs +++ b/src/Hexecs/Utils/ServiceProviderExtensions.cs @@ -5,7 +5,7 @@ internal static class ServiceProviderExtensions public static IEnumerable GetServices(this IServiceProvider? provider) where T: class { - var collection = provider?.GetService(typeof(IEnumerable)); + object? collection = provider?.GetService(typeof(IEnumerable)); return collection as IEnumerable ?? []; } -} \ No newline at end of file +} diff --git a/src/Hexecs/Utils/StringUtils.cs b/src/Hexecs/Utils/StringUtils.cs index a937fe4..aea4974 100644 --- a/src/Hexecs/Utils/StringUtils.cs +++ b/src/Hexecs/Utils/StringUtils.cs @@ -14,7 +14,8 @@ public static class StringUtils private const string Choices = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!?_@#$%"; - [ThreadStatic] private static StringBuilder? _stringBuilder; + [ThreadStatic] + private static StringBuilder? _stringBuilder; /// /// Преобразует StringBuilder в строку и возвращает его в пул. @@ -42,11 +43,12 @@ public static string GetRandom(int length) { Span stackBuffer = stackalloc char[length]; Random.Shared.GetItems(Choices, stackBuffer); + return new string(stackBuffer); } - var array = ArrayPool.Shared.Rent(length); - var arrayBuffer = array.AsSpan(0, length); + char[] array = ArrayPool.Shared.Rent(length); + Span arrayBuffer = array.AsSpan(0, length); Random.Shared.GetItems(Choices, arrayBuffer); var result = new string(arrayBuffer); @@ -55,7 +57,10 @@ public static string GetRandom(int length) return result; } - public static void GetRandom(Span buffer) => Random.Shared.GetItems(Choices, buffer); + public static void GetRandom(Span buffer) + { + Random.Shared.GetItems(Choices, buffer); + } /// /// Получает экземпляр StringBuilder из пула или создает новый. @@ -65,7 +70,7 @@ public static string GetRandom(int length) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static StringBuilder Rent(int capacity = 2048) { - var builder = _stringBuilder ?? new StringBuilder(capacity); + StringBuilder builder = _stringBuilder ?? new StringBuilder(capacity); builder.EnsureCapacity(capacity); return builder; @@ -79,8 +84,11 @@ public static StringBuilder Rent(int capacity = 2048) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Return(StringBuilder builder, bool clear = true) { - if (clear) builder.Clear(); + if (clear) + { + builder.Clear(); + } _stringBuilder = builder; } -} \ No newline at end of file +} diff --git a/src/Hexecs/Utils/TypeOf.cs b/src/Hexecs/Utils/TypeOf.cs index fef3dea..bcafe19 100644 --- a/src/Hexecs/Utils/TypeOf.cs +++ b/src/Hexecs/Utils/TypeOf.cs @@ -8,24 +8,34 @@ public static void BuildTypeName(Type type, ref ValueStringBuilder sb) { if (!type.IsGenericType) { - var simpleName = type.Name; + string simpleName = type.Name; sb.Append(simpleName); + return; } - var genericArguments = type.GetGenericArguments(); + Type[] genericArguments = type.GetGenericArguments(); - sb.Append(type - .GetGenericTypeDefinition().Name - .Replace($"`{genericArguments.Length}", string.Empty)); + sb.Append( + type + .GetGenericTypeDefinition() + .Name + .Replace($"`{genericArguments.Length}", string.Empty)); sb.Append('<'); var first = true; - foreach (var genericArgument in genericArguments) + + foreach (Type genericArgument in genericArguments) { - if (first) first = false; - else sb.Append(", "); + if (first) + { + first = false; + } + else + { + sb.Append(", "); + } BuildTypeName(genericArgument, ref sb); } @@ -36,10 +46,14 @@ public static void BuildTypeName(Type type, ref ValueStringBuilder sb) [SkipLocalsInit] public static string GetTypeName(Type type) { - if (!type.IsGenericType) return type.Name; + if (!type.IsGenericType) + { + return type.Name; + } var sb = new ValueStringBuilder(stackalloc char[128]); BuildTypeName(type, ref sb); + return sb.Flush(); } } @@ -51,5 +65,8 @@ internal static class TypeOf public static readonly int Id = Interlocked.Increment(ref TypeOf.NextId); [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static string GetTypeName() => TypeOf.GetTypeName(typeof(T)); -} \ No newline at end of file + public static string GetTypeName() + { + return TypeOf.GetTypeName(typeof(T)); + } +} diff --git a/src/Hexecs/Utils/ValueStringBuilder.cs b/src/Hexecs/Utils/ValueStringBuilder.cs index 1d2eea6..acffdd7 100644 --- a/src/Hexecs/Utils/ValueStringBuilder.cs +++ b/src/Hexecs/Utils/ValueStringBuilder.cs @@ -41,12 +41,16 @@ public ValueStringBuilder(int capacity) #region Append [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Append(bool value) => Append(value ? bool.TrueString : bool.FalseString); + public void Append(bool value) + { + Append(value ? bool.TrueString : bool.FalseString); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Append(char c) { - var pos = _length; + int pos = _length; + if ((uint)pos < (uint)_buffer.Length) { _buffer[pos] = c; @@ -62,107 +66,147 @@ public void Append(char c) public void Append(int value, ReadOnlySpan format = default, CultureInfo? culture = null) { Span buffer = stackalloc char[12]; - if (value.TryFormat(buffer, out var written, format, culture)) + + if (value.TryFormat(buffer, out int written, format, culture)) { Append(buffer[..written]); } - else CantFormatToString(value); + else + { + CantFormatToString(value); + } } [SkipLocalsInit] public void Append(DateTime value, ReadOnlySpan format = default, CultureInfo? culture = null) { Span buffer = stackalloc char[format.Length < 26 ? 26 : format.Length]; - if (value.TryFormat(buffer, out var written, format, culture)) + + if (value.TryFormat(buffer, out int written, format, culture)) { Append(buffer[..written]); } - else CantFormatToString(value); + else + { + CantFormatToString(value); + } } [SkipLocalsInit] public void Append(double value, ReadOnlySpan format = default, CultureInfo? culture = null) { Span buffer = stackalloc char[36]; - if (value.TryFormat(buffer, out var written, format, culture)) + + if (value.TryFormat(buffer, out int written, format, culture)) { Append(buffer[..written]); } - else CantFormatToString(value); + else + { + CantFormatToString(value); + } } [SkipLocalsInit] public void Append(float value, ReadOnlySpan format = default, CultureInfo? culture = null) { Span buffer = stackalloc char[36]; - if (value.TryFormat(buffer, out var written, format, culture)) + + if (value.TryFormat(buffer, out int written, format, culture)) { Append(buffer[..written]); } - else CantFormatToString(value); + else + { + CantFormatToString(value); + } } [SkipLocalsInit] public void Append(Guid value, ReadOnlySpan format = default) { Span buffer = stackalloc char[format.Length < 38 ? 38 : format.Length]; - if (value.TryFormat(buffer, out var written, format)) + + if (value.TryFormat(buffer, out int written, format)) { Append(buffer[..written]); } - else CantFormatToString(value); + else + { + CantFormatToString(value); + } } [SkipLocalsInit] public void Append(uint value, ReadOnlySpan format = default, CultureInfo? culture = null) { Span buffer = stackalloc char[68]; - if (value.TryFormat(buffer, out var written, format, culture)) + + if (value.TryFormat(buffer, out int written, format, culture)) { Append(buffer[..written]); } - else CantFormatToString(value); + else + { + CantFormatToString(value); + } } [SkipLocalsInit] public void Append(long value, ReadOnlySpan format = default, CultureInfo? culture = null) { Span buffer = stackalloc char[68]; - if (value.TryFormat(buffer, out var written, format, culture)) + + if (value.TryFormat(buffer, out int written, format, culture)) { Append(buffer[..written]); } - else CantFormatToString(value); + else + { + CantFormatToString(value); + } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Append(string? s) { - if (string.IsNullOrEmpty(s)) return; + if (string.IsNullOrEmpty(s)) + { + return; + } + + int pos = _length; - var pos = _length; if (s.Length == 1 && (uint)pos < (uint)_buffer.Length) { _buffer[pos] = s[0]; _length = pos + 1; } - else Append(s.AsSpan()); + else + { + Append(s.AsSpan()); + } } [SkipLocalsInit] public void Append(TimeSpan value, ReadOnlySpan format = default, CultureInfo? culture = null) { Span buffer = stackalloc char[format.Length < 36 ? 36 : format.Length]; - if (value.TryFormat(buffer, out var written, format, culture)) + + if (value.TryFormat(buffer, out int written, format, culture)) { Append(buffer[..written]); } - else CantFormatToString(value); + else + { + CantFormatToString(value); + } } public void Append(scoped Span value) { - var pos = _length; + int pos = _length; + if (pos > _buffer.Length - value.Length) { Grow(value.Length); @@ -173,11 +217,15 @@ public void Append(scoped Span value) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Append(in ReadOnlyMemory value) => Append(value.Span); - + public void Append(in ReadOnlyMemory value) + { + Append(value.Span); + } + public void Append(scoped ReadOnlySpan value) { - var pos = _length; + int pos = _length; + if (pos > _buffer.Length - value.Length) { Grow(value.Length); @@ -186,15 +234,21 @@ public void Append(scoped ReadOnlySpan value) value.CopyTo(_buffer[_length..]); _length += value.Length; } - + #endregion [MethodImpl(MethodImplOptions.AggressiveInlining)] - public readonly ReadOnlySpan AsReadonlySpan() => _buffer[.._length]; + public readonly ReadOnlySpan AsReadonlySpan() + { + return _buffer[.._length]; + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Span AsSpan() => _buffer; - + public Span AsSpan() + { + return _buffer; + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Clear() { @@ -204,19 +258,26 @@ public void Clear() [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Dispose() { - var toReturn = _array; + char[]? toReturn = _array; this = default; - if (toReturn != null) ArrayPool.Shared.Return(toReturn); + + if (toReturn != null) + { + ArrayPool.Shared.Return(toReturn); + } } public void EnsureCapacity(int capacity) { - if ((uint)capacity > (uint)_buffer.Length) Grow(capacity - _length); + if ((uint)capacity > (uint)_buffer.Length) + { + Grow(capacity - _length); + } } public string Flush() { - var result = _length == 0 + string result = _length == 0 ? string.Empty : _buffer[.._length].ToString(); @@ -224,15 +285,19 @@ public string Flush() return result; } - - public readonly override string ToString() => _length == 0 - ? string.Empty - : _buffer[.._length].ToString(); + + public readonly override string ToString() + { + return _length == 0 + ? string.Empty + : _buffer[.._length].ToString(); + } public void TrimEnd() { - var buffer = _buffer; - var end = _length - 1; + Span buffer = _buffer; + int end = _length - 1; + for (; end >= 0; end--) { if (!char.IsWhiteSpace(buffer[end])) @@ -244,7 +309,10 @@ public void TrimEnd() _length = end + 1; } - public void Whitespace() => Append(' '); + public void Whitespace() + { + Append(' '); + } [MethodImpl(MethodImplOptions.NoInlining)] private void GrowAndAppend(char c) @@ -262,12 +330,13 @@ private void Grow(int additionalCapacityBeyondPos) (uint)(_length + additionalCapacityBeyondPos), Math.Min((uint)_buffer.Length * 2, arrayMaxLength)); - var poolArray = ArrayPool.Shared.Rent(newCapacity); + char[] poolArray = ArrayPool.Shared.Rent(newCapacity); _buffer[.._length].CopyTo(poolArray); - var toReturn = _array; + char[]? toReturn = _array; _buffer = _array = poolArray; + if (toReturn != null) { ArrayPool.Shared.Return(toReturn); @@ -279,4 +348,4 @@ private static void CantFormatToString(T value) { throw new Exception($"Can't format {value} to string"); } -} \ No newline at end of file +} diff --git a/tests/Hexecs.Tests/Actors/ActorComponentShould.cs b/tests/Hexecs.Tests/Actors/ActorComponentShould.cs index d5258b8..0e42044 100644 --- a/tests/Hexecs.Tests/Actors/ActorComponentShould.cs +++ b/tests/Hexecs.Tests/Actors/ActorComponentShould.cs @@ -8,7 +8,7 @@ public sealed class ActorComponentShould(ActorTestFixture fixture) : IClassFixtu public void BeDisposedAfterDestroyComponent() { var monitor = new Mock(); - var actor = fixture.CreateActor(component1: new DisposableComponent(monitor.Object)); + Actor actor = fixture.CreateActor(component1: new DisposableComponent(monitor.Object)); actor.Destroy(); diff --git a/tests/Hexecs.Tests/Actors/ActorConstraintShould.cs b/tests/Hexecs.Tests/Actors/ActorConstraintShould.cs index 6f010b6..bea6ed2 100644 --- a/tests/Hexecs.Tests/Actors/ActorConstraintShould.cs +++ b/tests/Hexecs.Tests/Actors/ActorConstraintShould.cs @@ -1,4 +1,6 @@ -using Hexecs.Tests.Mocks.ActorComponents; +using FluentAssertions.Events; + +using Hexecs.Tests.Mocks.ActorComponents; namespace Hexecs.Tests.Actors; @@ -8,11 +10,11 @@ public sealed class ActorConstraintShould(ActorTestFixture fixture) : IClassFixt public void Should_Be_Applicable_When_Conditions_Met() { // Arrange - var actor = fixture.CreateActor(); // Создаем актора с компонентом - var constraint = ActorConstraint.Include(fixture.Actors).Build(); + Actor actor = fixture.CreateActor(); // Создаем актора с компонентом + ActorConstraint constraint = ActorConstraint.Include(fixture.Actors).Build(); // Act - var result = constraint.Applicable(actor.Id); + bool result = constraint.Applicable(actor.Id); // Assert result.Should().BeTrue(); @@ -22,11 +24,11 @@ public void Should_Be_Applicable_When_Conditions_Met() public void Should_Not_Be_Applicable_When_Excluded_Component_Exists() { // Arrange - var actor = fixture.CreateActor(); - var constraint = ActorConstraint.Exclude(fixture.Actors).Build(); + Actor actor = fixture.CreateActor(); + ActorConstraint constraint = ActorConstraint.Exclude(fixture.Actors).Build(); // Act - var result = constraint.Applicable(actor.Id); + bool result = constraint.Applicable(actor.Id); // Assert result.Should().BeFalse(); @@ -36,10 +38,10 @@ public void Should_Not_Be_Applicable_When_Excluded_Component_Exists() public void Should_Raise_Added_When_Actor_Becomes_Valid() { // Arrange - var actor = fixture.CreateActor(); // Пустой актор - var constraint = ActorConstraint.Include(fixture.Actors).Build(); + Actor actor = fixture.CreateActor(); // Пустой актор + ActorConstraint constraint = ActorConstraint.Include(fixture.Actors).Build(); - using var monitoredSubject = constraint.Monitor(); + using IMonitor monitoredSubject = constraint.Monitor(); // Act actor.Add(new Description()); // Теперь актор соответствует Include @@ -55,10 +57,10 @@ public void Should_Raise_Added_When_Actor_Becomes_Valid() public void Should_Raise_Removing_When_Actor_Becomes_Invalid() { // Arrange - var actor = fixture.CreateActor(); - var constraint = ActorConstraint.Include(fixture.Actors).Build(); + Actor actor = fixture.CreateActor(); + ActorConstraint constraint = ActorConstraint.Include(fixture.Actors).Build(); - using var monitoredSubject = constraint.Monitor(); + using IMonitor monitoredSubject = constraint.Monitor(); // Act actor.Remove(); @@ -74,10 +76,10 @@ public void Should_Raise_Removing_When_Actor_Becomes_Invalid() public void Builder_Should_Throw_On_Duplicate_Component() { // Arrange - var builder = ActorConstraint.Include(fixture.Actors); + ActorConstraint.Builder builder = ActorConstraint.Include(fixture.Actors); // Act - var action = () => builder.Include(); + Func action = () => builder.Include(); // Assert action.Should().Throw(); @@ -87,11 +89,11 @@ public void Builder_Should_Throw_On_Duplicate_Component() public void Should_Implement_Equality_Correctly() { // Arrange - var constraint1 = ActorConstraint.Include(fixture.Actors) + ActorConstraint constraint1 = ActorConstraint.Include(fixture.Actors) .Exclude() .Build(); - var constraint2 = ActorConstraint.Include(fixture.Actors) + ActorConstraint constraint2 = ActorConstraint.Include(fixture.Actors) .Exclude() .Build(); @@ -109,8 +111,8 @@ public void Should_Implement_Equality_Correctly() public void Should_Work_With_Multiple_Includes() { // Arrange - var actor = fixture.CreateActor(); - var constraint = ActorConstraint.Include(fixture.Actors).Build(); + Actor actor = fixture.CreateActor(); + ActorConstraint constraint = ActorConstraint.Include(fixture.Actors).Build(); // Act & Assert constraint.Applicable(actor.Id).Should().BeFalse("Нужны оба компонента"); @@ -123,10 +125,10 @@ public void Should_Work_With_Multiple_Includes() public void Should_Unsubscribe_On_Dispose() { // Arrange - var actor = fixture.CreateActor(); - var constraint = ActorConstraint.Include(fixture.Actors).Build(); + Actor actor = fixture.CreateActor(); + ActorConstraint constraint = ActorConstraint.Include(fixture.Actors).Build(); - using var monitoredSubject = constraint.Monitor(); + using IMonitor monitoredSubject = constraint.Monitor(); // Act ((IDisposable)constraint).Dispose(); diff --git a/tests/Hexecs.Tests/Actors/ActorContextShould.cs b/tests/Hexecs.Tests/Actors/ActorContextShould.cs index dad30e9..c76a389 100644 --- a/tests/Hexecs.Tests/Actors/ActorContextShould.cs +++ b/tests/Hexecs.Tests/Actors/ActorContextShould.cs @@ -12,11 +12,11 @@ public void BuildActor() { // arrange - var asset = fixture.Assets.GetAssetRef(); + AssetRef asset = fixture.Assets.GetAssetRef(); // act - var actor = fixture.Actors.BuildActor(asset); + Actor actor = fixture.Actors.BuildActor(asset); // assert @@ -43,7 +43,7 @@ public void CreateActorWithExpectedId() const uint expectedId = 100_234; // act - var actor = fixture.Actors.CreateActor(expectedId); + Actor actor = fixture.Actors.CreateActor(expectedId); // assert actor.Id.Value.Should().Be(expectedId); @@ -54,12 +54,12 @@ public void CreateActorWithExpectedId() public void CheckIfActorIsAlive() { // arrange - var actor = fixture.Actors.CreateActor(); + Actor actor = fixture.Actors.CreateActor(); const uint nonExistentId = 1_009_999; // act - var actorExists = fixture.Actors.ActorAlive(actor.Id); - var nonExistentActorExists = fixture.Actors.ActorAlive(new ActorId(nonExistentId)); + bool actorExists = fixture.Actors.ActorAlive(actor.Id); + bool nonExistentActorExists = fixture.Actors.ActorAlive(new ActorId(nonExistentId)); // assert actorExists.Should().BeTrue(); @@ -70,10 +70,10 @@ public void CheckIfActorIsAlive() public void DestroyActorById() { // arrange - var actor = fixture.Actors.CreateActor(); + Actor actor = fixture.Actors.CreateActor(); // act - var result = fixture.Actors.DestroyActor(actor.Id); + bool result = fixture.Actors.DestroyActor(actor.Id); // assert result.Should().BeTrue(); @@ -84,10 +84,10 @@ public void DestroyActorById() public void GetActorById() { // arrange - var createdActor = fixture.Actors.CreateActor(); + Actor createdActor = fixture.Actors.CreateActor(); // act - var retrievedActor = fixture.Actors.GetActor(createdActor.Id); + Actor retrievedActor = fixture.Actors.GetActor(createdActor.Id); // assert retrievedActor.Id.Should().Be(createdActor.Id); @@ -97,11 +97,11 @@ public void GetActorById() public void CloneActor() { // arrange - var asset = fixture.Assets.GetAssetRef(); - var originalActor = fixture.Actors.BuildActor(asset); + AssetRef asset = fixture.Assets.GetAssetRef(); + Actor originalActor = fixture.Actors.BuildActor(asset); // act - var clonedActor = fixture.Actors.Clone(originalActor.Id); + Actor clonedActor = fixture.Actors.Clone(originalActor.Id); // assert clonedActor.Id.Should().NotBe(originalActor.Id); @@ -114,10 +114,10 @@ public void CloneActor() public void ClearAllActors() { // arrange - var actor1 = fixture.Actors.CreateActor(); - var actor2 = fixture.Actors.CreateActor(); - var initialActor1Exists = fixture.Actors.ActorAlive(actor1.Id); - var initialActor2Exists = fixture.Actors.ActorAlive(actor2.Id); + Actor actor1 = fixture.Actors.CreateActor(); + Actor actor2 = fixture.Actors.CreateActor(); + bool initialActor1Exists = fixture.Actors.ActorAlive(actor1.Id); + bool initialActor2Exists = fixture.Actors.ActorAlive(actor2.Id); // act fixture.Actors.Clear(); @@ -134,16 +134,16 @@ public void ClearAllActors() public void TryGetActorWithComponent(int attackValue, int defenceValue) { // arrange - var actors = fixture.Actors; + ActorContext actors = fixture.Actors; - var actor = actors.CreateActor(); + Actor actor = actors.CreateActor(); actor.Add(new Attack { Value = attackValue }); actor.Add(new Defence { Value = defenceValue }); // act - var hasAttack = actors.TryGetActorRef(actor.Id, out var actorWithAttack); - var hasDefence = actors.TryGetActorRef(actor.Id, out var actorWithDefence); - var hasNonExistentComponent = actors.TryGetActorRef(actor.Id, out _); + bool hasAttack = actors.TryGetActorRef(actor.Id, out ActorRef actorWithAttack); + bool hasDefence = actors.TryGetActorRef(actor.Id, out ActorRef actorWithDefence); + bool hasNonExistentComponent = actors.TryGetActorRef(actor.Id, out _); // assert hasAttack.Should().BeTrue(); @@ -161,12 +161,12 @@ public void TryGetActorWithComponent(int attackValue, int defenceValue) public void GetActorDescription() { // arrange - var actor = fixture.Actors.CreateActor(); + Actor actor = fixture.Actors.CreateActor(); actor.Add(new Attack { Value = 10 }); actor.Add(new Defence { Value = 20 }); // act - var description = fixture.Actors.GetDescription(actor.Id); + string description = fixture.Actors.GetDescription(actor.Id); // assert description.Should().Contain(actor.Id.Value.ToString()); @@ -178,12 +178,12 @@ public void GetActorDescription() public void BindAndGetAsset() { // arrange - var asset = fixture.Assets.GetAssetRef(); - var actor = fixture.Actors.CreateActor(); + AssetRef asset = fixture.Assets.GetAssetRef(); + Actor actor = fixture.Actors.CreateActor(); // act fixture.Actors.SetBoundAsset(actor.Id, asset); - var boundAsset = fixture.Actors.GetBoundAsset(actor.Id); + Asset boundAsset = fixture.Actors.GetBoundAsset(actor.Id); // assert boundAsset.Should().NotBeNull(); @@ -194,7 +194,7 @@ public void BindAndGetAsset() public void AddComponentToActor() { // arrange - var actor = fixture.Actors.CreateActor(); + Actor actor = fixture.Actors.CreateActor(); var attack = new Attack { Value = 10 }; // act @@ -209,13 +209,13 @@ public void AddComponentToActor() public void CloneComponentFromOneActorToAnother() { // arrange - var actor1 = fixture.Actors.CreateActor(); - var actor2 = fixture.Actors.CreateActor(); + Actor actor1 = fixture.Actors.CreateActor(); + Actor actor2 = fixture.Actors.CreateActor(); var attack = new Attack { Value = 15 }; fixture.Actors.AddComponent(actor1.Id, attack); // act - ref var clonedComponent = ref fixture.Actors.CloneComponent(actor1.Id, actor2.Id); + ref Attack clonedComponent = ref fixture.Actors.CloneComponent(actor1.Id, actor2.Id); // assert fixture.Actors.HasComponent(actor2.Id).Should().BeTrue(); @@ -227,15 +227,15 @@ public void CloneComponentFromOneActorToAnother() public void EnumerateActorComponents() { // arrange - var actor = fixture.Actors.CreateActor(); + Actor actor = fixture.Actors.CreateActor(); fixture.Actors.AddComponent(actor.Id, new Attack { Value = 10 }); fixture.Actors.AddComponent(actor.Id, new Defence { Value = 20 }); // act - var components = fixture.Actors.Components(actor.Id); + ActorContext.ComponentEnumerator components = fixture.Actors.Components(actor.Id); var componentTypes = new List(); - foreach (var component in components) + foreach (IActorComponent component in components) { componentTypes.Add(component.GetType()); } @@ -249,11 +249,11 @@ public void EnumerateActorComponents() public void GetActorComponent() { // arrange - var actor = fixture.Actors.CreateActor(); + Actor actor = fixture.Actors.CreateActor(); fixture.Actors.AddComponent(actor.Id, new Attack { Value = 25 }); // act - ref var component = ref fixture.Actors.GetComponent(actor.Id); + ref Attack component = ref fixture.Actors.GetComponent(actor.Id); // assert component.Value.Should().Be(25); @@ -263,10 +263,10 @@ public void GetActorComponent() public void AddComponentIfNotExists() { // arrange - var actor = fixture.Actors.CreateActor(); + Actor actor = fixture.Actors.CreateActor(); // act - ref var component = ref fixture.Actors.GetOrAddComponent(actor.Id, _ => new Attack { Value = 30 }); + ref Attack component = ref fixture.Actors.GetOrAddComponent(actor.Id, _ => new Attack { Value = 30 }); // assert component.Value.Should().Be(30); @@ -277,11 +277,11 @@ public void AddComponentIfNotExists() public void GetExistingComponentWithGetOrAdd() { // arrange - var actor = fixture.Actors.CreateActor(); + Actor actor = fixture.Actors.CreateActor(); fixture.Actors.AddComponent(actor.Id, new Attack { Value = 40 }); // act - ref var component = ref fixture.Actors.GetOrAddComponent(actor.Id, _ => new Attack { Value = 50 }); + ref Attack component = ref fixture.Actors.GetOrAddComponent(actor.Id, _ => new Attack { Value = 50 }); // assert component.Value.Should().Be(40); // должно вернуть существующее значение @@ -292,12 +292,12 @@ public void GetExistingComponentWithGetOrAdd() public void CheckIfActorHasComponent() { // arrange - var actor = fixture.Actors.CreateActor(); + Actor actor = fixture.Actors.CreateActor(); fixture.Actors.AddComponent(actor.Id, new Attack { Value = 10 }); // act - var hasAttack = fixture.Actors.HasComponent(actor.Id); - var hasDefence = fixture.Actors.HasComponent(actor.Id); + bool hasAttack = fixture.Actors.HasComponent(actor.Id); + bool hasDefence = fixture.Actors.HasComponent(actor.Id); // assert hasAttack.Should().BeTrue(); @@ -308,7 +308,7 @@ public void CheckIfActorHasComponent() public void CallHandlerWhenComponentAdded() { // arrange - var actor = fixture.Actors.CreateActor(); + Actor actor = fixture.Actors.CreateActor(); uint? addedActorId = null; fixture.Actors.OnComponentAdded(id => addedActorId = id.Value); @@ -324,7 +324,7 @@ public void CallHandlerWhenComponentAdded() public void CallHandlerWithValueWhenComponentAdded() { // arrange - var actor = fixture.Actors.CreateActor(); + Actor actor = fixture.Actors.CreateActor(); uint? addedActorId = null; Attack? addedComponent = null; @@ -347,7 +347,7 @@ public void CallHandlerWithValueWhenComponentAdded() public void CallHandlerWhenComponentRemoved() { // arrange - var actor = fixture.Actors.CreateActor(); + Actor actor = fixture.Actors.CreateActor(); fixture.Actors.AddComponent(actor.Id, new Attack { Value = 10 }); uint? removedActorId = null; @@ -364,7 +364,7 @@ public void CallHandlerWhenComponentRemoved() public void CallHandlerWithValueWhenComponentRemoved() { // arrange - var actor = fixture.Actors.CreateActor(); + Actor actor = fixture.Actors.CreateActor(); fixture.Actors.AddComponent(actor.Id, new Attack { Value = 20 }); uint? removedActorId = null; @@ -389,7 +389,7 @@ public void CallHandlerWithValueWhenComponentRemoved() public void CallHandlerWhenComponentUpdated() { // arrange - var actor = fixture.Actors.CreateActor(); + Actor actor = fixture.Actors.CreateActor(); fixture.Actors.AddComponent(actor.Id, new Attack { Value = 10 }); uint? updatedActorId = null; @@ -419,11 +419,11 @@ public void CallHandlerWhenComponentUpdated() public void RemoveComponentFromActor() { // arrange - var actor = fixture.Actors.CreateActor(); + Actor actor = fixture.Actors.CreateActor(); fixture.Actors.AddComponent(actor.Id, new Attack { Value = 10 }); // act - var result = fixture.Actors.RemoveComponent(actor.Id); + bool result = fixture.Actors.RemoveComponent(actor.Id); // assert result.Should().BeTrue(); @@ -434,11 +434,11 @@ public void RemoveComponentFromActor() public void ReturnValueOfRemovedComponent() { // arrange - var actor = fixture.Actors.CreateActor(); + Actor actor = fixture.Actors.CreateActor(); fixture.Actors.AddComponent(actor.Id, new Attack { Value = 25 }); // act - var result = fixture.Actors.RemoveComponent(actor.Id, out Attack removedComponent); + bool result = fixture.Actors.RemoveComponent(actor.Id, out Attack removedComponent); // assert result.Should().BeTrue(); @@ -450,11 +450,11 @@ public void ReturnValueOfRemovedComponent() public void TryAddComponentToActor() { // arrange - var actor = fixture.Actors.CreateActor(); + Actor actor = fixture.Actors.CreateActor(); var attack = new Attack { Value = 35 }; // act - var result = fixture.Actors.TryAdd(actor.Id, attack); + bool result = fixture.Actors.TryAdd(actor.Id, attack); // assert result.Should().BeTrue(); @@ -466,12 +466,12 @@ public void TryAddComponentToActor() public void GetComponentRefIfExists() { // arrange - var actor = fixture.Actors.CreateActor(); + Actor actor = fixture.Actors.CreateActor(); fixture.Actors.AddComponent(actor.Id, new Attack { Value = 40 }); // act - ref var componentRef = ref fixture.Actors.TryGetComponentRef(actor.Id); - var isNull = Unsafe.IsNullRef(ref componentRef); + ref Attack componentRef = ref fixture.Actors.TryGetComponentRef(actor.Id); + bool isNull = Unsafe.IsNullRef(ref componentRef); // assert isNull.Should().BeFalse(); @@ -482,11 +482,11 @@ public void GetComponentRefIfExists() public void ReturnNullRefIfComponentDoesNotExist() { // arrange - var actor = fixture.Actors.CreateActor(); + Actor actor = fixture.Actors.CreateActor(); // act - ref var componentRef = ref fixture.Actors.TryGetComponentRef(actor.Id); - var isNull = Unsafe.IsNullRef(ref componentRef); + ref Attack componentRef = ref fixture.Actors.TryGetComponentRef(actor.Id); + bool isNull = Unsafe.IsNullRef(ref componentRef); // assert isNull.Should().BeTrue(); @@ -497,11 +497,11 @@ public void ReturnNullRefIfComponentDoesNotExist() public void UpdateExistingComponent(int initialValue, int updatedValue) { // arrange - var actor = fixture.Actors.CreateActor(); + Actor actor = fixture.Actors.CreateActor(); fixture.Actors.AddComponent(actor.Id, new Attack { Value = initialValue }); // act - var result = fixture.Actors.UpdateComponent(actor.Id, new Attack { Value = updatedValue }); + bool result = fixture.Actors.UpdateComponent(actor.Id, new Attack { Value = updatedValue }); // assert result.Should().BeTrue(); @@ -514,10 +514,10 @@ public void UpdateExistingComponent(int initialValue, int updatedValue) public void CreateComponentWhenUpdatingIfNotExists(int value) { // arrange - var actor = fixture.Actors.CreateActor(); + Actor actor = fixture.Actors.CreateActor(); // act - var result = fixture.Actors.UpdateComponent(actor.Id, new Attack { Value = value }); + bool result = fixture.Actors.UpdateComponent(actor.Id, new Attack { Value = value }); // assert result.Should().BeTrue(); @@ -529,12 +529,12 @@ public void CreateComponentWhenUpdatingIfNotExists(int value) public void TryGetBoundAsset() { // arrange - var asset = fixture.Assets.GetAssetRef(); - var actor = fixture.Actors.CreateActor(); + AssetRef asset = fixture.Assets.GetAssetRef(); + Actor actor = fixture.Actors.CreateActor(); fixture.Actors.SetBoundAsset(actor.Id, asset); // act - var success = fixture.Actors.TryGetBoundAsset(actor.Id, out var boundAsset); + bool success = fixture.Actors.TryGetBoundAsset(actor.Id, out Asset boundAsset); // assert success.Should().BeTrue(); @@ -545,10 +545,10 @@ public void TryGetBoundAsset() public void ReturnFalseWhenTryingToGetNonExistentBoundAsset() { // arrange - var actor = fixture.Actors.CreateActor(); + Actor actor = fixture.Actors.CreateActor(); // act - var success = fixture.Actors.TryGetBoundAsset(actor.Id, out var boundAsset); + bool success = fixture.Actors.TryGetBoundAsset(actor.Id, out Asset boundAsset); // assert success.Should().BeFalse(); @@ -560,7 +560,7 @@ public void GetActorToStringWithId() { // arrange const uint expectedId = 100_500; - var actor = fixture.Actors.CreateActor(expectedId); + Actor actor = fixture.Actors.CreateActor(expectedId); // act var actorString = actor.ToString(); @@ -574,13 +574,13 @@ public void ActorsShouldBeEnumerableViaContext() { // arrange fixture.Actors.Clear(); - var actor1 = fixture.Actors.CreateActor(); - var actor2 = fixture.Actors.CreateActor(); - var actor3 = fixture.Actors.CreateActor(); - var expectedIds = new[] { actor1.Id, actor2.Id, actor3.Id }; + Actor actor1 = fixture.Actors.CreateActor(); + Actor actor2 = fixture.Actors.CreateActor(); + Actor actor3 = fixture.Actors.CreateActor(); + ActorId[] expectedIds = [actor1.Id, actor2.Id, actor3.Id]; // act - var actualIds = fixture.Actors.Select(a => a.Id).ToArray(); + ActorId[] actualIds = [.. fixture.Actors.Select(a => a.Id)]; // assert actualIds.Should().BeEquivalentTo(expectedIds); @@ -590,11 +590,11 @@ public void ActorsShouldBeEnumerableViaContext() public void GetActorFromActorRef() { // arrange - var actor = fixture.Actors.CreateActor(); + Actor actor = fixture.Actors.CreateActor(); actor.Add(new Attack { Value = 10 }); // act - var actorRef = fixture.Actors.GetActorRef(actor.Id); + ActorRef actorRef = fixture.Actors.GetActorRef(actor.Id); Actor retrievedActor = actorRef; // assert @@ -607,17 +607,17 @@ public void GetActorWithPredicate() { // arrange fixture.Actors.Clear(); - var actor1 = fixture.Actors.CreateActor(); + Actor actor1 = fixture.Actors.CreateActor(); actor1.Add(new Attack { Value = 5 }); - var actor2 = fixture.Actors.CreateActor(); + Actor actor2 = fixture.Actors.CreateActor(); actor2.Add(new Attack { Value = 10 }); - var actor3 = fixture.Actors.CreateActor(); + Actor actor3 = fixture.Actors.CreateActor(); actor3.Add(new Attack { Value = 15 }); // act - var actorWithAttack10 = + ActorRef actorWithAttack10 = fixture.Actors.GetActorRef((in ActorRef actor) => actor.Get().Value == 10); // assert @@ -636,11 +636,11 @@ public void GetSingleActorWithComponent() { // arrange fixture.Actors.Clear(); - var actor = fixture.Actors.CreateActor(); + Actor actor = fixture.Actors.CreateActor(); actor.Add(new NonExistentComponent()); // act - var singleActor = fixture.Actors.SingleRef(); + ActorRef singleActor = fixture.Actors.SingleRef(); // assert singleActor @@ -672,10 +672,10 @@ public void ThrowWhenGettingSingleWithMultipleMatchingActors() { // arrange fixture.Actors.Clear(); - var actor1 = fixture.Actors.CreateActor(); + Actor actor1 = fixture.Actors.CreateActor(); actor1.Add(new Attack { Value = 10 }); - var actor2 = fixture.Actors.CreateActor(); + Actor actor2 = fixture.Actors.CreateActor(); actor2.Add(new Attack { Value = 20 }); // act @@ -689,13 +689,13 @@ public void ThrowWhenGettingSingleWithMultipleMatchingActors() public void RemoveBoundAssetWhenSettingEmptyAsset() { // arrange - var asset = fixture.Assets.GetAssetRef(); - var actor = fixture.Actors.CreateActor(); + AssetRef asset = fixture.Assets.GetAssetRef(); + Actor actor = fixture.Actors.CreateActor(); fixture.Actors.SetBoundAsset(actor.Id, asset); // act fixture.Actors.SetBoundAsset(actor.Id, Asset.Empty); - var hasAsset = fixture.Actors.TryGetBoundAsset(actor.Id, out _); + bool hasAsset = fixture.Actors.TryGetBoundAsset(actor.Id, out _); // assert hasAsset.Should().BeFalse(); @@ -708,7 +708,7 @@ public void BuildActorWithSpecificComponent() const int attackValue = 42; // act - var actor = fixture.Actors.CreateActor(); + Actor actor = fixture.Actors.CreateActor(); actor.Add(new Attack { Value = attackValue }); // assert @@ -720,7 +720,7 @@ public void BuildActorWithSpecificComponent() public void ThrowWhenGettingNonExistentComponent() { // arrange - var actor = fixture.Actors.CreateActor(); + Actor actor = fixture.Actors.CreateActor(); // act Action action = () => fixture.Actors.GetComponent(actor.Id); @@ -733,7 +733,7 @@ public void ThrowWhenGettingNonExistentComponent() public void ThrowWhenGettingBoundAssetForActorWithoutAsset() { // arrange - var actor = fixture.Actors.CreateActor(); + Actor actor = fixture.Actors.CreateActor(); // act Action action = () => fixture.Actors.GetBoundAsset(actor.Id); diff --git a/tests/Hexecs.Tests/Actors/ActorFilter1Should.cs b/tests/Hexecs.Tests/Actors/ActorFilter1Should.cs index cb3dbb4..3aaec64 100644 --- a/tests/Hexecs.Tests/Actors/ActorFilter1Should.cs +++ b/tests/Hexecs.Tests/Actors/ActorFilter1Should.cs @@ -132,6 +132,4 @@ public void RemoveActorAfterRemoveComponent() .Should() .BeFalse(); } - - } diff --git a/tests/Hexecs.Tests/Actors/ActorFilter2Should.cs b/tests/Hexecs.Tests/Actors/ActorFilter2Should.cs index c717fc7..1c905c8 100644 --- a/tests/Hexecs.Tests/Actors/ActorFilter2Should.cs +++ b/tests/Hexecs.Tests/Actors/ActorFilter2Should.cs @@ -9,15 +9,15 @@ public void ReturnsEmptyWhenNoActorsMatchFilter() { // arrange - var expected = fixture.CreateActor(); // Создаем актера с другим компонентом, чтобы убедиться, что он не попадет в фильтр + Actor expected = fixture.CreateActor(); // Создаем актера с другим компонентом, чтобы убедиться, что он не попадет в фильтр // act - var filter = fixture + ActorFilter filter = fixture .Actors .Filter(); // Фильтруем по Attack // assert - var actors = filter.ToArray(); + Actor[] actors = filter.ToArray(); actors .Should() .NotContain(actor => actor.Id == expected.Id); @@ -29,10 +29,10 @@ public void ContainsActorWithTwoComponentsWhenFilteredByTwoComponents() // arrange var attackComponent = fixture.CreateComponent(); var defenceComponent = fixture.CreateComponent(); - var actor = fixture.CreateActor(component1: attackComponent, component2: defenceComponent); + Actor actor = fixture.CreateActor(component1: attackComponent, component2: defenceComponent); // act - var filter = fixture + ActorFilter filter = fixture .Actors .Filter(); @@ -42,7 +42,7 @@ public void ContainsActorWithTwoComponentsWhenFilteredByTwoComponents() .Should() .BeTrue(); - var actorRef = filter.GetRef(actor.Id); + ActorRef actorRef = filter.GetRef(actor.Id); actorRef.Component1.Should().Be(attackComponent); actorRef.Component2.Should().Be(defenceComponent); } @@ -54,12 +54,12 @@ public void DoesNotContainActorWithOnlyOneOfTwoComponentsWhenFilteredByTwoCompon var attackComponent = fixture.CreateComponent(); var defenceComponent = fixture.CreateComponent(); - var actorWithBoth = fixture.CreateActor(component1: attackComponent, component2: defenceComponent); - var actorWithAttackOnly = fixture.CreateActor(component1: attackComponent); - var actorWithDefenceOnly = fixture.CreateActor(component1: defenceComponent); + Actor actorWithBoth = fixture.CreateActor(component1: attackComponent, component2: defenceComponent); + Actor actorWithAttackOnly = fixture.CreateActor(component1: attackComponent); + Actor actorWithDefenceOnly = fixture.CreateActor(component1: defenceComponent); // act - var filter = fixture + ActorFilter filter = fixture .Actors .Filter(); @@ -75,9 +75,9 @@ public void RemovesActorFromTwoComponentFilterWhenFirstComponentIsRemoved() // arrange var attackComponent = fixture.CreateComponent(); var defenceComponent = fixture.CreateComponent(); - var actor = fixture.CreateActor(component1: attackComponent, component2: defenceComponent); + Actor actor = fixture.CreateActor(component1: attackComponent, component2: defenceComponent); - var filter = fixture + ActorFilter filter = fixture .Actors .Filter(); @@ -96,9 +96,9 @@ public void RemovesActorFromTwoComponentFilterWhenSecondComponentIsRemoved() // arrange var attackComponent = fixture.CreateComponent(); var defenceComponent = fixture.CreateComponent(); - var actor = fixture.CreateActor(component1: attackComponent, component2: defenceComponent); + Actor actor = fixture.CreateActor(component1: attackComponent, component2: defenceComponent); - var filter = fixture + ActorFilter filter = fixture .Actors .Filter(); diff --git a/tests/Hexecs.Tests/Actors/ActorFilter3Should.cs b/tests/Hexecs.Tests/Actors/ActorFilter3Should.cs index 1e842b8..423c7e2 100644 --- a/tests/Hexecs.Tests/Actors/ActorFilter3Should.cs +++ b/tests/Hexecs.Tests/Actors/ActorFilter3Should.cs @@ -11,13 +11,13 @@ public void ContainsActorWithThreeComponentsWhenFilteredByThreeComponents() var attackComponent = fixture.CreateComponent(); var defenceComponent = fixture.CreateComponent(); var speedComponent = fixture.CreateComponent(); // Предполагаемый третий компонент - var actor = fixture.CreateActor( + Actor actor = fixture.CreateActor( component1: attackComponent, component2: defenceComponent, component3: speedComponent); // act - var filter = fixture + ActorFilter filter = fixture .Actors .Filter(); @@ -27,7 +27,7 @@ public void ContainsActorWithThreeComponentsWhenFilteredByThreeComponents() .Should() .BeTrue(); - var actorRef = filter.GetRef(actor.Id); + ActorRef actorRef = filter.GetRef(actor.Id); actorRef.Component1 .Should() .Be(attackComponent); @@ -49,19 +49,21 @@ public void DoesNotContainActorWithOnlyTwoOfThreeComponentsWhenFilteredByThreeCo var defenceComponent = fixture.CreateComponent(); var speedComponent = fixture.CreateComponent(); - var actorWithAllThree = fixture.CreateActor(component1: attackComponent, - component2: defenceComponent, component3: speedComponent); - var actorWithAttackDefence = + Actor actorWithAllThree = fixture.CreateActor( + component1: attackComponent, + component2: defenceComponent, + component3: speedComponent); + Actor actorWithAttackDefence = fixture.CreateActor(component1: attackComponent, component2: defenceComponent); - var actorWithAttackSpeed = - fixture.CreateActor(component1: attackComponent, + Actor actorWithAttackSpeed = + fixture.CreateActor( + component1: attackComponent, component2: speedComponent); // Используем component2 для Speed если CreateActor так работает - var actorWithDefenceSpeed = + Actor actorWithDefenceSpeed = fixture.CreateActor(component1: defenceComponent, component2: speedComponent); - // act - var filter = fixture + ActorFilter filter = fixture .Actors .Filter(); @@ -79,10 +81,12 @@ public void RemovesActorFromThreeComponentFilterWhenAComponentIsRemoved() var attackComponent = fixture.CreateComponent(); var defenceComponent = fixture.CreateComponent(); var speedComponent = fixture.CreateComponent(); - var actor = fixture.CreateActor(component1: attackComponent, - component2: defenceComponent, component3: speedComponent); + Actor actor = fixture.CreateActor( + component1: attackComponent, + component2: defenceComponent, + component3: speedComponent); - var filter = fixture + ActorFilter filter = fixture .Actors .Filter(); @@ -95,17 +99,18 @@ public void RemovesActorFromThreeComponentFilterWhenAComponentIsRemoved() filter.Contains(actor).Should().BeFalse(); } - [Fact(DisplayName = - "Добавляет актера в фильтр по трем компонентам, когда недостающий третий компонент (Speed) добавлен")] + [Fact( + DisplayName = + "Добавляет актера в фильтр по трем компонентам, когда недостающий третий компонент (Speed) добавлен")] public void AddsActorToThreeComponentFilterWhenThirdComponentIsAdded() { // arrange var attackComponent = fixture.CreateComponent(); var defenceComponent = fixture.CreateComponent(); - var actor = fixture.CreateActor(component1: attackComponent, component2: defenceComponent); + Actor actor = fixture.CreateActor(component1: attackComponent, component2: defenceComponent); - var filter = fixture + ActorFilter filter = fixture .Actors .Filter(); @@ -119,9 +124,9 @@ public void AddsActorToThreeComponentFilterWhenThirdComponentIsAdded() // assert filter.Contains(actor).Should().BeTrue(); - var actorRef = filter.GetRef(actor.Id); + ActorRef actorRef = filter.GetRef(actor.Id); actorRef.Component1.Should().Be(attackComponent); actorRef.Component2.Should().Be(defenceComponent); actorRef.Component3.Should().Be(speedComponent); } -} \ No newline at end of file +} diff --git a/tests/Hexecs.Tests/Actors/ActorListShould.cs b/tests/Hexecs.Tests/Actors/ActorListShould.cs index aa41a11..63f208c 100644 --- a/tests/Hexecs.Tests/Actors/ActorListShould.cs +++ b/tests/Hexecs.Tests/Actors/ActorListShould.cs @@ -83,6 +83,7 @@ public void Should_Enumerate_Added_Actors() // Act var resultIds = new List(); + foreach (ActorRef actor in list) { resultIds.Add(actor.Id); diff --git a/tests/Hexecs.Tests/Actors/ActorMarshalShould.cs b/tests/Hexecs.Tests/Actors/ActorMarshalShould.cs index 1505cdc..7131044 100644 --- a/tests/Hexecs.Tests/Actors/ActorMarshalShould.cs +++ b/tests/Hexecs.Tests/Actors/ActorMarshalShould.cs @@ -10,11 +10,11 @@ public void GetComponentId() { // arrange - var expectedId = ActorComponentType.Id; + ushort expectedId = ActorComponentType.Id; // act - var actualId = ActorMarshal.GetComponentId(); + ushort actualId = ActorMarshal.GetComponentId(); // assert @@ -28,11 +28,11 @@ public void GetComponentType() { // arrange - var id = ActorComponentType.Id; + ushort id = ActorComponentType.Id; // act - var actualType = ActorMarshal.GetComponentType(id); + Type actualType = ActorMarshal.GetComponentType(id); // assert @@ -47,12 +47,12 @@ public void GetComponentOwner() // arrange var component = fixture.CreateComponent(); - var actor = fixture.CreateActor(component1: component); - ref var componentRef = ref actor.Get(); + Actor actor = fixture.CreateActor(component1: component); + ref Attack componentRef = ref actor.Get(); // act - var actualActor = ActorMarshal.GetOwner(fixture.Actors, ref componentRef); + ActorRef actualActor = ActorMarshal.GetOwner(fixture.Actors, ref componentRef); // assert @@ -64,4 +64,4 @@ public void GetComponentOwner() .Should() .Be(component); } -} \ No newline at end of file +} diff --git a/tests/Hexecs.Tests/Actors/ActorMethodsConsistencyTests.cs b/tests/Hexecs.Tests/Actors/ActorMethodsConsistencyTests.cs index 2463f14..9491927 100644 --- a/tests/Hexecs.Tests/Actors/ActorMethodsConsistencyTests.cs +++ b/tests/Hexecs.Tests/Actors/ActorMethodsConsistencyTests.cs @@ -32,27 +32,28 @@ public class ActorMethodsConsistencyTests "GetHashCode" ]; - private static IEnumerable CommonMethodNames => - ReferenceType - .GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly) - .Select(m => m.Name) - .Where(name => !ExcludedMethods.Contains(name)) - .Distinct(); + private static IEnumerable CommonMethodNames => ReferenceType + .GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly) + .Select(m => m.Name) + .Where(name => !ExcludedMethods.Contains(name)) + .Distinct(); [Fact(DisplayName = "Все типы акторов должны иметь общие методы")] public void AllActorTypes_ShouldHaveCommonMethods() { - var expectedMethods = CommonMethodNames.ToList(); + List expectedMethods = CommonMethodNames.ToList(); - foreach (var type in ActorTypes.Where(t => t != ReferenceType)) + foreach (Type type in ActorTypes.Where(t => t != ReferenceType)) { - var methods = type.GetMethods(BindingFlags.Public | BindingFlags.Instance); - var methodNames = methods.Select(m => m.Name).Distinct().ToHashSet(); + MethodInfo[] methods = type.GetMethods(BindingFlags.Public | BindingFlags.Instance); + HashSet methodNames = methods.Select(m => m.Name).Distinct().ToHashSet(); - foreach (var expectedMethod in expectedMethods) + foreach (string expectedMethod in expectedMethods) { - methodNames.Should().Contain(expectedMethod, - because: $"тип {type.Name} должен содержать метод {expectedMethod} (как в {ReferenceType.Name})"); + methodNames.Should() + .Contain( + expectedMethod, + because: $"тип {type.Name} должен содержать метод {expectedMethod} (как в {ReferenceType.Name})"); } } } @@ -60,17 +61,19 @@ public void AllActorTypes_ShouldHaveCommonMethods() [Fact(DisplayName = "Все общие методы должны иметь одинаковые сигнатуры")] public void CommonMethods_ShouldHaveIdenticalSignatures() { - foreach (var methodName in CommonMethodNames) + foreach (string methodName in CommonMethodNames) { - var referenceMethods = GetMethodSignatures(ReferenceType, methodName); + List referenceMethods = GetMethodSignatures(ReferenceType, methodName); - foreach (var type in ActorTypes.Where(t => t != ReferenceType)) + foreach (Type type in ActorTypes.Where(t => t != ReferenceType)) { - var typeMethods = GetMethodSignatures(type, methodName); + List typeMethods = GetMethodSignatures(type, methodName); - typeMethods.Should().BeEquivalentTo(referenceMethods, - because: - $"метод {methodName} в {type.Name} должен иметь такую же сигнатуру как в {ReferenceType.Name}"); + typeMethods.Should() + .BeEquivalentTo( + referenceMethods, + because: + $"метод {methodName} в {type.Name} должен иметь такую же сигнатуру как в {ReferenceType.Name}"); } } } @@ -78,18 +81,20 @@ public void CommonMethods_ShouldHaveIdenticalSignatures() [Fact(DisplayName = "Все общие методы должны иметь AggressiveInlining-атрибут")] public void CommonMethods_ShouldHaveAggressiveInlining() { - foreach (var type in ActorTypes) + foreach (Type type in ActorTypes) { - var methods = type + IEnumerable methods = type .GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly) .Where(m => CommonMethodNames.Contains(m.Name)); - foreach (var method in methods) + foreach (MethodInfo method in methods) { - var implFlags = method.MethodImplementationFlags; + MethodImplAttributes implFlags = method.MethodImplementationFlags; - implFlags.Should().HaveFlag(MethodImplAttributes.AggressiveInlining, - because: $"метод {type.Name}.{method.Name} должен иметь атрибут AggressiveInlining"); + implFlags.Should() + .HaveFlag( + MethodImplAttributes.AggressiveInlining, + because: $"метод {type.Name}.{method.Name} должен иметь атрибут AggressiveInlining"); } } } @@ -106,9 +111,13 @@ private static List GetMethodSignatures(Type type, string metho private sealed class MethodSignature { public string Name { get; } + public string ReturnType { get; } + public string[] ParameterTypes { get; } + public string[] GenericConstraints { get; } + public int GenericArgumentCount { get; } public MethodSignature(MethodInfo method) @@ -129,34 +138,48 @@ public MethodSignature(MethodInfo method) private static string NormalizeTypeName(Type type) { if (type.IsGenericParameter) + { return "T"; + } if (type.IsGenericType) { - var baseName = type.GetGenericTypeDefinition().Name; - var args = string.Join(",", type.GetGenericArguments().Select(NormalizeTypeName)); + string baseName = type.GetGenericTypeDefinition().Name; + string args = string.Join(",", type.GetGenericArguments().Select(NormalizeTypeName)); + return $"{baseName}[{args}]"; } if (type.IsByRef) + { return $"ref {NormalizeTypeName(type.GetElementType()!)}"; + } return type.Name; } public override bool Equals(object? obj) { - if (obj is not MethodSignature other) return false; + if (obj is not MethodSignature other) + { + return false; + } + return Name == other.Name - && ReturnType == other.ReturnType - && GenericArgumentCount == other.GenericArgumentCount - && ParameterTypes.SequenceEqual(other.ParameterTypes) - && GenericConstraints.SequenceEqual(other.GenericConstraints); + && ReturnType == other.ReturnType + && GenericArgumentCount == other.GenericArgumentCount + && ParameterTypes.SequenceEqual(other.ParameterTypes) + && GenericConstraints.SequenceEqual(other.GenericConstraints); } - public override int GetHashCode() => HashCode.Combine(Name, ReturnType, GenericArgumentCount); + public override int GetHashCode() + { + return HashCode.Combine(Name, ReturnType, GenericArgumentCount); + } - public override string ToString() => - $"{ReturnType} {Name}<{GenericArgumentCount}>({string.Join(", ", ParameterTypes)})"; + public override string ToString() + { + return $"{ReturnType} {Name}<{GenericArgumentCount}>({string.Join(", ", ParameterTypes)})"; + } } -} \ No newline at end of file +} diff --git a/tests/Hexecs.Tests/Actors/ActorNodeShould.cs b/tests/Hexecs.Tests/Actors/ActorNodeShould.cs index 0db54d4..3e6d4ea 100644 --- a/tests/Hexecs.Tests/Actors/ActorNodeShould.cs +++ b/tests/Hexecs.Tests/Actors/ActorNodeShould.cs @@ -7,8 +7,8 @@ public void HasChild() { // Arrange - var expectedChild = fixture.CreateActor(); - var parent = fixture.CreateActor(); + Actor expectedChild = fixture.CreateActor(); + Actor parent = fixture.CreateActor(); // Act @@ -28,10 +28,10 @@ public void HasAllChild() { // Arrange - var expectedChild1 = fixture.CreateActor(); - var expectedChild3 = fixture.CreateActor(); - var expectedChild2 = fixture.CreateActor(); - var parent = fixture.CreateActor(); + Actor expectedChild1 = fixture.CreateActor(); + Actor expectedChild3 = fixture.CreateActor(); + Actor expectedChild2 = fixture.CreateActor(); + Actor parent = fixture.CreateActor(); // Act @@ -41,10 +41,11 @@ public void HasAllChild() // Assert - var children = parent.Children(); + ActorContext.ChildrenEnumerator children = parent.Children(); children .Length - .Should().Be(3); + .Should() + .Be(3); children .ToArray() @@ -57,8 +58,8 @@ public void HasParent() { // Arrange - var child = fixture.CreateActor(); - var expectedParent = fixture.CreateActor(); + Actor child = fixture.CreateActor(); + Actor expectedParent = fixture.CreateActor(); // Act @@ -67,7 +68,7 @@ public void HasParent() // Assert child - .TryGetParent(out var actualParent) + .TryGetParent(out Actor actualParent) .Should() .BeTrue(); @@ -81,8 +82,8 @@ public void RemoveChildAfterDestroyParent() { // Arrange - var child = fixture.CreateActor(); - var parent = fixture.CreateActor(); + Actor child = fixture.CreateActor(); + Actor parent = fixture.CreateActor(); parent.AddChild(child); @@ -93,7 +94,7 @@ public void RemoveChildAfterDestroyParent() // Assert child - .TryGetParent(out var actualParent) + .TryGetParent(out Actor actualParent) .Should() .BeFalse(); @@ -107,10 +108,10 @@ public void RemoveChildAfterDestroyChild() { // Arrange - var child1 = fixture.CreateActor(); - var child2 = fixture.CreateActor(); - var child3 = fixture.CreateActor(); - var parent = fixture.CreateActor(); + Actor child1 = fixture.CreateActor(); + Actor child2 = fixture.CreateActor(); + Actor child3 = fixture.CreateActor(); + Actor parent = fixture.CreateActor(); parent.AddChild(child1); parent.AddChild(child2); @@ -122,10 +123,11 @@ public void RemoveChildAfterDestroyChild() // Assert - var children = parent.Children(); + ActorContext.ChildrenEnumerator children = parent.Children(); children .Length - .Should().Be(2); + .Should() + .Be(2); children .ToArray() @@ -142,9 +144,9 @@ public void RemoveChildAfterDestroyChild() public void ChangeParentCorrectly() { // Arrange - var child = fixture.CreateActor(); - var parent1 = fixture.CreateActor(); - var parent2 = fixture.CreateActor(); + Actor child = fixture.CreateActor(); + Actor parent1 = fixture.CreateActor(); + Actor parent2 = fixture.CreateActor(); // Act parent1.AddChild(child); @@ -154,7 +156,7 @@ public void ChangeParentCorrectly() parent1.Children().Length.Should().Be(0); parent2.Children().Length.Should().Be(1); - child.TryGetParent(out var actualParent).Should().BeTrue(); + child.TryGetParent(out Actor actualParent).Should().BeTrue(); actualParent.Should().Be(parent2); } @@ -162,9 +164,9 @@ public void ChangeParentCorrectly() public void RemoveFirstChildCorrectly() { // Arrange - var parent = fixture.CreateActor(); - var child1 = fixture.CreateActor(); - var child2 = fixture.CreateActor(); + Actor parent = fixture.CreateActor(); + Actor child1 = fixture.CreateActor(); + Actor child2 = fixture.CreateActor(); parent.AddChild(child1); // child1 станет NextSibling для child2 parent.AddChild(child2); // child2 теперь FirstChildId @@ -180,10 +182,10 @@ public void RemoveFirstChildCorrectly() public void RemoveMiddleChildCorrectly() { // Arrange - var parent = fixture.CreateActor(); - var child1 = fixture.CreateActor(); - var child2 = fixture.CreateActor(); - var child3 = fixture.CreateActor(); + Actor parent = fixture.CreateActor(); + Actor child1 = fixture.CreateActor(); + Actor child2 = fixture.CreateActor(); + Actor child3 = fixture.CreateActor(); // Порядок в списке (LIFO): child3 -> child2 -> child1 parent.AddChild(child1); @@ -194,7 +196,7 @@ public void RemoveMiddleChildCorrectly() child2.Destroy(); // Удаляем средний // Assert - var children = parent.Children().ToArray(); + Actor[] children = parent.Children().ToArray(); children.Length.Should().Be(2); children[0].Should().Be(child3); children[1].Should().Be(child1); @@ -204,9 +206,9 @@ public void RemoveMiddleChildCorrectly() public void HasChildMethodWorks() { // Arrange - var parent = fixture.CreateActor(); - var child = fixture.CreateActor(); - var stranger = fixture.CreateActor(); + Actor parent = fixture.CreateActor(); + Actor child = fixture.CreateActor(); + Actor stranger = fixture.CreateActor(); // Act parent.AddChild(child); @@ -220,7 +222,7 @@ public void HasChildMethodWorks() public void ParentCannotAddItselfAsChild() { // Arrange - var actor = fixture.CreateActor(); + Actor actor = fixture.CreateActor(); // Act actor.AddChild(actor); @@ -229,4 +231,4 @@ public void ParentCannotAddItselfAsChild() actor.Children().Length.Should().Be(0); actor.TryGetParent(out _).Should().BeFalse(); } -} \ No newline at end of file +} diff --git a/tests/Hexecs.Tests/Actors/ActorRelationShould.cs b/tests/Hexecs.Tests/Actors/ActorRelationShould.cs index 30f3b4f..bf8437e 100644 --- a/tests/Hexecs.Tests/Actors/ActorRelationShould.cs +++ b/tests/Hexecs.Tests/Actors/ActorRelationShould.cs @@ -1,3 +1,4 @@ +using Hexecs.Actors.Relations; using Hexecs.Tests.Mocks; using Hexecs.Tests.Mocks.ActorComponents; @@ -10,8 +11,8 @@ public void CreateRelation() { // arrange - var actor1 = fixture.CreateActor(); - var actor2 = fixture.CreateActor(); + Actor actor1 = fixture.CreateActor(); + Actor actor2 = fixture.CreateActor(); // act @@ -37,20 +38,20 @@ public void EnumerateRelation() var expectedRelation = new RelationMock { Value = 123 }; - var actor1 = fixture.CreateActor(); - var actor2 = fixture.CreateActor(); + Actor actor1 = fixture.CreateActor(); + Actor actor2 = fixture.CreateActor(); actor1.AddRelation(actor2, in expectedRelation); // act - var relationEnumerator = actor1.Relations(); + ActorRelationEnumerator relationEnumerator = actor1.Relations(); // assert - foreach (var relation in relationEnumerator) + foreach (ActorRelation relation in relationEnumerator) { - var actualRelation = relation.Relation; + RelationMock actualRelation = relation.Relation; actualRelation .Should() .Be(expectedRelation); @@ -64,8 +65,8 @@ public void GetRelation() var expectedRelation = new RelationMock { Value = 123 }; - var actor1 = fixture.CreateActor(); - var actor2 = fixture.CreateActor(); + Actor actor1 = fixture.CreateActor(); + Actor actor2 = fixture.CreateActor(); actor1.AddRelation(actor2, in expectedRelation); @@ -85,8 +86,8 @@ public void RemoveRelation() { // arrange - var actor1 = fixture.CreateActor(); - var actor2 = fixture.CreateActor(); + Actor actor1 = fixture.CreateActor(); + Actor actor2 = fixture.CreateActor(); actor1.AddRelation(actor2, new RelationMock()); // act @@ -109,8 +110,8 @@ public void RemoveRelation() public void NotRemoveNonExistentRelation() { // arrange - var actor1 = fixture.CreateActor(); - var actor2 = fixture.CreateActor(); + Actor actor1 = fixture.CreateActor(); + Actor actor2 = fixture.CreateActor(); // act & assert actor1.Invoking(a => a.RemoveRelation(actor2)) @@ -122,8 +123,8 @@ public void NotRemoveNonExistentRelation() public void ReturnFalseForNonExistentRelation() { // arrange - var actor1 = fixture.CreateActor(); - var actor2 = fixture.CreateActor(); + Actor actor1 = fixture.CreateActor(); + Actor actor2 = fixture.CreateActor(); // act & assert actor1.HasRelation(actor2) @@ -135,10 +136,10 @@ public void ReturnFalseForNonExistentRelation() public void ReturnEmptyEnumeratorWhenNoRelations() { // arrange - var actor = fixture.CreateActor(); + Actor actor = fixture.CreateActor(); // act - var relations = actor.Relations(); + ActorRelationEnumerator relations = actor.Relations(); // assert relations.Length.Should().Be(0); @@ -148,15 +149,15 @@ public void ReturnEmptyEnumeratorWhenNoRelations() public void OverwriteExistingRelation() { // arrange - var actor1 = fixture.CreateActor(); - var actor2 = fixture.CreateActor(); + Actor actor1 = fixture.CreateActor(); + Actor actor2 = fixture.CreateActor(); var initialRelation = new RelationMock { Value = 100 }; var newRelation = new RelationMock { Value = 200 }; actor1.AddRelation(actor2, in initialRelation); // act - ref var existsRelation = ref actor1.GetRelation(actor2); + ref RelationMock existsRelation = ref actor1.GetRelation(actor2); existsRelation = newRelation; // assert @@ -168,9 +169,9 @@ public void OverwriteExistingRelation() public void SupportMultipleRelationsWithDifferentActors() { // arrange - var actor1 = fixture.CreateActor(); - var actor2 = fixture.CreateActor(); - var actor3 = fixture.CreateActor(); + Actor actor1 = fixture.CreateActor(); + Actor actor2 = fixture.CreateActor(); + Actor actor3 = fixture.CreateActor(); var relation12 = new RelationMock { Value = 100 }; var relation13 = new RelationMock { Value = 200 }; @@ -188,8 +189,8 @@ public void SupportMultipleRelationsWithDifferentActors() public void ThrowWhenAddingExistingRelation() { // arrange - var actor1 = fixture.CreateActor(); - var actor2 = fixture.CreateActor(); + Actor actor1 = fixture.CreateActor(); + Actor actor2 = fixture.CreateActor(); var relation = new RelationMock { Value = 100 }; actor1.AddRelation(actor2, in relation); @@ -204,8 +205,8 @@ public void ThrowWhenAddingExistingRelation() public void ThrowWhenGettingNonExistentRelation() { // arrange - var actor1 = fixture.CreateActor(); - var actor2 = fixture.CreateActor(); + Actor actor1 = fixture.CreateActor(); + Actor actor2 = fixture.CreateActor(); // act & assert actor1.Invoking(a => a.GetRelation(actor2)) diff --git a/tests/Hexecs.Tests/Actors/ActorShould.cs b/tests/Hexecs.Tests/Actors/ActorShould.cs index dd69d7f..901132a 100644 --- a/tests/Hexecs.Tests/Actors/ActorShould.cs +++ b/tests/Hexecs.Tests/Actors/ActorShould.cs @@ -1,4 +1,6 @@ using System.Runtime.CompilerServices; + +using Hexecs.Assets; using Hexecs.Tests.Mocks; using Hexecs.Tests.Mocks.ActorComponents; using Hexecs.Tests.Mocks.Assets; @@ -12,7 +14,7 @@ public void AddComponent() { // arrange - var actor = fixture.CreateActor(); + Actor actor = fixture.CreateActor(); var component = fixture.CreateComponent(); // act @@ -36,8 +38,8 @@ public void AddComponent() public void AddChildActor() { // arrange - var parent = fixture.CreateActor(); - var child = fixture.CreateActor(); + Actor parent = fixture.CreateActor(); + Actor child = fixture.CreateActor(); // act parent.AddChild(child); @@ -53,8 +55,8 @@ public void AddChildActor() public void AddRelationBetweenActors() { // arrange - var actor1 = fixture.CreateActor(); - var actor2 = fixture.CreateActor(); + Actor actor1 = fixture.CreateActor(); + Actor actor2 = fixture.CreateActor(); var relation = new RelationMock { Value = 42 }; // act @@ -77,13 +79,13 @@ public void AsActor1() { // arrange - var actor = fixture.CreateActor(); + Actor actor = fixture.CreateActor(); var component = fixture.CreateComponent(); actor.Add(component); // act - var actor1 = actor.AsRef(); + ActorRef actor1 = actor.AsRef(); // assert @@ -98,7 +100,7 @@ public void BeAlive() { // arrange - var actor = fixture.CreateActor(); + Actor actor = fixture.CreateActor(); // act, assert @@ -115,12 +117,12 @@ public void BeClone() var attack = fixture.CreateComponent(); var defence = fixture.CreateComponent(); - var actor = fixture.CreateActor(component1: attack, component2: defence); - var context = fixture.Actors; + Actor actor = fixture.CreateActor(component1: attack, component2: defence); + ActorContext context = fixture.Actors; // act - var clone = context.Clone(actor.Id); + Actor clone = context.Clone(actor.Id); // assert @@ -138,12 +140,12 @@ public void BeIs() { // arrange - var expected = fixture.CreateActor(); + Actor expected = fixture.CreateActor(); // act expected - .IsRef(out var actual) + .IsRef(out ActorRef actual) .Should() .BeTrue(); @@ -169,8 +171,8 @@ public void CheckEmptyActor() public void CheckRelationExistsBetweenActors() { // arrange - var actor1 = fixture.CreateActor(); - var actor2 = fixture.CreateActor(); + Actor actor1 = fixture.CreateActor(); + Actor actor2 = fixture.CreateActor(); var relation = new RelationMock { Value = 42 }; actor1.AddRelation(actor2, relation); @@ -185,7 +187,7 @@ public void CheckMultipleComponentsExistence() // arrange var attack = fixture.CreateComponent(); var defence = fixture.CreateComponent(); - var actor = fixture.CreateActor(component1: attack, component2: defence); + Actor actor = fixture.CreateActor(component1: attack, component2: defence); // act, assert actor @@ -203,10 +205,10 @@ public void CheckMultipleComponentsExistence() public void CheckActorDoesNotExistViaIsRef() { // arrange - var actor = fixture.CreateActor(); + Actor actor = fixture.CreateActor(); // act - var result = actor.IsRef(out var actorRef); + bool result = actor.IsRef(out ActorRef actorRef); // assert result.Should().BeFalse(); @@ -221,10 +223,10 @@ public void ConvertToActorRef() { // arrange var component = fixture.CreateComponent(); - var actor = fixture.CreateActor(component1: component); + Actor actor = fixture.CreateActor(component1: component); // act - var actorRef = actor.AsRef(); + ActorRef actorRef = actor.AsRef(); // assert actorRef.Component1.Should().Be(component); @@ -235,7 +237,7 @@ public void DoesntHaveNotExistsComponent() { // arrange - var actor = fixture.CreateActor(); + Actor actor = fixture.CreateActor(); // act, assert @@ -250,11 +252,11 @@ public void DoesntThrowIfTryGetDoesNotExistComponent() { // arrange - var actor = fixture.CreateActor(); + Actor actor = fixture.CreateActor(); // act - ref var componentRef = ref actor.TryGetRef(); + ref Attack componentRef = ref actor.TryGetRef(); // assert @@ -268,9 +270,9 @@ public void DoesntThrowIfTryGetDoesNotExistComponent() public void Equality() { // arrange - var actor1 = fixture.CreateActor(); - var actor2 = actor1; - var actor3 = fixture.CreateActor(); // Актор с другим ID + Actor actor1 = fixture.CreateActor(); + Actor actor2 = actor1; + Actor actor3 = fixture.CreateActor(); // Актор с другим ID // act, assert actor1.Equals(actor1).Should().BeTrue(); // Сам с собой @@ -285,11 +287,11 @@ public void GetBoundAsset() { // arrange - var asset = fixture.Assets.GetAssetRef(); - var actor = fixture.Actors.BuildActor(asset); + AssetRef asset = fixture.Assets.GetAssetRef(); + Actor actor = fixture.Actors.BuildActor(asset); // act - var retrievedAsset = actor.GetAsset(); + Asset retrievedAsset = actor.GetAsset(); // assert retrievedAsset @@ -304,10 +306,10 @@ public void GetComponentRef() { // arrange var attack = fixture.CreateComponent(); - var actor = fixture.CreateActor(component1: attack); + Actor actor = fixture.CreateActor(component1: attack); // act - ref var componentRef = ref actor.Get(); + ref Attack componentRef = ref actor.Get(); // assert Unsafe @@ -320,12 +322,12 @@ public void GetComponentRef() public void GetParentActor() { // arrange - var parent = fixture.CreateActor(); - var child = fixture.CreateActor(); + Actor parent = fixture.CreateActor(); + Actor child = fixture.CreateActor(); parent.AddChild(child); // act - var hasParent = child.TryGetParent(out var retrievedParent); + bool hasParent = child.TryGetParent(out Actor retrievedParent); // assert hasParent.Should().BeTrue(); @@ -336,13 +338,13 @@ public void GetParentActor() public void GetRelationBetweenActors() { // arrange - var actor1 = fixture.CreateActor(); - var actor2 = fixture.CreateActor(); + Actor actor1 = fixture.CreateActor(); + Actor actor2 = fixture.CreateActor(); var relation = new RelationMock { Value = 42 }; actor1.AddRelation(actor2, relation); // act - ref var retrievedRelation = ref actor1.GetRelation(actor2); + ref RelationMock retrievedRelation = ref actor1.GetRelation(actor2); // assert retrievedRelation.Should().Be(relation); @@ -352,7 +354,7 @@ public void GetRelationBetweenActors() public void ImplicitCastToBool() { // arrange - var actor = fixture.CreateActor(); + Actor actor = fixture.CreateActor(); var emptyActor = Actor.Empty; // act, assert @@ -364,7 +366,7 @@ public void ImplicitCastToBool() public void ImplicitCastToActorId() { // arrange - var actor = fixture.CreateActor(); + Actor actor = fixture.CreateActor(); // act ActorId actorId = actor; @@ -379,13 +381,13 @@ public void ImplicitCastToActorId() public void RemoveRelationBetweenActors() { // arrange - var actor1 = fixture.CreateActor(); - var actor2 = fixture.CreateActor(); + Actor actor1 = fixture.CreateActor(); + Actor actor2 = fixture.CreateActor(); var relation = new RelationMock { Value = 42 }; actor1.AddRelation(actor2, relation); // act - var result = actor1.RemoveRelation(actor2, out var removedRelation); + bool result = actor1.RemoveRelation(actor2, out RelationMock removedRelation); // assert result.Should().BeTrue(); @@ -398,7 +400,7 @@ public void NotBeAlive() { // arrange - var actor = fixture.CreateActor(); + Actor actor = fixture.CreateActor(); // act @@ -417,12 +419,12 @@ public void NotBeIs() { // arrange - var expected = fixture.CreateActor(); + Actor expected = fixture.CreateActor(); // act expected - .IsRef(out var actual) + .IsRef(out ActorRef actual) .Should() .BeFalse(); @@ -438,10 +440,10 @@ public void NotBeIs() public void NotRemoveNonExistingComponent() { // arrange - var actor = fixture.CreateActor(); + Actor actor = fixture.CreateActor(); // act - var result = actor.Remove(out var removed); + bool result = actor.Remove(out Defence removed); // assert result @@ -457,10 +459,10 @@ public void NotRemoveNonExistingComponent() public void NotTryGetNonExistingComponent() { // arrange - var actor = fixture.CreateActor(); + Actor actor = fixture.CreateActor(); // act - ref var result = ref actor.TryGetRef(); + ref Defence result = ref actor.TryGetRef(); // assert Unsafe @@ -475,12 +477,12 @@ public void RemoveComponent() // arrange var component = fixture.CreateComponent(); - var actor = fixture.CreateActor(component1: component); + Actor actor = fixture.CreateActor(component1: component); // act actor - .Remove(out var removed) + .Remove(out Attack removed) .Should() .BeTrue(); @@ -500,12 +502,12 @@ public void RemoveComponent() public void RemoveChildActor() { // arrange - var parent = fixture.CreateActor(); - var child = fixture.CreateActor(); + Actor parent = fixture.CreateActor(); + Actor child = fixture.CreateActor(); parent.AddChild(child); // act - var result = parent.RemoveChild(child); + bool result = parent.RemoveChild(child); // assert result.Should().BeTrue(); @@ -521,7 +523,7 @@ public void ThrowIfGetDoesNotExistComponent() { // arrange - var actor = fixture.CreateActor(); + Actor actor = fixture.CreateActor(); // act, assert @@ -536,7 +538,7 @@ public void ThrowIfAddingComponentExists() { // arrange - var actor = fixture.CreateActor(); + Actor actor = fixture.CreateActor(); // act, assert @@ -550,11 +552,11 @@ public void ThrowIfAddingComponentExists() public void TryAddComponent() { // arrange - var actor = fixture.CreateActor(); + Actor actor = fixture.CreateActor(); var component = fixture.CreateComponent(); // act - var result = actor.TryAdd(component); + bool result = actor.TryAdd(component); // assert result.Should().BeTrue(); @@ -567,11 +569,11 @@ public void TryGetBoundAsset() { // arrange - var asset = fixture.Assets.GetAssetRef(); - var actor = fixture.Actors.BuildActor(asset); + AssetRef asset = fixture.Assets.GetAssetRef(); + Actor actor = fixture.Actors.BuildActor(asset); // act - var result = actor.TryGetAsset(out var actualAsset); + bool result = actor.TryGetAsset(out Asset actualAsset); // assert @@ -591,7 +593,7 @@ public void TryGetExistingComponent() { // arrange var attack = fixture.CreateComponent(); - var actor = fixture.CreateActor(component1: attack); + Actor actor = fixture.CreateActor(component1: attack); // act var result = actor.TryGetRef(); @@ -607,11 +609,11 @@ public void UpdateActorComponent() { // arrange var initialComponent = fixture.CreateComponent(); - var actor = fixture.CreateActor(component1: initialComponent); + Actor actor = fixture.CreateActor(component1: initialComponent); var updatedComponent = fixture.CreateComponent(); // act - var result = actor.Update(updatedComponent); + bool result = actor.Update(updatedComponent); // assert result.Should().BeTrue(); diff --git a/tests/Hexecs.Tests/Actors/ActorSystemShould1.cs b/tests/Hexecs.Tests/Actors/ActorSystemShould1.cs index 6f1b7df..35eee6f 100644 --- a/tests/Hexecs.Tests/Actors/ActorSystemShould1.cs +++ b/tests/Hexecs.Tests/Actors/ActorSystemShould1.cs @@ -11,9 +11,9 @@ public sealed class ActorSystemShould1(ActorTestFixture fixture) : IClassFixture [Fact(DisplayName = "Параллельные системы должны быть вызваны параллельно")] public void ConfigureAndRunSystemsInParallel() { - var systems = fixture.CreateArray(_ => new Mock()); + Mock[] systems = fixture.CreateArray(_ => new Mock()); - using var world = new WorldBuilder() + using World world = new WorldBuilder() .UseDefaultParallelWorker(degreeOfParallelism: 4) .UseDefaultActorContext(cfg => cfg .CreateParallelUpdateSystem(systems.Select(mock => mock.Object))) @@ -39,7 +39,7 @@ public void UpdateActorsInParallel(int degreeOfParallelism, int actorCount) { // arrange - using var world = new WorldBuilder() + using World world = new WorldBuilder() .UseDefaultParallelWorker(degreeOfParallelism) .UseDefaultActorContext(cfg => cfg .CreateUpdateSystem(ctx => new ParallelUpdateSystem( @@ -47,10 +47,10 @@ public void UpdateActorsInParallel(int degreeOfParallelism, int actorCount) ctx.GetRequiredService()))) .Build(); - var actorContext = world.Actors; + ActorContext actorContext = world.Actors; for (uint i = 1; i <= actorCount; i++) { - var actor = actorContext.CreateActor(i); + Actor actor = actorContext.CreateActor(i); actor.Add(new Attack { Value = 0 }); } @@ -61,13 +61,13 @@ public void UpdateActorsInParallel(int degreeOfParallelism, int actorCount) // assert - var actorFilter = actorContext.Filter(); + ActorFilter actorFilter = actorContext.Filter(); actorFilter.Length .Should() .Be(actorCount); - foreach (var actor in actorFilter) + foreach (ActorRef actor in actorFilter) { actor.Component1.Value .Should() diff --git a/tests/Hexecs.Tests/Actors/ActorSystemShould2.cs b/tests/Hexecs.Tests/Actors/ActorSystemShould2.cs index 9cba2c3..5b3f6c6 100644 --- a/tests/Hexecs.Tests/Actors/ActorSystemShould2.cs +++ b/tests/Hexecs.Tests/Actors/ActorSystemShould2.cs @@ -11,9 +11,9 @@ public sealed class ActorSystemShould2(ActorTestFixture fixture) : IClassFixture [Fact(DisplayName = "Параллельные системы должны быть вызваны параллельно")] public void ConfigureAndRunSystemsInParallel() { - var systems = fixture.CreateArray(_ => new Mock()); + Mock[] systems = fixture.CreateArray(_ => new Mock()); - using var world = new WorldBuilder() + using World world = new WorldBuilder() .UseDefaultParallelWorker(degreeOfParallelism: 4) .UseDefaultActorContext(cfg => cfg .CreateParallelUpdateSystem(systems.Select(mock => mock.Object))) @@ -39,7 +39,7 @@ public void UpdateActorsInParallel(int degreeOfParallelism, int actorCount) { // arrange - using var world = new WorldBuilder() + using World world = new WorldBuilder() .UseDefaultParallelWorker(degreeOfParallelism) .UseDefaultActorContext(cfg => cfg .CreateUpdateSystem(ctx => new ParallelUpdateSystem( @@ -47,10 +47,10 @@ public void UpdateActorsInParallel(int degreeOfParallelism, int actorCount) ctx.GetRequiredService()))) .Build(); - var actorContext = world.Actors; + ActorContext actorContext = world.Actors; for (uint i = 1; i <= actorCount; i++) { - var actor = actorContext.CreateActor(i); + Actor actor = actorContext.CreateActor(i); actor.Add(new Attack { Value = 0 }); actor.Add(new Defence { Value = 0 }); } @@ -62,13 +62,13 @@ public void UpdateActorsInParallel(int degreeOfParallelism, int actorCount) // assert - var actorFilter = actorContext.Filter(); + ActorFilter actorFilter = actorContext.Filter(); actorFilter.Length .Should() .Be(actorCount); - foreach (var actor in actorFilter) + foreach (ActorRef actor in actorFilter) { actor.Component1.Value .Should() diff --git a/tests/Hexecs.Tests/Actors/ActorSystemShould3.cs b/tests/Hexecs.Tests/Actors/ActorSystemShould3.cs index 8d944cf..08bb489 100644 --- a/tests/Hexecs.Tests/Actors/ActorSystemShould3.cs +++ b/tests/Hexecs.Tests/Actors/ActorSystemShould3.cs @@ -11,9 +11,9 @@ public sealed class ActorSystemShould3(ActorTestFixture fixture) : IClassFixture [Fact(DisplayName = "Параллельные системы должны быть вызваны параллельно")] public void ConfigureAndRunSystemsInParallel() { - var systems = fixture.CreateArray(_ => new Mock()); + Mock[] systems = fixture.CreateArray(_ => new Mock()); - using var world = new WorldBuilder() + using World world = new WorldBuilder() .UseDefaultParallelWorker(degreeOfParallelism: 4) .UseDefaultActorContext(cfg => cfg .CreateParallelUpdateSystem(systems.Select(mock => mock.Object))) @@ -39,7 +39,7 @@ public void UpdateActorsInParallel(int degreeOfParallelism, int actorCount) { // arrange - using var world = new WorldBuilder() + using World world = new WorldBuilder() .UseDefaultParallelWorker(degreeOfParallelism) .UseDefaultActorContext(cfg => cfg .CreateUpdateSystem(ctx => new ParallelUpdateSystem( @@ -47,10 +47,10 @@ public void UpdateActorsInParallel(int degreeOfParallelism, int actorCount) ctx.GetRequiredService()))) .Build(); - var actorContext = world.Actors; + ActorContext actorContext = world.Actors; for (uint i = 1; i <= actorCount; i++) { - var actor = actorContext.CreateActor(i); + Actor actor = actorContext.CreateActor(i); actor.Add(new Attack { Value = 0 }); actor.Add(new Defence { Value = 0 }); actor.Add(new Speed { Value = 0 }); @@ -63,13 +63,13 @@ public void UpdateActorsInParallel(int degreeOfParallelism, int actorCount) // assert - var actorFilter = actorContext.Filter(); + ActorFilter actorFilter = actorContext.Filter(); actorFilter.Length .Should() .Be(actorCount); - foreach (var actor in actorFilter) + foreach (ActorRef actor in actorFilter) { actor.Component1.Value .Should() diff --git a/tests/Hexecs.Tests/Actors/ActorTestFixture.cs b/tests/Hexecs.Tests/Actors/ActorTestFixture.cs index b3a649d..1af476a 100644 --- a/tests/Hexecs.Tests/Actors/ActorTestFixture.cs +++ b/tests/Hexecs.Tests/Actors/ActorTestFixture.cs @@ -9,7 +9,9 @@ namespace Hexecs.Tests.Actors; public sealed class ActorTestFixture : BaseFixture, IDisposable { public ActorContext Actors => World.Actors; + public AssetContext Assets => World.Assets; + public readonly World World; public ActorTestFixture() @@ -25,14 +27,15 @@ public ActorTestFixture() public Actor CreateActor(uint? id = null) { - var actor = Actors.CreateActor(id); + Actor actor = Actors.CreateActor(id); + return actor; } public Actor CreateActor(uint? id = null, T1? component1 = null) where T1 : struct, IActorComponent { - var actor = Actors.CreateActor(id); + Actor actor = Actors.CreateActor(id); actor.Add(component1 ?? CreateComponent()); return actor; @@ -42,20 +45,23 @@ public Actor CreateActor(uint? id = null, T1? component1 = null, T2? com where T1 : struct, IActorComponent where T2 : struct, IActorComponent { - var actor = Actors.CreateActor(id); + Actor actor = Actors.CreateActor(id); actor.Add(component1 ?? CreateComponent()); actor.Add(component2 ?? CreateComponent()); return actor; } - public Actor CreateActor(uint? id = null, T1? component1 = null, T2? component2 = null, + public Actor CreateActor( + uint? id = null, + T1? component1 = null, + T2? component2 = null, T3? component3 = null) where T1 : struct, IActorComponent where T2 : struct, IActorComponent where T3 : struct, IActorComponent { - var actor = Actors.CreateActor(id); + Actor actor = Actors.CreateActor(id); actor.Add(component1 ?? CreateComponent()); actor.Add(component2 ?? CreateComponent()); actor.Add(component3 ?? CreateComponent()); @@ -68,12 +74,16 @@ public Actor[] CreateActors(int? length = null) { length ??= RandomInt(10, 100); - if (length is 0) return []; + if (length is 0) + { + return []; + } var actors = new Actor[length.Value]; + for (var i = 0; i < actors.Length; i++) { - var actor = Actors.CreateActor(); + Actor actor = Actors.CreateActor(); actor.Add(CreateComponent()); } @@ -86,12 +96,16 @@ public Actor[] CreateActors(int? length = null) { length ??= RandomInt(10, 100); - if (length is 0) return []; + if (length is 0) + { + return []; + } var actors = new Actor[length.Value]; + for (var i = 0; i < actors.Length; i++) { - var actor = Actors.CreateActor(); + Actor actor = Actors.CreateActor(); actor.Add(CreateComponent()); actor.Add(CreateComponent()); @@ -108,12 +122,16 @@ public Actor[] CreateActors(int? length = null) { length ??= RandomInt(10, 100); - if (length is 0) return []; + if (length is 0) + { + return []; + } var actors = new Actor[length.Value]; + for (var i = 0; i < actors.Length; i++) { - var actor = Actors.CreateActor(); + Actor actor = Actors.CreateActor(); actor.Add(CreateComponent()); actor.Add(CreateComponent()); actor.Add(CreateComponent()); @@ -128,10 +146,25 @@ public T CreateComponent() where T : struct, IActorComponent { object? result = null; - if (typeof(T) == typeof(Attack)) result = new Attack { Value = RandomInt() }; - if (typeof(T) == typeof(Defence)) result = new Defence { Value = RandomInt() }; - if (typeof(T) == typeof(Description)) result = new Description { Name = RandomString(10) }; - if (typeof(T) == typeof(Speed)) result = new Speed { Value = RandomInt() }; + if (typeof(T) == typeof(Attack)) + { + result = new Attack { Value = RandomInt() }; + } + + if (typeof(T) == typeof(Defence)) + { + result = new Defence { Value = RandomInt() }; + } + + if (typeof(T) == typeof(Description)) + { + result = new Description { Name = RandomString(10) }; + } + + if (typeof(T) == typeof(Speed)) + { + result = new Speed { Value = RandomInt() }; + } return result == null ? throw new NotSupportedException() @@ -140,10 +173,10 @@ public T CreateComponent() where T : struct, IActorComponent private void CreateAssets(IAssetLoader loader) { - var unit1 = loader.CreateAsset(UnitAsset.Alias1); + AssetConfigurator unit1 = loader.CreateAsset(UnitAsset.Alias1); unit1.Set(new UnitAsset(RandomInt(1, 10), RandomInt(11, 20))); - var unit2 = loader.CreateAsset(UnitAsset.Alias2); + AssetConfigurator unit2 = loader.CreateAsset(UnitAsset.Alias2); unit2.Set(new UnitAsset(RandomInt(1, 10), RandomInt(11, 20))); } @@ -151,4 +184,4 @@ public void Dispose() { World.Dispose(); } -} \ No newline at end of file +} diff --git a/tests/Hexecs.Tests/Assets/AssetTestFixture.cs b/tests/Hexecs.Tests/Assets/AssetTestFixture.cs index d674119..f6e4eef 100644 --- a/tests/Hexecs.Tests/Assets/AssetTestFixture.cs +++ b/tests/Hexecs.Tests/Assets/AssetTestFixture.cs @@ -37,6 +37,7 @@ public Asset CreateAsset() where T : struct, IAssetComponent .Build(); _assets = _world.Assets; + return Assets.GetAsset(assetId); } @@ -45,18 +46,19 @@ public Asset CreateAsset() where T2 : struct, IAssetComponent { var assetId = AssetId.Empty; - + _world = new WorldBuilder() .CreateAssetData(CreateAssets) .CreateAssetData(loader => { - var asset = loader.CreateAsset(CreateComponent()); + AssetConfigurator asset = loader.CreateAsset(CreateComponent()); asset.Set(CreateComponent()); assetId = asset.Id; }) .Build(); _assets = _world.Assets; + return Assets.GetAssetRef(assetId); } @@ -65,7 +67,10 @@ public AssetContext CreateAssetContext(Action? assets = null) var worldBuilder = new WorldBuilder(); worldBuilder.CreateAssetData(CreateAssets); - if (assets != null) worldBuilder.CreateAssetData(assets); + if (assets != null) + { + worldBuilder.CreateAssetData(assets); + } _world = worldBuilder.Build(); _assets = _world.Assets; @@ -77,8 +82,15 @@ public T CreateComponent() where T : struct, IAssetComponent { object? result = null; - if (typeof(T) == typeof(CarAsset)) result = new CarAsset(RandomInt(1, 10), RandomInt(11, 20)); - if (typeof(T) == typeof(UnitAsset)) result = new UnitAsset(RandomInt(1, 10), RandomInt(11, 20)); + if (typeof(T) == typeof(CarAsset)) + { + result = new CarAsset(RandomInt(1, 10), RandomInt(11, 20)); + } + + if (typeof(T) == typeof(UnitAsset)) + { + result = new UnitAsset(RandomInt(1, 10), RandomInt(11, 20)); + } return result == null ? throw new NotSupportedException() @@ -87,10 +99,10 @@ public T CreateComponent() where T : struct, IAssetComponent private void CreateAssets(IAssetLoader loader) { - var unit1 = loader.CreateAsset(UnitAsset.Alias1); + AssetConfigurator unit1 = loader.CreateAsset(UnitAsset.Alias1); unit1.Set(new UnitAsset(RandomInt(1, 10), RandomInt(11, 20))); - var unit2 = loader.CreateAsset(UnitAsset.Alias2); + AssetConfigurator unit2 = loader.CreateAsset(UnitAsset.Alias2); unit2.Set(new UnitAsset(RandomInt(1, 10), RandomInt(11, 20))); } @@ -99,4 +111,4 @@ public void Dispose() _assets?.Dispose(); _world?.Dispose(); } -} \ No newline at end of file +} diff --git a/tests/Hexecs.Tests/BaseFixture.cs b/tests/Hexecs.Tests/BaseFixture.cs index 8fec68e..8b5d4fb 100644 --- a/tests/Hexecs.Tests/BaseFixture.cs +++ b/tests/Hexecs.Tests/BaseFixture.cs @@ -1,4 +1,5 @@ using AutoFixture; + using Hexecs.Utils; namespace Hexecs.Tests; @@ -7,26 +8,41 @@ public abstract class BaseFixture { public Fixture Fixture => field ??= new Fixture(); - public readonly Random Random = new(); + public readonly Random Random = new Random(); + + public T[] CreateArray(Func factory) + { + return Enumerable + .Range(0, RandomInt(10, 100)) + .Select(factory) + .ToArray(); + } - public T[] CreateArray(Func factory) => Enumerable - .Range(0, RandomInt(10, 100)) - .Select(factory) - .ToArray(); + public T[] CreateArray(int length, Func factory) + { + return Enumerable + .Range(0, length) + .Select(factory) + .ToArray(); + } - public T[] CreateArray(int length, Func factory) => Enumerable - .Range(0, length) - .Select(factory) - .ToArray(); + public int RandomInt() + { + return Random.Next(); + } - public int RandomInt() => Random.Next(); + public int RandomInt(int from, int to) + { + return Random.Next(from, to); + } - public int RandomInt(int from, int to) => Random.Next(from, to); + public string RandomString(int length = 12) + { + return StringUtils.GetRandom(length); + } - public string RandomString(int length = 12) => StringUtils.GetRandom(length); - public int RandomPositiveInt(uint minValue = 0, uint maxValue = int.MaxValue) { return Random.Next((int)minValue, (int)maxValue); } -} \ No newline at end of file +} diff --git a/tests/Hexecs.Tests/Collections/InlineBucketShould.cs b/tests/Hexecs.Tests/Collections/InlineBucketShould.cs index 007c8e3..b372417 100644 --- a/tests/Hexecs.Tests/Collections/InlineBucketShould.cs +++ b/tests/Hexecs.Tests/Collections/InlineBucketShould.cs @@ -41,9 +41,11 @@ public void Add_MoreItemsThanInlineArraySize_ShouldWorkCorrectly() { // Arrange var bucket = new InlineBucket(); - int[] items = Enumerable - .Range(0, InlineBucket.InlineArraySize + 1) - .ToArray(); + int[] items = + [ + .. Enumerable + .Range(0, InlineBucket.InlineArraySize + 1) + ]; // Act foreach (int item in items) @@ -440,7 +442,7 @@ public void ToArray_ShouldReturnArrayWithAllItems() int[] array = bucket.ToArray(); // Assert - array.Should().BeEquivalentTo(new[] { 10, 20, 30 }); + array.Should().BeEquivalentTo([10, 20, 30]); } [Fact(DisplayName = "ToArray должен возвращать пустой массив для пустой коллекции")] diff --git a/tests/Hexecs.Tests/Configurations/ConfigurationserviceShould.cs b/tests/Hexecs.Tests/Configurations/ConfigurationserviceShould.cs index cc272ff..70493f2 100644 --- a/tests/Hexecs.Tests/Configurations/ConfigurationserviceShould.cs +++ b/tests/Hexecs.Tests/Configurations/ConfigurationserviceShould.cs @@ -15,7 +15,7 @@ public void GetValue_ShouldReturnValueFromSource() mockSource.Setup(s => s.TryGetValue(It.Is(k => k == "test-key"), out outValue!)) .Returns(true); - IConfigurationSource[] sources = new[] { mockSource.Object }; + IConfigurationSource[] sources = [mockSource.Object]; var values = new ConcurrentDictionary(); var service = new ConfigurationService(sources, values); @@ -35,7 +35,7 @@ public void GetValue_ShouldCacheValueAfterFirstAccess() mockSource.Setup(s => s.TryGetValue(It.Is(k => k == "test-key"), out outValue!)) .Returns(true); - IConfigurationSource[] sources = new[] { mockSource.Object }; + IConfigurationSource[] sources = [mockSource.Object]; var values = new ConcurrentDictionary(); var service = new ConfigurationService(sources, values); @@ -58,7 +58,7 @@ public void GetValue_ShouldReturnNull_WhenValueNotFound() mockSource.Setup(s => s.TryGetValue(It.IsAny(), out outValue)) .Returns(false); - IConfigurationSource[] sources = new[] { mockSource.Object }; + IConfigurationSource[] sources = [mockSource.Object]; var values = new ConcurrentDictionary(); var service = new ConfigurationService(sources, values); @@ -85,7 +85,7 @@ public void GetValue_ShouldCheckAllSourcesInOrder() .Setup(s => s.TryGetValue(It.Is(k => k == "test-key"), out outValue2!)) .Returns(true); - IConfigurationSource[] sources = new[] { mockSource1.Object, mockSource2.Object }; + IConfigurationSource[] sources = [mockSource1.Object, mockSource2.Object]; var values = new ConcurrentDictionary(); var service = new ConfigurationService(sources, values); @@ -107,7 +107,7 @@ public void GetRequiredValue_ShouldReturnValue_WhenFound() mockSource.Setup(s => s.TryGetValue(It.Is(k => k == "test-key"), out outValue)) .Returns(true); - IConfigurationSource[] sources = new[] { mockSource.Object }; + IConfigurationSource[] sources = [mockSource.Object]; var values = new ConcurrentDictionary(); var service = new ConfigurationService(sources, values); @@ -127,7 +127,7 @@ public void GetRequiredValue_ShouldThrowException_WhenValueNotFound() mockSource.Setup(s => s.TryGetValue(It.IsAny(), out outValue)) .Returns(false); - IConfigurationSource[] sources = new[] { mockSource.Object }; + IConfigurationSource[] sources = [mockSource.Object]; var values = new ConcurrentDictionary(); var service = new ConfigurationService(sources, values); diff --git a/tests/Hexecs.Tests/Dependencies/DependencyShould.cs b/tests/Hexecs.Tests/Dependencies/DependencyShould.cs index b675ebe..714c6c0 100644 --- a/tests/Hexecs.Tests/Dependencies/DependencyShould.cs +++ b/tests/Hexecs.Tests/Dependencies/DependencyShould.cs @@ -8,13 +8,13 @@ public class DependencyTests public void Resolve_WithInstance_ReturnsInstance() { // Arrange - var contract = typeof(string); + Type contract = typeof(string); var lifetime = DependencyLifetime.Transient; var instance = "Test Instance"; var dependency = new Dependency(lifetime, contract, instance); // Act - var resolvedInstance = dependency.Resolve(Mock.Of()); + object resolvedInstance = dependency.Resolve(Mock.Of()); // Assert resolvedInstance.Should().BeSameAs(instance); @@ -24,7 +24,7 @@ public void Resolve_WithInstance_ReturnsInstance() public void Resolve_WithResolver_ReturnsResolvedInstance() { // Arrange - var contract = typeof(string); + Type contract = typeof(string); var lifetime = DependencyLifetime.Transient; var resolverResult = "Test Resolved Instance"; var resolver = new Func(provider => resolverResult); @@ -32,7 +32,7 @@ public void Resolve_WithResolver_ReturnsResolvedInstance() var dependency = new Dependency(lifetime, contract, resolver); // Act - var resolvedInstance = dependency.Resolve(Mock.Of()); + object resolvedInstance = dependency.Resolve(Mock.Of()); // Assert resolvedInstance @@ -44,21 +44,22 @@ public void Resolve_WithResolver_ReturnsResolvedInstance() public void Resolve_WithNullResolver_And_Null_Instance_ThrowsException() { // Arrange - var contract = typeof(string); + Type contract = typeof(string); var lifetime = DependencyLifetime.Transient; var dependency = new Dependency(lifetime, contract, null!); // Act & Assert dependency .Invoking(d => d.Resolve(Mock.Of())) - .Should().Throw(); + .Should() + .Throw(); } [Fact] public void Dependency_CtorWithInstance_SetsPropertiesCorrectly() { // Arrange - var contract = typeof(string); + Type contract = typeof(string); var lifetime = DependencyLifetime.Transient; var instance = "Test Instance"; @@ -76,7 +77,7 @@ public void Dependency_CtorWithInstance_SetsPropertiesCorrectly() public void Dependency_CtorWithResolver_SetsPropertiesCorrectly() { // Arrange - var contract = typeof(string); + Type contract = typeof(string); var lifetime = DependencyLifetime.Transient; var resolver = new Func(provider => "Resolved Instance"); @@ -89,4 +90,4 @@ public void Dependency_CtorWithResolver_SetsPropertiesCorrectly() dependency.Resolver.Should().BeSameAs(resolver); dependency.Instance.Should().BeNull(); } -} \ No newline at end of file +} diff --git a/tests/Hexecs.Tests/Loggers/LogServiceShould.cs b/tests/Hexecs.Tests/Loggers/LogServiceShould.cs index a26d4b7..0db6332 100644 --- a/tests/Hexecs.Tests/Loggers/LogServiceShould.cs +++ b/tests/Hexecs.Tests/Loggers/LogServiceShould.cs @@ -8,14 +8,14 @@ public sealed class LogServiceShould public void CreateEmptyLoggerInstance() { // Arrange - + // Act var emptyLogger = LogService.Empty; - + // Assert emptyLogger.IsEnabled(LogLevel.Info).Should().BeFalse(); } - + [Theory(DisplayName = "Корректно проверять доступность уровня логирования")] [InlineData(LogLevel.Debug)] [InlineData(LogLevel.Info)] @@ -26,82 +26,82 @@ public void CheckLevelEnabledCorrectly(LogLevel level) // Arrange var mockSink1 = new Mock(); var mockSink2 = new Mock(); - + mockSink1.Setup(x => x.IsEnabled(level)).Returns(true); mockSink2.Setup(x => x.IsEnabled(level)).Returns(false); - - var logService = new LogService(new[] { mockSink1.Object, mockSink2.Object }); - + + var logService = new LogService([mockSink1.Object, mockSink2.Object]); + // Act - var isEnabled = logService.IsEnabled(level); - + bool isEnabled = logService.IsEnabled(level); + // Assert isEnabled.Should().BeTrue(); } - + [Fact(DisplayName = "Вернуть false для IsEnabled когда нет писателей")] public void ReturnFalseForIsEnabledWhenNoWriters() { // Arrange - var logService = new LogService(Array.Empty()); - + var logService = new LogService([]); + // Act - var isEnabled = logService.IsEnabled(LogLevel.Info); - + bool isEnabled = logService.IsEnabled(LogLevel.Info); + // Assert isEnabled.Should().BeFalse(); } - + [Fact(DisplayName = "Вернуть false для IsEnabled когда все писатели выключены")] public void ReturnFalseForIsEnabledWhenAllWritersDisabled() { // Arrange var mockSink1 = new Mock(); var mockSink2 = new Mock(); - + mockSink1.Setup(x => x.IsEnabled(It.IsAny())).Returns(false); mockSink2.Setup(x => x.IsEnabled(It.IsAny())).Returns(false); - - var logService = new LogService(new[] { mockSink1.Object, mockSink2.Object }); - + + var logService = new LogService([mockSink1.Object, mockSink2.Object]); + // Act - var isEnabled = logService.IsEnabled(LogLevel.Info); - + bool isEnabled = logService.IsEnabled(LogLevel.Info); + // Assert isEnabled.Should().BeFalse(); } - + [Fact(DisplayName = "Создать контекстный логгер с строковым контекстом")] public void CreateContextLoggerWithStringContext() { // Arrange var mockSink = new Mock(); - var logService = new LogService(new[] { mockSink.Object }); + var logService = new LogService([mockSink.Object]); var contextName = "TestContext"; - + // Act - var logger = logService.CreateContext(contextName); - + ContextLogger logger = logService.CreateContext(contextName); + // Assert logger.Should().NotBeNull(); logger.Should().BeOfType(); } - + [Fact(DisplayName = "Создать контекстный логгер с контекстом на основе типа")] public void CreateContextLoggerWithTypeContext() { // Arrange var mockSink = new Mock(); - var logService = new LogService(new[] { mockSink.Object }); - + var logService = new LogService([mockSink.Object]); + // Act - var logger = logService.CreateContext(typeof(LogServiceShould)); - + ContextLogger logger = logService.CreateContext(typeof(LogServiceShould)); + // Assert logger.Should().NotBeNull(); logger.Should().BeOfType(); } - + [Theory(DisplayName = "Записывать сообщение без параметров во все писатели")] [AutoData] public void WriteMessageToAllWriters(string context, string template, LogLevel level) @@ -109,17 +109,17 @@ public void WriteMessageToAllWriters(string context, string template, LogLevel l // Arrange var mockSink1 = new Mock(); var mockSink2 = new Mock(); - - var logService = new LogService(new[] { mockSink1.Object, mockSink2.Object }); - + + var logService = new LogService([mockSink1.Object, mockSink2.Object]); + // Act logService.Write(level, context, template); - + // Assert mockSink1.Verify(x => x.Write(level, context, template), Times.Once); mockSink2.Verify(x => x.Write(level, context, template), Times.Once); } - + [Theory(DisplayName = "Записывать сообщение с одним параметром во все писатели")] [AutoData] public void WriteMessageWithOneParameterToAllWriters(string context, string template, int arg1, LogLevel level) @@ -127,17 +127,17 @@ public void WriteMessageWithOneParameterToAllWriters(string context, string temp // Arrange var mockSink1 = new Mock(); var mockSink2 = new Mock(); - - var logService = new LogService(new[] { mockSink1.Object, mockSink2.Object }); - + + var logService = new LogService([mockSink1.Object, mockSink2.Object]); + // Act logService.Write(level, context, template, arg1); - + // Assert mockSink1.Verify(x => x.Write(level, context, template, arg1), Times.Once); mockSink2.Verify(x => x.Write(level, context, template, arg1), Times.Once); } - + [Theory(DisplayName = "Записывать сообщение с двумя параметрами во все писатели")] [AutoData] public void WriteMessageWithTwoParametersToAllWriters(string context, string template, int arg1, string arg2, LogLevel level) @@ -145,88 +145,106 @@ public void WriteMessageWithTwoParametersToAllWriters(string context, string tem // Arrange var mockSink1 = new Mock(); var mockSink2 = new Mock(); - - var logService = new LogService(new[] { mockSink1.Object, mockSink2.Object }); - + + var logService = new LogService([mockSink1.Object, mockSink2.Object]); + // Act logService.Write(level, context, template, arg1, arg2); - + // Assert mockSink1.Verify(x => x.Write(level, context, template, arg1, arg2), Times.Once); mockSink2.Verify(x => x.Write(level, context, template, arg1, arg2), Times.Once); } - + [Theory(DisplayName = "Записывать сообщение с тремя параметрами во все писатели")] [AutoData] - public void WriteMessageWithThreeParametersToAllWriters(string context, string template, - int arg1, string arg2, bool arg3, LogLevel level) + public void WriteMessageWithThreeParametersToAllWriters( + string context, + string template, + int arg1, + string arg2, + bool arg3, + LogLevel level) { // Arrange var mockSink1 = new Mock(); var mockSink2 = new Mock(); - - var logService = new LogService(new[] { mockSink1.Object, mockSink2.Object }); - + + var logService = new LogService([mockSink1.Object, mockSink2.Object]); + // Act logService.Write(level, context, template, arg1, arg2, arg3); - + // Assert mockSink1.Verify(x => x.Write(level, context, template, arg1, arg2, arg3), Times.Once); mockSink2.Verify(x => x.Write(level, context, template, arg1, arg2, arg3), Times.Once); } - + [Theory(DisplayName = "Записывать сообщение с четырьмя параметрами во все писатели")] [AutoData] - public void WriteMessageWithFourParametersToAllWriters(string context, string template, - int arg1, string arg2, bool arg3, double arg4, LogLevel level) + public void WriteMessageWithFourParametersToAllWriters( + string context, + string template, + int arg1, + string arg2, + bool arg3, + double arg4, + LogLevel level) { // Arrange var mockSink1 = new Mock(); var mockSink2 = new Mock(); - - var logService = new LogService(new[] { mockSink1.Object, mockSink2.Object }); - + + var logService = new LogService([mockSink1.Object, mockSink2.Object]); + // Act logService.Write(level, context, template, arg1, arg2, arg3, arg4); - + // Assert mockSink1.Verify(x => x.Write(level, context, template, arg1, arg2, arg3, arg4), Times.Once); mockSink2.Verify(x => x.Write(level, context, template, arg1, arg2, arg3, arg4), Times.Once); } - + [Theory(DisplayName = "Записывать сообщение с пятью параметрами во все писатели")] [AutoData] - public void WriteMessageWithFiveParametersToAllWriters(string context, string template, - int arg1, string arg2, bool arg3, double arg4, char arg5, LogLevel level) + public void WriteMessageWithFiveParametersToAllWriters( + string context, + string template, + int arg1, + string arg2, + bool arg3, + double arg4, + char arg5, + LogLevel level) { // Arrange var mockSink1 = new Mock(); var mockSink2 = new Mock(); - - var logService = new LogService(new[] { mockSink1.Object, mockSink2.Object }); - + + var logService = new LogService([mockSink1.Object, mockSink2.Object]); + // Act logService.Write(level, context, template, arg1, arg2, arg3, arg4, arg5); - + // Assert mockSink1.Verify(x => x.Write(level, context, template, arg1, arg2, arg3, arg4, arg5), Times.Once); mockSink2.Verify(x => x.Write(level, context, template, arg1, arg2, arg3, arg4, arg5), Times.Once); } - + [Fact(DisplayName = "Вызывать Dispose у всех писателей при вызове Dispose")] public void DisposeAllWritersWhenDisposing() { // Arrange var mockSink1 = new Mock(); var mockSink2 = new Mock(); - - var logService = new LogService(new[] { mockSink1.Object, mockSink2.Object }); - + + var logService = new LogService([mockSink1.Object, mockSink2.Object]); + // Act logService.Dispose(); - + // Assert mockSink1.Verify(x => x.Dispose(), Times.Once); mockSink2.Verify(x => x.Dispose(), Times.Once); } -} \ No newline at end of file +} diff --git a/tests/Hexecs.Tests/Loggers/TextSinkShould.cs b/tests/Hexecs.Tests/Loggers/TextSinkShould.cs index a95cec7..9ea68af 100644 --- a/tests/Hexecs.Tests/Loggers/TextSinkShould.cs +++ b/tests/Hexecs.Tests/Loggers/TextSinkShould.cs @@ -1,5 +1,6 @@ using System.Collections.Concurrent; using System.Text; + using Hexecs.Loggers; using Hexecs.Loggers.Sinks; using Hexecs.Loggers.Writers; @@ -23,11 +24,10 @@ public void CheckEnabledLevelCorrectly(LogLevel minLevel, LogLevel checkLevel, b minLevel, [], new ConcurrentDictionary(), - mockWriter.Object - ); + mockWriter.Object); // Act - var result = sink.IsEnabled(checkLevel); + bool result = sink.IsEnabled(checkLevel); // Assert result.Should().Be(expected); @@ -45,15 +45,14 @@ public void WriteMessageWithoutParameters(string context, string message) LogLevel.Trace, [], new ConcurrentDictionary(), - streamWriter - ); + streamWriter); // Act sink.Write(LogLevel.Info, context, message); streamWriter.Flush(); // Assert - var result = Encoding.UTF8.GetString(memoryStream.ToArray()); + string result = Encoding.UTF8.GetString(memoryStream.ToArray()); result.Should().Contain("[INF "); result.Should().Contain(context); result.Should().Contain(message); @@ -77,8 +76,7 @@ public void UseDefaultValueWriterIfFactoryCannotCreateWriter() LogLevel.Trace, [valueWriterFactory.Object], valueWriters, - streamWriter - ); + streamWriter); // Act sink.Write(LogLevel.Info, "TestContext", "Value: {1}", 42); @@ -103,8 +101,7 @@ public async Task CallFlushAsyncAndDisposeAsyncForStreamWriterWhenDisposingAsync LogLevel.Trace, [], new ConcurrentDictionary(), - mockWriter.Object - ); + mockWriter.Object); // Act await sink.DisposeAsync(); @@ -125,15 +122,14 @@ public void AddPrefixWithLevelDateAndContext() LogLevel.Trace, [], new ConcurrentDictionary(), - streamWriter - ); + streamWriter); // Act sink.Write(LogLevel.Info, "TestContext", "Test message"); streamWriter.Flush(); // Assert - var result = Encoding.UTF8.GetString(memoryStream.ToArray()); + string result = Encoding.UTF8.GetString(memoryStream.ToArray()); result.Should().MatchRegex(@"\[INF \d{2}:\d{2}:\d{2}\] TestContext: Test message"); } @@ -147,8 +143,7 @@ public void UseCorrectPrefixesForDifferentLogLevels() LogLevel.Trace, [], new ConcurrentDictionary(), - traceWriter - ); + traceWriter); var debugStream = new MemoryStream(); var debugWriter = new StreamWriter(debugStream, Encoding.UTF8, 1024, true); @@ -156,8 +151,7 @@ public void UseCorrectPrefixesForDifferentLogLevels() LogLevel.Trace, [], new ConcurrentDictionary(), - debugWriter - ); + debugWriter); var infoStream = new MemoryStream(); var infoWriter = new StreamWriter(infoStream, Encoding.UTF8, 1024, true); @@ -165,8 +159,7 @@ public void UseCorrectPrefixesForDifferentLogLevels() LogLevel.Trace, [], new ConcurrentDictionary(), - infoWriter - ); + infoWriter); var warnStream = new MemoryStream(); var warnWriter = new StreamWriter(warnStream, Encoding.UTF8, 1024, true); @@ -174,8 +167,7 @@ public void UseCorrectPrefixesForDifferentLogLevels() LogLevel.Trace, [], new ConcurrentDictionary(), - warnWriter - ); + warnWriter); var errorStream = new MemoryStream(); var errorWriter = new StreamWriter(errorStream, Encoding.UTF8, 1024, true); @@ -183,8 +175,7 @@ public void UseCorrectPrefixesForDifferentLogLevels() LogLevel.Trace, [], new ConcurrentDictionary(), - errorWriter - ); + errorWriter); // Act traceSink.Write(LogLevel.Trace, "Context", "Message"); @@ -206,4 +197,4 @@ public void UseCorrectPrefixesForDifferentLogLevels() Encoding.UTF8.GetString(warnStream.ToArray()).Should().Contain("[WRN "); Encoding.UTF8.GetString(errorStream.ToArray()).Should().Contain("[ERR "); } -} \ No newline at end of file +} diff --git a/tests/Hexecs.Tests/Mocks/ActorComponents/DisposableComponent.cs b/tests/Hexecs.Tests/Mocks/ActorComponents/DisposableComponent.cs index 8419a0d..4da7fbb 100644 --- a/tests/Hexecs.Tests/Mocks/ActorComponents/DisposableComponent.cs +++ b/tests/Hexecs.Tests/Mocks/ActorComponents/DisposableComponent.cs @@ -2,5 +2,8 @@ public readonly struct DisposableComponent(IDisposable monitor) : IActorComponent, IDisposable { - public void Dispose() => monitor.Dispose(); + public void Dispose() + { + monitor.Dispose(); + } } \ No newline at end of file diff --git a/tests/Hexecs.Tests/Mocks/CommandMock.cs b/tests/Hexecs.Tests/Mocks/CommandMock.cs index 10be833..a70865f 100644 --- a/tests/Hexecs.Tests/Mocks/CommandMock.cs +++ b/tests/Hexecs.Tests/Mocks/CommandMock.cs @@ -4,4 +4,4 @@ namespace Hexecs.Tests.Mocks; public readonly record struct CommandMock(int Value) : ICommand; -public readonly record struct CommandMockWithResult(int Value) : ICommand; \ No newline at end of file +public readonly record struct CommandMockWithResult(int Value) : ICommand; diff --git a/tests/Hexecs.Tests/Pipelines/CommandShould.cs b/tests/Hexecs.Tests/Pipelines/CommandShould.cs index 2c9ae40..546df71 100644 --- a/tests/Hexecs.Tests/Pipelines/CommandShould.cs +++ b/tests/Hexecs.Tests/Pipelines/CommandShould.cs @@ -13,7 +13,7 @@ public void BeHandled() var handler = new Mock>(); handler.Setup(h => h.Handle(It.IsAny())); - var context = fixture.World.CreateActorContext(ctx => ctx.AddCommandHandler(handler.Object)); + ActorContext context = fixture.World.CreateActorContext(ctx => ctx.AddCommandHandler(handler.Object)); var command = new CommandMock(25); // act @@ -35,14 +35,14 @@ public void BeWithResultHandled() // arrange var result = new PipelineResult(111); - var handler = fixture.CreateCommandHandler(cmd => result); - - var context = fixture.World.CreateActorContext(ctx => ctx.AddCommandHandler(handler)); + ICommandHandler handler = fixture.CreateCommandHandler(cmd => result); + + ActorContext context = fixture.World.CreateActorContext(ctx => ctx.AddCommandHandler(handler)); var command = new CommandMockWithResult(25); // act - var actualResult = context + PipelineResult actualResult = context .Invoking(ctx => ctx.Execute(command)) .Should() .NotThrow() @@ -56,7 +56,7 @@ public void BeWithResultHandled() fixture.World.RemoveActorContext(context); } - + [Fact] public void NotBeHandled() { @@ -65,7 +65,7 @@ public void NotBeHandled() var handler = new Mock>(); handler.Setup(h => h.Handle(It.IsAny())); - var context = fixture.World.CreateActorContext(ctx => ctx.AddCommandHandler(handler.Object)); + ActorContext context = fixture.World.CreateActorContext(ctx => ctx.AddCommandHandler(handler.Object)); var command = new CommandMock(25); // act @@ -80,4 +80,4 @@ public void NotBeHandled() fixture.World.RemoveActorContext(context); } -} \ No newline at end of file +} diff --git a/tests/Hexecs.Tests/Pipelines/MessageShould.cs b/tests/Hexecs.Tests/Pipelines/MessageShould.cs index 6e268ab..0c07387 100644 --- a/tests/Hexecs.Tests/Pipelines/MessageShould.cs +++ b/tests/Hexecs.Tests/Pipelines/MessageShould.cs @@ -13,14 +13,14 @@ public void BeHandled() var handler = new Mock>(); handler.Setup(h => h.Handle(It.IsAny())); - var context = fixture.World.CreateActorContext(ctx => ctx.AddMessageHandler(handler.Object)); + ActorContext context = fixture.World.CreateActorContext(ctx => ctx.AddMessageHandler(handler.Object)); var message = new MessageMock(25); context.Invoking(ctx => ctx.Send(message)) .Should() .NotThrow(); - var queue = context.GetMessageQueue(); + IMessageQueue queue = context.GetMessageQueue(); // act @@ -39,7 +39,7 @@ public void NotBeHandled() var handler = new Mock>(); handler.Setup(h => h.Handle(It.IsAny())); - var context = fixture.World.CreateActorContext(ctx => ctx.AddMessageHandler(handler.Object)); + ActorContext context = fixture.World.CreateActorContext(ctx => ctx.AddMessageHandler(handler.Object)); var message = new MessageMockNotRegistered(25); // act diff --git a/tests/Hexecs.Tests/Pipelines/NotificationShould.cs b/tests/Hexecs.Tests/Pipelines/NotificationShould.cs index bb75297..90e0a6c 100644 --- a/tests/Hexecs.Tests/Pipelines/NotificationShould.cs +++ b/tests/Hexecs.Tests/Pipelines/NotificationShould.cs @@ -13,7 +13,7 @@ public void BeHandled_IfOneHandler() var handler1 = new Mock>(); handler1.Setup(h => h.Handle(It.IsAny())); - var context = fixture.World.CreateActorContext(ctx => ctx.AddNotificationHandler(handler1.Object)); + ActorContext context = fixture.World.CreateActorContext(ctx => ctx.AddNotificationHandler(handler1.Object)); var notification = new NotificationMock(25); // act @@ -35,16 +35,16 @@ public void BeHandled_IfManyHandlers() { // arrange - var handlers = fixture.CreateArray(_ => + Mock>[] handlers = fixture.CreateArray(_ => { var handler = new Mock>(); handler.Setup(h => h.Handle(It.IsAny())); return handler; }); - var context = fixture.World.CreateActorContext(ctx => ctx.CreateNotificationHandler(builder => + ActorContext context = fixture.World.CreateActorContext(ctx => ctx.CreateNotificationHandler(builder => { - foreach (var handler in handlers) + foreach (Mock> handler in handlers) { builder.Add(handler.Object); } @@ -61,7 +61,7 @@ public void BeHandled_IfManyHandlers() // assert - foreach (var handler in handlers) + foreach (Mock> handler in handlers) { handler.Verify(h => h.Handle(notification), Times.Once); } @@ -77,7 +77,7 @@ public void NotBeHandled() var handler1 = new Mock>(); handler1.Setup(h => h.Handle(It.IsAny())); - var context = fixture.World.CreateActorContext(ctx => ctx.AddNotificationHandler(handler1.Object)); + ActorContext context = fixture.World.CreateActorContext(ctx => ctx.AddNotificationHandler(handler1.Object)); var notification = new NotificationMockNotRegistered(25); // act diff --git a/tests/Hexecs.Tests/Pipelines/PipelineTestFixture.cs b/tests/Hexecs.Tests/Pipelines/PipelineTestFixture.cs index 06eecf6..0e16c08 100644 --- a/tests/Hexecs.Tests/Pipelines/PipelineTestFixture.cs +++ b/tests/Hexecs.Tests/Pipelines/PipelineTestFixture.cs @@ -32,21 +32,30 @@ private sealed class CommandHandler(Func h : ICommandHandler where TCommand : struct, ICommand { - public TResult Handle(in TCommand command) => handler(command); + public TResult Handle(in TCommand command) + { + return handler(command); + } } private sealed class QueryHandler(Func handler) : IQueryHandler where TQuery : struct, IQuery { - public TResult Handle(in TQuery query) => handler(query); + public TResult Handle(in TQuery query) + { + return handler(query); + } } private sealed class NotificationHandler(Action handler) : INotificationHandler where TNotification : struct, INotification { - public void Handle(in TNotification notification) => handler(notification); + public void Handle(in TNotification notification) + { + handler(notification); + } } public void Dispose() diff --git a/tests/Hexecs.Tests/Pipelines/QueryShould.cs b/tests/Hexecs.Tests/Pipelines/QueryShould.cs index b99039e..a8c6c12 100644 --- a/tests/Hexecs.Tests/Pipelines/QueryShould.cs +++ b/tests/Hexecs.Tests/Pipelines/QueryShould.cs @@ -11,14 +11,14 @@ public void BeHandled() // arrange var result = new PipelineResult(111); - var handler = fixture.CreateQueryHandler(cmd => result); + IQueryHandler handler = fixture.CreateQueryHandler(cmd => result); - var context = fixture.World.CreateActorContext(ctx => ctx.AddQueryHandler(handler)); + ActorContext context = fixture.World.CreateActorContext(ctx => ctx.AddQueryHandler(handler)); var query = new QueryMock(25); // act - var actualResult = context + PipelineResult actualResult = context .Invoking(ctx => ctx.Ask(query)) .Should() .NotThrow() @@ -41,7 +41,7 @@ public void NotBeHandled() var handler = new Mock>(); handler.Setup(h => h.Handle(It.IsAny())); - var context = fixture.World.CreateActorContext(ctx => ctx.AddQueryHandler(handler.Object)); + ActorContext context = fixture.World.CreateActorContext(ctx => ctx.AddQueryHandler(handler.Object)); var query = new QueryMockNotRegistered(25); // act diff --git a/tests/Hexecs.Tests/Utils/ArgsShould.cs b/tests/Hexecs.Tests/Utils/ArgsShould.cs index 9f2c707..a1ecaef 100644 --- a/tests/Hexecs.Tests/Utils/ArgsShould.cs +++ b/tests/Hexecs.Tests/Utils/ArgsShould.cs @@ -10,7 +10,7 @@ public void Rent_ShouldReturnArgsInstance() // Arrange // Act - var args = Args.Rent(); + Args args = Args.Rent(); // Assert args.Should().NotBeNull(); @@ -24,7 +24,7 @@ public void Rent_WithNameAndValue_ShouldReturnArgsInstanceWithSetValue(string na // Arrange // Act - var args = Args.Rent(name, value); + Args args = Args.Rent(name, value); // Assert args.Should().NotBeNull(); @@ -36,7 +36,7 @@ public void Rent_WithNameAndValue_ShouldReturnArgsInstanceWithSetValue(string na public void Get_ShouldReturnSetValue(string name, string value) { // Arrange - var args = Args.Rent().Set(name, value); + Args args = Args.Rent().Set(name, value); // Act var result = args.Get(name); @@ -50,7 +50,7 @@ public void Get_ShouldReturnSetValue(string name, string value) public void Get_ShouldThrowException_WhenValueNotFound(string name) { // Arrange - var args = Args.Rent(); + Args args = Args.Rent(); // Act Action act = () => args.Get(name); @@ -66,7 +66,7 @@ public void Get_ShouldThrowException_WhenValueNotFound(string name) public void Return_ShouldClearAllValueStorages() { // Arrange - var args = Args.Rent() + Args args = Args.Rent() .Set("intValue", 42) .Set("stringValue", "test") .Set("boolValue", true); @@ -81,16 +81,17 @@ public void Return_ShouldClearAllValueStorages() args.TryGet("boolValue", out _).Should().BeFalse(); } - [Theory(DisplayName = - "Метод TryGet(name, out value) должен возвращать true и значение, если значение найдено")] + [Theory( + DisplayName = + "Метод TryGet(name, out value) должен возвращать true и значение, если значение найдено")] [AutoData] public void TryGet_ShouldReturnTrueAndValue_WhenValueExists(string name, double value) { // Arrange - var args = Args.Rent().Set(name, value); + Args args = Args.Rent().Set(name, value); // Act - var result = args.TryGet(name, out var outValue); + bool result = args.TryGet(name, out double outValue); // Assert result.Should().BeTrue(); @@ -102,10 +103,10 @@ public void TryGet_ShouldReturnTrueAndValue_WhenValueExists(string name, double public void TryGet_ShouldReturnFalse_WhenValueNotFound(string name) { // Arrange - var args = Args.Rent(); + Args args = Args.Rent(); // Act - var result = args.TryGet(name, out var outValue); + bool result = args.TryGet(name, out DateTime outValue); // Assert result.Should().BeFalse(); @@ -117,10 +118,10 @@ public void TryGet_ShouldReturnFalse_WhenValueNotFound(string name) public void TryGet_ShouldReturnFalse_WhenTypeDoesNotMatch(string name, int value) { // Arrange - var args = Args.Rent().Set(name, value); + Args args = Args.Rent().Set(name, value); // Act - var result = args.TryGet(name, out var outValue); + bool result = args.TryGet(name, out string outValue); // Assert result.Should().BeFalse(); @@ -132,14 +133,14 @@ public void TryGet_ShouldReturnFalse_WhenTypeDoesNotMatch(string name, int value public void Set_ShouldAddNewValue(string name, Guid value) { // Arrange - var args = Args.Rent(); + Args args = Args.Rent(); // Act - var result = args.Set(name, value); + Args result = args.Set(name, value); // Assert result.Should().BeSameAs(args); - args.TryGet(name, out var outValue).Should().BeTrue(); + args.TryGet(name, out Guid outValue).Should().BeTrue(); outValue.Should().Be(value); } @@ -148,10 +149,10 @@ public void Set_ShouldAddNewValue(string name, Guid value) public void Set_ShouldUpdateExistingValue(string name, int initialValue, int newValue) { // Arrange - var args = Args.Rent().Set(name, initialValue); + Args args = Args.Rent().Set(name, initialValue); // Act - var result = args.Set(name, newValue); + Args result = args.Set(name, newValue); // Assert result.Should().BeSameAs(args); @@ -162,7 +163,7 @@ public void Set_ShouldUpdateExistingValue(string name, int initialValue, int new public void GetEnumerator_ShouldEnumerateAllAddedValues() { // Arrange - var args = Args.Rent() + Args args = Args.Rent() .Set("intValue", 42) .Set("stringValue", "test") .Set("boolValue", true); @@ -175,23 +176,24 @@ public void GetEnumerator_ShouldEnumerateAllAddedValues() }; // Act - var result = args.ToDictionary(kv => kv.Key, kv => kv.Value); + Dictionary result = args.ToDictionary(kv => kv.Key, kv => kv.Value); // Assert result.Should().BeEquivalentTo(expected); } - [Theory(DisplayName = - "Метод Rent должен возвращать существующий экземпляр из пула, если он был возвращен методом Return")] + [Theory( + DisplayName = + "Метод Rent должен возвращать существующий экземпляр из пула, если он был возвращен методом Return")] [AutoData] public void Rent_ShouldReturnExistingInstanceFromPool(string name, int value) { // Arrange - var args1 = Args.Rent().Set(name, value); + Args args1 = Args.Rent().Set(name, value); args1.Return(); // Возвращаем в пул // Act - var args2 = Args.Rent(); + Args args2 = Args.Rent(); // Assert args2.Should().NotBeNull(); @@ -211,7 +213,7 @@ public void Args_ShouldSupportDifferentValueTypes() var customValue = new CustomValue { Value = "custom" }; // Act - заполнение объекта Args всеми тестовыми значениями - var args = Args + Args args = Args .Rent() .Set("intValue", intValue) .Set("doubleValue", doubleValue) @@ -236,7 +238,7 @@ public void Args_ShouldSupportDifferentValueTypes() public void AfterReturn_AllValuesOfTypeShouldBeUnavailable() { // Arrange - var args = Args.Rent() + Args args = Args.Rent() .Set("value1", 1) .Set("value2", 2) .Set("value3", 3); @@ -255,4 +257,4 @@ private class CustomValue { public required string Value { get; set; } } -} \ No newline at end of file +} diff --git a/tests/Hexecs.Tests/Utils/ArrayUtilsShould.cs b/tests/Hexecs.Tests/Utils/ArrayUtilsShould.cs index bb194f3..2312878 100644 --- a/tests/Hexecs.Tests/Utils/ArrayUtilsShould.cs +++ b/tests/Hexecs.Tests/Utils/ArrayUtilsShould.cs @@ -2,7 +2,7 @@ namespace Hexecs.Tests.Utils; -public sealed class ArrayUtilsShould +public sealed class ArrayUtilsShould { /// /// Проверяет, что метод Clear не вызывает ошибок при очистке пустого массива @@ -11,11 +11,11 @@ public sealed class ArrayUtilsShould public void Clear_EmptyArray_ShouldDoNothing() { // Arrange - var array = Array.Empty(); - - // Act + int[] array = []; + + // Act ArrayUtils.Clear(array); - + // Assert array .Should() @@ -25,15 +25,15 @@ public void Clear_EmptyArray_ShouldDoNothing() /// /// Проверяет, что метод Clear корректно очищает все элементы заполненного массива /// - [Fact(DisplayName = "Очистка заполненного массива должна обнулить все элементы")] + [Fact(DisplayName = "Очистка заполненного массива должна обнулить все элементы")] public void Clear_FilledArray_ShouldClearAllElements() { // Arrange var array = new[] { 1, 2, 3, 4, 5 }; - + // Act ArrayUtils.Clear(array); - + // Assert array .Should() @@ -48,10 +48,10 @@ public void Clear_WithLength_ShouldClearSpecifiedNumberOfElements() { // Arrange var array = new[] { 1, 2, 3, 4, 5 }; - + // Act ArrayUtils.Clear(array, 3); - + // Assert array.Take(3).Should().OnlyContain(x => x == 0); array.Skip(3).Should().BeEquivalentTo([4, 5]); @@ -65,10 +65,10 @@ public void Cut_ValidIndex_ShouldRemoveElementAndShiftArray() { // Arrange var array = new[] { 1, 2, 3, 4, 5 }; - + // Act ArrayUtils.Cut(array, 1); - + // Assert array.Take(4).Should().BeEquivalentTo([1, 3, 4, 5]); array[4].Should().Be(0); @@ -82,10 +82,10 @@ public void Cut_LastIndex_ShouldClearLastElement() { // Arrange var array = new[] { 1, 2, 3, 4, 5 }; - + // Act ArrayUtils.Cut(array, 4); - + // Assert array.Take(4).Should().BeEquivalentTo([1, 2, 3, 4]); array[4].Should().Be(0); @@ -99,11 +99,11 @@ public void EnsureCapacity_SmallerCapacity_ShouldNotResize() { // Arrange var array = new int[5]; - var originalReference = array; - + int[] originalReference = array; + // Act ArrayUtils.EnsureCapacity(ref array, 3); - + // Assert array.Should().BeSameAs(originalReference); array.Length.Should().Be(5); @@ -117,10 +117,10 @@ public void EnsureCapacity_LargerCapacity_ShouldResize() { // Arrange var array = new[] { 1, 2, 3 }; - + // Act ArrayUtils.EnsureCapacity(ref array, 5); - + // Assert array.Length.Should().Be(5); array.Take(3).Should().BeEquivalentTo([1, 2, 3]); @@ -134,10 +134,10 @@ public void Insert_WithinBounds_ShouldInsertElement() { // Arrange var array = new[] { 1, 2, 3 }; - + // Act ArrayUtils.Insert(ref array, 1, 10); - + // Assert array[1].Should().Be(10); } @@ -150,10 +150,10 @@ public void Insert_BeyondBounds_ShouldResizeAndInsert() { // Arrange var array = new[] { 1, 2, 3 }; - + // Act ArrayUtils.Insert(ref array, 5, 10); - + // Assert array.Length.Should().BeGreaterThan(5); array[5].Should().Be(10); @@ -167,10 +167,10 @@ public void Remove_ExistingItem_ShouldRemoveAndReturnTrue() { // Arrange var array = new[] { 1, 2, 3, 4, 5 }; - + // Act - var result = ArrayUtils.Remove(array, 3); - + bool result = ArrayUtils.Remove(array, 3); + // Assert result.Should().BeTrue(); array.Take(4).Should().BeEquivalentTo([1, 2, 4, 5]); @@ -185,12 +185,12 @@ public void Remove_NonExistingItem_ShouldReturnFalse() { // Arrange var array = new[] { 1, 2, 3, 4, 5 }; - + // Act - var result = ArrayUtils.Remove(array, 10); - + bool result = ArrayUtils.Remove(array, 10); + // Assert result.Should().BeFalse(); array.Should().BeEquivalentTo([1, 2, 3, 4, 5]); } -} \ No newline at end of file +} diff --git a/tests/Hexecs.Tests/Utils/TypeOfShould.cs b/tests/Hexecs.Tests/Utils/TypeOfShould.cs index 0b3d840..c12c23a 100644 --- a/tests/Hexecs.Tests/Utils/TypeOfShould.cs +++ b/tests/Hexecs.Tests/Utils/TypeOfShould.cs @@ -8,10 +8,10 @@ public sealed class TypeOfTests public void GetTypeName_ForNonGenericType_ShouldReturnTypeName() { // Arrange - var type = typeof(int); + Type type = typeof(int); // Act - var result = TypeOf.GetTypeName(type); + string result = TypeOf.GetTypeName(type); // Assert result.Should().Be("Int32"); @@ -21,10 +21,10 @@ public void GetTypeName_ForNonGenericType_ShouldReturnTypeName() public void GetTypeName_ForGenericType_ShouldReturnFormattedTypeName() { // Arrange - var type = typeof(List); + Type type = typeof(List); // Act - var result = TypeOf.GetTypeName(type); + string result = TypeOf.GetTypeName(type); // Assert result.Should().Be("List"); @@ -34,10 +34,10 @@ public void GetTypeName_ForGenericType_ShouldReturnFormattedTypeName() public void GetTypeName_ForNestedGenericType_ShouldReturnFormattedTypeName() { // Arrange - var type = typeof(Dictionary>); + Type type = typeof(Dictionary>); // Act - var result = TypeOf.GetTypeName(type); + string result = TypeOf.GetTypeName(type); // Assert result.Should().Be("Dictionary>"); @@ -47,9 +47,9 @@ public void GetTypeName_ForNestedGenericType_ShouldReturnFormattedTypeName() public void TypeOf_Generic_Id_ShouldBeUnique() { // Act - var id1 = TypeOf.Id; - var id2 = TypeOf.Id; - var id3 = TypeOf>.Id; + int id1 = TypeOf.Id; + int id2 = TypeOf.Id; + int id3 = TypeOf>.Id; // Assert id1.Should().NotBe(id2); @@ -65,4 +65,4 @@ public void TypeOf_Generic_GetTypeName_ShouldReturnCorrectName() TypeOf.GetTypeName().Should().Be("String"); TypeOf>.GetTypeName().Should().Be("List"); } -} \ No newline at end of file +} diff --git a/tests/Hexecs.Tests/Utils/ValueStringBuilderShould.cs b/tests/Hexecs.Tests/Utils/ValueStringBuilderShould.cs index 657452c..7e0c52a 100644 --- a/tests/Hexecs.Tests/Utils/ValueStringBuilderShould.cs +++ b/tests/Hexecs.Tests/Utils/ValueStringBuilderShould.cs @@ -1,4 +1,5 @@ using System.Globalization; + using Hexecs.Utils; namespace Hexecs.Tests.Utils; @@ -238,7 +239,7 @@ public void Append_CharSpan_AppendsCorrectString() // Arrange Span buffer = stackalloc char[32]; var builder = new ValueStringBuilder(buffer); - Span value = stackalloc char[] { 'T', 'e', 's', 't' }; + Span value = ['T', 'e', 's', 't']; // Act builder.Append(value); diff --git a/tests/Hexecs.Tests/Values/ValueServiceShould.cs b/tests/Hexecs.Tests/Values/ValueServiceShould.cs index 589a422..257667a 100644 --- a/tests/Hexecs.Tests/Values/ValueServiceShould.cs +++ b/tests/Hexecs.Tests/Values/ValueServiceShould.cs @@ -24,7 +24,7 @@ public void HasTable_ShouldReturnTrue_ForExistingTable() var service = new ValueService([table]); // Act - var result = service.HasTable(tableName); + bool result = service.HasTable(tableName); // Assert result.Should().BeTrue(); @@ -37,7 +37,7 @@ public void HasTable_ShouldReturnFalse_ForNonExistingTable() var service = ValueService.Empty; // Act - var result = service.HasTable("NonExistingTable"); + bool result = service.HasTable("NonExistingTable"); // Assert result.Should().BeFalse(); @@ -52,7 +52,7 @@ public void GetTable_ShouldReturnTableByName() var service = new ValueService([table]); // Act - var result = service.GetTable(tableName); + IValueTable result = service.GetTable(tableName); // Assert result.Should().NotBeNull(); @@ -84,7 +84,7 @@ public void GetTableWithKey_ShouldReturnTypedTable_WithCorrectKeyType() var service = new ValueService([table]); // Act - var result = service.GetTable(tableName); + IValueTable result = service.GetTable(tableName); // Assert result.Should().NotBeNull(); @@ -116,7 +116,7 @@ public void GetTableWithKeyAndValue_ShouldReturnTypedTable_WithCorrectTypes() var service = new ValueService([table]); // Act - var result = service.GetTable(tableName); + IValueTable result = service.GetTable(tableName); // Assert result.Should().NotBeNull(); @@ -171,7 +171,7 @@ public void GetValue_ShouldReturnValueFromTable() table.Set(key, value); // Act - var result = service.GetValue(tableName, key); + int result = service.GetValue(tableName, key); // Assert result.Should().Be(value); @@ -222,7 +222,7 @@ public void RemoveValueWithKey_ShouldRemoveValueFromTable() table.Set(key, value); // Act - var result = service.RemoveValue(tableName, key); + bool result = service.RemoveValue(tableName, key); // Assert result.Should().BeTrue(); @@ -241,7 +241,7 @@ public void RemoveValueWithKeyAndValue_ShouldRemoveAndReturnValue() table.Set(key, value); // Act - var result = service.RemoveValue(tableName, key, out var removedValue); + bool result = service.RemoveValue(tableName, key, out int removedValue); // Assert result.Should().BeTrue(); @@ -261,7 +261,7 @@ public void TryGetValue_ShouldReturnValue_WhenExists() table.Set(key, value); // Act - var result = service.TryGetValue(tableName, key, out var retrievedValue); + bool result = service.TryGetValue(tableName, key, out int retrievedValue); // Assert result.Should().BeTrue(); @@ -277,7 +277,7 @@ public void TryGetValue_ShouldReturnFalse_WhenKeyDoesNotExist() var service = new ValueService([table]); // Act - var result = service.TryGetValue(tableName, 999, out var retrievedValue); + bool result = service.TryGetValue(tableName, 999, out int retrievedValue); // Assert result.Should().BeFalse(); @@ -298,13 +298,13 @@ public void GetValues_ShouldReturnAllKeyValuePairs() { 3, 30 } }; - foreach (var kvp in data) + foreach (KeyValuePair kvp in data) { table.Set(kvp.Key, kvp.Value); } // Act - var values = service.GetValues(tableName).ToDictionary(kvp => kvp.Key, kvp => kvp.Value); + Dictionary values = service.GetValues(tableName).ToDictionary(kvp => kvp.Key, kvp => kvp.Value); // Assert values.Should().BeEquivalentTo(data); @@ -317,7 +317,7 @@ public void Clear_ShouldClearAllTables() var table1 = new ValueTable("Table1"); var table2 = new ValueTable("Table2"); var service = new ValueService([table1, table2]); - + table1.Set(1, 10); table2.Set("test", 20.5); @@ -336,12 +336,12 @@ public void ClearTable_ShouldClearSpecificTable() var table1 = new ValueTable("Table1"); var table2 = new ValueTable("Table2"); var service = new ValueService([table1, table2]); - + table1.Set(1, 10); table2.Set("test", 20.5); // Act - var result = service.ClearTable("Table1"); + bool result = service.ClearTable("Table1"); // Assert result.Should().BeTrue(); @@ -356,9 +356,9 @@ public void ClearTable_ShouldReturnFalse_ForNonExistingTable() var service = ValueService.Empty; // Act - var result = service.ClearTable("NonExistingTable"); + bool result = service.ClearTable("NonExistingTable"); // Assert result.Should().BeFalse(); } -} \ No newline at end of file +} diff --git a/tests/Hexecs.Tests/Worlds/DiceShould.cs b/tests/Hexecs.Tests/Worlds/DiceShould.cs index 2923014..bca2f53 100644 --- a/tests/Hexecs.Tests/Worlds/DiceShould.cs +++ b/tests/Hexecs.Tests/Worlds/DiceShould.cs @@ -1,3 +1,5 @@ +using Hexecs.Worlds; + namespace Hexecs.Tests.Worlds; public sealed class DiceShould(WorldTestFixture fixture) : IClassFixture @@ -5,25 +7,29 @@ public sealed class DiceShould(WorldTestFixture fixture) : IClassFixture w.GetService()) .Should() .NotThrow() @@ -26,11 +27,11 @@ public void NotThrowWhenDependencyNotRegistered() .Should() .BeNull(); } - + [Fact] public void ResolveSingleton() { - var dependency = _world.Invoking(w => w.GetService()) + Singleton? dependency = _world.Invoking(w => w.GetService()) .Should() .NotThrow() .Which; @@ -39,11 +40,11 @@ public void ResolveSingleton() .Should() .NotBeNull(); } - + [Fact] public void ResolveSingletonArray() { - var array = _world.Invoking(w => w.GetServices()) + Singleton[] array = _world.Invoking(w => w.GetServices()) .Should() .NotThrow() .Which; @@ -52,18 +53,18 @@ public void ResolveSingletonArray() .Should() .OnlyHaveUniqueItems(); } - + [Fact] public void ResolveSameSingletonArray() { - var array1 = _world.GetServices(); - var array2 = _world.GetServices(); + Singleton[] array1 = _world.GetServices(); + Singleton[] array2 = _world.GetServices(); array1 .Should() .BeSameAs(array2); } - + [Fact] public void ResolveSameSingleton() { @@ -74,7 +75,7 @@ public void ResolveSameSingleton() .Should() .Be(dependency2); } - + [Fact] public void ResolveSameScoped() { @@ -85,11 +86,11 @@ public void ResolveSameScoped() .Should() .Be(dependency2); } - + [Fact] public void ResolveScoped() { - var dependency = _world.Invoking(w => w.GetService()) + Scoped? dependency = _world.Invoking(w => w.GetService()) .Should() .NotThrow() .Which; @@ -98,11 +99,11 @@ public void ResolveScoped() .Should() .NotBeNull(); } - + [Fact] public void ResolveTransient() { - var dependency = _world.Invoking(w => w.GetService()) + Transient? dependency = _world.Invoking(w => w.GetService()) .Should() .NotThrow() .Which; @@ -111,7 +112,7 @@ public void ResolveTransient() .Should() .NotBeNull(); } - + [Fact] public void ResolveNotSameTransient() { @@ -122,4 +123,4 @@ public void ResolveNotSameTransient() .Should() .NotBe(dependency2); } -} \ No newline at end of file +} From f5ed2d9b8e9f9c3ab06b1e5070aa46c6ac275f79 Mon Sep 17 00:00:00 2001 From: Kirill Bazhaikin Date: Thu, 27 Aug 2026 03:09:15 +0300 Subject: [PATCH 11/11] Added editorconfig --- src/Hexecs/Actors/ActorConstraint.Builder.cs | 40 ++-- .../Actors/ActorConstraint.Subscription.cs | 24 +- src/Hexecs/Actors/ActorContext.Bounds.cs | 20 +- src/Hexecs/Actors/ActorContext.Builders.cs | 14 +- src/Hexecs/Actors/ActorContext.Children.cs | 102 +++++--- .../Actors/ActorContext.ChildrenEnumerator.cs | 25 +- .../ActorContext.ComponenetEnumerator.cs | 26 ++- src/Hexecs/Actors/ActorContext.Components.cs | 138 +++++++---- .../Actors/ActorContext.DependencyProvider.cs | 17 +- src/Hexecs/Actors/ActorContext.Dictionary.cs | 113 +++++---- src/Hexecs/Actors/ActorContext.Entry.cs | 125 +++++++--- src/Hexecs/Actors/ActorContext.Enumerator.cs | 45 +++- src/Hexecs/Actors/ActorContext.Filters.cs | 34 +-- src/Hexecs/Actors/ActorContext.Pipelines.cs | 39 ++-- src/Hexecs/Actors/ActorContext.Relations.cs | 68 ++++-- .../Actors/ActorContext.Serialization.cs | 34 +-- src/Hexecs/Actors/ActorContext.Systems.cs | 41 ++-- src/Hexecs/Actors/ActorContext.cs | 109 +++++---- ...ctorContextBuilder.ComponentPoolBuilder.cs | 22 +- .../Actors/ActorContextBuilder.Entry.cs | 7 +- .../Actors/ActorContextBuilder.Extensions.cs | 38 +-- ...ActorContextBuilder.NotificationBuilder.cs | 28 ++- ...torContextBuilder.ParallelSystemBuilder.cs | 38 +-- src/Hexecs/Actors/ActorContextBuilder.cs | 97 +++++--- src/Hexecs/Actors/ActorDictionary.cs | 25 +- src/Hexecs/Actors/ActorError.cs | 9 +- src/Hexecs/Actors/ActorFilter1.Dictionary.cs | 46 ++-- src/Hexecs/Actors/ActorFilter1.Enumerator.cs | 23 +- src/Hexecs/Actors/ActorFilter1.Operation.cs | 17 +- .../Actors/ActorFilter1.SkipTakeEnumerator.cs | 25 +- src/Hexecs/Actors/ActorFilter1.cs | 76 ++++-- src/Hexecs/Actors/ActorFilter2.Dictionary.cs | 46 ++-- src/Hexecs/Actors/ActorFilter2.Enumerator.cs | 23 +- src/Hexecs/Actors/ActorFilter2.Operation.cs | 17 +- .../Actors/ActorFilter2.SkipTakeEnumerator.cs | 25 +- src/Hexecs/Actors/ActorFilter2.cs | 89 +++++-- src/Hexecs/Actors/ActorFilter3.Dictionary.cs | 46 ++-- src/Hexecs/Actors/ActorFilter3.Enumerator.cs | 21 +- src/Hexecs/Actors/ActorFilter3.Operation.cs | 17 +- .../Actors/ActorFilter3.SkipTakeEnumerator.cs | 25 +- src/Hexecs/Actors/ActorFilter3.cs | 96 ++++++-- src/Hexecs/Actors/ActorId.cs | 56 +++-- src/Hexecs/Actors/ActorList.Enumerator.cs | 22 +- src/Hexecs/Actors/ActorList.cs | 47 +++- src/Hexecs/Actors/ActorMarshal.cs | 36 ++- src/Hexecs/Actors/ActorRef1.cs | 63 +++-- src/Hexecs/Actors/ActorRef2.cs | 108 ++++++--- src/Hexecs/Actors/ActorRef3.cs | 218 +++++++++++++----- src/Hexecs/Actors/ActorRelation.cs | 59 +++-- src/Hexecs/Actors/Bounds/BoundComponent.cs | 4 +- .../Actors/Bounds/BoundComponentConverter.cs | 7 +- .../Actors/Bounds/BoundComponentDebugProxy.cs | 5 +- .../Components/ActorComponentConfiguration.cs | 8 +- .../ActorComponentPool.AddResult.cs | 12 +- .../ActorComponentPool.Dictionary.cs | 75 ++++-- .../ActorComponentPool.Enumerator.cs | 28 ++- .../ActorComponentPool.Serialization.cs | 9 +- .../Actors/Components/ActorComponentPool.cs | 75 +++--- .../Actors/Components/ActorComponentType.cs | 25 +- .../Actors/Development/ActorIdDebugProxy.cs | 4 +- src/Hexecs/Actors/IActorBuilder.cs | 8 +- src/Hexecs/Actors/IActorComponent.cs | 2 +- src/Hexecs/Actors/IActorFilter.cs | 2 +- src/Hexecs/Actors/IDrawSystem.cs | 2 +- src/Hexecs/Actors/IUpdateSystem.cs | 2 +- src/Hexecs/Actors/IViewComponent.cs | 2 +- src/Hexecs/Actors/Loggers/ActorIdLogWriter.cs | 6 +- src/Hexecs/Actors/Loggers/ActorLogWriter.cs | 4 +- src/Hexecs/Actors/Nodes/ActorNode.cs | 69 ++++-- .../Nodes/ActorNodeComponentConverter.cs | 8 +- .../Actors/Pipelines/ActorCommandHandler.cs | 20 +- .../Actors/Pipelines/ActorMessageHandler.cs | 11 +- .../Pipelines/ActorNotificationHandler.cs | 11 +- .../Actors/Pipelines/ActorQueryHandler.cs | 11 +- .../Relations/ActorRelationComponent.cs | 53 +++-- .../ActorRelationComponentConverter.cs | 10 +- .../Relations/ActorRelationPool.Enumerator.cs | 15 +- .../Actors/Relations/ActorRelationPool.cs | 132 +++++++---- .../Actors/Relations/ActorRelationType.cs | 25 +- .../IActorComponentConverter.cs | 2 +- src/Hexecs/Actors/Systems/DrawSystem.cs | 11 +- src/Hexecs/Actors/Systems/DrawSystem1.cs | 14 +- src/Hexecs/Actors/Systems/DrawSystem2.cs | 14 +- src/Hexecs/Actors/Systems/DrawSystem3.cs | 14 +- src/Hexecs/Actors/Systems/ParallelSystem.cs | 20 +- src/Hexecs/Actors/Systems/UpdateSystem.cs | 11 +- src/Hexecs/Actors/Systems/UpdateSystem1.cs | 28 ++- src/Hexecs/Actors/Systems/UpdateSystem2.cs | 32 ++- src/Hexecs/Actors/Systems/UpdateSystem3.cs | 28 ++- src/Hexecs/Assets/Asset.cs | 39 +++- src/Hexecs/Assets/AssetComponentRef.cs | 14 +- src/Hexecs/Assets/AssetId.cs | 56 +++-- src/Hexecs/Assets/AssetMarshal.cs | 29 ++- src/Hexecs/Assets/AssetRef1.cs | 69 ++++-- src/Hexecs/Assets/AssetRef2.cs | 71 ++++-- src/Hexecs/Assets/AssetRef3.cs | 146 ++++++++---- 96 files changed, 2562 insertions(+), 1160 deletions(-) diff --git a/src/Hexecs/Actors/ActorConstraint.Builder.cs b/src/Hexecs/Actors/ActorConstraint.Builder.cs index 00b5dbb..0751c38 100644 --- a/src/Hexecs/Actors/ActorConstraint.Builder.cs +++ b/src/Hexecs/Actors/ActorConstraint.Builder.cs @@ -35,19 +35,30 @@ public ActorConstraint Build() public void Clear() { - if (_subscriptions.Length > 0) ArrayPool.Shared.Return(_subscriptions); + if (_subscriptions.Length > 0) + { + ArrayPool.Shared.Return(_subscriptions); + } + _length = 0; } public bool Equals(ActorConstraint? constraint) { - if (constraint == null || constraint._hash != _hash) return false; + if (constraint == null || constraint._hash != _hash) + { + return false; + } + + Span currentSubscriptions = _subscriptions.AsSpan(0, _length); + Subscription[] constraintSubscriptions = constraint._subscriptions; - var currentSubscriptions = _subscriptions.AsSpan(0, _length); - var constraintSubscriptions = constraint._subscriptions; for (var i = 0; i < currentSubscriptions.Length; i++) { - if (!_subscriptions[i].Equals(constraintSubscriptions[i])) return false; + if (!_subscriptions[i].Equals(constraintSubscriptions[i])) + { + return false; + } } return true; @@ -55,7 +66,7 @@ public bool Equals(ActorConstraint? constraint) public Builder Exclude() where T : struct, IActorComponent { - var pool = Context.GetOrCreateComponentPool(); + ActorComponentPool pool = Context.GetOrCreateComponentPool(); AddSubscription(false, pool, id => !pool.Has(id)); @@ -64,7 +75,7 @@ public Builder Exclude() where T : struct, IActorComponent public Builder Include() where T : struct, IActorComponent { - var pool = Context.GetOrCreateComponentPool(); + ActorComponentPool pool = Context.GetOrCreateComponentPool(); AddSubscription(true, pool, pool.Has); @@ -75,12 +86,15 @@ public Builder Include() where T : struct, IActorComponent private void AddSubscription(bool include, IActorComponentPool pool, Func check) where T : struct, IActorComponent { - var id = ActorComponentType.Id; + ushort id = ActorComponentType.Id; // ReSharper disable once ForeachCanBePartlyConvertedToQueryUsingAnotherGetEnumerator - foreach (var exists in _subscriptions.AsSpan(0, _length)) + foreach (Subscription exists in _subscriptions.AsSpan(0, _length)) { - if (exists.ComponentId == id) ActorError.ConstraintExists(); + if (exists.ComponentId == id) + { + ActorError.ConstraintExists(); + } } ArrayUtils.Insert( @@ -93,10 +107,10 @@ private void AddSubscription(bool include, IActorComponentPool pool, Func(bool include, IActorComponentPool pool, Func /// Внутренняя структура, представляющая подписку на события пула компонентов. - /// Используется для отслеживания изменений в компонентах актёров + /// Используется для отслеживания изменений в компонентах актёров /// и применения ограничений в реальном времени. /// private readonly struct Subscription : IComparable, IEquatable @@ -97,7 +97,8 @@ public void Unsubscribe(ActorConstraint constraint) /// Результат сравнения public int CompareTo(Subscription other) { - var componentIdComparison = _pool.Id.CompareTo(other._pool.Id); + int componentIdComparison = _pool.Id.CompareTo(other._pool.Id); + return componentIdComparison != 0 ? componentIdComparison : _include.CompareTo(other._include); @@ -108,22 +109,31 @@ public int CompareTo(Subscription other) /// /// Подписка для сравнения /// Возвращает true, если подписки равны; иначе false - public bool Equals(Subscription other) => _include == other._include && - _pool.Id == other._pool.Id; + public bool Equals(Subscription other) + { + return _include == other._include && + _pool.Id == other._pool.Id; + } /// /// Определяет, равен ли указанный объект текущей подписке. /// /// Объект для сравнения /// Возвращает true, если объекты равны; иначе false - public override bool Equals(object? obj) => obj is Subscription other && Equals(other); + public override bool Equals(object? obj) + { + return obj is Subscription other && Equals(other); + } /// /// Возвращает хеш-код для текущей подписки. /// /// Хеш-код - public override int GetHashCode() => HashCode.Combine(_pool.Id, _include ? 2 : 3); + public override int GetHashCode() + { + return HashCode.Combine(_pool.Id, _include ? 2 : 3); + } #endregion } -} \ No newline at end of file +} diff --git a/src/Hexecs/Actors/ActorContext.Bounds.cs b/src/Hexecs/Actors/ActorContext.Bounds.cs index 7b3c282..af375ec 100644 --- a/src/Hexecs/Actors/ActorContext.Bounds.cs +++ b/src/Hexecs/Actors/ActorContext.Bounds.cs @@ -1,4 +1,5 @@ using Hexecs.Actors.Bounds; +using Hexecs.Actors.Components; using Hexecs.Assets; namespace Hexecs.Actors; @@ -13,8 +14,12 @@ public sealed partial class ActorContext /// Возникает, если актёр не имеет привязанного ассета public Asset GetBoundAsset(ActorId actorId) { - ref var component = ref TryGetComponentRef(actorId); - if (Unsafe.IsNullRef(ref component)) ActorError.AssetNotFound(actorId); + ref BoundComponent component = ref TryGetComponentRef(actorId); + + if (Unsafe.IsNullRef(ref component)) + { + ActorError.AssetNotFound(actorId); + } return World.Assets.GetAsset(component.AssetId); } @@ -27,14 +32,17 @@ public Asset GetBoundAsset(ActorId actorId) /// Возвращает true, если актёр имеет привязанный ассет, иначе false public bool TryGetBoundAsset(ActorId actorId, out Asset asset) { - ref var component = ref TryGetComponentRef(actorId); + ref BoundComponent component = ref TryGetComponentRef(actorId); + if (Unsafe.IsNullRef(ref component)) { asset = Asset.Empty; + return false; } asset = World.Assets.GetAsset(component.AssetId); + return true; } @@ -45,7 +53,8 @@ public bool TryGetBoundAsset(ActorId actorId, out Asset asset) /// Ассет для привязки internal void SetBoundAsset(ActorId actorId, in Asset asset) { - var pool = GetOrCreateComponentPool(); + ActorComponentPool pool = GetOrCreateComponentPool(); + if (asset.IsEmpty) { pool.Remove(actorId); @@ -53,10 +62,11 @@ internal void SetBoundAsset(ActorId actorId, in Asset asset) else { var component = new BoundComponent(asset.Id); + if (!pool.Update(actorId, component)) { pool.Add(actorId, component); } } } -} \ No newline at end of file +} diff --git a/src/Hexecs/Actors/ActorContext.Builders.cs b/src/Hexecs/Actors/ActorContext.Builders.cs index c7f88f3..1fd66f2 100644 --- a/src/Hexecs/Actors/ActorContext.Builders.cs +++ b/src/Hexecs/Actors/ActorContext.Builders.cs @@ -20,16 +20,20 @@ public sealed partial class ActorContext /// public Actor BuildActor(in Asset asset, Args? args = null) { - var actorIdRaw = GetNextActorId(); + uint actorIdRaw = GetNextActorId(); AddEntry(actorIdRaw); var actor = new Actor(this, new ActorId(actorIdRaw)); - if (asset.IsEmpty) return actor; - + if (asset.IsEmpty) + { + return actor; + } + args ??= Args.Rent(); - foreach (var builder in _builders) + + foreach (IActorBuilder builder in _builders) { builder.Build(in actor, in asset, args); } @@ -44,4 +48,4 @@ internal void LoadBuilders(IEnumerable builders) { _builders = [.. builders]; } -} \ No newline at end of file +} diff --git a/src/Hexecs/Actors/ActorContext.Children.cs b/src/Hexecs/Actors/ActorContext.Children.cs index 654ac46..905781e 100644 --- a/src/Hexecs/Actors/ActorContext.Children.cs +++ b/src/Hexecs/Actors/ActorContext.Children.cs @@ -6,11 +6,17 @@ public sealed partial class ActorContext { public void AddChild(ActorId parentId, ActorId childId) { - if (parentId == childId) return; + if (parentId == childId) + { + return; + } - ref var childNode = ref GetOrAddComponent(childId); + ref ActorNodeComponent childNode = ref GetOrAddComponent(childId); - if (childNode.ParentId == parentId) return; + if (childNode.ParentId == parentId) + { + return; + } // Если у ребенка уже есть родитель — отсоединяем if (childNode.ParentId.IsNotEmpty) @@ -18,17 +24,17 @@ public void AddChild(ActorId parentId, ActorId childId) RemoveChild(childNode.ParentId, childId); } - ref var parentNode = ref GetOrAddComponent(parentId); + ref ActorNodeComponent parentNode = ref GetOrAddComponent(parentId); // Вставляем ребенка в начало списка детей родителя - var oldFirstId = parentNode.FirstChildId; + ActorId oldFirstId = parentNode.FirstChildId; childNode.ParentId = parentId; childNode.NextSiblingId = oldFirstId; childNode.PrevSiblingId = ActorId.Empty; if (oldFirstId.IsNotEmpty) { - ref var oldFirstNode = ref GetComponent(oldFirstId); + ref ActorNodeComponent oldFirstNode = ref GetComponent(oldFirstId); oldFirstNode.PrevSiblingId = childId; } @@ -38,7 +44,8 @@ public void AddChild(ActorId parentId, ActorId childId) public ChildrenEnumerator Children(ActorId parentId) { - ref var component = ref TryGetComponentRef(parentId); + ref ActorNodeComponent component = ref TryGetComponentRef(parentId); + return Unsafe.IsNullRef(ref component) || component.FirstChildId.IsEmpty ? ChildrenEnumerator.Empty : new ChildrenEnumerator(this, component.FirstChildId, component.ChildCount); @@ -46,12 +53,19 @@ public ChildrenEnumerator Children(ActorId parentId) public bool HasChild(ActorId parentId, ActorId childId) { - ref var component = ref TryGetComponentRef(parentId); - if (Unsafe.IsNullRef(ref component) || component.FirstChildId.IsEmpty) return false; + ref ActorNodeComponent component = ref TryGetComponentRef(parentId); + + if (Unsafe.IsNullRef(ref component) || component.FirstChildId.IsEmpty) + { + return false; + } - foreach (var child in Children(parentId)) + foreach (Actor child in Children(parentId)) { - if (child.Id == childId) return true; + if (child.Id == childId) + { + return true; + } } return false; @@ -59,16 +73,24 @@ public bool HasChild(ActorId parentId, ActorId childId) public bool RemoveChild(ActorId parentId, ActorId childId) { - ref var parentNode = ref TryGetComponentRef(parentId); - if (Unsafe.IsNullRef(ref parentNode)) return false; + ref ActorNodeComponent parentNode = ref TryGetComponentRef(parentId); - ref var childNode = ref TryGetComponentRef(childId); - if (Unsafe.IsNullRef(ref childNode) || childNode.ParentId != parentId) return false; + if (Unsafe.IsNullRef(ref parentNode)) + { + return false; + } + + ref ActorNodeComponent childNode = ref TryGetComponentRef(childId); + + if (Unsafe.IsNullRef(ref childNode) || childNode.ParentId != parentId) + { + return false; + } // 1. Обновляем ссылку у предыдущего соседа или у родителя if (childNode.PrevSiblingId.IsNotEmpty) { - ref var prevNode = ref GetComponent(childNode.PrevSiblingId); + ref ActorNodeComponent prevNode = ref GetComponent(childNode.PrevSiblingId); prevNode.NextSiblingId = childNode.NextSiblingId; } else @@ -80,7 +102,7 @@ public bool RemoveChild(ActorId parentId, ActorId childId) // 2. Обновляем ссылку у следующего соседа if (childNode.NextSiblingId.IsNotEmpty) { - ref var nextNode = ref GetComponent(childNode.NextSiblingId); + ref ActorNodeComponent nextNode = ref GetComponent(childNode.NextSiblingId); nextNode.PrevSiblingId = childNode.PrevSiblingId; } @@ -95,32 +117,41 @@ public bool RemoveChild(ActorId parentId, ActorId childId) public bool TryGetParent(ActorId childId, out Actor parent) { - ref var component = ref TryGetComponentRef(childId); + ref ActorNodeComponent component = ref TryGetComponentRef(childId); + if (!Unsafe.IsNullRef(ref component) && component.ParentId.IsNotEmpty) { parent = new Actor(this, component.ParentId); + return true; } parent = Actor.Empty; + return false; } private void OnNodeRemoving(ref ActorNodeComponent node) { - var parentId = node.ParentId; + ActorId parentId = node.ParentId; + if (parentId.IsNotEmpty) { - ref var parentNode = ref TryGetComponentRef(parentId); + ref ActorNodeComponent parentNode = ref TryGetComponentRef(parentId); + if (!Unsafe.IsNullRef(ref parentNode)) { - var prevId = node.PrevSiblingId; - var nextId = node.NextSiblingId; + ActorId prevId = node.PrevSiblingId; + ActorId nextId = node.NextSiblingId; if (prevId.IsNotEmpty) { - ref var prevNode = ref TryGetComponentRef(prevId); - if (!Unsafe.IsNullRef(ref prevNode)) prevNode.NextSiblingId = nextId; + ref ActorNodeComponent prevNode = ref TryGetComponentRef(prevId); + + if (!Unsafe.IsNullRef(ref prevNode)) + { + prevNode.NextSiblingId = nextId; + } } else { @@ -129,8 +160,12 @@ private void OnNodeRemoving(ref ActorNodeComponent node) if (nextId.IsNotEmpty) { - ref var nextNode = ref TryGetComponentRef(nextId); - if (!Unsafe.IsNullRef(ref nextNode)) nextNode.PrevSiblingId = prevId; + ref ActorNodeComponent nextNode = ref TryGetComponentRef(nextId); + + if (!Unsafe.IsNullRef(ref nextNode)) + { + nextNode.PrevSiblingId = prevId; + } } parentNode.ChildCount--; @@ -138,13 +173,18 @@ private void OnNodeRemoving(ref ActorNodeComponent node) } // 2. У всех детей обнуляем ссылки (теперь они сироты без соседей) - var currentChildId = node.FirstChildId; + ActorId currentChildId = node.FirstChildId; + while (currentChildId.IsNotEmpty) { - ref var childNode = ref TryGetComponentRef(currentChildId); - if (Unsafe.IsNullRef(ref childNode)) break; + ref ActorNodeComponent childNode = ref TryGetComponentRef(currentChildId); + + if (Unsafe.IsNullRef(ref childNode)) + { + break; + } - var nextSiblingId = childNode.NextSiblingId; + ActorId nextSiblingId = childNode.NextSiblingId; childNode.ParentId = ActorId.Empty; childNode.PrevSiblingId = ActorId.Empty; @@ -153,4 +193,4 @@ private void OnNodeRemoving(ref ActorNodeComponent node) currentChildId = nextSiblingId; } } -} \ No newline at end of file +} diff --git a/src/Hexecs/Actors/ActorContext.ChildrenEnumerator.cs b/src/Hexecs/Actors/ActorContext.ChildrenEnumerator.cs index 718ba0f..a8ba2c2 100644 --- a/src/Hexecs/Actors/ActorContext.ChildrenEnumerator.cs +++ b/src/Hexecs/Actors/ActorContext.ChildrenEnumerator.cs @@ -9,13 +9,13 @@ public ref struct ChildrenEnumerator public static ChildrenEnumerator Empty { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => new(); + get => new ChildrenEnumerator(); } public readonly Actor Current { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => new(_context, _currentId); + get => new Actor(_context, _currentId); } public readonly int Length @@ -41,26 +41,35 @@ internal ChildrenEnumerator(ActorContext context, ActorId firstChildId, uint cou [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool MoveNext() { - if (_nextId.IsEmpty) return false; + if (_nextId.IsEmpty) + { + return false; + } _currentId = _nextId; - ref var node = ref _context.GetComponent(_currentId); + ref ActorNodeComponent node = ref _context.GetComponent(_currentId); _nextId = node.NextSiblingId; return true; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public readonly ChildrenEnumerator GetEnumerator() => this; + public readonly ChildrenEnumerator GetEnumerator() + { + return this; + } public Actor[] ToArray() { - if (_count == 0) return []; + if (_count == 0) + { + return []; + } var result = new Actor[_count]; var index = 0; - foreach (var actor in this) + foreach (Actor actor in this) { result[index++] = actor; } @@ -68,4 +77,4 @@ public Actor[] ToArray() return result; } } -} \ No newline at end of file +} diff --git a/src/Hexecs/Actors/ActorContext.ComponenetEnumerator.cs b/src/Hexecs/Actors/ActorContext.ComponenetEnumerator.cs index 1e27bd0..a1ae03c 100644 --- a/src/Hexecs/Actors/ActorContext.ComponenetEnumerator.cs +++ b/src/Hexecs/Actors/ActorContext.ComponenetEnumerator.cs @@ -9,7 +9,7 @@ public ref struct ComponentEnumerator public static ComponentEnumerator Empty { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => new(); + get => new ComponentEnumerator(); } public readonly IActorComponent Current @@ -23,7 +23,7 @@ public readonly int Length [MethodImpl(MethodImplOptions.AggressiveInlining)] get => _componentIds.Length; } - + private int _index; private readonly ActorId _actorId; private readonly ReadOnlySpan _componentIds; @@ -48,18 +48,28 @@ internal ComponentEnumerator(ActorId actorId, IActorComponentPool?[] pools, Read } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool MoveNext() => ++_index < _componentIds.Length; + public bool MoveNext() + { + return ++_index < _componentIds.Length; + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public readonly ComponentEnumerator GetEnumerator() => this; + public readonly ComponentEnumerator GetEnumerator() + { + return this; + } public readonly IActorComponent[] ToArray() { - var ids = _componentIds; + ReadOnlySpan ids = _componentIds; + + if (ids.Length == 0) + { + return []; + } - if (ids.Length == 0) return []; + IActorComponent[] array = ArrayUtils.Create(ids.Length); - var array = ArrayUtils.Create(ids.Length); for (var i = 0; i < ids.Length; i++) { array[i] = _pools[ids[i]]!.Get(_actorId); @@ -68,4 +78,4 @@ public readonly IActorComponent[] ToArray() return array; } } -} \ No newline at end of file +} diff --git a/src/Hexecs/Actors/ActorContext.Components.cs b/src/Hexecs/Actors/ActorContext.Components.cs index 0d5a3b0..73afc53 100644 --- a/src/Hexecs/Actors/ActorContext.Components.cs +++ b/src/Hexecs/Actors/ActorContext.Components.cs @@ -8,9 +8,9 @@ public sealed partial class ActorContext { private IActorComponentPool?[] _componentPools; #if NET9_0_OR_GREATER - private readonly Lock _componentPoolLock = new(); + private readonly Lock _componentPoolLock = new Lock(); #else - private readonly object _componentPoolLock = new(); + private readonly object _componentPoolLock = new object(); #endif private readonly IActorComponentConfiguration?[] _componentConfigurations; @@ -24,10 +24,10 @@ public sealed partial class ActorContext public ref T AddComponent(ActorId actorId, in T component) where T : struct, IActorComponent { - var pool = GetOrCreateComponentPool(); - ref var result = ref pool.Add(actorId, in component); + ActorComponentPool pool = GetOrCreateComponentPool(); + ref T result = ref pool.Add(actorId, in component); - ref var entry = ref GetEntryRefExact(actorId.Value); + ref Entry entry = ref GetEntryRefExact(actorId.Value); entry.Add(ActorComponentType.Id); return ref result; @@ -44,16 +44,22 @@ public ref T AddComponent(ActorId actorId, in T component) /// Выбрасывается, если компонент типа уже существует у того актёра, которому клонируется компонент. public ref T CloneComponent(ActorId ownerId, ActorId cloneId) where T : struct, IActorComponent { - var pool = GetComponentPool(); - if (pool == null) ActorError.ComponentNotFound(ownerId); + ActorComponentPool? pool = GetComponentPool(); + + if (pool == null) + { + ActorError.ComponentNotFound(ownerId); + } + + ref Entry clone = ref GetEntryRefExact(cloneId.Value); - ref var clone = ref GetEntryRefExact(cloneId.Value); if (clone.TryAdd(ActorComponentType.Id)) { return ref pool.Clone(ownerId, cloneId); } ActorError.ComponentExists(cloneId); + return ref Unsafe.NullRef(); } @@ -65,7 +71,8 @@ public ref T CloneComponent(ActorId ownerId, ActorId cloneId) where T : struc /// Перечислитель компонентов. Возвращает , если актёр не найден. public ComponentEnumerator Components(ActorId actorId) { - ref var entry = ref GetEntryRef(actorId.Value); + ref Entry entry = ref GetEntryRef(actorId.Value); + return Unsafe.IsNullRef(ref entry) ? ComponentEnumerator.Empty : new ComponentEnumerator(actorId, _componentPools, entry.ToArray()); @@ -80,15 +87,21 @@ public ComponentEnumerator Components(ActorId actorId) /// Выбрасывается, если актёр не имеет компонента типа . public ref T GetComponent(ActorId actorId) where T : struct, IActorComponent { - var pool = GetComponentPool(); - if (pool == null) ActorError.ComponentNotFound(actorId); + ActorComponentPool? pool = GetComponentPool(); + + if (pool == null) + { + ActorError.ComponentNotFound(actorId); + } + return ref pool.Get(actorId); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public ComponentsAccess GetComponents() where T : struct, IActorComponent { - var pool = GetComponentPool(); + ActorComponentPool? pool = GetComponentPool(); + return pool != null ? pool.GetComponentAccess() : new ComponentsAccess(); @@ -104,13 +117,13 @@ public ComponentsAccess GetComponents() where T : struct, IActorComponent public ref T GetOrAddComponent(ActorId actorId, Func? factory = null) where T : struct, IActorComponent { - var pool = GetOrCreateComponentPool(); - ref var component = ref pool.GetOrCreate(actorId, out var added, factory); + ActorComponentPool pool = GetOrCreateComponentPool(); + ref T component = ref pool.GetOrCreate(actorId, out bool added, factory); // ReSharper disable once InvertIf if (added) { - ref var entry = ref GetEntryRefExact(actorId.Value); + ref Entry entry = ref GetEntryRefExact(actorId.Value); entry.Add(ActorComponentType.Id); } @@ -126,7 +139,8 @@ public ref T GetOrAddComponent(ActorId actorId, Func? factory = n [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool HasComponent(ActorId actorId) where T : struct, IActorComponent { - var pool = GetComponentPool(); + ActorComponentPool? pool = GetComponentPool(); + return pool != null && pool.Has(actorId); } @@ -138,7 +152,7 @@ public bool HasComponent(ActorId actorId) where T : struct, IActorComponent public void OnComponentAdded(Action handler) where T : struct, IActorComponent { - var pool = GetOrCreateComponentPool(); + ActorComponentPool pool = GetOrCreateComponentPool(); pool.Added += handler; } @@ -150,7 +164,7 @@ public void OnComponentAdded(Action handler) public void OnComponentAdded(ActorComponentAdded handler) where T : struct, IActorComponent { - var pool = GetOrCreateComponentPool(); + ActorComponentPool pool = GetOrCreateComponentPool(); pool.ComponentAdded += handler; } @@ -162,7 +176,7 @@ public void OnComponentAdded(ActorComponentAdded handler) public void OnComponentRemoving(Action handler) where T : struct, IActorComponent { - var pool = GetOrCreateComponentPool(); + ActorComponentPool pool = GetOrCreateComponentPool(); pool.Removing += handler; } @@ -174,7 +188,7 @@ public void OnComponentRemoving(Action handler) public void OnComponentRemoving(ActorComponentRemoving handler) where T : struct, IActorComponent { - var pool = GetOrCreateComponentPool(); + ActorComponentPool pool = GetOrCreateComponentPool(); pool.ComponentRemoving += handler; } @@ -186,7 +200,7 @@ public void OnComponentRemoving(ActorComponentRemoving handler) public void OnComponentUpdating(ActorComponentUpdating handler) where T : struct, IActorComponent { - var pool = GetOrCreateComponentPool(); + ActorComponentPool pool = GetOrCreateComponentPool(); pool.ComponentUpdating += handler; } @@ -199,11 +213,13 @@ public void OnComponentUpdating(ActorComponentUpdating handler) public bool RemoveComponent(ActorId actorId) where T : struct, IActorComponent { - var pool = GetComponentPool(); + ActorComponentPool? pool = GetComponentPool(); + if (pool != null && pool.Remove(actorId)) { - ref var entry = ref GetEntryRefExact(actorId.Value); + ref Entry entry = ref GetEntryRefExact(actorId.Value); entry.Remove(ActorComponentType.Id); + return true; } @@ -220,14 +236,16 @@ public bool RemoveComponent(ActorId actorId) public bool RemoveComponent(ActorId actorId, out T component) where T : struct, IActorComponent { - var pool = GetComponentPool(); + ActorComponentPool? pool = GetComponentPool(); + if (pool == null || !pool.Remove(actorId, out component)) { component = default; + return false; } - ref var entry = ref GetEntryRefExact(actorId.Value); + ref Entry entry = ref GetEntryRefExact(actorId.Value); entry.Remove(ActorComponentType.Id); return true; @@ -243,13 +261,17 @@ public bool RemoveComponent(ActorId actorId, out T component) public bool TryAdd(ActorId actorId, in T component) where T : struct, IActorComponent { - var pool = GetOrCreateComponentPool(); - var result = pool.TryAdd(actorId, in component); + ActorComponentPool pool = GetOrCreateComponentPool(); + bool result = pool.TryAdd(actorId, in component); - if (!result) return false; + if (!result) + { + return false; + } - ref var entry = ref GetEntryRefExact(actorId.Value); + ref Entry entry = ref GetEntryRefExact(actorId.Value); entry.Add(ActorComponentType.Id); + return true; } @@ -263,7 +285,8 @@ public bool TryAdd(ActorId actorId, in T component) public ref T TryGetComponentRef(ActorId actorId) where T : struct, IActorComponent { - var pool = GetComponentPool(); + ActorComponentPool? pool = GetComponentPool(); + if (pool != null) { return ref pool.TryGet(actorId.Value); @@ -283,14 +306,25 @@ public ref T TryGetComponentRef(ActorId actorId) public bool UpdateComponent(ActorId actorId, in T component, bool createIfNotExists = true) where T : struct, IActorComponent { - var pool = GetComponentPool(); - if (pool == null) return false; + ActorComponentPool? pool = GetComponentPool(); - if (pool.Update(actorId, in component)) return true; + if (pool == null) + { + return false; + } - if (!createIfNotExists) return false; + if (pool.Update(actorId, in component)) + { + return true; + } + + if (!createIfNotExists) + { + return false; + } AddComponent(actorId, in component); + return true; } @@ -307,12 +341,13 @@ public bool UpdateComponent(ActorId actorId, in T component, bool createIfNot [MethodImpl(MethodImplOptions.AggressiveInlining)] internal ActorComponentPool? GetComponentPool() where T : struct, IActorComponent { - var id = ActorComponentType.Id; - var pools = _componentPools; + ushort id = ActorComponentType.Id; + IActorComponentPool?[] pools = _componentPools; if (id < pools.Length) { - var pool = pools[id]; + IActorComponentPool? pool = pools[id]; + return pool == null ? null : Unsafe.As>(pool); @@ -331,12 +366,13 @@ public bool UpdateComponent(ActorId actorId, in T component, bool createIfNot [MethodImpl(MethodImplOptions.AggressiveInlining)] internal ActorComponentPool GetOrCreateComponentPool() where T : struct, IActorComponent { - var id = ActorComponentType.Id; - var pools = _componentPools; + ushort id = ActorComponentType.Id; + IActorComponentPool?[] pools = _componentPools; if ((uint)id < (uint)pools.Length) { - var existsPool = pools[id]; + IActorComponentPool? existsPool = pools[id]; + if (existsPool != null) { return Unsafe.As>(existsPool); @@ -358,12 +394,16 @@ private ActorComponentPool CreateComponentPoolSlow(ushort id) where T : st // Повторная проверка под локом (Double-Check Locking) if (id < _componentPools.Length) { - var existsPool = _componentPools[id]; - if (existsPool != null) return Unsafe.As>(existsPool); + IActorComponentPool? existsPool = _componentPools[id]; + + if (existsPool != null) + { + return Unsafe.As>(existsPool); + } } ArrayUtils.EnsureCapacity(ref _componentPools, id); - ref var pool = ref _componentPools[id]; + ref IActorComponentPool? pool = ref _componentPools[id]; pool ??= new ActorComponentPool(this, GetOrCreateComponentConfiguration()); return Unsafe.As>(pool); @@ -373,13 +413,17 @@ private ActorComponentPool CreateComponentPoolSlow(ushort id) where T : st private ActorComponentConfiguration GetOrCreateComponentConfiguration() where T : struct, IActorComponent { - var id = ActorComponentType.Id; + ushort id = ActorComponentType.Id; + + if (id >= _componentConfigurations.Length) + { + return ActorComponentConfiguration.Empty; + } - if (id >= _componentConfigurations.Length) return ActorComponentConfiguration.Empty; + IActorComponentConfiguration? existsConfiguration = _componentConfigurations[id]; - var existsConfiguration = _componentConfigurations[id]; return existsConfiguration == null ? ActorComponentConfiguration.Empty : Unsafe.As>(existsConfiguration); } -} \ No newline at end of file +} diff --git a/src/Hexecs/Actors/ActorContext.DependencyProvider.cs b/src/Hexecs/Actors/ActorContext.DependencyProvider.cs index 4f0f296..591b91c 100644 --- a/src/Hexecs/Actors/ActorContext.DependencyProvider.cs +++ b/src/Hexecs/Actors/ActorContext.DependencyProvider.cs @@ -7,11 +7,20 @@ public sealed partial class ActorContext : IDependencyProvider private readonly DependencyProvider _dependencyProvider; [MethodImpl(MethodImplOptions.AggressiveInlining)] - public object? GetService(Type contract) => _dependencyProvider.GetService(contract); + public object? GetService(Type contract) + { + return _dependencyProvider.GetService(contract); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public TService? GetService() where TService : class => _dependencyProvider.GetService(); + public TService? GetService() where TService : class + { + return _dependencyProvider.GetService(); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public TService[] GetServices() where TService : class => _dependencyProvider.GetServices(); -} \ No newline at end of file + public TService[] GetServices() where TService : class + { + return _dependencyProvider.GetServices(); + } +} diff --git a/src/Hexecs/Actors/ActorContext.Dictionary.cs b/src/Hexecs/Actors/ActorContext.Dictionary.cs index 5c6d4df..071245e 100644 --- a/src/Hexecs/Actors/ActorContext.Dictionary.cs +++ b/src/Hexecs/Actors/ActorContext.Dictionary.cs @@ -1,4 +1,5 @@ -using Hexecs.Actors.Nodes; +using Hexecs.Actors.Components; +using Hexecs.Actors.Nodes; using Hexecs.Actors.Relations; namespace Hexecs.Actors; @@ -23,39 +24,44 @@ public int Length private ref Entry AddEntry(uint actorId) { - ref var entry = ref TryAddEntry(actorId); + ref Entry entry = ref TryAddEntry(actorId); + if (!Unsafe.IsNullRef(ref entry)) { Created?.Invoke(new ActorId(actorId)); + return ref entry; } ActorError.AlreadyExists(actorId); // выбрасывает ошибку + return ref Unsafe.NullRef(); } private void ClearEntry(uint actorIdRaw, ref Entry entry) { var actorId = new ActorId(actorIdRaw); - ref var node = ref TryGetComponentRef(actorId); + ref ActorNodeComponent node = ref TryGetComponentRef(actorId); + if (!Unsafe.IsNullRef(ref node)) { OnNodeRemoving(ref node); } - - ref var relationsComponent = ref TryGetComponentRef(actorId); + + ref ActorRelationComponent relationsComponent = ref TryGetComponentRef(actorId); + if (!Unsafe.IsNullRef(ref relationsComponent)) { - foreach (var relationId in relationsComponent) + foreach (uint relationId in relationsComponent) { - var relationPool = _relationPools[relationId]; + IActorRelationPool? relationPool = _relationPools[relationId]; relationPool?.Remove(actorId); } } - foreach (var componentId in entry) + foreach (ushort componentId in entry) { - var componentPool = _componentPools[componentId]; + IActorComponentPool? componentPool = _componentPools[componentId]; componentPool?.Remove(actorId); } @@ -64,15 +70,15 @@ private void ClearEntry(uint actorIdRaw, ref Entry entry) private void ClearEntries() { - var dense = _dense; - var values = _values; - var sparsePages = _sparsePages; + uint[] dense = _dense; + Entry[] values = _values; + uint[]?[] sparsePages = _sparsePages; for (var i = 0; i < _count; i++) { - var key = dense[i]; + uint key = dense[i]; - ref var entry = ref values[i]; + ref Entry entry = ref values[i]; entry.Dispose(); var pageIndex = (int)(key >> PageBits); @@ -86,7 +92,7 @@ private void EnsureDenseCapacity() { if (_count >= _dense.Length) { - var newSize = _dense.Length * 2; + int newSize = _dense.Length * 2; Array.Resize(ref _dense, newSize); Array.Resize(ref _values, newSize); } @@ -96,7 +102,7 @@ private void EnsurePageArraySize(int pageIndex) { if (pageIndex >= _sparsePages.Length) { - var newSize = Math.Max(_sparsePages.Length * 2, pageIndex + 1); + int newSize = Math.Max(_sparsePages.Length * 2, pageIndex + 1); Array.Resize(ref _sparsePages, newSize); } } @@ -105,15 +111,19 @@ private void EnsurePageArraySize(int pageIndex) private ref Entry GetEntryRef(uint actorId) { var pageIndex = (int)(actorId >> PageBits); + if ((uint)pageIndex < (uint)_sparsePages.Length) { - var page = _sparsePages[pageIndex]; + uint[]? page = _sparsePages[pageIndex]; + if (page != null) { - var denseIndexPlusOne = page[actorId & PageMask]; + uint denseIndexPlusOne = page[actorId & PageMask]; + if (denseIndexPlusOne != 0) { - var index = (int)denseIndexPlusOne - 1; + int index = (int)denseIndexPlusOne - 1; + if (_dense[index] == actorId) { return ref _values[index]; @@ -127,48 +137,67 @@ private ref Entry GetEntryRef(uint actorId) private ref Entry GetEntryRefExact(uint key) { - ref var entry = ref GetEntryRef(key); + ref Entry entry = ref GetEntryRef(key); + if (!Unsafe.IsNullRef(ref entry)) { return ref entry; } ActorError.NotFound(key); // exception + return ref Unsafe.NullRef(); } private bool RemoveEntry(uint actorId) { var pageIndex = (int)(actorId >> PageBits); - if ((uint)pageIndex >= (uint)_sparsePages.Length) return false; - var page = _sparsePages[pageIndex]; - if (page == null) return false; + if ((uint)pageIndex >= (uint)_sparsePages.Length) + { + return false; + } + + uint[]? page = _sparsePages[pageIndex]; + + if (page == null) + { + return false; + } var offset = (int)(actorId & PageMask); - var denseIndexPlusOne = page[offset]; - if (denseIndexPlusOne == 0) return false; + uint denseIndexPlusOne = page[offset]; + + if (denseIndexPlusOne == 0) + { + return false; + } - var denseIndex = (int)denseIndexPlusOne - 1; - if (_dense[denseIndex] != actorId) return false; + int denseIndex = (int)denseIndexPlusOne - 1; + + if (_dense[denseIndex] != actorId) + { + return false; + } // 1. Уведомляем системы ПЕРЕД какими-либо изменениями структуры Destroying?.Invoke(new ActorId(actorId)); // 2. Очищаем данные сущности (пулы компонентов и т.д.) - ref var entryToRemove = ref _values[denseIndex]; + ref Entry entryToRemove = ref _values[denseIndex]; ClearEntry(actorId, ref entryToRemove); - var lastIndex = _count - 1; + int lastIndex = _count - 1; + if (denseIndex != lastIndex) { - var lastKey = _dense[lastIndex]; + uint lastKey = _dense[lastIndex]; // Переносим ключ _dense[denseIndex] = lastKey; - // ВАЖНО: Переносим данные. - // Поскольку мы уже вызвали ClearEntry для entryToRemove, + // ВАЖНО: Переносим данные. + // Поскольку мы уже вызвали ClearEntry для entryToRemove, // мы можем просто перезаписать её. _values[denseIndex] = _values[lastIndex]; @@ -178,8 +207,8 @@ private bool RemoveEntry(uint actorId) } // 3. ОБЯЗАТЕЛЬНО обнуляем хвост, чтобы не было дубликатов ссылок на массивы - _values[lastIndex] = default; - + _values[lastIndex] = default; + // 4. Финализируем удаление page[offset] = 0; _count = lastIndex; @@ -191,15 +220,17 @@ private bool RemoveEntry(uint actorId) private ref Entry TryAddEntry(uint actorId) { var pageIndex = (int)(actorId >> PageBits); - var pages = _sparsePages; + uint[]?[] pages = _sparsePages; // Максимально компактная проверка на готовность страницы и места if ((uint)pageIndex < (uint)pages.Length) { - var page = pages[pageIndex]; + uint[]? page = pages[pageIndex]; + if (page != null && (uint)_count < (uint)_dense.Length) { - ref var slot = ref page[actorId & PageMask]; + ref uint slot = ref page[actorId & PageMask]; + if (slot == 0) // Чистая вставка (самый частый случай в ECS) { var idx = (uint)_count; @@ -228,14 +259,16 @@ private ref Entry TryAddEntrySlow(uint actorId) var pageIndex = (int)(actorId >> PageBits); EnsurePageArraySize(pageIndex); - ref var page = ref _sparsePages[pageIndex]; + ref uint[]? page = ref _sparsePages[pageIndex]; + if (page == null) { page = ArrayUtils.Create(PageSize); Array.Clear(page, 0, page.Length); } - ref var denseIndexPlusOne = ref page[actorId & PageMask]; + ref uint denseIndexPlusOne = ref page[actorId & PageMask]; + if (denseIndexPlusOne != 0) { if (_dense[denseIndexPlusOne - 1] == actorId) @@ -251,4 +284,4 @@ private ref Entry TryAddEntrySlow(uint actorId) return ref _values[denseIndex]; } -} \ No newline at end of file +} diff --git a/src/Hexecs/Actors/ActorContext.Entry.cs b/src/Hexecs/Actors/ActorContext.Entry.cs index 03afa77..d1e8e09 100644 --- a/src/Hexecs/Actors/ActorContext.Entry.cs +++ b/src/Hexecs/Actors/ActorContext.Entry.cs @@ -1,4 +1,5 @@ using System.Text.Json; + using Hexecs.Serializations; namespace Hexecs.Actors; @@ -23,11 +24,20 @@ public int Length public void Add(ushort item) { - if (_length < InlineArraySize) _inlineArray[_length] = item; + if (_length < InlineArraySize) + { + _inlineArray[_length] = item; + } else { - if (_array == null) _array = ArrayPool.Shared.Rent(InlineArraySize); - else ArrayUtils.Insert(ref _array, ArrayPool.Shared, _length - InlineArraySize, item); + if (_array == null) + { + _array = ArrayPool.Shared.Rent(InlineArraySize); + } + else + { + ArrayUtils.Insert(ref _array, ArrayPool.Shared, _length - InlineArraySize, item); + } } _length++; @@ -35,24 +45,33 @@ public void Add(ushort item) public void Dispose() { - if (_array is { Length: > 0 }) ArrayPool.Shared.Return(_array); + if (_array is { Length: > 0 }) + { + ArrayPool.Shared.Return(_array); + } + _array = null; _length = 0; } public readonly EntryComponentEnumerator GetEnumerator() { - ref var inlineRef = ref Unsafe.AsRef(in _inlineArray); - ref var reference = ref Unsafe.As(ref inlineRef); - var span = MemoryMarshal.CreateSpan(ref reference, InlineArraySize); + ref InlineItemArray inlineRef = ref Unsafe.AsRef(in _inlineArray); + ref ushort reference = ref Unsafe.As(ref inlineRef); + Span span = MemoryMarshal.CreateSpan(ref reference, InlineArraySize); + return new EntryComponentEnumerator(span, _array ?? [], _length); } public readonly int IndexOf(ushort item) { - if (_length == 0) return -1; + if (_length == 0) + { + return -1; + } + + int inlineLength = Math.Min(_length, InlineArraySize); - var inlineLength = Math.Min(_length, InlineArraySize); for (var i = 0; i < inlineLength; i++) { if (_inlineArray[i] == item) @@ -61,12 +80,19 @@ public readonly int IndexOf(ushort item) } } - if (_array == null || _array.Length == 0) return -1; + if (_array == null || _array.Length == 0) + { + return -1; + } + + Span span = _array.AsSpan(0, _length - InlineArraySize); - var span = _array.AsSpan(0, _length - InlineArraySize); for (var i = 0; i < span.Length; i++) { - if (span[i] == item) return InlineArraySize + i; + if (span[i] == item) + { + return InlineArraySize + i; + } } return -1; @@ -74,17 +100,24 @@ public readonly int IndexOf(ushort item) public bool Remove(ushort item) { - if (_length == 0) return false; + if (_length == 0) + { + return false; + } - var arraySize = _length - InlineArraySize; - var inlineLength = Math.Min(_length, InlineArraySize); + int arraySize = _length - InlineArraySize; + int inlineLength = Math.Min(_length, InlineArraySize); for (var index = 0; index < inlineLength; index++) { - if (_inlineArray[index] != item) continue; + if (_inlineArray[index] != item) + { + continue; + } + + int inlineEnd = inlineLength - 1; - var inlineEnd = inlineLength - 1; - for (var i = index; i < inlineEnd; i++) + for (int i = index; i < inlineEnd; i++) { _inlineArray[i] = _inlineArray[i + 1]; } @@ -97,15 +130,24 @@ public bool Remove(ushort item) } _length--; + return true; } - if (_array == null || _array.Length == 0 || arraySize <= 0) return false; + if (_array == null || _array.Length == 0 || arraySize <= 0) + { + return false; + } + + Span span = _array.AsSpan(0, arraySize); - var span = _array.AsSpan(0, arraySize); for (var i = 0; i < span.Length; i++) { - if (span[i] != item) continue; + if (span[i] != item) + { + continue; + } + ArrayUtils.Cut(_array, i, arraySize); _length--; @@ -123,7 +165,8 @@ public readonly void Serialize(uint actorId, Utf8JsonWriter writer) writer.WritePropertyName("Components"); writer.WriteStartArray(); - foreach (var component in this) + + foreach (ushort component in this) { writer.WriteNumberValue(component); } @@ -136,16 +179,21 @@ public readonly void Serialize(uint actorId, Utf8JsonWriter writer) public readonly ushort this[int index] { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => index < InlineArraySize - ? _inlineArray[index] - : _array![index - InlineArraySize]; + get => + index < InlineArraySize + ? _inlineArray[index] + : _array![index - InlineArraySize]; } public readonly ushort[] ToArray() { - if (_length == 0) return []; + if (_length == 0) + { + return []; + } + + ushort[] result = ArrayUtils.Create(_length); - var result = ArrayUtils.Create(_length); for (var i = 0; i < _length; i++) { result[i] = this[i]; @@ -156,10 +204,15 @@ public readonly ushort[] ToArray() public bool TryAdd(ushort item) { - var has = IndexOf(item) > -1; - if (has) return false; + bool has = IndexOf(item) > -1; + + if (has) + { + return false; + } Add(item); + return true; } @@ -168,9 +221,10 @@ public ref struct EntryComponentEnumerator public readonly ref ushort Current { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => ref _index < InlineArraySize - ? ref _inlineArray[_index] - : ref _array[_index - InlineArraySize]; + get => + ref _index < InlineArraySize + ? ref _inlineArray[_index] + : ref _array[_index - InlineArraySize]; } private readonly Span _inlineArray; @@ -188,7 +242,10 @@ internal EntryComponentEnumerator(Span inlineArray, ushort[] array, int } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool MoveNext() => ++_index < _length; + public bool MoveNext() + { + return ++_index < _length; + } } [InlineArray(InlineArraySize)] @@ -197,4 +254,4 @@ private struct InlineItemArray private ushort _item; } } -} \ No newline at end of file +} diff --git a/src/Hexecs/Actors/ActorContext.Enumerator.cs b/src/Hexecs/Actors/ActorContext.Enumerator.cs index 603173a..398c643 100644 --- a/src/Hexecs/Actors/ActorContext.Enumerator.cs +++ b/src/Hexecs/Actors/ActorContext.Enumerator.cs @@ -3,19 +3,28 @@ public sealed partial class ActorContext { [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Enumerator GetEnumerator() => new(this); + public Enumerator GetEnumerator() + { + return new Enumerator(this); + } - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); - [SuppressMessage("ReSharper", "MemberHidesStaticFromOuterClass")] public struct Enumerator : IEnumerator, IEnumerable { public readonly Actor Current { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => new(_context, new ActorId(_dense[_index])); + get => new Actor(_context, new ActorId(_dense[_index])); } public readonly int Length @@ -23,12 +32,12 @@ public readonly int Length [MethodImpl(MethodImplOptions.AggressiveInlining)] get => _count; } - + private int _index; private readonly ActorContext _context; private readonly uint[] _dense; private readonly int _count; - + [MethodImpl(MethodImplOptions.AggressiveInlining)] internal Enumerator(ActorContext context) { @@ -39,10 +48,16 @@ internal Enumerator(ActorContext context) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool MoveNext() => ++_index < _count; + public bool MoveNext() + { + return ++_index < _count; + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public readonly Enumerator GetEnumerator() => this; + public readonly Enumerator GetEnumerator() + { + return this; + } #region Interfaces @@ -56,9 +71,15 @@ readonly void IDisposable.Dispose() { } - readonly IEnumerator IEnumerable.GetEnumerator() => this; + readonly IEnumerator IEnumerable.GetEnumerator() + { + return this; + } - readonly IEnumerator IEnumerable.GetEnumerator() => this; + readonly IEnumerator IEnumerable.GetEnumerator() + { + return this; + } void IEnumerator.Reset() { @@ -67,4 +88,4 @@ void IEnumerator.Reset() #endregion } -} \ No newline at end of file +} diff --git a/src/Hexecs/Actors/ActorContext.Filters.cs b/src/Hexecs/Actors/ActorContext.Filters.cs index 297c08a..6c0b4e9 100644 --- a/src/Hexecs/Actors/ActorContext.Filters.cs +++ b/src/Hexecs/Actors/ActorContext.Filters.cs @@ -20,10 +20,10 @@ public sealed partial class ActorContext public ActorFilter Filter() where T1 : struct, IActorComponent { - var key = typeof(ActorFilter); + Type key = typeof(ActorFilter); // ReSharper disable once InvertIf - if (!_filters.TryGetValue(key, out var collection)) + if (!_filters.TryGetValue(key, out IActorFilter? collection)) { collection = new ActorFilter(this); _filters.Add(key, collection); @@ -46,21 +46,23 @@ public ActorFilter Filter() public ActorFilter Filter(Action constraint) where T1 : struct, IActorComponent { - var builder = ResolveConstraintBuilder(); + ActorConstraint.Builder builder = ResolveConstraintBuilder(); constraint(builder); - foreach (var filter in _filtersWithConstraint) + foreach (IActorFilter filter in _filtersWithConstraint) { // ReSharper disable once InvertIf if (filter is ActorFilter expected && builder.Equals(filter.Constraint)) { ReturnConstraintBuilder(builder); + return expected; } } var newFilter = new ActorFilter(this, FlushConstraintBuilder(builder)); _filtersWithConstraint.Add(newFilter); + return newFilter; } @@ -82,10 +84,10 @@ public ActorFilter Filter() where T1 : struct, IActorComponent where T2 : struct, IActorComponent { - var key = typeof(ActorFilter); + Type key = typeof(ActorFilter); // ReSharper disable once InvertIf - if (!_filters.TryGetValue(key, out var collection)) + if (!_filters.TryGetValue(key, out IActorFilter? collection)) { collection = new ActorFilter(this); _filters.Add(key, collection); @@ -110,21 +112,23 @@ public ActorFilter Filter(Action constr where T1 : struct, IActorComponent where T2 : struct, IActorComponent { - var builder = ResolveConstraintBuilder(); + ActorConstraint.Builder builder = ResolveConstraintBuilder(); constraint(builder); - foreach (var filter in _filtersWithConstraint) + foreach (IActorFilter filter in _filtersWithConstraint) { // ReSharper disable once InvertIf if (filter is ActorFilter expected && builder.Equals(filter.Constraint)) { ReturnConstraintBuilder(builder); + return expected; } } var newFilter = new ActorFilter(this, FlushConstraintBuilder(builder)); _filtersWithConstraint.Add(newFilter); + return newFilter; } @@ -148,10 +152,10 @@ public ActorFilter Filter() where T2 : struct, IActorComponent where T3 : struct, IActorComponent { - var key = typeof(ActorFilter); + Type key = typeof(ActorFilter); // ReSharper disable once InvertIf - if (!_filters.TryGetValue(key, out var collection)) + if (!_filters.TryGetValue(key, out IActorFilter? collection)) { collection = new ActorFilter(this); _filters.Add(key, collection); @@ -178,21 +182,23 @@ public ActorFilter Filter(Action expected && builder.Equals(filter.Constraint)) { ReturnConstraintBuilder(builder); + return expected; } } var newFilter = new ActorFilter(this, FlushConstraintBuilder(builder)); _filtersWithConstraint.Add(newFilter); + return newFilter; } @@ -201,7 +207,7 @@ public ActorFilter Filter(Action(in TQuery query) where TQuery : struct, IQuery { - var handler = GetQueryHandler(); + IQueryHandler handler = GetQueryHandler(); + return handler.Handle(in query); } @@ -42,7 +44,8 @@ public TResult Ask(in TQuery query) public Result Execute(in TCommand command) where TCommand : struct, ICommand { - var handler = GetCommandHandler(); + ICommandHandler handler = GetCommandHandler(); + return handler.Handle(in command); } @@ -58,7 +61,8 @@ public Result Execute(in TCommand command) public TResult Execute(in TCommand command) where TCommand : struct, ICommand { - var handler = GetCommandHandler(); + ICommandHandler handler = GetCommandHandler(); + return handler.Handle(in command); } @@ -71,13 +75,15 @@ public TResult Execute(in TCommand command) public ICommandHandler GetCommandHandler() where TCommand : struct, ICommand { - var id = CommandType.Id; + ushort id = CommandType.Id; + if (id < _commands.Length && _commands[id] is ICommandHandler handler) { return handler; } PipelineError.CommandHandlerNotRegistered(typeof(TCommand)); + return null!; } @@ -90,13 +96,15 @@ public ICommandHandler GetCommandHandler() public IQueryHandler GetQueryHandler() where TQuery : struct, IQuery { - var id = QueryType.Id; + ushort id = QueryType.Id; + if (id < _queries.Length && _queries[id] is IQueryHandler handler) { return handler; } PipelineError.QueryHandlerNotRegistered(typeof(TQuery)); + return null!; } @@ -108,13 +116,15 @@ public IQueryHandler GetQueryHandler() public INotificationHandler GetNotificationHandler() where TNotification : struct, INotification { - var id = NotificationType.Id; + ushort id = NotificationType.Id; + if (id < _notifications.Length && _notifications[id] is INotificationHandler handler) { return handler; } PipelineError.NotificationHandlerNotRegistered(typeof(TNotification)); + return null!; } @@ -126,13 +136,15 @@ public INotificationHandler GetNotificationHandler public IMessageQueue GetMessageQueue() where TMessage : struct, IMessage { - var id = MessageType.Id; + uint id = MessageType.Id; + if (id < _messages.Length && _messages[id] is IMessageQueue queue) { return queue; } PipelineError.MessageHandlerNotRegistered(typeof(TMessage)); + return null!; } @@ -143,7 +155,7 @@ public IMessageQueue GetMessageQueue() /// Группа очередей сообщений или ошибка, если группа не найдена. public IMessageQueue GetMessageQueueGroup(string queueName) { - return _messageGroups.TryGetValue(queueName, out var messageQueue) + return _messageGroups.TryGetValue(queueName, out MessageQueueGroup? messageQueue) ? messageQueue : PipelineError.QueueNotFound(queueName); } @@ -158,7 +170,7 @@ public IMessageQueue GetMessageQueueGroup(string queueName) public void Publish(in TNotification notification) where TNotification : struct, INotification { - var handler = GetNotificationHandler(); + INotificationHandler handler = GetNotificationHandler(); handler.Handle(in notification); } @@ -176,7 +188,7 @@ public void Publish(in TNotification notification) public void Send(in TMessage message) where TMessage : struct, IMessage { - var queue = GetMessageQueue(); + IMessageQueue queue = GetMessageQueue(); queue.Enqueue(in message); } @@ -191,10 +203,11 @@ public void Send(in TMessage message) public bool TrySend(in TMessage message) where TMessage : struct, IMessage { - var queue = GetMessageQueue(); + IMessageQueue queue = GetMessageQueue(); + return queue.TryEnqueue(in message); } - + internal void LoadPipelines( ICommandHandler?[] commands, IQueryHandler?[] queries, @@ -214,4 +227,4 @@ internal void LoadPipelines( group => new MessageQueueGroup(group.Key, group.ToArray()!), ReferenceComparer.Instance); } -} \ No newline at end of file +} diff --git a/src/Hexecs/Actors/ActorContext.Relations.cs b/src/Hexecs/Actors/ActorContext.Relations.cs index 436a39c..1eb3e83 100644 --- a/src/Hexecs/Actors/ActorContext.Relations.cs +++ b/src/Hexecs/Actors/ActorContext.Relations.cs @@ -6,9 +6,9 @@ public sealed partial class ActorContext { private IActorRelationPool?[] _relationPools; #if NET9_0_OR_GREATER - private readonly Lock _relationPoolLock = new(); + private readonly Lock _relationPoolLock = new Lock(); #else - private readonly object _relationPoolLock = new(); + private readonly object _relationPoolLock = new object(); #endif /// @@ -23,15 +23,15 @@ public sealed partial class ActorContext public ref T AddRelation(ActorId subject, ActorId relative, in T relation) where T : struct { - var relationPool = GetOrCreateRelationPool(); - ref var addResult = ref relationPool.Add(subject, relative, in relation); + ActorRelationPool relationPool = GetOrCreateRelationPool(); + ref T addResult = ref relationPool.Add(subject, relative, in relation); - var relationId = ActorRelationType.Id; + ushort relationId = ActorRelationType.Id; - ref var subjectRelations = ref GetOrAddComponent(subject, ActorRelationComponent.Create); + ref ActorRelationComponent subjectRelations = ref GetOrAddComponent(subject, ActorRelationComponent.Create); subjectRelations.TryAdd(relationId); - ref var relativeRelations = ref GetOrAddComponent(relative, ActorRelationComponent.Create); + ref ActorRelationComponent relativeRelations = ref GetOrAddComponent(relative, ActorRelationComponent.Create); relativeRelations.TryAdd(relationId); return ref addResult; @@ -47,8 +47,13 @@ public ref T AddRelation(ActorId subject, ActorId relative, in T relation) /// Вызывается, если отношение не найдено. public ref T GetRelation(ActorId subject, ActorId relative) where T : struct { - var pool = GetRelationPool(); - if (pool == null) ActorError.RelationNotFound(subject, relative); + ActorRelationPool? pool = GetRelationPool(); + + if (pool == null) + { + ActorError.RelationNotFound(subject, relative); + } + return ref pool.Get(subject, relative); } @@ -61,7 +66,8 @@ public ref T GetRelation(ActorId subject, ActorId relative) where T : struct /// True, если отношение существует, иначе false. public bool HasRelation(ActorId subject, ActorId relative) where T : struct { - var pool = GetRelationPool(); + ActorRelationPool? pool = GetRelationPool(); + return pool != null && pool.Has(subject, relative); } @@ -73,7 +79,7 @@ public bool HasRelation(ActorId subject, ActorId relative) where T : struct /// Перечислитель отношений. public ActorRelationEnumerator Relations(ActorId subject) where T : struct { - var pool = GetRelationPool(); + ActorRelationPool? pool = GetRelationPool(); // ReSharper disable once MergeConditionalExpression return pool == null @@ -104,31 +110,35 @@ public bool RemoveRelation(ActorId subject, ActorId relative) where T : struc [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool RemoveRelation(ActorId subject, ActorId relative, out T relation) where T : struct { - var pool = GetRelationPool(); + ActorRelationPool? pool = GetRelationPool(); + if (pool == null) { relation = default; + return false; } - var removeResult = pool.Remove(subject, relative, out relation); + bool removeResult = pool.Remove(subject, relative, out relation); + if (!removeResult) { relation = default; + return false; } - var relationId = ActorRelationType.Id; + ushort relationId = ActorRelationType.Id; if (pool.Count(subject) == 0) { - ref var subjectRelations = ref GetComponent(subject); + ref ActorRelationComponent subjectRelations = ref GetComponent(subject); subjectRelations.Remove(relationId); } if (pool.Count(relative) == 0) { - ref var relativeRelations = ref GetComponent(relative); + ref ActorRelationComponent relativeRelations = ref GetComponent(relative); relativeRelations.Remove(relationId); } @@ -137,10 +147,15 @@ public bool RemoveRelation(ActorId subject, ActorId relative, out T relation) private ActorRelationPool? GetRelationPool() where T : struct { - var id = ActorRelationType.Id; + ushort id = ActorRelationType.Id; + + if (id >= _relationPools.Length) + { + return null; + } + + IActorRelationPool? pool = _relationPools[id]; - if (id >= _relationPools.Length) return null; - var pool = _relationPools[id]; return pool == null ? null : Unsafe.As>(pool); @@ -148,11 +163,16 @@ public bool RemoveRelation(ActorId subject, ActorId relative, out T relation) private ActorRelationPool GetOrCreateRelationPool() where T : struct { - var relationId = ActorRelationType.Id; + ushort relationId = ActorRelationType.Id; + if (relationId < _relationPools.Length) { - var existsPool = _relationPools[relationId]; - if (existsPool != null) return Unsafe.As>(existsPool); + IActorRelationPool? existsPool = _relationPools[relationId]; + + if (existsPool != null) + { + return Unsafe.As>(existsPool); + } } #if NET9_0_OR_GREATER @@ -162,10 +182,10 @@ private ActorRelationPool GetOrCreateRelationPool() where T : struct #endif { ArrayUtils.EnsureCapacity(ref _relationPools, relationId); - ref var pool = ref _relationPools[relationId]; + ref IActorRelationPool? pool = ref _relationPools[relationId]; pool ??= new ActorRelationPool(this); return Unsafe.As>(pool); } } -} \ No newline at end of file +} diff --git a/src/Hexecs/Actors/ActorContext.Serialization.cs b/src/Hexecs/Actors/ActorContext.Serialization.cs index 53190a7..4453990 100644 --- a/src/Hexecs/Actors/ActorContext.Serialization.cs +++ b/src/Hexecs/Actors/ActorContext.Serialization.cs @@ -1,4 +1,5 @@ using System.Text.Json; + using Hexecs.Actors.Components; using Hexecs.Actors.Relations; using Hexecs.Serializations; @@ -27,7 +28,7 @@ private void SerializeComponents(Utf8JsonWriter writer) { writer.WriteStartArray(); - foreach (var pool in _componentPools) + foreach (IActorComponentPool? pool in _componentPools) { pool?.Serialize(writer); } @@ -39,9 +40,12 @@ private void SerializeComponentTypes(Utf8JsonWriter writer) { writer.WriteStartArray(); - foreach (var pool in _componentPools) + foreach (IActorComponentPool? pool in _componentPools) { - if (pool == null) continue; + if (pool == null) + { + continue; + } writer.WriteStartObject(); @@ -59,17 +63,18 @@ private void SerializeEntries(Utf8JsonWriter writer) { writer.WriteStartArray(); - var count = _count; - var dense = _dense; - var values = _values; + int count = _count; + uint[] dense = _dense; + Entry[] values = _values; for (var i = 0; i < count; i++) { // Извлекаем ID из плотного массива ключей - var actorId = dense[i]; + uint actorId = dense[i]; + // Получаем ссылку на данные по тому же индексу - ref readonly var entry = ref values[i]; - + ref readonly Entry entry = ref values[i]; + entry.Serialize(actorId, writer); } @@ -80,7 +85,7 @@ private void SerializeRelations(Utf8JsonWriter writer) { writer.WriteStartArray(); - foreach (var pool in _relationPools) + foreach (IActorRelationPool? pool in _relationPools) { pool?.Serialize(writer); } @@ -92,9 +97,12 @@ private void SerializeRelationTypes(Utf8JsonWriter writer) { writer.WriteStartArray(); - foreach (var pool in _relationPools) + foreach (IActorRelationPool? pool in _relationPools) { - if (pool == null) continue; + if (pool == null) + { + continue; + } writer.WriteStartObject(); @@ -107,4 +115,4 @@ private void SerializeRelationTypes(Utf8JsonWriter writer) writer.WriteEndArray(); } -} \ No newline at end of file +} diff --git a/src/Hexecs/Actors/ActorContext.Systems.cs b/src/Hexecs/Actors/ActorContext.Systems.cs index 0c36177..e386d2b 100644 --- a/src/Hexecs/Actors/ActorContext.Systems.cs +++ b/src/Hexecs/Actors/ActorContext.Systems.cs @@ -14,7 +14,7 @@ public sealed partial class ActorContext /// Время мира. public void Draw(in WorldTime time) { - foreach (var system in _drawSystems) + foreach (IDrawSystem system in _drawSystems) { system.Draw(in time); } @@ -28,68 +28,81 @@ public void Draw(in WorldTime time) /// Если система не найдена public T GetDrawSystem() where T : class, IDrawSystem { - foreach (var exists in _drawSystems) + foreach (IDrawSystem exists in _drawSystems) { - if (exists is T expected) return expected; + if (exists is T expected) + { + return expected; + } } ActorError.DrawSystemNotFound(); + return null; } - + public T GetUpdateSystem() where T : class, IUpdateSystem { - foreach (var exists in _updateSystems) + foreach (IUpdateSystem exists in _updateSystems) { switch (exists) { case T expected: return expected; - case ParallelSystem parallelSystem when parallelSystem.TryGetSystem(out var parallel): + case ParallelSystem parallelSystem when parallelSystem.TryGetSystem(out T? parallel): return parallel; } } ActorError.UpdateSystemNotFound(); + return null; } public bool TryGetDrawSystem([NotNullWhen(true)] out T? system) where T : class, IDrawSystem { - foreach (var exists in _drawSystems) + foreach (IDrawSystem exists in _drawSystems) { - if (exists is not T expected) continue; - + if (exists is not T expected) + { + continue; + } + system = expected; + return true; } system = null; + return false; } - + public bool TryGetUpdateSystem([NotNullWhen(true)] out T? system) where T : class, IUpdateSystem { - foreach (var exists in _updateSystems) + foreach (IUpdateSystem exists in _updateSystems) { switch (exists) { case T expected: system = expected; + return true; - case ParallelSystem parallelSystem when parallelSystem.TryGetSystem(out var parallel): + case ParallelSystem parallelSystem when parallelSystem.TryGetSystem(out T? parallel): system = parallel; + return true; } } system = null; + return false; } public void Update(in WorldTime time) { - foreach (var system in _updateSystems) + foreach (IUpdateSystem system in _updateSystems) { system.Update(in time); } @@ -100,4 +113,4 @@ internal void LoadSystems(IEnumerable drawSystems, IEnumerableВозникает, если актёр с указанным идентификатором не найден public Actor Clone(ActorId actorId, bool withParent = true) { - var cloneIdRaw = GetNextActorId(); - ref var cloneEntry = ref AddEntry(cloneIdRaw); + uint cloneIdRaw = GetNextActorId(); + ref Entry cloneEntry = ref AddEntry(cloneIdRaw); var cloneId = new ActorId(cloneIdRaw); - ref var entry = ref GetEntryRefExact(actorId.Value); - foreach (var componentId in entry) + ref Entry entry = ref GetEntryRefExact(actorId.Value); + foreach (ushort componentId in entry) { - var componentPool = _componentPools[componentId]!; + IActorComponentPool componentPool = _componentPools[componentId]!; componentPool.Clone(actorId, cloneId); cloneEntry.Add(componentId); } // ReSharper disable once InvertIf - if (withParent && TryGetParent(actorId, out var parent)) + if (withParent && TryGetParent(actorId, out Actor parent)) { AddChild(parent.Id, cloneId); } @@ -168,8 +168,12 @@ public Actor Clone(ActorId actorId, bool withParent = true) [MethodImpl(MethodImplOptions.AggressiveInlining)] public Actor CreateActor(uint? expectedId = null) { - if (expectedId == ActorId.EmptyId) ActorError.InvalidId(); - var actorId = expectedId ?? GetNextActorId(); + if (expectedId == ActorId.EmptyId) + { + ActorError.InvalidId(); + } + + uint actorId = expectedId ?? GetNextActorId(); AddEntry(actorId); return new Actor(this, new ActorId(actorId)); @@ -196,14 +200,14 @@ public void Dispose() { Clear(); - foreach (var filter in _filters.Values) + foreach (IActorFilter filter in _filters.Values) { filter.Dispose(); } _filters.Clear(); - foreach (var filter in _filtersWithConstraint) + foreach (IActorFilter filter in _filtersWithConstraint) { filter.Dispose(); } @@ -223,7 +227,11 @@ public void Dispose() /// Возникает, если актёр с указанным идентификатором не найден public Actor GetActor(ActorId actorId) { - if (!ActorAlive(actorId)) ActorError.NotFound(actorId); + if (!ActorAlive(actorId)) + { + ActorError.NotFound(actorId); + } + return new Actor(this, actorId); } @@ -236,10 +244,10 @@ public Actor GetActor(ActorId actorId) public ActorRef GetActorRef() where T1 : struct, IActorComponent { - var pool = GetComponentPool(); + ActorComponentPool? pool = GetComponentPool(); if (pool != null) { - var first = pool.First(); + ActorRef first = pool.First(); if (!first.IsEmpty) { return first; @@ -260,8 +268,11 @@ public ActorRef GetActorRef() public ActorRef GetActorRef(ActorId actorId) where T1 : struct, IActorComponent { - ref var component = ref TryGetComponentRef(actorId); - if (Unsafe.IsNullRef(ref component)) ActorError.ComponentNotFound(actorId); + ref T1 component = ref TryGetComponentRef(actorId); + if (Unsafe.IsNullRef(ref component)) + { + ActorError.ComponentNotFound(actorId); + } return new ActorRef(this, actorId, ref component); } @@ -276,10 +287,10 @@ public ActorRef GetActorRef(ActorId actorId) public ActorRef GetActorRef(ActorPredicate predicate) where T1 : struct, IActorComponent { - var pool = GetComponentPool(); + ActorComponentPool? pool = GetComponentPool(); if (pool != null) { - var exists = pool.First(predicate); + ActorRef exists = pool.First(predicate); if (!exists.IsEmpty) { return exists; @@ -306,31 +317,34 @@ public string GetDescription(ActorId actorId, int maxComponentDescription = 5) public void GetDescription(ActorId actorId, ref ValueStringBuilder builder, int maxComponentDescription = 5) { - ref var entry = ref GetEntryRef(actorId.Value); + ref Entry entry = ref GetEntryRef(actorId.Value); if (Unsafe.IsNullRef(ref entry)) { builder.Append('\''); builder.Append(StringUtils.EmptyValue); builder.Append('\''); - + return; } builder.Append("Id = "); builder.Append(actorId.Value); - var componentsLength = entry.Length; - if (componentsLength == 0) return; + int componentsLength = entry.Length; + if (componentsLength == 0) + { + return; + } builder.Append(" ("); - var pool = ArrayPool.Shared; - var buffer = pool.Rent(componentsLength); + ArrayPool pool = ArrayPool.Shared; + string[] buffer = pool.Rent(componentsLength); var index = 0; var printMore = false; // ReSharper disable once ForeachCanBePartlyConvertedToQueryUsingAnotherGetEnumerator - foreach (var componentId in entry) + foreach (ushort componentId in entry) { if (maxComponentDescription == index) { @@ -349,15 +363,25 @@ public void GetDescription(ActorId actorId, ref ValueStringBuilder builder, int Array.Sort(buffer, 0, index); var first = true; - foreach (var componentName in buffer.AsSpan(0, index)) + foreach (string componentName in buffer.AsSpan(0, index)) { - if (first == false) builder.Append(", "); - else first = false; + if (first == false) + { + builder.Append(", "); + } + else + { + first = false; + } builder.Append(componentName); } - if (printMore) builder.Append(", ..."); + if (printMore) + { + builder.Append(", ..."); + } + builder.Append(')'); pool.Return(buffer); @@ -372,18 +396,25 @@ public void GetDescription(ActorId actorId, ref ValueStringBuilder builder, int public ActorRef SingleRef() where T1 : struct, IActorComponent { - var componentId = ActorComponentType.Id; + ushort componentId = ActorComponentType.Id; if (_singles.ContainsKey(componentId)) { var componentPool = (ActorComponentPool)_componentPools[componentId]!; return componentPool.First(); } - var pool = GetComponentPool(); - if (pool == null) ActorError.SingleNotFound(); - if (pool.Length > 1) ActorError.NotSingle(); + ActorComponentPool? pool = GetComponentPool(); + if (pool == null) + { + ActorError.SingleNotFound(); + } + + if (pool.Length > 1) + { + ActorError.NotSingle(); + } - var single = pool.First(); + ActorRef single = pool.First(); _singles.Add(componentId, single.Id.Value); return single; @@ -399,7 +430,7 @@ public ActorRef SingleRef() public bool TryGetActorRef(ActorId actorId, out ActorRef actor) where T1 : struct, IActorComponent { - ref var component = ref TryGetComponentRef(actorId); + ref T1 component = ref TryGetComponentRef(actorId); if (Unsafe.IsNullRef(ref component)) { actor = ActorRef.Empty; @@ -416,12 +447,12 @@ public bool TryGetActorRef(ActorId actorId, out ActorRef actor) /// Следующий доступный идентификатор актёра private uint GetNextActorId() { - if (_freeIds.TryPop(out var reusedId)) + if (_freeIds.TryPop(out uint reusedId)) { return reusedId; } - var actorId = Interlocked.Increment(ref _nextActorId); + uint actorId = Interlocked.Increment(ref _nextActorId); while (!Unsafe.IsNullRef(ref GetEntryRef(actorId))) // is alive { actorId = Interlocked.Increment(ref _nextActorId); @@ -429,4 +460,4 @@ private uint GetNextActorId() return actorId; } -} \ No newline at end of file +} diff --git a/src/Hexecs/Actors/ActorContextBuilder.ComponentPoolBuilder.cs b/src/Hexecs/Actors/ActorContextBuilder.ComponentPoolBuilder.cs index 24a7f8b..5b506d6 100644 --- a/src/Hexecs/Actors/ActorContextBuilder.ComponentPoolBuilder.cs +++ b/src/Hexecs/Actors/ActorContextBuilder.ComponentPoolBuilder.cs @@ -16,29 +16,36 @@ internal ActorComponentPoolBuilder() { } - internal ActorComponentConfiguration Build() => new(_capacity, _cloneHandler, _disposeHandler, _converter); + internal ActorComponentConfiguration Build() + { + return new ActorComponentConfiguration(_capacity, _cloneHandler, _disposeHandler, _converter); + } public ActorComponentPoolBuilder AddCloneHandler(ActorCloneHandler handler) { _cloneHandler = handler; + return this; } public ActorComponentPoolBuilder AddConverter(IActorComponentConverter converter) { _converter = converter; + return this; } public ActorComponentPoolBuilder AddDisposeHandler(ActorDisposeHandler handler) { _disposeHandler = handler; + return this; } public ActorComponentPoolBuilder Capacity(int capacity) { _capacity = capacity; + return this; } @@ -46,6 +53,7 @@ public ActorComponentPoolBuilder CreateConverter() where TConverter : class, IActorComponentConverter, new() { _converter = new TConverter(); + return this; } } @@ -53,24 +61,22 @@ public ActorComponentPoolBuilder CreateConverter() public static class ActorComponentPoolBuilderExtensions { /// - /// Добавить обработчик клонирования компонентов, реализующих интерфейс + /// Добавить обработчик клонирования компонентов, реализующих интерфейс /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ActorComponentPoolBuilder AddCloneHandler( - this ActorComponentPoolBuilder builder) + public static ActorComponentPoolBuilder AddCloneHandler(this ActorComponentPoolBuilder builder) where TComponent : struct, IActorComponent, ICloneable { return builder.AddCloneHandler(static (in TComponent component) => component.Clone()); } /// - /// Добавить обработчик очистки для компонентов, реализующих интерфейс + /// Добавить обработчик очистки для компонентов, реализующих интерфейс /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ActorComponentPoolBuilder AddDisposeHandler( - this ActorComponentPoolBuilder builder) + public static ActorComponentPoolBuilder AddDisposeHandler(this ActorComponentPoolBuilder builder) where TComponent : struct, IActorComponent, IDisposable { return builder.AddDisposeHandler(static (ref TComponent component) => component.Dispose()); } -} \ No newline at end of file +} diff --git a/src/Hexecs/Actors/ActorContextBuilder.Entry.cs b/src/Hexecs/Actors/ActorContextBuilder.Entry.cs index a54659d..4b9c4ba 100644 --- a/src/Hexecs/Actors/ActorContextBuilder.Entry.cs +++ b/src/Hexecs/Actors/ActorContextBuilder.Entry.cs @@ -29,6 +29,9 @@ public Entry(Func builder) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public TResult Invoke(ActorContext context) => _instance ?? _builder(context); + public TResult Invoke(ActorContext context) + { + return _instance ?? _builder(context); + } } -} \ No newline at end of file +} diff --git a/src/Hexecs/Actors/ActorContextBuilder.Extensions.cs b/src/Hexecs/Actors/ActorContextBuilder.Extensions.cs index 41afff0..239b7a2 100644 --- a/src/Hexecs/Actors/ActorContextBuilder.Extensions.cs +++ b/src/Hexecs/Actors/ActorContextBuilder.Extensions.cs @@ -14,11 +14,13 @@ public static class ActorContextBuilderExtensions /// Тип строителя актёров. /// Этот же экземпляр ActorContextBuilder для цепочки вызовов. public ActorContextBuilder CreateBuilder< - [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.Interfaces | - DynamicallyAccessedMemberTypes.PublicConstructors)] + [DynamicallyAccessedMembers( + DynamicallyAccessedMemberTypes.Interfaces | + DynamicallyAccessedMemberTypes.PublicConstructors)] T>() where T : class, IActorBuilder { builder.CreateBuilder(static ctx => (IActorBuilder)ctx.Activate(typeof(T))); + return builder; } @@ -29,14 +31,14 @@ public ActorContextBuilder CreateBuilder< /// Использует рефлексию. /// public ActorContextBuilder CreateCommandHandler< - [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.Interfaces | - DynamicallyAccessedMemberTypes.PublicConstructors)] - THandler> - () + [DynamicallyAccessedMembers( + DynamicallyAccessedMemberTypes.Interfaces | + DynamicallyAccessedMemberTypes.PublicConstructors)] + THandler>() where THandler : class, ICommandHandler { - var commandType = PipelineUtils.GetCommandType(typeof(THandler)); - var commandId = CommandType.GetId(commandType); + Type commandType = PipelineUtils.GetCommandType(typeof(THandler)); + ushort commandId = CommandType.GetId(commandType); builder.InsertCommandHandlerEntry( commandId, @@ -54,11 +56,11 @@ public ActorContextBuilder CreateCommandHandler< /// Использует рефлексию. /// public ActorContextBuilder CreateDrawSystem< - [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] - TSystem> - () where TSystem : class, IDrawSystem + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] + TSystem>() where TSystem : class, IDrawSystem { builder.CreateDrawSystem(static ctx => (IDrawSystem)ctx.Activate(typeof(TSystem))); + return builder; } @@ -69,11 +71,11 @@ public ActorContextBuilder CreateDrawSystem< /// Использует рефлексию. /// public ActorContextBuilder CreateUpdateSystem< - [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] - TSystem> - () where TSystem : class, IUpdateSystem + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] + TSystem>() where TSystem : class, IUpdateSystem { builder.CreateUpdateSystem(static ctx => (IUpdateSystem)ctx.Activate(typeof(TSystem))); + return builder; } } @@ -85,11 +87,11 @@ public ActorContextBuilder CreateUpdateSystem< /// Использует рефлексию. /// public static ActorContextBuilder.ParallelSystemBuilder CreateUpdateSystem< - [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] - TSystem> - (this ActorContextBuilder.ParallelSystemBuilder builder) where TSystem : class, IUpdateSystem + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] + TSystem>(this ActorContextBuilder.ParallelSystemBuilder builder) where TSystem : class, IUpdateSystem { builder.Create(static ctx => (IUpdateSystem)ctx.Activate(typeof(TSystem))); + return builder; } -} \ No newline at end of file +} diff --git a/src/Hexecs/Actors/ActorContextBuilder.NotificationBuilder.cs b/src/Hexecs/Actors/ActorContextBuilder.NotificationBuilder.cs index 0c1648f..5ffd07f 100644 --- a/src/Hexecs/Actors/ActorContextBuilder.NotificationBuilder.cs +++ b/src/Hexecs/Actors/ActorContextBuilder.NotificationBuilder.cs @@ -13,27 +13,33 @@ public sealed class NotificationBuilder public NotificationBuilder Add(INotificationHandler handler) { _handlers.Add(new Entry>(handler)); + return this; } public NotificationBuilder Create(Func> handler) { _handlers.Add(new Entry>(handler)); + return this; } - internal Func Build() => actorContext => + internal Func Build() { - INotificationHandler result = _handlers.Count == 1 - ? new SimpleNotificationPipeline(_handlers[0].Invoke(actorContext)) - : new NotificationPipeline(_handlers - .Select((entry, ctx) => entry.Invoke(ctx), actorContext) - .Order(OrderComparer>.CreateInstance()) - .ToArray()); + return actorContext => + { + INotificationHandler result = _handlers.Count == 1 + ? new SimpleNotificationPipeline(_handlers[0].Invoke(actorContext)) + : new NotificationPipeline( + _handlers + .Select((entry, ctx) => entry.Invoke(ctx), actorContext) + .Order(OrderComparer>.CreateInstance()) + .ToArray()); - _handlers.Clear(); + _handlers.Clear(); - return result; - }; + return result; + }; + } } -} \ No newline at end of file +} diff --git a/src/Hexecs/Actors/ActorContextBuilder.ParallelSystemBuilder.cs b/src/Hexecs/Actors/ActorContextBuilder.ParallelSystemBuilder.cs index 79e86fa..f9232c8 100644 --- a/src/Hexecs/Actors/ActorContextBuilder.ParallelSystemBuilder.cs +++ b/src/Hexecs/Actors/ActorContextBuilder.ParallelSystemBuilder.cs @@ -13,22 +13,23 @@ public sealed class ParallelSystemBuilder(int order) public ParallelSystemBuilder Add(IUpdateSystem system) { _systems.Add(new Entry(system)); + return this; } public ParallelSystemBuilder Add(params Span systems) { - foreach (var updateSystem in systems) + foreach (IUpdateSystem updateSystem in systems) { Add(updateSystem); } return this; } - + public ParallelSystemBuilder Add(IEnumerable systems) { - foreach (var updateSystem in systems) + foreach (IUpdateSystem updateSystem in systems) { Add(updateSystem); } @@ -39,29 +40,38 @@ public ParallelSystemBuilder Add(IEnumerable systems) public ParallelSystemBuilder Create(Func system) { _systems.Add(new Entry(system)); + return this; } public ParallelSystemBuilder Worker(IParallelWorker worker) { _worker = worker; + return this; } - internal Func Build() => actorContext => + internal Func Build() { - var parallelSystems = _systems.ToArray( - static (builder, ctx) => builder.Invoke(ctx), - actorContext); + return actorContext => + { + IUpdateSystem[] parallelSystems = _systems.ToArray( + static (builder, ctx) => builder.Invoke(ctx), + actorContext); + + IParallelWorker? worker = _worker ?? actorContext.GetService(); - var worker = _worker ?? actorContext.GetService(); - if (worker == null) ActorError.ParallelWorkerNotRegistered(); + if (worker == null) + { + ActorError.ParallelWorkerNotRegistered(); + } - var result = new ParallelSystem(actorContext, order, parallelSystems, worker); + var result = new ParallelSystem(actorContext, order, parallelSystems, worker); - _systems.Clear(); + _systems.Clear(); - return result; - }; + return result; + }; + } } -} \ No newline at end of file +} diff --git a/src/Hexecs/Actors/ActorContextBuilder.cs b/src/Hexecs/Actors/ActorContextBuilder.cs index f30deeb..a6c8d0c 100644 --- a/src/Hexecs/Actors/ActorContextBuilder.cs +++ b/src/Hexecs/Actors/ActorContextBuilder.cs @@ -90,6 +90,7 @@ internal ActorContextBuilder(bool isDefault, int id, DependencyProvider dependen public ActorContextBuilder AddBuilder(IActorBuilder builder) { _builders.Add(new Entry(builder)); + return this; } @@ -101,6 +102,7 @@ public ActorContextBuilder AddBuilder(IActorBuilder builder) public ActorContextBuilder CreateBuilder(Func builder) { _builders.Add(new Entry(builder)); + return this; } @@ -112,21 +114,21 @@ public ActorContextBuilder CreateBuilder(Func build public ActorContextBuilder Capacity(int capacity) { _capacity = capacity; + return this; } /// /// Настройка пула компонентов /// - public ActorContextBuilder ConfigureComponentPool( - Action> component) + public ActorContextBuilder ConfigureComponentPool(Action> component) where TComponent : struct, IActorComponent { var index = (int)ActorComponentType.Id; CollectionsMarshal.SetCount(_componentConfigurations, index + 1); - var span = CollectionsMarshal.AsSpan(_componentConfigurations); - ref var value = ref span[index]; + Span span = CollectionsMarshal.AsSpan(_componentConfigurations); + ref IActorComponentConfiguration? value = ref span[index]; if (value == null) { @@ -140,7 +142,6 @@ public ActorContextBuilder ConfigureComponentPool( ActorError.ComponentPoolAlreadyConfigured(typeof(TComponent)); } - return this; } @@ -201,8 +202,7 @@ public ActorContextBuilder CreateCommandHandler(FuncТип команды. /// Тип результата команды. /// Функция, создающая обработчик команды. - public ActorContextBuilder CreateCommandHandler( - Func> handler) + public ActorContextBuilder CreateCommandHandler(Func> handler) where TCommand : struct, ICommand { InsertCommandHandlerEntry( @@ -218,11 +218,17 @@ internal void InsertCommandHandlerEntry(uint commandTypeId, Type commandType, En var index = (int)commandTypeId; CollectionsMarshal.SetCount(_commands, index + 1); - var span = CollectionsMarshal.AsSpan(_commands); - ref var value = ref span[index]; + Span> span = CollectionsMarshal.AsSpan(_commands); + ref Entry value = ref span[index]; - if (value.IsEmpty) value = entry; - else PipelineError.CommandHandlerAlreadyRegistered(commandType); + if (value.IsEmpty) + { + value = entry; + } + else + { + PipelineError.CommandHandlerAlreadyRegistered(commandType); + } } #endregion @@ -233,7 +239,10 @@ internal void InsertCommandHandlerEntry(uint commandTypeId, Type commandType, En /// Регистрирует систему отрисовки актёров. /// /// Экземпляр системы актёров. - public ActorContextBuilder AddDrawSystem(IDrawSystem system) => InsertDrawSystem(new Entry(system)); + public ActorContextBuilder AddDrawSystem(IDrawSystem system) + { + return InsertDrawSystem(new Entry(system)); + } /// /// Регистрирует функцию для создания системы отрисовки актёров с доступом к контексту актёров. @@ -247,6 +256,7 @@ public ActorContextBuilder CreateDrawSystem(Func syst private ActorContextBuilder InsertDrawSystem(Entry entry) { _drawSystems.Add(entry); + return this; } @@ -264,6 +274,7 @@ public ActorContextBuilder AddQueryHandler(IQueryHandler { InsertQueryHandlerEntry(new Entry(handler)); + return this; } @@ -273,11 +284,11 @@ public ActorContextBuilder AddQueryHandler(IQueryHandlerТип запроса. /// Тип результата запроса. /// Функция, создающая обработчик запроса. - public ActorContextBuilder CreateQueryHandler( - Func> handler) + public ActorContextBuilder CreateQueryHandler(Func> handler) where TQuery : struct, IQuery { InsertQueryHandlerEntry(new Entry(handler)); + return this; } @@ -287,11 +298,17 @@ private void InsertQueryHandlerEntry(Entry entry var index = (int)QueryType.Id; CollectionsMarshal.SetCount(_queries, index + 1); - var span = CollectionsMarshal.AsSpan(_queries); - ref var value = ref span[index]; + Span> span = CollectionsMarshal.AsSpan(_queries); + ref Entry value = ref span[index]; - if (value.IsEmpty) value = entry; - else PipelineError.QueryHandlerAlreadyRegistered(typeof(TQuery)); + if (value.IsEmpty) + { + value = entry; + } + else + { + PipelineError.QueryHandlerAlreadyRegistered(typeof(TQuery)); + } } #endregion @@ -304,7 +321,10 @@ private void InsertQueryHandlerEntry(Entry entry /// Тип сообщения. /// Экземпляр обработчика сообщения. public ActorContextBuilder AddMessageHandler(IMessageHandler handler) - where TMessage : struct, IMessage => CreateMessageHandler(_ => handler); + where TMessage : struct, IMessage + { + return CreateMessageHandler(_ => handler); + } /// /// Регистрирует функцию для создания обработчика сообщения указанного типа с доступом к контексту актёров. @@ -317,11 +337,17 @@ public ActorContextBuilder CreateMessageHandler(Func.Id; CollectionsMarshal.SetCount(_messages, index + 1); - var span = CollectionsMarshal.AsSpan(_messages); - ref var value = ref span[index]; + Span?> span = CollectionsMarshal.AsSpan(_messages); + ref Func? value = ref span[index]; - if (value != null) PipelineError.MessageQueueAlreadyRegistered(typeof(TMessage)); - else value = context => new MessageQueue(handler(context)); + if (value != null) + { + PipelineError.MessageQueueAlreadyRegistered(typeof(TMessage)); + } + else + { + value = context => new MessageQueue(handler(context)); + } return this; } @@ -342,8 +368,8 @@ public ActorContextBuilder AddNotificationHandler(INotificationHa var index = (int)NotificationType.Id; CollectionsMarshal.SetCount(_notifications, index + 1); - var span = CollectionsMarshal.AsSpan(_notifications); - ref var value = ref span[index]; + Span> span = CollectionsMarshal.AsSpan(_notifications); + ref Entry value = ref span[index]; if (value.IsEmpty) { @@ -363,15 +389,14 @@ public ActorContextBuilder AddNotificationHandler(INotificationHa /// Тип уведомления. /// Действие для конфигурации конвейера обработчиков уведомлений. /// Этот же экземпляр ActorContextBuilder для цепочки вызовов. - public ActorContextBuilder CreateNotificationHandler( - Action> pipeline) + public ActorContextBuilder CreateNotificationHandler(Action> pipeline) where TNotification : struct, INotification { var index = (int)NotificationType.Id; CollectionsMarshal.SetCount(_notifications, index + 1); - var span = CollectionsMarshal.AsSpan(_notifications); - ref var value = ref span[index]; + Span> span = CollectionsMarshal.AsSpan(_notifications); + ref Entry value = ref span[index]; if (value.IsEmpty) { @@ -420,6 +445,7 @@ public ActorContextBuilder CreateParallelUpdateSystem(int order, Action(builder.Build())); + return this; } @@ -433,6 +459,7 @@ public ActorContextBuilder CreateParallelUpdateSystem(IEnumerable builder.Add(parallelSystems); _updateSystems.Add(new Entry(builder.Build())); + return this; } @@ -448,6 +475,7 @@ public ActorContextBuilder CreateParallelUpdateSystem(Action entry) { _updateSystems.Add(entry); + return this; } @@ -482,10 +510,11 @@ internal ActorContext Build() _messages.Clear(); // 2. Builder'ы вряд ли зависят от систем, но скорее всего будут зависеть от шины данных. - instance.LoadBuilders(_builders - .Select(static (entry, ctx) => entry.Invoke(ctx), instance) - .Concat(World.GetServices()) - .Order(OrderComparer.CreateInstance())); + instance.LoadBuilders( + _builders + .Select(static (entry, ctx) => entry.Invoke(ctx), instance) + .Concat(World.GetServices()) + .Order(OrderComparer.CreateInstance())); _builders.Clear(); @@ -504,4 +533,4 @@ internal ActorContext Build() return instance; } -} \ No newline at end of file +} diff --git a/src/Hexecs/Actors/ActorDictionary.cs b/src/Hexecs/Actors/ActorDictionary.cs index eacf224..1206496 100644 --- a/src/Hexecs/Actors/ActorDictionary.cs +++ b/src/Hexecs/Actors/ActorDictionary.cs @@ -55,7 +55,11 @@ public bool ContainsKey(TKey key) public void Dispose() { - if (_disposed) return; + if (_disposed) + { + return; + } + _disposed = true; _actors.Clear(); @@ -70,36 +74,43 @@ public void Fill(bool clearBefore = true) { ObjectDisposedException.ThrowIf(_disposed, this); - if (clearBefore) OnCleared(); + if (clearBefore) + { + OnCleared(); + } + + ActorComponentPool.Enumerator poolEnumerator = _pool.GetEnumerator(); - var poolEnumerator = _pool.GetEnumerator(); while (poolEnumerator.MoveNext()) { - var actor = poolEnumerator.Current; + ActorRef actor = poolEnumerator.Current; _actors.Add(_keyExtractor(actor.Component1), actor.Id); } } public ActorRef GetActorRef(TKey key) { - if (!_disposed && _actors.TryGetValue(key, out var actorId)) + if (!_disposed && _actors.TryGetValue(key, out ActorId actorId)) { return new ActorRef(Context, actorId, ref _pool.Get(actorId)); } ActorError.KeyNotFound(); + return ActorRef.Empty; } public bool TryGetActorRef(TKey key, out ActorRef actor) { - if (!_disposed && _actors.TryGetValue(key, out var actorId)) + if (!_disposed && _actors.TryGetValue(key, out ActorId actorId)) { actor = new ActorRef(Context, actorId, ref _pool.Get(actorId)); + return true; } actor = ActorRef.Empty; + return false; } @@ -124,4 +135,4 @@ private void OnComponentUpdating(ActorId actorId, ref T1 exists, in T1 expected) _actors.Remove(_keyExtractor(exists), out _); _actors.Add(_keyExtractor(expected), actorId); } -} \ No newline at end of file +} diff --git a/src/Hexecs/Actors/ActorError.cs b/src/Hexecs/Actors/ActorError.cs index adaa743..20bea5b 100644 --- a/src/Hexecs/Actors/ActorError.cs +++ b/src/Hexecs/Actors/ActorError.cs @@ -163,8 +163,11 @@ public static void KeyNotFound() /// /// Идентификатор актёра [DoesNotReturn] - public static void NotFound(ActorId actorId) => NotFound(actorId.Value); - + public static void NotFound(ActorId actorId) + { + NotFound(actorId.Value); + } + /// /// Генерирует исключение, когда актёр с указанным идентификатором не найден. /// @@ -269,4 +272,4 @@ public static void ValueNotFound(string name, Type type) { throw new Exception($"Value '{name}' (type {TypeOf.GetTypeName(type)}) isn't found"); } -} \ No newline at end of file +} diff --git a/src/Hexecs/Actors/ActorFilter1.Dictionary.cs b/src/Hexecs/Actors/ActorFilter1.Dictionary.cs index 207a75e..b43f75d 100644 --- a/src/Hexecs/Actors/ActorFilter1.Dictionary.cs +++ b/src/Hexecs/Actors/ActorFilter1.Dictionary.cs @@ -8,7 +8,7 @@ public ReadOnlySpan Keys [MethodImpl(MethodImplOptions.AggressiveInlining)] get => _dense.AsSpan(0, _count); } - + public int Length { [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -22,14 +22,18 @@ public int Length [MethodImpl(MethodImplOptions.AggressiveInlining)] private void AddEntry(uint actorId) { - if (TryAddEntry(actorId)) return; + if (TryAddEntry(actorId)) + { + return; + } + ActorError.AlreadyExists(actorId); } private void ClearEntries() { - var dense = _dense; - var sparse = _sparse; + uint[] dense = _dense; + uint[] sparse = _sparse; for (var i = 0; i < _count; i++) { @@ -42,10 +46,10 @@ private void ClearEntries() [MethodImpl(MethodImplOptions.AggressiveInlining)] private bool ContainsEntry(uint actorId) { - var sparse = _sparse; + uint[] sparse = _sparse; if (actorId < (uint)sparse.Length) { - var denseIndexPlusOne = sparse[actorId]; + uint denseIndexPlusOne = sparse[actorId]; return denseIndexPlusOne != 0 && _dense[denseIndexPlusOne - 1] == actorId; } @@ -56,32 +60,32 @@ private void EnsureCapacity(uint actorId) { if (_count >= _dense.Length) { - var newSize = _dense.Length * 2; + int newSize = _dense.Length * 2; Array.Resize(ref _dense, newSize); } if (actorId >= (uint)_sparse.Length) { - var newSize = Math.Max((uint)_sparse.Length * 2, actorId + 1); + uint newSize = Math.Max((uint)_sparse.Length * 2, actorId + 1); Array.Resize(ref _sparse, (int)newSize); } } private bool RemoveEntry(uint actorId) { - var sparse = _sparse; + uint[] sparse = _sparse; if (actorId < (uint)sparse.Length) { - var slot = sparse[actorId]; + uint slot = sparse[actorId]; if (slot != 0) { - var denseIndex = (int)slot - 1; + int denseIndex = (int)slot - 1; if (_dense[denseIndex] == actorId) { - var lastIndex = _count - 1; + int lastIndex = _count - 1; if (denseIndex != lastIndex) { - var lastKey = _dense[lastIndex]; + uint lastKey = _dense[lastIndex]; _dense[denseIndex] = lastKey; _sparse[lastKey] = slot; } @@ -103,7 +107,7 @@ private bool TryAddEntry(uint actorId) { if (actorId < (uint)_sparse.Length && (uint)_count < (uint)_dense.Length) { - ref var slot = ref _sparse[actorId]; + ref uint slot = ref _sparse[actorId]; if (slot == 0) { var idx = (uint)_count; @@ -115,7 +119,10 @@ private bool TryAddEntry(uint actorId) return true; } - if (_dense[slot - 1] == actorId) return false; + if (_dense[slot - 1] == actorId) + { + return false; + } } return TryAddEntrySlow(actorId); @@ -126,10 +133,13 @@ private bool TryAddEntrySlow(uint actorId) { EnsureCapacity(actorId); - ref var denseIndexPlusOne = ref _sparse[actorId]; + ref uint denseIndexPlusOne = ref _sparse[actorId]; if (denseIndexPlusOne != 0) { - if (_dense[denseIndexPlusOne - 1] == actorId) return false; + if (_dense[denseIndexPlusOne - 1] == actorId) + { + return false; + } } var denseIndex = (uint)_count; @@ -140,4 +150,4 @@ private bool TryAddEntrySlow(uint actorId) Added?.Invoke(new ActorId(actorId)); return true; } -} \ No newline at end of file +} diff --git a/src/Hexecs/Actors/ActorFilter1.Enumerator.cs b/src/Hexecs/Actors/ActorFilter1.Enumerator.cs index 93b259f..2304e66 100644 --- a/src/Hexecs/Actors/ActorFilter1.Enumerator.cs +++ b/src/Hexecs/Actors/ActorFilter1.Enumerator.cs @@ -24,7 +24,7 @@ public readonly ActorRef Current [MethodImpl(MethodImplOptions.AggressiveInlining)] get { - var id = _ids[_index]; + uint id = _ids[_index]; return new ActorRef( _context, @@ -38,7 +38,7 @@ public readonly int Length [MethodImpl(MethodImplOptions.AggressiveInlining)] get => _ids.Length; } - + private readonly ActorContext _context; private readonly ActorFilter _filter; private readonly ComponentsAccess _pool1; @@ -53,19 +53,28 @@ internal Enumerator(ActorFilter filter) _filter = filter; _pool1 = filter._pool1.GetComponentAccess(); - var count = filter._count; + int count = filter._count; _ids = filter._dense.AsSpan(0, count); _index = -1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Dispose() => _filter.ProcessPostponedUpdates(); + public void Dispose() + { + _filter.ProcessPostponedUpdates(); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool MoveNext() => ++_index < _ids.Length; + public bool MoveNext() + { + return ++_index < _ids.Length; + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public readonly Enumerator GetEnumerator() => this; + public readonly Enumerator GetEnumerator() + { + return this; + } } -} \ No newline at end of file +} diff --git a/src/Hexecs/Actors/ActorFilter1.Operation.cs b/src/Hexecs/Actors/ActorFilter1.Operation.cs index ddb0e04..e20a035 100644 --- a/src/Hexecs/Actors/ActorFilter1.Operation.cs +++ b/src/Hexecs/Actors/ActorFilter1.Operation.cs @@ -16,13 +16,22 @@ private readonly struct Operation public bool IsClear => Type == TypeClear; [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Operation Add(ActorId id) => new(id, TypeAdd); + public static Operation Add(ActorId id) + { + return new Operation(id, TypeAdd); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Operation Remove(ActorId id) => new(id, TypeRemove); + public static Operation Remove(ActorId id) + { + return new Operation(id, TypeRemove); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Operation Clear() => new(ActorId.Empty, TypeClear); + public static Operation Clear() + { + return new Operation(ActorId.Empty, TypeClear); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] private Operation(ActorId id, byte type) @@ -31,4 +40,4 @@ private Operation(ActorId id, byte type) Type = type; } } -} \ No newline at end of file +} diff --git a/src/Hexecs/Actors/ActorFilter1.SkipTakeEnumerator.cs b/src/Hexecs/Actors/ActorFilter1.SkipTakeEnumerator.cs index 73b7589..cf92ea1 100644 --- a/src/Hexecs/Actors/ActorFilter1.SkipTakeEnumerator.cs +++ b/src/Hexecs/Actors/ActorFilter1.SkipTakeEnumerator.cs @@ -24,7 +24,7 @@ public readonly ActorRef Current [MethodImpl(MethodImplOptions.AggressiveInlining)] get { - var id = _ids[_index]; + uint id = _ids[_index]; return new ActorRef( _context, @@ -53,21 +53,30 @@ internal SkipTakeEnumerator(ActorFilter filter, int skip, int take = int.Max _filter = filter; _pool1 = filter._pool1.GetComponentAccess(); - var count = filter._count; - var actualSkip = Math.Min(skip, count); - var actualTake = Math.Min(take, count - actualSkip); + int count = filter._count; + int actualSkip = Math.Min(skip, count); + int actualTake = Math.Min(take, count - actualSkip); _ids = filter._dense.AsSpan(actualSkip, actualTake); _index = -1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Dispose() => _filter.ProcessPostponedUpdates(); + public void Dispose() + { + _filter.ProcessPostponedUpdates(); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool MoveNext() => ++_index < _ids.Length; + public bool MoveNext() + { + return ++_index < _ids.Length; + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public readonly SkipTakeEnumerator GetEnumerator() => this; + public readonly SkipTakeEnumerator GetEnumerator() + { + return this; + } } -} \ No newline at end of file +} diff --git a/src/Hexecs/Actors/ActorFilter1.cs b/src/Hexecs/Actors/ActorFilter1.cs index 9aa1a2e..4321826 100644 --- a/src/Hexecs/Actors/ActorFilter1.cs +++ b/src/Hexecs/Actors/ActorFilter1.cs @@ -19,9 +19,9 @@ public sealed partial class ActorFilter : IActorFilter private readonly ConcurrentQueue _postponedUpdates; private int _postponedReadersCount; #if NET9_0_OR_GREATER - private readonly Lock _postponedSyncLock = new(); + private readonly Lock _postponedSyncLock = new Lock(); #else - private readonly object _postponedSyncLock = new(); + private readonly object _postponedSyncLock = new object(); #endif private readonly ActorComponentPool _pool1; @@ -34,7 +34,7 @@ internal ActorFilter(ActorContext context, ActorConstraint? constraint = null, i Context = context; capacity = Math.Max(capacity, context.Length); - + _sparse = new uint[capacity]; _dense = new uint[capacity]; @@ -52,7 +52,7 @@ internal ActorFilter(ActorContext context, ActorConstraint? constraint = null, i _pool1.ComponentAdded += OnAddedComponent1; _pool1.ComponentRemoving += OnRemovingComponent1; - foreach (var actor in context) + foreach (Actor actor in context) { OnAdded(actor.Id); } @@ -63,19 +63,32 @@ internal ActorFilter(ActorContext context, ActorConstraint? constraint = null, i #region Contains [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Contains(ActorId actorId) => ContainsEntry(actorId.Value); + public bool Contains(ActorId actorId) + { + return ContainsEntry(actorId.Value); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Contains(in Actor actor) => ContainsEntry(actor.Id.Value); + public bool Contains(in Actor actor) + { + return ContainsEntry(actor.Id.Value); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Contains(in ActorRef actor) => ContainsEntry(actor.Id.Value); + public bool Contains(in ActorRef actor) + { + return ContainsEntry(actor.Id.Value); + } #endregion public void Dispose() { - if (_disposed) return; + if (_disposed) + { + return; + } + _disposed = true; ClearEntries(); @@ -95,7 +108,10 @@ public void Dispose() [MethodImpl(MethodImplOptions.AggressiveInlining)] public ActorRef GetRef(ActorId actorId) { - if (!ContainsEntry(actorId.Value)) ActorError.NotFound(actorId); + if (!ContainsEntry(actorId.Value)) + { + ActorError.NotFound(actorId); + } return new ActorRef( Context, @@ -105,9 +121,12 @@ public ActorRef GetRef(ActorId actorId) public ActorRef GetRef(ActorPredicate predicate) { - foreach (var actor in this) + foreach (ActorRef actor in this) { - if (predicate(in actor)) return actor; + if (predicate(in actor)) + { + return actor; + } } ActorError.ApplicableNotFound(); @@ -127,12 +146,15 @@ public Actor[] ToArray() try { - var count = _count; - if (count == 0) return []; + int count = _count; + if (count == 0) + { + return []; + } var actors = new Actor[count]; - var keys = _dense; - var ctx = Context; + uint[] keys = _dense; + ActorContext ctx = Context; for (var i = 0; i < count; i++) { @@ -194,7 +216,10 @@ private void OnRemovingComponent1(ActorId actorId, ref T1 component) private void Add(ActorId actorId) { - if (Constraint != null && !Constraint.Applicable(actorId)) return; + if (Constraint != null && !Constraint.Applicable(actorId)) + { + return; + } if (Volatile.Read(ref _postponedReadersCount) == 0) { @@ -218,7 +243,10 @@ private void Add(ActorId actorId) private void ProcessPostponedUpdates() { - if (Interlocked.Decrement(ref _postponedReadersCount) > 0) return; + if (Interlocked.Decrement(ref _postponedReadersCount) > 0) + { + return; + } var isClear = false; #if NET9_0_OR_GREATER @@ -227,9 +255,12 @@ private void ProcessPostponedUpdates() lock (_postponedSyncLock) #endif { - if (Volatile.Read(ref _postponedReadersCount) > 0) return; + if (Volatile.Read(ref _postponedReadersCount) > 0) + { + return; + } - while (_postponedUpdates.TryDequeue(out var operation)) + while (_postponedUpdates.TryDequeue(out Operation operation)) { if (operation.IsClear) { @@ -249,7 +280,10 @@ private void ProcessPostponedUpdates() } // Вызываем событие вне лока, чтобы избежать дедлоков - if (isClear) Cleared?.Invoke(); + if (isClear) + { + Cleared?.Invoke(); + } } private void Remove(ActorId actorId) @@ -276,4 +310,4 @@ private void Remove(ActorId actorId) ActorContext IActorFilter.Context => Context; ActorConstraint? IActorFilter.Constraint => Constraint; -} \ No newline at end of file +} diff --git a/src/Hexecs/Actors/ActorFilter2.Dictionary.cs b/src/Hexecs/Actors/ActorFilter2.Dictionary.cs index bec2e47..590fe9a 100644 --- a/src/Hexecs/Actors/ActorFilter2.Dictionary.cs +++ b/src/Hexecs/Actors/ActorFilter2.Dictionary.cs @@ -8,7 +8,7 @@ public ReadOnlySpan Keys [MethodImpl(MethodImplOptions.AggressiveInlining)] get => _dense.AsSpan(0, _count); } - + public int Length { [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -22,14 +22,18 @@ public int Length [MethodImpl(MethodImplOptions.AggressiveInlining)] private void AddEntry(uint actorId) { - if (TryAddEntry(actorId)) return; + if (TryAddEntry(actorId)) + { + return; + } + ActorError.AlreadyExists(actorId); } private void ClearEntries() { - var dense = _dense; - var sparse = _sparse; + uint[] dense = _dense; + uint[] sparse = _sparse; for (var i = 0; i < _count; i++) { @@ -42,10 +46,10 @@ private void ClearEntries() [MethodImpl(MethodImplOptions.AggressiveInlining)] private bool ContainsEntry(uint actorId) { - var sparse = _sparse; + uint[] sparse = _sparse; if (actorId < (uint)sparse.Length) { - var denseIndexPlusOne = sparse[actorId]; + uint denseIndexPlusOne = sparse[actorId]; return denseIndexPlusOne != 0 && _dense[denseIndexPlusOne - 1] == actorId; } @@ -56,32 +60,32 @@ private void EnsureCapacity(uint actorId) { if (_count >= _dense.Length) { - var newSize = _dense.Length * 2; + int newSize = _dense.Length * 2; Array.Resize(ref _dense, newSize); } if (actorId >= (uint)_sparse.Length) { - var newSize = Math.Max((uint)_sparse.Length * 2, actorId + 1); + uint newSize = Math.Max((uint)_sparse.Length * 2, actorId + 1); Array.Resize(ref _sparse, (int)newSize); } } private bool RemoveEntry(uint actorId) { - var sparse = _sparse; + uint[] sparse = _sparse; if (actorId < (uint)sparse.Length) { - var slot = sparse[actorId]; + uint slot = sparse[actorId]; if (slot != 0) { - var denseIndex = (int)slot - 1; + int denseIndex = (int)slot - 1; if (_dense[denseIndex] == actorId) { - var lastIndex = _count - 1; + int lastIndex = _count - 1; if (denseIndex != lastIndex) { - var lastKey = _dense[lastIndex]; + uint lastKey = _dense[lastIndex]; _dense[denseIndex] = lastKey; _sparse[lastKey] = slot; } @@ -103,7 +107,7 @@ private bool TryAddEntry(uint actorId) { if (actorId < (uint)_sparse.Length && (uint)_count < (uint)_dense.Length) { - ref var slot = ref _sparse[actorId]; + ref uint slot = ref _sparse[actorId]; if (slot == 0) { var idx = (uint)_count; @@ -115,7 +119,10 @@ private bool TryAddEntry(uint actorId) return true; } - if (_dense[slot - 1] == actorId) return false; + if (_dense[slot - 1] == actorId) + { + return false; + } } return TryAddEntrySlow(actorId); @@ -126,10 +133,13 @@ private bool TryAddEntrySlow(uint actorId) { EnsureCapacity(actorId); - ref var denseIndexPlusOne = ref _sparse[actorId]; + ref uint denseIndexPlusOne = ref _sparse[actorId]; if (denseIndexPlusOne != 0) { - if (_dense[denseIndexPlusOne - 1] == actorId) return false; + if (_dense[denseIndexPlusOne - 1] == actorId) + { + return false; + } } var denseIndex = (uint)_count; @@ -140,4 +150,4 @@ private bool TryAddEntrySlow(uint actorId) Added?.Invoke(new ActorId(actorId)); return true; } -} \ No newline at end of file +} diff --git a/src/Hexecs/Actors/ActorFilter2.Enumerator.cs b/src/Hexecs/Actors/ActorFilter2.Enumerator.cs index e9e9f44..74be101 100644 --- a/src/Hexecs/Actors/ActorFilter2.Enumerator.cs +++ b/src/Hexecs/Actors/ActorFilter2.Enumerator.cs @@ -24,7 +24,7 @@ public readonly ActorRef Current [MethodImpl(MethodImplOptions.AggressiveInlining)] get { - var id = _ids[_index]; + uint id = _ids[_index]; return new ActorRef( _context, @@ -39,7 +39,7 @@ public readonly int Length [MethodImpl(MethodImplOptions.AggressiveInlining)] get => _ids.Length; } - + private readonly ActorContext _context; private readonly ActorFilter _filter; private readonly ComponentsAccess _pool1; @@ -56,19 +56,28 @@ internal Enumerator(ActorFilter filter) _pool1 = filter._pool1.GetComponentAccess(); _pool2 = filter._pool2.GetComponentAccess(); - var count = filter._count; + int count = filter._count; _ids = filter._dense.AsSpan(0, count); _index = -1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Dispose() => _filter.ProcessPostponedUpdates(); + public void Dispose() + { + _filter.ProcessPostponedUpdates(); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool MoveNext() => ++_index < _ids.Length; + public bool MoveNext() + { + return ++_index < _ids.Length; + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public readonly Enumerator GetEnumerator() => this; + public readonly Enumerator GetEnumerator() + { + return this; + } } -} \ No newline at end of file +} diff --git a/src/Hexecs/Actors/ActorFilter2.Operation.cs b/src/Hexecs/Actors/ActorFilter2.Operation.cs index 148b0d8..554f54a 100644 --- a/src/Hexecs/Actors/ActorFilter2.Operation.cs +++ b/src/Hexecs/Actors/ActorFilter2.Operation.cs @@ -16,13 +16,22 @@ private readonly struct Operation public bool IsClear => Type == TypeClear; [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Operation Add(ActorId id) => new(id, TypeAdd); + public static Operation Add(ActorId id) + { + return new Operation(id, TypeAdd); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Operation Remove(ActorId id) => new(id, TypeRemove); + public static Operation Remove(ActorId id) + { + return new Operation(id, TypeRemove); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Operation Clear() => new(ActorId.Empty, TypeClear); + public static Operation Clear() + { + return new Operation(ActorId.Empty, TypeClear); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] private Operation(ActorId id, byte type) @@ -31,4 +40,4 @@ private Operation(ActorId id, byte type) Type = type; } } -} \ No newline at end of file +} diff --git a/src/Hexecs/Actors/ActorFilter2.SkipTakeEnumerator.cs b/src/Hexecs/Actors/ActorFilter2.SkipTakeEnumerator.cs index 8448f13..6896a30 100644 --- a/src/Hexecs/Actors/ActorFilter2.SkipTakeEnumerator.cs +++ b/src/Hexecs/Actors/ActorFilter2.SkipTakeEnumerator.cs @@ -24,7 +24,7 @@ public readonly ActorRef Current [MethodImpl(MethodImplOptions.AggressiveInlining)] get { - var id = _ids[_index]; + uint id = _ids[_index]; return new ActorRef( _context, @@ -56,21 +56,30 @@ internal SkipTakeEnumerator(ActorFilter filter, int skip, int take = int _pool1 = filter._pool1.GetComponentAccess(); _pool2 = filter._pool2.GetComponentAccess(); - var count = filter._count; - var actualSkip = Math.Min(skip, count); - var actualTake = Math.Min(take, count - actualSkip); + int count = filter._count; + int actualSkip = Math.Min(skip, count); + int actualTake = Math.Min(take, count - actualSkip); _ids = filter._dense.AsSpan(actualSkip, actualTake); _index = -1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Dispose() => _filter.ProcessPostponedUpdates(); + public void Dispose() + { + _filter.ProcessPostponedUpdates(); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool MoveNext() => ++_index < _ids.Length; + public bool MoveNext() + { + return ++_index < _ids.Length; + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public readonly SkipTakeEnumerator GetEnumerator() => this; + public readonly SkipTakeEnumerator GetEnumerator() + { + return this; + } } -} \ No newline at end of file +} diff --git a/src/Hexecs/Actors/ActorFilter2.cs b/src/Hexecs/Actors/ActorFilter2.cs index 9f875cc..9a50721 100644 --- a/src/Hexecs/Actors/ActorFilter2.cs +++ b/src/Hexecs/Actors/ActorFilter2.cs @@ -20,9 +20,9 @@ public sealed partial class ActorFilter : IActorFilter private readonly ConcurrentQueue _postponedUpdates; private int _postponedReadersCount; #if NET9_0_OR_GREATER - private readonly Lock _postponedSyncLock = new(); + private readonly Lock _postponedSyncLock = new Lock(); #else - private readonly object _postponedSyncLock = new(); + private readonly object _postponedSyncLock = new object(); #endif private readonly ActorComponentPool _pool1; @@ -57,7 +57,7 @@ internal ActorFilter(ActorContext context, ActorConstraint? constraint = null, i _pool2.ComponentAdded += OnAddedComponent2; _pool2.ComponentRemoving += OnRemovingComponent2; - foreach (var actor in context) + foreach (Actor actor in context) { OnAdded(actor.Id); } @@ -68,19 +68,32 @@ internal ActorFilter(ActorContext context, ActorConstraint? constraint = null, i #region Contains [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Contains(ActorId actorId) => ContainsEntry(actorId.Value); + public bool Contains(ActorId actorId) + { + return ContainsEntry(actorId.Value); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Contains(in Actor actor) => ContainsEntry(actor.Id.Value); + public bool Contains(in Actor actor) + { + return ContainsEntry(actor.Id.Value); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Contains(in ActorRef actor) => ContainsEntry(actor.Id.Value); + public bool Contains(in ActorRef actor) + { + return ContainsEntry(actor.Id.Value); + } #endregion public void Dispose() { - if (_disposed) return; + if (_disposed) + { + return; + } + _disposed = true; ClearEntries(); @@ -102,7 +115,10 @@ public void Dispose() [MethodImpl(MethodImplOptions.AggressiveInlining)] public ActorRef GetRef(ActorId actorId) { - if (!ContainsEntry(actorId.Value)) ActorError.NotFound(actorId); + if (!ContainsEntry(actorId.Value)) + { + ActorError.NotFound(actorId); + } return new ActorRef( Context, @@ -113,9 +129,12 @@ ref _pool1.Get(actorId), public ActorRef GetRef(ActorPredicate predicate) { - foreach (var actor in this) + foreach (ActorRef actor in this) { - if (predicate(in actor)) return actor; + if (predicate(in actor)) + { + return actor; + } } ActorError.ApplicableNotFound(); @@ -135,12 +154,15 @@ public Actor[] ToArray() try { - var count = _count; - if (count == 0) return []; + int count = _count; + if (count == 0) + { + return []; + } var actors = new Actor[count]; - var keys = _dense; - var ctx = Context; + uint[] keys = _dense; + ActorContext ctx = Context; for (var i = 0; i < count; i++) { @@ -201,15 +223,27 @@ private void OnCleared() _postponedUpdates.Enqueue(Operation.Clear()); } - private void OnRemoving(ActorId actorId) => Remove(actorId); + private void OnRemoving(ActorId actorId) + { + Remove(actorId); + } - private void OnRemovingComponent1(ActorId actorId, ref T1 component) => Remove(actorId); + private void OnRemovingComponent1(ActorId actorId, ref T1 component) + { + Remove(actorId); + } - private void OnRemovingComponent2(ActorId actorId, ref T2 component) => Remove(actorId); + private void OnRemovingComponent2(ActorId actorId, ref T2 component) + { + Remove(actorId); + } private void Add(ActorId actorId) { - if (Constraint != null && !Constraint.Applicable(actorId)) return; + if (Constraint != null && !Constraint.Applicable(actorId)) + { + return; + } if (Volatile.Read(ref _postponedReadersCount) == 0) { @@ -233,7 +267,10 @@ private void Add(ActorId actorId) private void ProcessPostponedUpdates() { - if (Interlocked.Decrement(ref _postponedReadersCount) > 0) return; + if (Interlocked.Decrement(ref _postponedReadersCount) > 0) + { + return; + } var isClear = false; #if NET9_0_OR_GREATER @@ -242,9 +279,12 @@ private void ProcessPostponedUpdates() lock (_postponedSyncLock) #endif { - if (Volatile.Read(ref _postponedReadersCount) > 0) return; + if (Volatile.Read(ref _postponedReadersCount) > 0) + { + return; + } - while (_postponedUpdates.TryDequeue(out var operation)) + while (_postponedUpdates.TryDequeue(out Operation operation)) { if (operation.IsClear) { @@ -264,7 +304,10 @@ private void ProcessPostponedUpdates() } // Вызываем событие вне лока, чтобы избежать дедлоков - if (isClear) Cleared?.Invoke(); + if (isClear) + { + Cleared?.Invoke(); + } } private void Remove(ActorId actorId) @@ -291,4 +334,4 @@ private void Remove(ActorId actorId) ActorContext IActorFilter.Context => Context; ActorConstraint? IActorFilter.Constraint => Constraint; -} \ No newline at end of file +} diff --git a/src/Hexecs/Actors/ActorFilter3.Dictionary.cs b/src/Hexecs/Actors/ActorFilter3.Dictionary.cs index 2167956..695ce5b 100644 --- a/src/Hexecs/Actors/ActorFilter3.Dictionary.cs +++ b/src/Hexecs/Actors/ActorFilter3.Dictionary.cs @@ -8,7 +8,7 @@ public ReadOnlySpan Keys [MethodImpl(MethodImplOptions.AggressiveInlining)] get => _dense.AsSpan(0, _count); } - + public int Length { [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -22,14 +22,18 @@ public int Length [MethodImpl(MethodImplOptions.AggressiveInlining)] private void AddEntry(uint actorId) { - if (TryAddEntry(actorId)) return; + if (TryAddEntry(actorId)) + { + return; + } + ActorError.AlreadyExists(actorId); } private void ClearEntries() { - var dense = _dense; - var sparse = _sparse; + uint[] dense = _dense; + uint[] sparse = _sparse; for (var i = 0; i < _count; i++) { @@ -42,10 +46,10 @@ private void ClearEntries() [MethodImpl(MethodImplOptions.AggressiveInlining)] private bool ContainsEntry(uint actorId) { - var sparse = _sparse; + uint[] sparse = _sparse; if (actorId < (uint)sparse.Length) { - var denseIndexPlusOne = sparse[actorId]; + uint denseIndexPlusOne = sparse[actorId]; return denseIndexPlusOne != 0 && _dense[denseIndexPlusOne - 1] == actorId; } @@ -56,32 +60,32 @@ private void EnsureCapacity(uint actorId) { if (_count >= _dense.Length) { - var newSize = _dense.Length * 2; + int newSize = _dense.Length * 2; Array.Resize(ref _dense, newSize); } if (actorId >= (uint)_sparse.Length) { - var newSize = Math.Max((uint)_sparse.Length * 2, actorId + 1); + uint newSize = Math.Max((uint)_sparse.Length * 2, actorId + 1); Array.Resize(ref _sparse, (int)newSize); } } private bool RemoveEntry(uint actorId) { - var sparse = _sparse; + uint[] sparse = _sparse; if (actorId < (uint)sparse.Length) { - var slot = sparse[actorId]; + uint slot = sparse[actorId]; if (slot != 0) { - var denseIndex = (int)slot - 1; + int denseIndex = (int)slot - 1; if (_dense[denseIndex] == actorId) { - var lastIndex = _count - 1; + int lastIndex = _count - 1; if (denseIndex != lastIndex) { - var lastKey = _dense[lastIndex]; + uint lastKey = _dense[lastIndex]; _dense[denseIndex] = lastKey; _sparse[lastKey] = slot; } @@ -103,7 +107,7 @@ private bool TryAddEntry(uint actorId) { if (actorId < (uint)_sparse.Length && (uint)_count < (uint)_dense.Length) { - ref var slot = ref _sparse[actorId]; + ref uint slot = ref _sparse[actorId]; if (slot == 0) { var idx = (uint)_count; @@ -115,7 +119,10 @@ private bool TryAddEntry(uint actorId) return true; } - if (_dense[slot - 1] == actorId) return false; + if (_dense[slot - 1] == actorId) + { + return false; + } } return TryAddEntrySlow(actorId); @@ -126,10 +133,13 @@ private bool TryAddEntrySlow(uint actorId) { EnsureCapacity(actorId); - ref var denseIndexPlusOne = ref _sparse[actorId]; + ref uint denseIndexPlusOne = ref _sparse[actorId]; if (denseIndexPlusOne != 0) { - if (_dense[denseIndexPlusOne - 1] == actorId) return false; + if (_dense[denseIndexPlusOne - 1] == actorId) + { + return false; + } } var denseIndex = (uint)_count; @@ -140,4 +150,4 @@ private bool TryAddEntrySlow(uint actorId) Added?.Invoke(new ActorId(actorId)); return true; } -} \ No newline at end of file +} diff --git a/src/Hexecs/Actors/ActorFilter3.Enumerator.cs b/src/Hexecs/Actors/ActorFilter3.Enumerator.cs index bd60051..9a8c4de 100644 --- a/src/Hexecs/Actors/ActorFilter3.Enumerator.cs +++ b/src/Hexecs/Actors/ActorFilter3.Enumerator.cs @@ -24,7 +24,7 @@ public readonly ActorRef Current [MethodImpl(MethodImplOptions.AggressiveInlining)] get { - var id = _ids[_index]; + uint id = _ids[_index]; return new ActorRef( _context, @@ -59,19 +59,28 @@ internal Enumerator(ActorFilter filter) _pool2 = filter._pool2.GetComponentAccess(); _pool3 = filter._pool3.GetComponentAccess(); - var count = filter._count; + int count = filter._count; _ids = filter._dense.AsSpan(0, count); _index = -1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Dispose() => _filter.ProcessPostponedUpdates(); + public void Dispose() + { + _filter.ProcessPostponedUpdates(); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool MoveNext() => ++_index < _ids.Length; + public bool MoveNext() + { + return ++_index < _ids.Length; + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public readonly Enumerator GetEnumerator() => this; + public readonly Enumerator GetEnumerator() + { + return this; + } } -} \ No newline at end of file +} diff --git a/src/Hexecs/Actors/ActorFilter3.Operation.cs b/src/Hexecs/Actors/ActorFilter3.Operation.cs index a0044dd..3211bed 100644 --- a/src/Hexecs/Actors/ActorFilter3.Operation.cs +++ b/src/Hexecs/Actors/ActorFilter3.Operation.cs @@ -16,13 +16,22 @@ private readonly struct Operation public bool IsClear => Type == TypeClear; [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Operation Add(ActorId id) => new(id, TypeAdd); + public static Operation Add(ActorId id) + { + return new Operation(id, TypeAdd); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Operation Remove(ActorId id) => new(id, TypeRemove); + public static Operation Remove(ActorId id) + { + return new Operation(id, TypeRemove); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Operation Clear() => new(ActorId.Empty, TypeClear); + public static Operation Clear() + { + return new Operation(ActorId.Empty, TypeClear); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] private Operation(ActorId id, byte type) @@ -31,4 +40,4 @@ private Operation(ActorId id, byte type) Type = type; } } -} \ No newline at end of file +} diff --git a/src/Hexecs/Actors/ActorFilter3.SkipTakeEnumerator.cs b/src/Hexecs/Actors/ActorFilter3.SkipTakeEnumerator.cs index 660669b..0349e01 100644 --- a/src/Hexecs/Actors/ActorFilter3.SkipTakeEnumerator.cs +++ b/src/Hexecs/Actors/ActorFilter3.SkipTakeEnumerator.cs @@ -24,7 +24,7 @@ public readonly ActorRef Current [MethodImpl(MethodImplOptions.AggressiveInlining)] get { - var id = _ids[_index]; + uint id = _ids[_index]; return new ActorRef( _context, @@ -59,21 +59,30 @@ internal SkipTakeEnumerator(ActorFilter filter, int skip, int take = _pool2 = filter._pool2.GetComponentAccess(); _pool3 = filter._pool3.GetComponentAccess(); - var count = filter._count; - var actualSkip = Math.Min(skip, count); - var actualTake = Math.Min(take, count - actualSkip); + int count = filter._count; + int actualSkip = Math.Min(skip, count); + int actualTake = Math.Min(take, count - actualSkip); _ids = filter._dense.AsSpan(actualSkip, actualTake); _index = -1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Dispose() => _filter.ProcessPostponedUpdates(); + public void Dispose() + { + _filter.ProcessPostponedUpdates(); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool MoveNext() => ++_index < _ids.Length; + public bool MoveNext() + { + return ++_index < _ids.Length; + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public readonly SkipTakeEnumerator GetEnumerator() => this; + public readonly SkipTakeEnumerator GetEnumerator() + { + return this; + } } -} \ No newline at end of file +} diff --git a/src/Hexecs/Actors/ActorFilter3.cs b/src/Hexecs/Actors/ActorFilter3.cs index f4a8ab9..2f46dd1 100644 --- a/src/Hexecs/Actors/ActorFilter3.cs +++ b/src/Hexecs/Actors/ActorFilter3.cs @@ -21,9 +21,9 @@ public sealed partial class ActorFilter : IActorFilter private readonly ConcurrentQueue _postponedUpdates; private int _postponedReadersCount; #if NET9_0_OR_GREATER - private readonly Lock _postponedSyncLock = new(); + private readonly Lock _postponedSyncLock = new Lock(); #else - private readonly object _postponedSyncLock = new(); + private readonly object _postponedSyncLock = new object(); #endif private readonly ActorComponentPool _pool1; @@ -38,7 +38,7 @@ internal ActorFilter(ActorContext context, ActorConstraint? constraint = null, i Context = context; capacity = Math.Max(capacity, context.Length); - + _sparse = new uint[capacity]; _dense = new uint[capacity]; @@ -62,7 +62,7 @@ internal ActorFilter(ActorContext context, ActorConstraint? constraint = null, i _pool3.ComponentAdded += OnAddedComponent3; _pool3.ComponentRemoving += OnRemovingComponent3; - foreach (var actor in context) + foreach (Actor actor in context) { OnAdded(actor.Id); } @@ -73,19 +73,32 @@ internal ActorFilter(ActorContext context, ActorConstraint? constraint = null, i #region Contains [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Contains(ActorId actorId) => ContainsEntry(actorId.Value); + public bool Contains(ActorId actorId) + { + return ContainsEntry(actorId.Value); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Contains(in Actor actor) => ContainsEntry(actor.Id.Value); + public bool Contains(in Actor actor) + { + return ContainsEntry(actor.Id.Value); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Contains(in ActorRef actor) => ContainsEntry(actor.Id.Value); + public bool Contains(in ActorRef actor) + { + return ContainsEntry(actor.Id.Value); + } #endregion public void Dispose() { - if (_disposed) return; + if (_disposed) + { + return; + } + _disposed = true; ClearEntries(); @@ -109,7 +122,10 @@ public void Dispose() [MethodImpl(MethodImplOptions.AggressiveInlining)] public ActorRef GetRef(ActorId actorId) { - if (!ContainsEntry(actorId.Value)) ActorError.NotFound(actorId); + if (!ContainsEntry(actorId.Value)) + { + ActorError.NotFound(actorId); + } return new ActorRef( Context, @@ -121,9 +137,12 @@ ref _pool2.Get(actorId), public ActorRef GetRef(ActorPredicate predicate) { - foreach (var actor in this) + foreach (ActorRef actor in this) { - if (predicate(in actor)) return actor; + if (predicate(in actor)) + { + return actor; + } } ActorError.ApplicableNotFound(); @@ -143,12 +162,15 @@ public Actor[] ToArray() try { - var count = _count; - if (count == 0) return []; + int count = _count; + if (count == 0) + { + return []; + } var actors = new Actor[count]; - var keys = _dense; - var ctx = Context; + uint[] keys = _dense; + ActorContext ctx = Context; for (var i = 0; i < count; i++) { @@ -217,17 +239,32 @@ private void OnCleared() _postponedUpdates.Enqueue(Operation.Clear()); } - private void OnRemoving(ActorId actorId) => Remove(actorId); + private void OnRemoving(ActorId actorId) + { + Remove(actorId); + } - private void OnRemovingComponent1(ActorId actorId, ref T1 component) => Remove(actorId); + private void OnRemovingComponent1(ActorId actorId, ref T1 component) + { + Remove(actorId); + } - private void OnRemovingComponent2(ActorId actorId, ref T2 component) => Remove(actorId); + private void OnRemovingComponent2(ActorId actorId, ref T2 component) + { + Remove(actorId); + } - private void OnRemovingComponent3(ActorId actorId, ref T3 component) => Remove(actorId); + private void OnRemovingComponent3(ActorId actorId, ref T3 component) + { + Remove(actorId); + } private void Add(ActorId actorId) { - if (Constraint != null && !Constraint.Applicable(actorId)) return; + if (Constraint != null && !Constraint.Applicable(actorId)) + { + return; + } if (Volatile.Read(ref _postponedReadersCount) == 0) { @@ -251,7 +288,10 @@ private void Add(ActorId actorId) private void ProcessPostponedUpdates() { - if (Interlocked.Decrement(ref _postponedReadersCount) > 0) return; + if (Interlocked.Decrement(ref _postponedReadersCount) > 0) + { + return; + } var isClear = false; #if NET9_0_OR_GREATER @@ -260,9 +300,12 @@ private void ProcessPostponedUpdates() lock (_postponedSyncLock) #endif { - if (Volatile.Read(ref _postponedReadersCount) > 0) return; + if (Volatile.Read(ref _postponedReadersCount) > 0) + { + return; + } - while (_postponedUpdates.TryDequeue(out var operation)) + while (_postponedUpdates.TryDequeue(out Operation operation)) { if (operation.IsClear) { @@ -282,7 +325,10 @@ private void ProcessPostponedUpdates() } // Вызываем событие вне лока, чтобы избежать дедлоков - if (isClear) Cleared?.Invoke(); + if (isClear) + { + Cleared?.Invoke(); + } } private void Remove(ActorId actorId) @@ -309,4 +355,4 @@ private void Remove(ActorId actorId) ActorContext IActorFilter.Context => Context; ActorConstraint? IActorFilter.Constraint => Constraint; -} \ No newline at end of file +} diff --git a/src/Hexecs/Actors/ActorId.cs b/src/Hexecs/Actors/ActorId.cs index 0604f9f..9a06616 100644 --- a/src/Hexecs/Actors/ActorId.cs +++ b/src/Hexecs/Actors/ActorId.cs @@ -24,7 +24,7 @@ namespace Hexecs.Actors; public static ActorId Empty { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => new(EmptyId); + get => new ActorId(EmptyId); } /// @@ -73,7 +73,7 @@ public Actor Unwrap(ActorContext context) public override string ToString() { - return ActorMarshal.TryGetDebugContext(out var context) + return ActorMarshal.TryGetDebugContext(out ActorContext? context) ? context.GetDescription(this) : IsEmpty ? StringUtils.EmptyValue @@ -83,36 +83,66 @@ public override string ToString() #region Equality [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(ActorId other) => Value == other.Value; + public bool Equals(ActorId other) + { + return Value == other.Value; + } - public override bool Equals(object? obj) => obj is ActorId other && Equals(other); + public override bool Equals(object? obj) + { + return obj is ActorId other && Equals(other); + } - public override int GetHashCode() => HashCode.Combine(Value); + public override int GetHashCode() + { + return HashCode.Combine(Value); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(in ActorId left, in ActorId right) => left.Value == right.Value; + public static bool operator ==(in ActorId left, in ActorId right) + { + return left.Value == right.Value; + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(in ActorId left, in ActorId right) => left.Value != right.Value; + public static bool operator !=(in ActorId left, in ActorId right) + { + return left.Value != right.Value; + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator <(in ActorId left, in ActorId right) => left.Value < right.Value; + public static bool operator <(in ActorId left, in ActorId right) + { + return left.Value < right.Value; + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator >(in ActorId left, in ActorId right) => left.Value > right.Value; + public static bool operator >(in ActorId left, in ActorId right) + { + return left.Value > right.Value; + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator <=(in ActorId left, in ActorId right) => left.Value <= right.Value; + public static bool operator <=(in ActorId left, in ActorId right) + { + return left.Value <= right.Value; + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator >=(in ActorId left, in ActorId right) => left.Value >= right.Value; + public static bool operator >=(in ActorId left, in ActorId right) + { + return left.Value >= right.Value; + } #endregion #region Implicit [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator bool(in ActorId actor) => actor.IsNotEmpty; + public static implicit operator bool(in ActorId actor) + { + return actor.IsNotEmpty; + } #endregion -} \ No newline at end of file +} diff --git a/src/Hexecs/Actors/ActorList.Enumerator.cs b/src/Hexecs/Actors/ActorList.Enumerator.cs index 405cfa7..874a0e7 100644 --- a/src/Hexecs/Actors/ActorList.Enumerator.cs +++ b/src/Hexecs/Actors/ActorList.Enumerator.cs @@ -9,14 +9,15 @@ public ref struct Enumerator public static Enumerator Empty { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => new(); + get => new Enumerator(); } public readonly ActorRef Current { get { - var id = _ids[_index]; + ActorId id = _ids[_index]; + return new ActorRef( context: _pool.Context, id: id, @@ -51,16 +52,23 @@ internal Enumerator(ActorList list) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool MoveNext() => ++_index < _ids.Length; + public bool MoveNext() + { + return ++_index < _ids.Length; + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public readonly Enumerator GetEnumerator() => this; + public readonly Enumerator GetEnumerator() + { + return this; + } public Actor[] ToArray() { var count = 0; - var actors = ArrayUtils.Create(_ids.Length); - foreach (var actor in this) + Actor[] actors = ArrayUtils.Create(_ids.Length); + + foreach (ActorRef actor in this) { actors[count++] = actor; } @@ -68,4 +76,4 @@ public Actor[] ToArray() return actors; } } -} \ No newline at end of file +} diff --git a/src/Hexecs/Actors/ActorList.cs b/src/Hexecs/Actors/ActorList.cs index c4507e9..0017874 100644 --- a/src/Hexecs/Actors/ActorList.cs +++ b/src/Hexecs/Actors/ActorList.cs @@ -32,7 +32,7 @@ public ActorList( int capacity = 8) { _arrayPool = arrayPool ?? ArrayPool.Shared; - + _array = capacity == 0 ? [] : _arrayPool.Rent(capacity); @@ -44,12 +44,18 @@ public ActorList( context.Cleared += OnCleared; } - public void Add(in ActorRef actor) => Add(actor.Id); + public void Add(in ActorRef actor) + { + Add(actor.Id); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Add(ActorId actorId) { - if (_disposed) ActorError.Disposed(typeof(ActorList)); + if (_disposed) + { + ActorError.Disposed(typeof(ActorList)); + } ArrayUtils.Insert(ref _array, _arrayPool, _length, actorId); _length++; @@ -57,7 +63,10 @@ public void Add(ActorId actorId) public void Clear() { - if (_array.Length > 0) _arrayPool.Return(_array); + if (_array.Length > 0) + { + _arrayPool.Return(_array); + } _array = []; _length = 0; @@ -76,7 +85,11 @@ public bool Contains(ActorId actorId) public void Dispose() { - if (_disposed) return; + if (_disposed) + { + return; + } + _disposed = true; Clear(); @@ -101,8 +114,12 @@ public bool Remove(in ActorRef actor) [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Remove(ActorId actorId) { - var index = Array.IndexOf(_array, actorId, 0, _length); - if (index == -1) return false; + int index = Array.IndexOf(_array, actorId, 0, _length); + + if (index == -1) + { + return false; + } ArrayUtils.Cut(_array, index); _length--; @@ -111,14 +128,20 @@ public bool Remove(ActorId actorId) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private Span AsSpan() => _length == 0 - ? Span.Empty - : _array.AsSpan(0, _length); + private Span AsSpan() + { + return _length == 0 + ? Span.Empty + : _array.AsSpan(0, _length); + } - private void OnCleared() => Clear(); + private void OnCleared() + { + Clear(); + } private void OnRemoved(ActorId actorId) { Remove(actorId); } -} \ No newline at end of file +} diff --git a/src/Hexecs/Actors/ActorMarshal.cs b/src/Hexecs/Actors/ActorMarshal.cs index 356960c..fe17c27 100644 --- a/src/Hexecs/Actors/ActorMarshal.cs +++ b/src/Hexecs/Actors/ActorMarshal.cs @@ -19,16 +19,19 @@ public static class ActorMarshal public static void ClearComponentsData(ActorContext context) where T : struct, IActorComponent { - var pool = context.GetComponentPool(); + ActorComponentPool? pool = context.GetComponentPool(); pool?.GetValues().Clear(); } - + /// /// Получает идентификатор типа компонента. /// /// Тип компонента актёра. /// Идентификатор типа компонента. - public static ushort GetComponentId() where T : struct, IActorComponent => ActorComponentType.Id; + public static ushort GetComponentId() where T : struct, IActorComponent + { + return ActorComponentType.Id; + } /// /// Получает идентификатор типа компонента по его типу. @@ -38,7 +41,11 @@ public static void ClearComponentsData(ActorContext context) /// Выбрасывается, если переданный тип не является компонентом актёра. public static ushort GetComponentId(Type componentType) { - if (componentType.IsAssignableTo(typeof(IActorComponent))) ActorError.NotComponentType(componentType); + if (componentType.IsAssignableTo(typeof(IActorComponent))) + { + ActorError.NotComponentType(componentType); + } + return ActorComponentType.GetId(componentType); } @@ -48,7 +55,10 @@ public static ushort GetComponentId(Type componentType) /// Идентификатор типа компонента. /// Тип компонента. /// Выбрасывается, если по указанному идентификатору не найден тип компонента. - public static Type GetComponentType(ushort componentId) => ActorComponentType.GetType(componentId); + public static Type GetComponentType(ushort componentId) + { + return ActorComponentType.GetType(componentId); + } /// /// Получает владельца компонента. @@ -64,10 +74,10 @@ public static ushort GetComponentId(Type componentType) public static ActorRef GetOwner(ActorContext context, ref T component) where T : struct, IActorComponent { - var pool = context.GetComponentPool(); + ActorComponentPool? pool = context.GetComponentPool(); if (pool != null) { - foreach (var exists in pool) + foreach (ActorRef exists in pool) { if (Unsafe.AreSame(ref component, ref exists.Component1)) { @@ -83,7 +93,10 @@ public static ActorRef GetOwner(ActorContext context, ref T component) /// /// Реализует ли этот компонент интерфейс /// - public static bool IsViewComponent() where T : struct, IActorComponent => ActorComponentType.IsView; + public static bool IsViewComponent() where T : struct, IActorComponent + { + return ActorComponentType.IsView; + } /// /// Устанавливает ассет для актёра. @@ -99,7 +112,10 @@ public static void SetAsset(in Actor actor, in Asset asset) /// Удаляет ассет у актёра. /// /// Актёр, у которого удаляется ассет. - public static void RemoveAsset(in Actor actor) => SetAsset(in actor, Asset.Empty); + public static void RemoveAsset(in Actor actor) + { + SetAsset(in actor, Asset.Empty); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool TryGetDebugContext([NotNullWhen(true)] out ActorContext? actorContext) @@ -107,4 +123,4 @@ public static bool TryGetDebugContext([NotNullWhen(true)] out ActorContext? acto actorContext = WorldDebug.World?.Actors; return actorContext != null; } -} \ No newline at end of file +} diff --git a/src/Hexecs/Actors/ActorRef1.cs b/src/Hexecs/Actors/ActorRef1.cs index 18de0b6..f46aa5e 100644 --- a/src/Hexecs/Actors/ActorRef1.cs +++ b/src/Hexecs/Actors/ActorRef1.cs @@ -89,7 +89,10 @@ internal ActorRef(ActorContext context, ActorId id, ref T1 component1) /// Компонент для добавления. /// Выбрасывается, если актёр не найден в контексте или компонент уже существует. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Add(in T component) where T : struct, IActorComponent => Context.AddComponent(Id, in component); + public void Add(in T component) where T : struct, IActorComponent + { + Context.AddComponent(Id, in component); + } /// /// Добавляет дочернего актёра к текущему. @@ -97,7 +100,10 @@ internal ActorRef(ActorContext context, ActorId id, ref T1 component1) /// Дочерний актёр. /// Выбрасывается, если один из актёров не найден или дочерний актёр уже добавлен. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void AddChild(in Actor child) => Context.AddChild(Id, child.Id); + public void AddChild(in Actor child) + { + Context.AddChild(Id, child.Id); + } /// /// Добавляет отношение между текущим актёром и указанным родственным актёром. @@ -154,7 +160,10 @@ public bool Destroy() /// Ссылка на компонент. /// Выбрасывается, если актёр не найден или не содержит указанный компонент. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ref T Get() where T : struct, IActorComponent => ref Context.GetComponent(Id); + public ref T Get() where T : struct, IActorComponent + { + return ref Context.GetComponent(Id); + } /// /// Получает ассет, связанный с актёром. @@ -392,24 +401,33 @@ public bool Update(in T component, bool createIfNotExists = true) /// Ссылка на актёра для сравнения. /// Возвращает true, если ссылки на актёров равны; иначе false. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(ActorRef other) => Id == other.Id && Context == other.Context; + public bool Equals(ActorRef other) + { + return Id == other.Id && Context == other.Context; + } /// /// Проверяет равенство с другим объектом. /// /// Объект для сравнения. /// Возвращает true, если объекты равны; иначе false. - public override bool Equals(object? obj) => obj switch + public override bool Equals(object? obj) { - Actor actor => actor.IsRef(out var expected) && Equals(expected), - _ => false - }; + return obj switch + { + Actor actor => actor.IsRef(out ActorRef expected) && Equals(expected), + _ => false + }; + } /// /// Возвращает хеш-код для ссылки на актёра. /// /// Хеш-код ссылки на актёра. - public override int GetHashCode() => HashCode.Combine(Id); + public override int GetHashCode() + { + return HashCode.Combine(Id); + } /// /// Сравнивает две ссылки на актёров на равенство. @@ -418,7 +436,10 @@ public bool Update(in T component, bool createIfNotExists = true) /// Правая ссылка на актёра. /// Возвращает true, если ссылки на актёров равны; иначе false. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(in ActorRef left, in ActorRef right) => left.Equals(right); + public static bool operator ==(in ActorRef left, in ActorRef right) + { + return left.Equals(right); + } /// /// Сравнивает две ссылки на актёров на неравенство. @@ -427,7 +448,10 @@ public bool Update(in T component, bool createIfNotExists = true) /// Правая ссылка на актёра. /// Возвращает true, если ссылки на актёров не равны; иначе false. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(in ActorRef left, in ActorRef right) => !left.Equals(right); + public static bool operator !=(in ActorRef left, in ActorRef right) + { + return !left.Equals(right); + } #endregion @@ -439,7 +463,10 @@ public bool Update(in T component, bool createIfNotExists = true) /// Ссылка на актёра для преобразования. /// Возвращает true, если ссылка на актёра не пустая; иначе false. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator bool(in ActorRef actor) => !actor.IsEmpty; + public static implicit operator bool(in ActorRef actor) + { + return !actor.IsEmpty; + } /// /// Неявное преобразование ссылки на актёра в ActorId. @@ -447,7 +474,10 @@ public bool Update(in T component, bool createIfNotExists = true) /// Ссылка на актёра для преобразования. /// Идентификатор актёра. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator ActorId(in ActorRef actor) => actor.Id; + public static implicit operator ActorId(in ActorRef actor) + { + return actor.Id; + } /// /// Неявное преобразование ссылки на актёра в актёра. @@ -455,7 +485,10 @@ public bool Update(in T component, bool createIfNotExists = true) /// Ссылка на актёра для преобразования. /// Актёр. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator Actor(in ActorRef actor) => new(actor.Context, actor.Id); + public static implicit operator Actor(in ActorRef actor) + { + return new Actor(actor.Context, actor.Id); + } #endregion -} \ No newline at end of file +} diff --git a/src/Hexecs/Actors/ActorRef2.cs b/src/Hexecs/Actors/ActorRef2.cs index 556fb1f..7691028 100644 --- a/src/Hexecs/Actors/ActorRef2.cs +++ b/src/Hexecs/Actors/ActorRef2.cs @@ -65,10 +65,16 @@ internal ActorRef(ActorContext context, ActorId id, ref T1 component1, ref T2 co } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Add(in T component) where T : struct, IActorComponent => Context.AddComponent(Id, in component); + public void Add(in T component) where T : struct, IActorComponent + { + Context.AddComponent(Id, in component); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void AddChild(in Actor child) => Context.AddChild(Id, child.Id); + public void AddChild(in Actor child) + { + Context.AddChild(Id, child.Id); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] public ref T AddRelation(in Actor relative, in T relation) where T : struct @@ -77,22 +83,40 @@ public ref T AddRelation(in Actor relative, in T relation) where T : struct } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ActorRef AsRef() where T : struct, IActorComponent => Context.GetActorRef(Id); + public ActorRef AsRef() where T : struct, IActorComponent + { + return Context.GetActorRef(Id); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ActorContext.ChildrenEnumerator Children() => Context.Children(Id); + public ActorContext.ChildrenEnumerator Children() + { + return Context.Children(Id); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Destroy() => Context.DestroyActor(Id); + public bool Destroy() + { + return Context.DestroyActor(Id); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ref T Get() where T : struct, IActorComponent => ref Context.GetComponent(Id); + public ref T Get() where T : struct, IActorComponent + { + return ref Context.GetComponent(Id); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Asset GetAsset() => Context.GetBoundAsset(Id); + public Asset GetAsset() + { + return Context.GetBoundAsset(Id); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ref T GetRelation(in Actor relative) where T : struct => ref Context.GetRelation(Id, relative.Id); + public ref T GetRelation(in Actor relative) where T : struct + { + return ref Context.GetRelation(Id, relative.Id); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Has() @@ -170,7 +194,7 @@ public override string ToString() } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool TryAdd(in T component) + public bool TryAdd(in T component) where T : struct, IActorComponent { return Context.TryAdd(Id, in component); @@ -183,7 +207,7 @@ public bool TryGetAsset(out Asset asset) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ref T TryGetRef() + public ref T TryGetRef() where T : struct, IActorComponent { return ref Context.TryGetComponentRef(Id); @@ -204,42 +228,72 @@ public bool Update(in T component, bool createIfNotExists = true) where T : s #region Equality [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(ActorRef other) => Id == other.Id && Context == other.Context; + public bool Equals(ActorRef other) + { + return Id == other.Id && Context == other.Context; + } - public override bool Equals(object? obj) => obj is Actor other && Id == other.Id; + public override bool Equals(object? obj) + { + return obj is Actor other && Id == other.Id; + } - public override int GetHashCode() => HashCode.Combine(Id); + public override int GetHashCode() + { + return HashCode.Combine(Id); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(in ActorRef left, in ActorRef right) => left.Equals(right); + public static bool operator ==(in ActorRef left, in ActorRef right) + { + return left.Equals(right); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(in ActorRef left, in ActorRef right) => !left.Equals(right); + public static bool operator !=(in ActorRef left, in ActorRef right) + { + return !left.Equals(right); + } #endregion #region Implicit [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator bool(in ActorRef actor) => !actor.IsEmpty; + public static implicit operator bool(in ActorRef actor) + { + return !actor.IsEmpty; + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator ActorId(in ActorRef actor) => actor.Id; + public static implicit operator ActorId(in ActorRef actor) + { + return actor.Id; + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator Actor(in ActorRef actor) => new(actor.Context, actor.Id); + public static implicit operator Actor(in ActorRef actor) + { + return new Actor(actor.Context, actor.Id); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator ActorRef(in ActorRef actor) => new( - actor.Context, - actor.Id, - ref actor._component1); + public static implicit operator ActorRef(in ActorRef actor) + { + return new ActorRef( + actor.Context, + actor.Id, + ref actor._component1); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator ActorRef(in ActorRef actor) => new( - actor.Context, - actor.Id, - ref actor._component2); + public static implicit operator ActorRef(in ActorRef actor) + { + return new ActorRef( + actor.Context, + actor.Id, + ref actor._component2); + } #endregion -} \ No newline at end of file +} diff --git a/src/Hexecs/Actors/ActorRef3.cs b/src/Hexecs/Actors/ActorRef3.cs index a51402e..beb29d3 100644 --- a/src/Hexecs/Actors/ActorRef3.cs +++ b/src/Hexecs/Actors/ActorRef3.cs @@ -74,10 +74,16 @@ internal ActorRef(ActorContext context, ActorId id, ref T1 component1, ref T2 co } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Add(in T component) where T : struct, IActorComponent => Context.AddComponent(Id, in component); + public void Add(in T component) where T : struct, IActorComponent + { + Context.AddComponent(Id, in component); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void AddChild(in Actor child) => Context.AddChild(Id, child.Id); + public void AddChild(in Actor child) + { + Context.AddChild(Id, child.Id); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] public ref T AddRelation(in Actor relative, in T relation) where T : struct @@ -86,31 +92,58 @@ public ref T AddRelation(in Actor relative, in T relation) where T : struct } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ActorRef AsRef() where T : struct, IActorComponent => Context.GetActorRef(Id); + public ActorRef AsRef() where T : struct, IActorComponent + { + return Context.GetActorRef(Id); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ActorContext.ChildrenEnumerator Children() => Context.Children(Id); + public ActorContext.ChildrenEnumerator Children() + { + return Context.Children(Id); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Destroy() => Context.DestroyActor(Id); + public bool Destroy() + { + return Context.DestroyActor(Id); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ref T Get() where T : struct, IActorComponent => ref Context.GetComponent(Id); + public ref T Get() where T : struct, IActorComponent + { + return ref Context.GetComponent(Id); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Asset GetAsset() => Context.GetBoundAsset(Id); + public Asset GetAsset() + { + return Context.GetBoundAsset(Id); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ref T GetRelation(in Actor relative) where T : struct => ref Context.GetRelation(Id, relative.Id); + public ref T GetRelation(in Actor relative) where T : struct + { + return ref Context.GetRelation(Id, relative.Id); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Has() where T : struct, IActorComponent => Context.HasComponent(Id); + public bool Has() where T : struct, IActorComponent + { + return Context.HasComponent(Id); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool HasChild(in Actor child) => Context.HasChild(Id, child.Id); + public bool HasChild(in Actor child) + { + return Context.HasChild(Id, child.Id); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool HasRelation(in Actor relative) where T : struct => Context.HasRelation(Id, relative.Id); + public bool HasRelation(in Actor relative) where T : struct + { + return Context.HasRelation(Id, relative.Id); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool IsRef(out ActorRef actor) where T : struct, IActorComponent @@ -119,10 +152,16 @@ public bool IsRef(out ActorRef actor) where T : struct, IActorComponent } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ActorRelationEnumerator Relations() where T : struct => Context.Relations(Id); + public ActorRelationEnumerator Relations() where T : struct + { + return Context.Relations(Id); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Remove() where T : struct, IActorComponent => Context.RemoveComponent(Id); + public bool Remove() where T : struct, IActorComponent + { + return Context.RemoveComponent(Id); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Remove(out T component) where T : struct, IActorComponent @@ -131,10 +170,16 @@ public bool Remove(out T component) where T : struct, IActorComponent } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool RemoveChild(in Actor child) => Context.RemoveChild(Id, child.Id); + public bool RemoveChild(in Actor child) + { + return Context.RemoveChild(Id, child.Id); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool RemoveRelation(in Actor relative) where T : struct => Context.RemoveRelation(Id, relative.Id); + public bool RemoveRelation(in Actor relative) where T : struct + { + return Context.RemoveRelation(Id, relative.Id); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool RemoveRelation(in Actor relative, out T relation) where T : struct @@ -142,21 +187,36 @@ public bool RemoveRelation(in Actor relative, out T relation) where T : struc return Context.RemoveRelation(Id, relative.Id, out relation); } - public override string ToString() => Context == null - ? StringUtils.EmptyValue - : Context.GetDescription(Id); + public override string ToString() + { + return Context == null + ? StringUtils.EmptyValue + : Context.GetDescription(Id); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool TryAdd(in T component) where T : struct, IActorComponent => Context.TryAdd(Id, in component); + public bool TryAdd(in T component) where T : struct, IActorComponent + { + return Context.TryAdd(Id, in component); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool TryGetAsset(out Asset asset) => Context.TryGetBoundAsset(Id, out asset); + public bool TryGetAsset(out Asset asset) + { + return Context.TryGetBoundAsset(Id, out asset); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ref T TryGetRef() where T : struct, IActorComponent => ref Context.TryGetComponentRef(Id); + public ref T TryGetRef() where T : struct, IActorComponent + { + return ref Context.TryGetComponentRef(Id); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool TryGetParent(out Actor parent) => Context.TryGetParent(Id, out parent); + public bool TryGetParent(out Actor parent) + { + return Context.TryGetParent(Id, out parent); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Update(in T component, bool createIfNotExists = true) where T : struct, IActorComponent @@ -167,69 +227,111 @@ public bool Update(in T component, bool createIfNotExists = true) where T : s #region Equality [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(ActorRef other) => Id == other.Id && Context == other.Context; + public bool Equals(ActorRef other) + { + return Id == other.Id && Context == other.Context; + } - public override bool Equals(object? obj) => obj is Actor other && Id == other.Id; + public override bool Equals(object? obj) + { + return obj is Actor other && Id == other.Id; + } - public override int GetHashCode() => HashCode.Combine(Id); + public override int GetHashCode() + { + return HashCode.Combine(Id); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(in ActorRef left, in ActorRef right) => left.Equals(right); + public static bool operator ==(in ActorRef left, in ActorRef right) + { + return left.Equals(right); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(in ActorRef left, in ActorRef right) => !left.Equals(right); + public static bool operator !=(in ActorRef left, in ActorRef right) + { + return !left.Equals(right); + } #endregion #region Implicit [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator bool(in ActorRef actor) => !actor.IsEmpty; + public static implicit operator bool(in ActorRef actor) + { + return !actor.IsEmpty; + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator ActorId(in ActorRef actor) => actor.Id; + public static implicit operator ActorId(in ActorRef actor) + { + return actor.Id; + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator Actor(in ActorRef actor) => new(actor.Context, actor.Id); + public static implicit operator Actor(in ActorRef actor) + { + return new Actor(actor.Context, actor.Id); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator ActorRef(in ActorRef actor) => new( - actor.Context, - actor.Id, - ref actor._component1); + public static implicit operator ActorRef(in ActorRef actor) + { + return new ActorRef( + actor.Context, + actor.Id, + ref actor._component1); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator ActorRef(in ActorRef actor) => new( - actor.Context, - actor.Id, - ref actor._component2); + public static implicit operator ActorRef(in ActorRef actor) + { + return new ActorRef( + actor.Context, + actor.Id, + ref actor._component2); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator ActorRef(in ActorRef actor) => new( - actor.Context, - actor.Id, - ref actor._component3); + public static implicit operator ActorRef(in ActorRef actor) + { + return new ActorRef( + actor.Context, + actor.Id, + ref actor._component3); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator ActorRef(in ActorRef actor) => new( - actor.Context, - actor.Id, - ref actor._component1, - ref actor._component2); + public static implicit operator ActorRef(in ActorRef actor) + { + return new ActorRef( + actor.Context, + actor.Id, + ref actor._component1, + ref actor._component2); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator ActorRef(in ActorRef actor) => new( - actor.Context, - actor.Id, - ref actor._component1, - ref actor._component3); + public static implicit operator ActorRef(in ActorRef actor) + { + return new ActorRef( + actor.Context, + actor.Id, + ref actor._component1, + ref actor._component3); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator ActorRef(in ActorRef actor) => new( - actor.Context, - actor.Id, - ref actor._component2, - ref actor._component3); + public static implicit operator ActorRef(in ActorRef actor) + { + return new ActorRef( + actor.Context, + actor.Id, + ref actor._component2, + ref actor._component3); + } #endregion -} \ No newline at end of file +} diff --git a/src/Hexecs/Actors/ActorRelation.cs b/src/Hexecs/Actors/ActorRelation.cs index fb4a58d..a664068 100644 --- a/src/Hexecs/Actors/ActorRelation.cs +++ b/src/Hexecs/Actors/ActorRelation.cs @@ -11,7 +11,7 @@ public readonly ref struct ActorRelation public ActorRelation Empty { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => new(null!, ActorId.Empty, ref Unsafe.NullRef()); + get => new ActorRelation(null!, ActorId.Empty, ref Unsafe.NullRef()); } public readonly ActorId Id; @@ -94,13 +94,22 @@ public Asset GetAsset() } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ref T GetRelation(in Actor relative) where T : struct => ref Context.GetRelation(Id, relative.Id); + public ref T GetRelation(in Actor relative) where T : struct + { + return ref Context.GetRelation(Id, relative.Id); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Has() where T : struct, IActorComponent => Context.HasComponent(Id); + public bool Has() where T : struct, IActorComponent + { + return Context.HasComponent(Id); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool HasRelation(in Actor relative) where T : struct => Context.HasRelation(Id, relative.Id); + public bool HasRelation(in Actor relative) where T : struct + { + return Context.HasRelation(Id, relative.Id); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool IsRef(out ActorRef actor) where T : struct, IActorComponent @@ -109,10 +118,16 @@ public bool IsRef(out ActorRef actor) where T : struct, IActorComponent } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ActorRelationEnumerator Relations() where T : struct => Context.Relations(Id); + public ActorRelationEnumerator Relations() where T : struct + { + return Context.Relations(Id); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Remove() where T : struct, IActorComponent => Context.RemoveComponent(Id); + public bool Remove() where T : struct, IActorComponent + { + return Context.RemoveComponent(Id); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Remove(out T component) where T : struct, IActorComponent @@ -121,10 +136,16 @@ public bool Remove(out T component) where T : struct, IActorComponent } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool RemoveChild(in Actor child) => Context.RemoveChild(Id, child.Id); + public bool RemoveChild(in Actor child) + { + return Context.RemoveChild(Id, child.Id); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool RemoveRelation(in Actor relative) where T : struct => Context.RemoveRelation(Id, relative.Id); + public bool RemoveRelation(in Actor relative) where T : struct + { + return Context.RemoveRelation(Id, relative.Id); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool RemoveRelation(in Actor relative, out T relation) where T : struct @@ -133,10 +154,16 @@ public bool RemoveRelation(in Actor relative, out T relation) where T : struc } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool TryGetAsset(out Asset asset) => Context.TryGetBoundAsset(Id, out asset); + public bool TryGetAsset(out Asset asset) + { + return Context.TryGetBoundAsset(Id, out asset); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool TryGetParent(out Actor parent) => Context.TryGetParent(Id, out parent); + public bool TryGetParent(out Actor parent) + { + return Context.TryGetParent(Id, out parent); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Update(in T component, bool createIfNotExists = true) where T : struct, IActorComponent @@ -147,10 +174,16 @@ public bool Update(in T component, bool createIfNotExists = true) where T : s #region Implicit [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator Actor(in ActorRelation relation) => new(relation.Context, relation.Id); + public static implicit operator Actor(in ActorRelation relation) + { + return new Actor(relation.Context, relation.Id); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator bool(in ActorRelation relation) => !relation.IsEmpty; + public static implicit operator bool(in ActorRelation relation) + { + return !relation.IsEmpty; + } #endregion -} \ No newline at end of file +} diff --git a/src/Hexecs/Actors/Bounds/BoundComponent.cs b/src/Hexecs/Actors/Bounds/BoundComponent.cs index 06cc966..881b918 100644 --- a/src/Hexecs/Actors/Bounds/BoundComponent.cs +++ b/src/Hexecs/Actors/Bounds/BoundComponent.cs @@ -30,10 +30,10 @@ public static ActorComponentConfiguration CreatePoolConfiguratio public override string ToString() { - return AssetMarshal.TryGetDebugContext(out var context) + return AssetMarshal.TryGetDebugContext(out AssetContext? context) ? context.GetDescription(AssetId) : AssetId.IsEmpty ? StringUtils.EmptyValue : AssetId.ToString(); } -} \ No newline at end of file +} diff --git a/src/Hexecs/Actors/Bounds/BoundComponentConverter.cs b/src/Hexecs/Actors/Bounds/BoundComponentConverter.cs index b21b985..b5654d0 100644 --- a/src/Hexecs/Actors/Bounds/BoundComponentConverter.cs +++ b/src/Hexecs/Actors/Bounds/BoundComponentConverter.cs @@ -1,4 +1,5 @@ using System.Text.Json; + using Hexecs.Actors.Serializations; using Hexecs.Serializations; @@ -6,8 +7,8 @@ namespace Hexecs.Actors.Bounds; internal sealed class BoundComponentConverter : IActorComponentConverter { - public static readonly BoundComponentConverter Instance = new(); - + public static readonly BoundComponentConverter Instance = new BoundComponentConverter(); + public BoundComponent Deserialize(ActorContext context, ref Utf8JsonReader reader) { throw new NotImplementedException(); @@ -17,4 +18,4 @@ public void Serialize(ActorContext context, Utf8JsonWriter writer, in BoundCompo { writer.WriteProperty(nameof(BoundComponent.AssetId), component.AssetId); } -} \ No newline at end of file +} diff --git a/src/Hexecs/Actors/Bounds/BoundComponentDebugProxy.cs b/src/Hexecs/Actors/Bounds/BoundComponentDebugProxy.cs index 4e2ea43..fb20aa1 100644 --- a/src/Hexecs/Actors/Bounds/BoundComponentDebugProxy.cs +++ b/src/Hexecs/Actors/Bounds/BoundComponentDebugProxy.cs @@ -13,11 +13,12 @@ public BoundComponentDebugProxy(BoundComponent bound) if (bound.AssetId.IsEmpty) { Components = []; + return; } - Components = AssetMarshal.TryGetDebugContext(out var assetContext) + Components = AssetMarshal.TryGetDebugContext(out AssetContext? assetContext) ? assetContext.Components(bound.AssetId).ToArray() : []; } -} \ No newline at end of file +} diff --git a/src/Hexecs/Actors/Components/ActorComponentConfiguration.cs b/src/Hexecs/Actors/Components/ActorComponentConfiguration.cs index 68a1bd4..d81d851 100644 --- a/src/Hexecs/Actors/Components/ActorComponentConfiguration.cs +++ b/src/Hexecs/Actors/Components/ActorComponentConfiguration.cs @@ -22,11 +22,7 @@ internal sealed class ActorComponentConfiguration( /// /// Пустая конфигурация без каких-либо настроек /// - public static readonly ActorComponentConfiguration Empty = new( - null, - null, - null, - null); + public static readonly ActorComponentConfiguration Empty = new ActorComponentConfiguration(null, null, null, null); /// /// Начальная емкость пула компонентов. Null означает использование емкости по умолчанию. @@ -52,4 +48,4 @@ internal sealed class ActorComponentConfiguration( /// /// Маркерный интерфейс для конфигурации компонентов актёра /// -internal interface IActorComponentConfiguration; \ No newline at end of file +internal interface IActorComponentConfiguration; diff --git a/src/Hexecs/Actors/Components/ActorComponentPool.AddResult.cs b/src/Hexecs/Actors/Components/ActorComponentPool.AddResult.cs index fb6f8b2..70ab303 100644 --- a/src/Hexecs/Actors/Components/ActorComponentPool.AddResult.cs +++ b/src/Hexecs/Actors/Components/ActorComponentPool.AddResult.cs @@ -5,10 +5,16 @@ internal sealed partial class ActorComponentPool private readonly ref struct AddResult { [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static AddResult Failure() => new(-1, ref Unsafe.NullRef()); + public static AddResult Failure() + { + return new AddResult(-1, ref Unsafe.NullRef()); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static AddResult Success(int index, ref T component) => new(index, ref component); + public static AddResult Success(int index, ref T component) + { + return new AddResult(index, ref component); + } public readonly ref T Component; public readonly int Index; @@ -26,4 +32,4 @@ private AddResult(int index, ref T component) Index = index; } } -} \ No newline at end of file +} diff --git a/src/Hexecs/Actors/Components/ActorComponentPool.Dictionary.cs b/src/Hexecs/Actors/Components/ActorComponentPool.Dictionary.cs index 53afa5f..7118429 100644 --- a/src/Hexecs/Actors/Components/ActorComponentPool.Dictionary.cs +++ b/src/Hexecs/Actors/Components/ActorComponentPool.Dictionary.cs @@ -16,10 +16,12 @@ public int Length [MethodImpl(MethodImplOptions.AggressiveInlining)] private bool ContainsEntry(uint ownerId) { - var sparse = _sparse; + uint[] sparse = _sparse; + if (ownerId < (uint)sparse.Length) { - var denseIndexPlusOne = sparse[ownerId]; + uint denseIndexPlusOne = sparse[ownerId]; + return denseIndexPlusOne != 0 && _dense[denseIndexPlusOne - 1] == ownerId; } @@ -31,7 +33,7 @@ private void EnsureCapacity(uint ownerId) // Проверка емкости плотных массивов (количество элементов) if (_count >= _dense.Length) { - var newSize = _dense.Length * 2; + int newSize = _dense.Length * 2; Array.Resize(ref _dense, newSize); Array.Resize(ref _values, newSize); } @@ -39,7 +41,7 @@ private void EnsureCapacity(uint ownerId) // Проверка емкости разреженного массива (максимальный ID) if (ownerId >= (uint)_sparse.Length) { - var newSize = Math.Max((uint)_sparse.Length * 2, ownerId + 1); + uint newSize = Math.Max((uint)_sparse.Length * 2, ownerId + 1); Array.Resize(ref _sparse, (int)newSize); } } @@ -47,13 +49,16 @@ private void EnsureCapacity(uint ownerId) [MethodImpl(MethodImplOptions.AggressiveInlining)] private ref T GetEntryRef(uint actorId) { - var sparse = _sparse; + uint[] sparse = _sparse; + if (actorId < (uint)sparse.Length) { - var denseIndexPlusOne = sparse[actorId]; + uint denseIndexPlusOne = sparse[actorId]; + if (denseIndexPlusOne != 0) { - var index = (int)denseIndexPlusOne - 1; + int index = (int)denseIndexPlusOne - 1; + if (_dense[index] == actorId) { return ref _values[index]; @@ -66,16 +71,19 @@ private ref T GetEntryRef(uint actorId) private bool RemoveEntry(uint ownerId, out T value) { - var sparse = _sparse; + uint[] sparse = _sparse; + if (ownerId < (uint)sparse.Length) { - var slot = sparse[ownerId]; + uint slot = sparse[ownerId]; + if (slot != 0) { - var denseIndex = (int)slot - 1; + int denseIndex = (int)slot - 1; + if (_dense[denseIndex] == ownerId) { - ref var componentRef = ref _values[denseIndex]; + ref T componentRef = ref _values[denseIndex]; value = componentRef; var actorId = new ActorId(_dense[denseIndex]); @@ -83,10 +91,11 @@ private bool RemoveEntry(uint ownerId, out T value) ComponentRemoving?.Invoke(actorId, ref componentRef); _disposeHandler?.Invoke(ref componentRef); - var lastIndex = _count - 1; + int lastIndex = _count - 1; + if (denseIndex != lastIndex) { - var lastKey = _dense[lastIndex]; + uint lastKey = _dense[lastIndex]; _dense[denseIndex] = lastKey; _values[denseIndex] = _values[lastIndex]; @@ -96,12 +105,14 @@ private bool RemoveEntry(uint ownerId, out T value) _sparse[ownerId] = 0; _count = lastIndex; + return true; } } } value = default; + return false; } @@ -111,20 +122,25 @@ private AddResult TryAddEntry(uint ownerId) // Fast Path: если ID влезает в массив и есть место в dense if (ownerId < (uint)_sparse.Length && (uint)_count < (uint)_dense.Length) { - ref var slot = ref _sparse[ownerId]; + ref uint slot = ref _sparse[ownerId]; + if (slot == 0) { var idx = (uint)_count; slot = idx + 1; _dense[idx] = ownerId; - ref var internalRef = ref _values[idx]; - var result = AddResult.Success(_count, ref internalRef); + ref T internalRef = ref _values[idx]; + AddResult result = AddResult.Success(_count, ref internalRef); _count++; + return result; } - if (_dense[slot - 1] == ownerId) return AddResult.Failure(); + if (_dense[slot - 1] == ownerId) + { + return AddResult.Failure(); + } } return TryAddEntrySlow(ownerId); @@ -135,18 +151,22 @@ private AddResult TryAddEntrySlow(uint ownerId) { EnsureCapacity(ownerId); - ref var denseIndexPlusOne = ref _sparse[ownerId]; + ref uint denseIndexPlusOne = ref _sparse[ownerId]; + if (denseIndexPlusOne != 0) { - if (_dense[denseIndexPlusOne - 1] == ownerId) return AddResult.Failure(); + if (_dense[denseIndexPlusOne - 1] == ownerId) + { + return AddResult.Failure(); + } } var denseIndex = (uint)_count; denseIndexPlusOne = denseIndex + 1; _dense[denseIndex] = ownerId; - ref var internalRef = ref _values[denseIndex]; - var result = AddResult.Success(_count, ref internalRef); + ref T internalRef = ref _values[denseIndex]; + AddResult result = AddResult.Success(_count, ref internalRef); _count++; return result; @@ -157,29 +177,34 @@ private AddResult UpsertEntry(uint ownerId, out bool exists) { if (ownerId < (uint)_sparse.Length) { - ref var slot = ref _sparse[ownerId]; + ref uint slot = ref _sparse[ownerId]; + if (slot != 0) { - var denseIndex = (int)slot - 1; + int denseIndex = (int)slot - 1; + if (_dense[denseIndex] == ownerId) { exists = true; + return AddResult.Success(denseIndex, ref _values[denseIndex]); } } if ((uint)_count < (uint)_dense.Length) { - var idx = _count; + int idx = _count; slot = (uint)idx + 1; _dense[idx] = ownerId; _count = idx + 1; exists = false; + return AddResult.Success(idx, ref _values[idx]); } } exists = false; + return TryAddEntrySlow(ownerId); } -} \ No newline at end of file +} diff --git a/src/Hexecs/Actors/Components/ActorComponentPool.Enumerator.cs b/src/Hexecs/Actors/Components/ActorComponentPool.Enumerator.cs index bd9badd..be966bb 100644 --- a/src/Hexecs/Actors/Components/ActorComponentPool.Enumerator.cs +++ b/src/Hexecs/Actors/Components/ActorComponentPool.Enumerator.cs @@ -3,7 +3,10 @@ namespace Hexecs.Actors.Components; internal sealed partial class ActorComponentPool { [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Enumerator GetEnumerator() => new(this); + public Enumerator GetEnumerator() + { + return new Enumerator(this); + } public ref struct Enumerator { @@ -12,14 +15,15 @@ public readonly ActorRef Current [MethodImpl(MethodImplOptions.AggressiveInlining)] get { - var index = _index; + int index = _index; + return new ActorRef( - _context, - new ActorId(_dense[index]), + _context, + new ActorId(_dense[index]), ref _values[index]); } } - + public readonly int Index { [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -31,7 +35,7 @@ public readonly int Length [MethodImpl(MethodImplOptions.AggressiveInlining)] get => _count; } - + // Сначала ссылки (8 байт) private readonly ActorContext _context; private readonly uint[] _dense; @@ -52,9 +56,15 @@ internal Enumerator(ActorComponentPool pool) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool MoveNext() => ++_index < _count; + public bool MoveNext() + { + return ++_index < _count; + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public readonly Enumerator GetEnumerator() => this; + public readonly Enumerator GetEnumerator() + { + return this; + } } -} \ No newline at end of file +} diff --git a/src/Hexecs/Actors/Components/ActorComponentPool.Serialization.cs b/src/Hexecs/Actors/Components/ActorComponentPool.Serialization.cs index 203dc27..995752a 100644 --- a/src/Hexecs/Actors/Components/ActorComponentPool.Serialization.cs +++ b/src/Hexecs/Actors/Components/ActorComponentPool.Serialization.cs @@ -1,4 +1,5 @@ using System.Text.Json; + using Hexecs.Serializations; namespace Hexecs.Actors.Components; @@ -22,9 +23,9 @@ private void SerializeInstances(Utf8JsonWriter writer) { writer.WriteStartArray(); - var count = _count; - var keys = _dense; - var values = _values; + int count = _count; + uint[] keys = _dense; + T[] values = _values; for (var i = 0; i < count; i++) { @@ -43,4 +44,4 @@ private void SerializeInstances(Utf8JsonWriter writer) writer.WriteEndArray(); writer.Flush(); } -} \ No newline at end of file +} diff --git a/src/Hexecs/Actors/Components/ActorComponentPool.cs b/src/Hexecs/Actors/Components/ActorComponentPool.cs index 13cacdd..37dd65d 100644 --- a/src/Hexecs/Actors/Components/ActorComponentPool.cs +++ b/src/Hexecs/Actors/Components/ActorComponentPool.cs @@ -38,7 +38,7 @@ public ActorComponentPool(ActorContext context, ActorComponentConfiguration c { Context = context; - var capacity = HashHelper.GetPrime(configuration.Capacity ?? Math.Max(context.Length, 16)); + int capacity = HashHelper.GetPrime(configuration.Capacity ?? Math.Max(context.Length, 16)); _sparse = new uint[capacity]; _dense = new uint[capacity]; @@ -51,10 +51,10 @@ public ActorComponentPool(ActorContext context, ActorComponentConfiguration c public ref T Add(ActorId ownerId, in T component) { - var result = TryAddEntry(ownerId.Value); + AddResult result = TryAddEntry(ownerId.Value); if (result.IsSuccess) { - ref var componentRef = ref result.Component; + ref T componentRef = ref result.Component; componentRef = component; Added?.Invoke(ownerId); @@ -69,12 +69,12 @@ public ref T Add(ActorId ownerId, in T component) public void Clear() { - var dense = _dense; - var sparse = _sparse; + uint[] dense = _dense; + uint[] sparse = _sparse; if (_disposeHandler != null) { - foreach (ref var component in _values.AsSpan(0, _count)) + foreach (ref T component in _values.AsSpan(0, _count)) { _disposeHandler(ref component); } @@ -83,7 +83,7 @@ public void Clear() // Очищаем только те индексы в sparse, которые реально используются for (var i = 0; i < _count; i++) { - var key = dense[i]; + uint key = dense[i]; sparse[key] = 0; } @@ -92,15 +92,18 @@ public void Clear() public ref T Clone(ActorId ownerId, ActorId cloneId) { - ref var ownerEntry = ref GetEntryRef(ownerId.Value); - if (Unsafe.IsNullRef(ref ownerEntry)) ActorError.ComponentNotFound(ownerId); + ref T ownerEntry = ref GetEntryRef(ownerId.Value); + if (Unsafe.IsNullRef(ref ownerEntry)) + { + ActorError.ComponentNotFound(ownerId); + } if (_cloneHandler == null) { return ref Add(cloneId, in ownerEntry); } - var clone = _cloneHandler(in ownerEntry); + T clone = _cloneHandler(in ownerEntry); return ref Add(cloneId, Unsafe.AsRef(in clone)); } @@ -113,10 +116,10 @@ public ActorRef First() public ActorRef First(ActorPredicate predicate) { - var count = _count; - var keys = _dense; - var values = _values; - var context = Context; + int count = _count; + uint[] keys = _dense; + T[] values = _values; + ActorContext context = Context; for (var i = 0; i < count; i++) { @@ -133,7 +136,7 @@ public ActorRef First(ActorPredicate predicate) [MethodImpl(MethodImplOptions.AggressiveInlining)] public ref T Get(ActorId ownerId) { - ref var entry = ref GetEntryRef(ownerId.Value); + ref T entry = ref GetEntryRef(ownerId.Value); if (!Unsafe.IsNullRef(ref entry)) { return ref entry; @@ -143,12 +146,15 @@ public ref T Get(ActorId ownerId) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ComponentsAccess GetComponentAccess() => new(_sparse, _values); + public ComponentsAccess GetComponentAccess() + { + return new ComponentsAccess(_sparse, _values); + } public ref T GetOrCreate(ActorId ownerId, out bool added, Func? factory = null) { - var result = UpsertEntry(ownerId.Value, out var exists); - ref var componentRef = ref result.Component; + AddResult result = UpsertEntry(ownerId.Value, out bool exists); + ref T componentRef = ref result.Component; if (exists) { @@ -192,11 +198,14 @@ public bool Remove(ActorId ownerId, out T component) public bool TryAdd(ActorId ownerId, in T component) { - var result = TryAddEntry(ownerId.Value); + AddResult result = TryAddEntry(ownerId.Value); - if (!result.IsSuccess) return false; + if (!result.IsSuccess) + { + return false; + } - ref var componentRef = ref result.Component; + ref T componentRef = ref result.Component; componentRef = component; Added?.Invoke(ownerId); @@ -206,12 +215,18 @@ public bool TryAdd(ActorId ownerId, in T component) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ref T TryGet(uint ownerId) => ref GetEntryRef(ownerId); + public ref T TryGet(uint ownerId) + { + return ref GetEntryRef(ownerId); + } public bool Update(ActorId ownerId, in T component) { - ref var exists = ref GetEntryRef(ownerId.Value); - if (Unsafe.IsNullRef(ref exists)) return false; + ref T exists = ref GetEntryRef(ownerId.Value); + if (Unsafe.IsNullRef(ref exists)) + { + return false; + } ComponentUpdating?.Invoke(ownerId, ref exists, in component); @@ -227,9 +242,15 @@ ActorContext IActorComponentPool.Context get => Context; } - void IActorComponentPool.Clone(ActorId ownerId, ActorId cloneId) => Clone(ownerId, cloneId); + void IActorComponentPool.Clone(ActorId ownerId, ActorId cloneId) + { + Clone(ownerId, cloneId); + } - IActorComponent IActorComponentPool.Get(ActorId ownerId) => Get(ownerId); + IActorComponent IActorComponentPool.Get(ActorId ownerId) + { + return Get(ownerId); + } #endregion -} \ No newline at end of file +} diff --git a/src/Hexecs/Actors/Components/ActorComponentType.cs b/src/Hexecs/Actors/Components/ActorComponentType.cs index ec3f25d..23deba6 100644 --- a/src/Hexecs/Actors/Components/ActorComponentType.cs +++ b/src/Hexecs/Actors/Components/ActorComponentType.cs @@ -2,13 +2,13 @@ internal static class ActorComponentType { - private static readonly Dictionary ComponentTypes = new(128, ReferenceComparer.Instance); + private static readonly Dictionary ComponentTypes = new Dictionary(128, ReferenceComparer.Instance); #if NET9_0_OR_GREATER - private static readonly Lock LockObj = new(); + private static readonly Lock LockObj = new Lock(); #else - private static readonly object LockObj = new(); + private static readonly object LockObj = new object(); #endif - private static ushort _nextId; + private static ushort NextId; /// /// Получает уникальный идентификатор для указанного типа компонента. @@ -23,9 +23,12 @@ public static ushort GetId(Type type) lock (LockObj) #endif { - if (ComponentTypes.TryGetValue(type, out var exists)) return exists; + if (ComponentTypes.TryGetValue(type, out ushort exists)) + { + return exists; + } - var componentTypeId = _nextId++; + ushort componentTypeId = NextId++; ComponentTypes[type] = componentTypeId; return componentTypeId; @@ -46,12 +49,16 @@ public static Type GetType(ushort id) lock (LockObj) #endif { - foreach (var (type, existsId) in ComponentTypes) + foreach ((Type type, ushort existsId) in ComponentTypes) { - if (existsId == id) return type; + if (existsId == id) + { + return type; + } } ActorError.ComponentTypeNotFound(id); + return null; } } @@ -69,4 +76,4 @@ internal static class ActorComponentType /// Реализует ли этот компонент интерфейс /// public static readonly bool IsView = typeof(T).IsAssignableTo(typeof(IViewComponent)); -} \ No newline at end of file +} diff --git a/src/Hexecs/Actors/Development/ActorIdDebugProxy.cs b/src/Hexecs/Actors/Development/ActorIdDebugProxy.cs index aef5304..c7eac7f 100644 --- a/src/Hexecs/Actors/Development/ActorIdDebugProxy.cs +++ b/src/Hexecs/Actors/Development/ActorIdDebugProxy.cs @@ -6,9 +6,9 @@ internal sealed class ActorIdDebugProxy(ActorId actorId) { public IActorComponent[] Components => _components ??= actorId.IsEmpty ? [] - : ActorMarshal.TryGetDebugContext(out var actorContext) + : ActorMarshal.TryGetDebugContext(out ActorContext? actorContext) ? actorContext.Components(actorId).ToArray() : []; private IActorComponent[]? _components; -} \ No newline at end of file +} diff --git a/src/Hexecs/Actors/IActorBuilder.cs b/src/Hexecs/Actors/IActorBuilder.cs index 24ba803..428d122 100644 --- a/src/Hexecs/Actors/IActorBuilder.cs +++ b/src/Hexecs/Actors/IActorBuilder.cs @@ -18,10 +18,10 @@ public interface IActorBuilder } /// -/// Типизированный интерфейс строителя актёров, специализированный для работы +/// Типизированный интерфейс строителя актёров, специализированный для работы /// с определённым типом компонента ассета. /// -/// Тип компонента ассета, который используется +/// Тип компонента ассета, который используется /// для построения актёра. Должен быть структурой и реализовывать интерфейс IAssetComponent. public interface IActorBuilder : IActorBuilder where TAsset : struct, IAssetComponent @@ -36,9 +36,9 @@ public interface IActorBuilder : IActorBuilder void IActorBuilder.Build(in Actor actor, in Asset asset, Args args) { - if (asset.IsRef(out var expected)) + if (asset.IsRef(out AssetRef expected)) { Build(in actor, in expected, args); } } -} \ No newline at end of file +} diff --git a/src/Hexecs/Actors/IActorComponent.cs b/src/Hexecs/Actors/IActorComponent.cs index 97042ae..e242076 100644 --- a/src/Hexecs/Actors/IActorComponent.cs +++ b/src/Hexecs/Actors/IActorComponent.cs @@ -8,4 +8,4 @@ /// Компоненты реализуются как структуры, что обеспечивает эффективное хранение и доступ к данным. /// Они организованы в пулы, где каждый пул управляет компонентами определенного типа. /// -public interface IActorComponent; \ No newline at end of file +public interface IActorComponent; diff --git a/src/Hexecs/Actors/IActorFilter.cs b/src/Hexecs/Actors/IActorFilter.cs index e885d72..c9324f5 100644 --- a/src/Hexecs/Actors/IActorFilter.cs +++ b/src/Hexecs/Actors/IActorFilter.cs @@ -57,4 +57,4 @@ public interface IActorFilter : IDisposable /// Экземпляр актёра для проверки. /// Возвращает true, если актёр удовлетворяет условиям фильтра; иначе false. bool Contains(in Actor actor); -} \ No newline at end of file +} diff --git a/src/Hexecs/Actors/IDrawSystem.cs b/src/Hexecs/Actors/IDrawSystem.cs index 77c5dbe..ec8ad6e 100644 --- a/src/Hexecs/Actors/IDrawSystem.cs +++ b/src/Hexecs/Actors/IDrawSystem.cs @@ -26,4 +26,4 @@ public interface IDrawSystem /// /// Информация о времени мира, предоставляющая временные метрики текущего кадра. void Draw(in WorldTime time); -} \ No newline at end of file +} diff --git a/src/Hexecs/Actors/IUpdateSystem.cs b/src/Hexecs/Actors/IUpdateSystem.cs index 3be5bc7..e6dfb6d 100644 --- a/src/Hexecs/Actors/IUpdateSystem.cs +++ b/src/Hexecs/Actors/IUpdateSystem.cs @@ -26,4 +26,4 @@ public interface IUpdateSystem /// /// Информация о времени мира, предоставляющая временные метрики текущего кадра. void Update(in WorldTime time); -} \ No newline at end of file +} diff --git a/src/Hexecs/Actors/IViewComponent.cs b/src/Hexecs/Actors/IViewComponent.cs index 8e71ce4..17ea381 100644 --- a/src/Hexecs/Actors/IViewComponent.cs +++ b/src/Hexecs/Actors/IViewComponent.cs @@ -6,4 +6,4 @@ /// /// Используйте эти компоненты для обработки . /// -public interface IViewComponent : IActorComponent; \ No newline at end of file +public interface IViewComponent : IActorComponent; diff --git a/src/Hexecs/Actors/Loggers/ActorIdLogWriter.cs b/src/Hexecs/Actors/Loggers/ActorIdLogWriter.cs index 713e23d..614cf6f 100644 --- a/src/Hexecs/Actors/Loggers/ActorIdLogWriter.cs +++ b/src/Hexecs/Actors/Loggers/ActorIdLogWriter.cs @@ -4,7 +4,7 @@ namespace Hexecs.Actors.Loggers; internal sealed class ActorIdLogWriter : ILogValueWriter { - public static readonly ActorIdLogWriter Instance = new(); + public static readonly ActorIdLogWriter Instance = new ActorIdLogWriter(); private ActorIdLogWriter() { @@ -18,7 +18,7 @@ public void Write(ref ValueStringBuilder stringBuilder, ActorId actor) } else { - if (ActorMarshal.TryGetDebugContext(out var context)) + if (ActorMarshal.TryGetDebugContext(out ActorContext? context)) { context.GetDescription(actor, ref stringBuilder); } @@ -28,4 +28,4 @@ public void Write(ref ValueStringBuilder stringBuilder, ActorId actor) } } } -} \ No newline at end of file +} diff --git a/src/Hexecs/Actors/Loggers/ActorLogWriter.cs b/src/Hexecs/Actors/Loggers/ActorLogWriter.cs index 9414012..ead9df2 100644 --- a/src/Hexecs/Actors/Loggers/ActorLogWriter.cs +++ b/src/Hexecs/Actors/Loggers/ActorLogWriter.cs @@ -4,7 +4,7 @@ namespace Hexecs.Actors.Loggers; internal sealed class ActorLogWriter : ILogValueWriter { - public static readonly ActorLogWriter Instance = new(); + public static readonly ActorLogWriter Instance = new ActorLogWriter(); private ActorLogWriter() { @@ -21,4 +21,4 @@ public void Write(ref ValueStringBuilder stringBuilder, Actor actor) actor.Context.GetDescription(actor.Id, ref stringBuilder); } } -} \ No newline at end of file +} diff --git a/src/Hexecs/Actors/Nodes/ActorNode.cs b/src/Hexecs/Actors/Nodes/ActorNode.cs index b3d92c4..025bffb 100644 --- a/src/Hexecs/Actors/Nodes/ActorNode.cs +++ b/src/Hexecs/Actors/Nodes/ActorNode.cs @@ -18,13 +18,18 @@ public ActorNode? Parent public void AddChild(ActorNode child) { - var existsParent = child._parent; - if (existsParent == this) ActorError.ChildAlreadyAdded(Id, child.Id); + ActorNode? existsParent = child._parent; + + if (existsParent == this) + { + ActorError.ChildAlreadyAdded(Id, child.Id); + } + if (existsParent != null && ArrayUtils.Remove(existsParent._children, this)) { existsParent._length--; } - + ArrayUtils.InsertOrCreate(ref _children, ArrayPool.Shared, _length, child); child._parent = this; @@ -33,14 +38,20 @@ public void AddChild(ActorNode child) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Span AsSpan() => _children == null - ? Span.Empty - : _children.AsSpan(0, _length); - + public Span AsSpan() + { + return _children == null + ? Span.Empty + : _children.AsSpan(0, _length); + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ReadOnlySpan AsReadOnlySpan() => _children == null - ? ReadOnlySpan.Empty - : _children.AsSpan(0, _length); + public ReadOnlySpan AsReadOnlySpan() + { + return _children == null + ? ReadOnlySpan.Empty + : _children.AsSpan(0, _length); + } public void Dispose() { @@ -49,9 +60,12 @@ public void Dispose() _parent._length--; } - if (_children == null) return; + if (_children == null) + { + return; + } - foreach (var child in AsSpan()) + foreach (ActorNode child in AsSpan()) { child._parent = null; } @@ -64,12 +78,18 @@ public void Dispose() public bool HasChild(uint childId) { - if (_children == null) return false; + if (_children == null) + { + return false; + } // ReSharper disable once ForeachCanBeConvertedToQueryUsingAnotherGetEnumerator - foreach (var childNode in AsReadOnlySpan()) + foreach (ActorNode childNode in AsReadOnlySpan()) { - if (childNode.Id == childId) return true; + if (childNode.Id == childId) + { + return true; + } } return false; @@ -77,17 +97,26 @@ public bool HasChild(uint childId) public bool RemoveChild(uint childId) { - if (_children == null || _length == 0) return false; + if (_children == null || _length == 0) + { + return false; + } + + Span children = AsSpan(); - var children = AsSpan(); for (var i = 0; i < children.Length; i++) { - var childNode = _children[i]; - if (childNode.Id != childId) continue; + ActorNode childNode = _children[i]; + + if (childNode.Id != childId) + { + continue; + } ArrayUtils.Cut(_children, i); childNode._parent = null; + break; } @@ -102,4 +131,4 @@ public bool RemoveChild(uint childId) return true; } -} \ No newline at end of file +} diff --git a/src/Hexecs/Actors/Nodes/ActorNodeComponentConverter.cs b/src/Hexecs/Actors/Nodes/ActorNodeComponentConverter.cs index d8ec77c..5b92ab0 100644 --- a/src/Hexecs/Actors/Nodes/ActorNodeComponentConverter.cs +++ b/src/Hexecs/Actors/Nodes/ActorNodeComponentConverter.cs @@ -1,12 +1,13 @@ using System.Text.Json; + using Hexecs.Actors.Serializations; namespace Hexecs.Actors.Nodes; internal sealed class ActorNodeComponentConverter : IActorComponentConverter { - public static readonly ActorNodeComponentConverter Instance = new(); - + public static readonly ActorNodeComponentConverter Instance = new ActorNodeComponentConverter(); + public ActorNodeComponent Deserialize(ActorContext context, ref Utf8JsonReader reader) { throw new NotImplementedException(); @@ -14,6 +15,5 @@ public ActorNodeComponent Deserialize(ActorContext context, ref Utf8JsonReader r public void Serialize(ActorContext context, Utf8JsonWriter writer, in ActorNodeComponent component) { - } -} \ No newline at end of file +} diff --git a/src/Hexecs/Actors/Pipelines/ActorCommandHandler.cs b/src/Hexecs/Actors/Pipelines/ActorCommandHandler.cs index ba858ca..8954558 100644 --- a/src/Hexecs/Actors/Pipelines/ActorCommandHandler.cs +++ b/src/Hexecs/Actors/Pipelines/ActorCommandHandler.cs @@ -52,9 +52,12 @@ protected ContextLogger Log public abstract Result Handle(in TCommand command); [MethodImpl(MethodImplOptions.AggressiveInlining)] - private ContextLogger CreateLogger() => Context - .GetRequiredService() - .CreateContext(GetType().Name); + private ContextLogger CreateLogger() + { + return Context + .GetRequiredService() + .CreateContext(GetType().Name); + } } /// @@ -103,7 +106,10 @@ protected ContextLogger Log public abstract TResult Handle(in TCommand command); [MethodImpl(MethodImplOptions.AggressiveInlining)] - private ContextLogger CreateLogger() => Context - .GetRequiredService() - .CreateContext(GetType().Name); -} \ No newline at end of file + private ContextLogger CreateLogger() + { + return Context + .GetRequiredService() + .CreateContext(GetType().Name); + } +} diff --git a/src/Hexecs/Actors/Pipelines/ActorMessageHandler.cs b/src/Hexecs/Actors/Pipelines/ActorMessageHandler.cs index 6bd8e05..18178eb 100644 --- a/src/Hexecs/Actors/Pipelines/ActorMessageHandler.cs +++ b/src/Hexecs/Actors/Pipelines/ActorMessageHandler.cs @@ -47,7 +47,10 @@ protected ContextLogger Log public abstract void Handle(in TMessage message); [MethodImpl(MethodImplOptions.AggressiveInlining)] - private ContextLogger CreateLogger() => Context - .GetRequiredService() - .CreateContext(GetType().Name); -} \ No newline at end of file + private ContextLogger CreateLogger() + { + return Context + .GetRequiredService() + .CreateContext(GetType().Name); + } +} diff --git a/src/Hexecs/Actors/Pipelines/ActorNotificationHandler.cs b/src/Hexecs/Actors/Pipelines/ActorNotificationHandler.cs index 568395d..04230ab 100644 --- a/src/Hexecs/Actors/Pipelines/ActorNotificationHandler.cs +++ b/src/Hexecs/Actors/Pipelines/ActorNotificationHandler.cs @@ -48,7 +48,10 @@ protected ContextLogger Log public abstract void Handle(in TNotification notification); [MethodImpl(MethodImplOptions.AggressiveInlining)] - private ContextLogger CreateLogger() => Context - .GetRequiredService() - .CreateContext(GetType().Name); -} \ No newline at end of file + private ContextLogger CreateLogger() + { + return Context + .GetRequiredService() + .CreateContext(GetType().Name); + } +} diff --git a/src/Hexecs/Actors/Pipelines/ActorQueryHandler.cs b/src/Hexecs/Actors/Pipelines/ActorQueryHandler.cs index ee3b328..d1eb77b 100644 --- a/src/Hexecs/Actors/Pipelines/ActorQueryHandler.cs +++ b/src/Hexecs/Actors/Pipelines/ActorQueryHandler.cs @@ -47,7 +47,10 @@ protected ContextLogger Log public abstract TResult Handle(in TQuery query); [MethodImpl(MethodImplOptions.AggressiveInlining)] - private ContextLogger CreateLogger() => Context - .GetRequiredService() - .CreateContext(GetType().Name); -} \ No newline at end of file + private ContextLogger CreateLogger() + { + return Context + .GetRequiredService() + .CreateContext(GetType().Name); + } +} diff --git a/src/Hexecs/Actors/Relations/ActorRelationComponent.cs b/src/Hexecs/Actors/Relations/ActorRelationComponent.cs index 66d7b6b..99cbfd2 100644 --- a/src/Hexecs/Actors/Relations/ActorRelationComponent.cs +++ b/src/Hexecs/Actors/Relations/ActorRelationComponent.cs @@ -6,7 +6,10 @@ namespace Hexecs.Actors.Relations; [method: MethodImpl(MethodImplOptions.AggressiveInlining)] internal struct ActorRelationComponent(int capacity) : IActorComponent, IDisposable { - public static ActorRelationComponent Create(ActorId _) => new(4); + public static ActorRelationComponent Create(ActorId _) + { + return new ActorRelationComponent(4); + } public static ActorComponentConfiguration CreatePoolConfiguration() { @@ -32,13 +35,17 @@ public void Add(uint relationId) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public readonly ReadOnlySpan AsReadOnlySpan() => _array == null - ? ReadOnlySpan.Empty - : _array.AsSpan(0, _length); + public readonly ReadOnlySpan AsReadOnlySpan() + { + return _array == null + ? ReadOnlySpan.Empty + : _array.AsSpan(0, _length); + } public void Dispose() { - var arr = _array; + uint[]? arr = _array; + if (arr != null) { _array = null; // Защита от двойного Dispose @@ -49,22 +56,33 @@ public void Dispose() } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public readonly ArrayEnumerator GetEnumerator() => _array == null - ? ArrayEnumerator.Empty - : new ArrayEnumerator(_array, _length); + public readonly ArrayEnumerator GetEnumerator() + { + return _array == null + ? ArrayEnumerator.Empty + : new ArrayEnumerator(_array, _length); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public readonly bool Has(uint relationId) => _length != 0 && AsReadOnlySpan().Contains(relationId); + public readonly bool Has(uint relationId) + { + return _length != 0 && AsReadOnlySpan().Contains(relationId); + } public bool Remove(uint relationId) { - var span = AsReadOnlySpan(); + ReadOnlySpan span = AsReadOnlySpan(); + for (var i = 0; i < span.Length; i++) { - if (span[i] != relationId) continue; + if (span[i] != relationId) + { + continue; + } // Swap-Back: $O(1)$ - var lastIndex = --_length; + int lastIndex = --_length; + if (i < lastIndex) { _array![i] = _array[lastIndex]; @@ -78,10 +96,15 @@ public bool Remove(uint relationId) public bool TryAdd(uint relationId) { - var has = Has(relationId); - if (has) return false; + bool has = Has(relationId); + + if (has) + { + return false; + } Add(relationId); + return true; } -} \ No newline at end of file +} diff --git a/src/Hexecs/Actors/Relations/ActorRelationComponentConverter.cs b/src/Hexecs/Actors/Relations/ActorRelationComponentConverter.cs index 808d917..0d323cb 100644 --- a/src/Hexecs/Actors/Relations/ActorRelationComponentConverter.cs +++ b/src/Hexecs/Actors/Relations/ActorRelationComponentConverter.cs @@ -5,7 +5,7 @@ namespace Hexecs.Actors.Relations; internal sealed class ActorRelationComponentConverter : IActorComponentConverter { - public static readonly ActorRelationComponentConverter Instance = new(); + public static readonly ActorRelationComponentConverter Instance = new ActorRelationComponentConverter(); public ActorRelationComponent Deserialize(ActorContext context, ref Utf8JsonReader reader) { @@ -16,11 +16,11 @@ public void Serialize(ActorContext context, Utf8JsonWriter writer, in ActorRelat { writer.WriteStartArray(); - foreach (var relationId in component) + foreach (uint relationId in component) { - writer.WriteNumberValue(relationId); + writer.WriteNumberValue(relationId); } - + writer.WriteEndArray(); } -} \ No newline at end of file +} diff --git a/src/Hexecs/Actors/Relations/ActorRelationPool.Enumerator.cs b/src/Hexecs/Actors/Relations/ActorRelationPool.Enumerator.cs index 3a6a03c..6f41612 100644 --- a/src/Hexecs/Actors/Relations/ActorRelationPool.Enumerator.cs +++ b/src/Hexecs/Actors/Relations/ActorRelationPool.Enumerator.cs @@ -6,16 +6,16 @@ public ref struct ActorRelationEnumerator public static ActorRelationEnumerator Empty { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => new(null!, ReadOnlySpan.Empty, ActorId.Empty); + get => new ActorRelationEnumerator(null!, ReadOnlySpan.Empty, ActorId.Empty); } public readonly ActorRelation Current { get { - var index = _indices[_currentIndex]; - var key = _pool.Keys[index]; - ref var reference = ref _pool.Values[index]; + int index = _indices[_currentIndex]; + ActorRelationPool.RelationKey key = _pool.Keys[index]; + ref T reference = ref _pool.Values[index]; return new ActorRelation(_pool.Context, key.First == _subject ? key.Second : key.First, ref reference); @@ -42,7 +42,10 @@ internal ActorRelationEnumerator(ActorRelationPool pool, ReadOnlySpan in } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public readonly ActorRelationEnumerator GetEnumerator() => this; + public readonly ActorRelationEnumerator GetEnumerator() + { + return this; + } public void Dispose() { @@ -54,4 +57,4 @@ public bool MoveNext() _currentIndex++; return _currentIndex < _indices.Length; } -} \ No newline at end of file +} diff --git a/src/Hexecs/Actors/Relations/ActorRelationPool.cs b/src/Hexecs/Actors/Relations/ActorRelationPool.cs index 03740b8..98a20e5 100644 --- a/src/Hexecs/Actors/Relations/ActorRelationPool.cs +++ b/src/Hexecs/Actors/Relations/ActorRelationPool.cs @@ -30,6 +30,7 @@ public Type Type private const int PageMask = PageSize - 1; internal ReadOnlySpan Keys => _keys.AsSpan(0, _count); + internal T[] Values => _values; public ActorRelationPool(ActorContext context, int capacity = 16) @@ -48,23 +49,28 @@ public ActorRelationPool(ActorContext context, int capacity = 16) public ref T Add(ActorId subject, ActorId relative, in T value) { var key = new RelationKey(subject, relative); + // Если такая связь уже есть (неважно, кто субъект, а кто цель), выбрасываем ошибку - if (_indexMap.ContainsKey(key)) ActorError.RelationAlreadyExists(subject, relative); + if (_indexMap.ContainsKey(key)) + { + ActorError.RelationAlreadyExists(subject, relative); + } if (_count >= _values.Length) { - var newCapacity = _values.Length * 2; + int newCapacity = _values.Length * 2; ArrayUtils.Resize(ref _values, newCapacity); ArrayUtils.Resize(ref _keys, newCapacity); } - var index = _count++; + int index = _count++; _keys[index] = key; _values[index] = value; _indexMap[key] = index; // ВАЖНО: Добавляем индекс в списки ОБОИХ участников AddToAdjacency(subject.Value, index); + // Если это не связь сам с собой, добавляем и второму if (subject != relative) { @@ -80,9 +86,13 @@ public void Clear() ArrayUtils.Clear(_values, _count); ArrayUtils.Clear(_keys, _count); - foreach (var page in _sparsePages) + foreach (Bucket[]? page in _sparsePages) { - if (page == null) continue; + if (page == null) + { + continue; + } + for (var i = 0; i < page.Length; i++) { page[i].Dispose(); @@ -94,14 +104,16 @@ public void Clear() public int Count(ActorId subject) { - var subjectIdRaw = subject.Value; + uint subjectIdRaw = subject.Value; var pageIndex = (int)(subjectIdRaw >> PageBits); + if (pageIndex >= _sparsePages.Length) { return 0; } - var page = _sparsePages[pageIndex]; + Bucket[]? page = _sparsePages[pageIndex]; + if (page == null) { return 0; @@ -113,63 +125,83 @@ public int Count(ActorId subject) public ref T Get(ActorId subject, ActorId relative) { var key = new RelationKey(subject, relative); - if (_indexMap.TryGetValue(key, out var index)) + + if (_indexMap.TryGetValue(key, out int index)) { return ref _values[index]; } ActorError.RelationNotFound(subject, relative); + return ref Unsafe.NullRef(); } public ActorRelationEnumerator GetRelations(ActorId subject) { - var subjectIdRaw = subject.Value; + uint subjectIdRaw = subject.Value; var pageIndex = (int)(subjectIdRaw >> PageBits); + if (pageIndex >= _sparsePages.Length) { return ActorRelationEnumerator.Empty; } - var page = _sparsePages[pageIndex]; + Bucket[]? page = _sparsePages[pageIndex]; + if (page == null) { return ActorRelationEnumerator.Empty; } return new ActorRelationEnumerator( - pool: this, - indices: page[subjectIdRaw & PageMask].AsReadOnlySpan(), + pool: this, + indices: page[subjectIdRaw & PageMask].AsReadOnlySpan(), subject); } public bool Has(ActorId subject, ActorId relative) { var key = new RelationKey(subject, relative); + return _indexMap.ContainsKey(key); } public bool Remove(ActorId subject) { - var subjectIdRaw = subject.Value; - + uint subjectIdRaw = subject.Value; + var pageIndex = (int)(subjectIdRaw >> PageBits); - if (pageIndex >= _sparsePages.Length) return false; - var page = _sparsePages[pageIndex]; - if (page == null) return false; - ref var bucket = ref page[subjectIdRaw & PageMask]; - if (bucket.Length == 0) return false; + if (pageIndex >= _sparsePages.Length) + { + return false; + } + + Bucket[]? page = _sparsePages[pageIndex]; + + if (page == null) + { + return false; + } + + ref Bucket bucket = ref page[subjectIdRaw & PageMask]; + + if (bucket.Length == 0) + { + return false; + } var removedAny = false; - // Итерируемся с конца бакета, так как при Remove связь удаляется из бакета + + // Итерируемся с конца бакета, так как при Remove связь удаляется из бакета // (но Swap-Back в основном пуле все равно может перемешать индексы других связей в этом же бакете) while (bucket.Length > 0) { // Берем всегда первый индекс из бакета - var index = bucket.AsReadOnlySpan()[0]; - var key = _keys[index]; + int index = bucket.AsReadOnlySpan()[0]; + RelationKey key = _keys[index]; + if (Remove(key.First, key.Second, out _)) { removedAny = true; @@ -187,9 +219,11 @@ public bool Remove(ActorId subject) public bool Remove(ActorId subject, ActorId relative, out T removed) { var key = new RelationKey(subject, relative); - if (!_indexMap.TryGetValue(key, out var index)) + + if (!_indexMap.TryGetValue(key, out int index)) { removed = default; + return false; } @@ -198,16 +232,18 @@ public bool Remove(ActorId subject, ActorId relative, out T removed) // Удаляем из списков смежности ОБОИХ участников RemoveFromAdjacency(key.First.Value, index); + if (key.First != key.Second) { RemoveFromAdjacency(key.Second.Value, index); } - var lastIndex = _count - 1; + int lastIndex = _count - 1; + if (index != lastIndex) { - var lastKey = _keys[lastIndex]; - var lastValue = _values[lastIndex]; + RelationKey lastKey = _keys[lastIndex]; + T lastValue = _values[lastIndex]; _keys[index] = lastKey; _values[index] = lastValue; @@ -215,6 +251,7 @@ public bool Remove(ActorId subject, ActorId relative, out T removed) // Обновляем индексы в списках смежности для перемещенной связи у ОБОИХ участников ReplaceInAdjacency(lastKey.First.Value, lastIndex, index); + if (lastKey.First != lastKey.Second) { ReplaceInAdjacency(lastKey.Second.Value, lastIndex, index); @@ -231,30 +268,33 @@ public bool Remove(ActorId subject, ActorId relative, out T removed) private void AddToAdjacency(uint actorId, int index) { var pageIndex = (int)(actorId >> PageBits); + if (pageIndex >= _sparsePages.Length) { ArrayUtils.EnsureCapacity(ref _sparsePages, pageIndex + 1); } - ref var page = ref _sparsePages[pageIndex]; + ref Bucket[]? page = ref _sparsePages[pageIndex]; page ??= new Bucket[PageSize]; - ref var bucket = ref page[actorId & PageMask]; + ref Bucket bucket = ref page[actorId & PageMask]; bucket.Add(index); } private void RemoveFromAdjacency(uint actorId, int index) { var pageIndex = (int)(actorId >> PageBits); - var page = _sparsePages[pageIndex]; - ref var bucket = ref page![actorId & PageMask]; + Bucket[]? page = _sparsePages[pageIndex]; + ref Bucket bucket = ref page![actorId & PageMask]; + + Span span = bucket.AsSpan(); - var span = bucket.AsSpan(); for (var i = 0; i < span.Length; i++) { if (span[i] == index) { bucket.RemoveAtSwapBack(i); + return; } } @@ -263,14 +303,16 @@ private void RemoveFromAdjacency(uint actorId, int index) private void ReplaceInAdjacency(uint actorId, int oldIndex, int newIndex) { var pageIndex = (int)(actorId >> PageBits); - var page = _sparsePages[pageIndex]; - ref var bucket = ref page![actorId & PageMask]; - var span = bucket.AsSpan(); + Bucket[]? page = _sparsePages[pageIndex]; + ref Bucket bucket = ref page![actorId & PageMask]; + Span span = bucket.AsSpan(); + for (var i = 0; i < span.Length; i++) { if (span[i] == oldIndex) { span[i] = newIndex; + return; } } @@ -296,15 +338,27 @@ public RelationKey(ActorId first, ActorId second) } } - public override int GetHashCode() => HashCode.Combine(First, Second); + public override int GetHashCode() + { + return HashCode.Combine(First, Second); + } - public bool Equals(RelationKey other) => First == other.First && Second == other.Second; + public bool Equals(RelationKey other) + { + return First == other.First && Second == other.Second; + } - public override bool Equals(object? obj) => obj is RelationKey key && Equals(key); + public override bool Equals(object? obj) + { + return obj is RelationKey key && Equals(key); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Is(ActorId value) => First == value || Second == value; + public bool Is(ActorId value) + { + return First == value || Second == value; + } } ActorContext IActorRelationPool.Context => Context; -} \ No newline at end of file +} diff --git a/src/Hexecs/Actors/Relations/ActorRelationType.cs b/src/Hexecs/Actors/Relations/ActorRelationType.cs index fbd2cfb..f96887f 100644 --- a/src/Hexecs/Actors/Relations/ActorRelationType.cs +++ b/src/Hexecs/Actors/Relations/ActorRelationType.cs @@ -2,13 +2,13 @@ internal static class ActorRelationType { - private static readonly Dictionary RelationTypes = new(128, ReferenceComparer.Instance); + private static readonly Dictionary RelationTypes = new Dictionary(128, ReferenceComparer.Instance); #if NET9_0_OR_GREATER - private static readonly Lock LockObj = new(); + private static readonly Lock LockObj = new Lock(); #else - private static readonly object LockObj = new(); + private static readonly object LockObj = new object(); #endif - private static ushort _nextId; + private static ushort NextId; public static ushort GetId(Type type) { @@ -18,9 +18,12 @@ public static ushort GetId(Type type) lock (LockObj) #endif { - if (RelationTypes.TryGetValue(type, out var exists)) return exists; + if (RelationTypes.TryGetValue(type, out ushort exists)) + { + return exists; + } - var componentTypeId = _nextId++; + ushort componentTypeId = NextId++; RelationTypes[type] = componentTypeId; return componentTypeId; @@ -35,12 +38,16 @@ public static Type GetType(uint id) lock (LockObj) #endif { - foreach (var (type, existsId) in RelationTypes) + foreach ((Type type, ushort existsId) in RelationTypes) { - if (existsId == id) return type; + if (existsId == id) + { + return type; + } } ActorError.RelationTypeNotFound(id); + return null; } } @@ -50,4 +57,4 @@ internal static class ActorRelationType where T : struct { public static readonly ushort Id = ActorRelationType.GetId(typeof(T)); -} \ No newline at end of file +} diff --git a/src/Hexecs/Actors/Serializations/IActorComponentConverter.cs b/src/Hexecs/Actors/Serializations/IActorComponentConverter.cs index 59cd443..a424bb1 100644 --- a/src/Hexecs/Actors/Serializations/IActorComponentConverter.cs +++ b/src/Hexecs/Actors/Serializations/IActorComponentConverter.cs @@ -8,4 +8,4 @@ public interface IActorComponentConverter T Deserialize(ActorContext context, ref Utf8JsonReader reader); void Serialize(ActorContext context, Utf8JsonWriter writer, in T component); -} \ No newline at end of file +} diff --git a/src/Hexecs/Actors/Systems/DrawSystem.cs b/src/Hexecs/Actors/Systems/DrawSystem.cs index ee47e11..0928b8d 100644 --- a/src/Hexecs/Actors/Systems/DrawSystem.cs +++ b/src/Hexecs/Actors/Systems/DrawSystem.cs @@ -47,13 +47,16 @@ protected ContextLogger Log public abstract void Draw(in WorldTime time); [MethodImpl(MethodImplOptions.AggressiveInlining)] - private ContextLogger CreateLogger() => Context - .GetRequiredService() - .CreateContext(GetType()); + private ContextLogger CreateLogger() + { + return Context + .GetRequiredService() + .CreateContext(GetType()); + } ActorContext IDrawSystem.Context => Context; public virtual void Dispose() { } -} \ No newline at end of file +} diff --git a/src/Hexecs/Actors/Systems/DrawSystem1.cs b/src/Hexecs/Actors/Systems/DrawSystem1.cs index 00aed6e..bfa4c1a 100644 --- a/src/Hexecs/Actors/Systems/DrawSystem1.cs +++ b/src/Hexecs/Actors/Systems/DrawSystem1.cs @@ -23,15 +23,21 @@ protected virtual void AfterDraw(in WorldTime time) /// /// Время мира /// Если возвращает false, то обновление не происходит - protected virtual bool BeforeDraw(in WorldTime time) => true; + protected virtual bool BeforeDraw(in WorldTime time) + { + return true; + } public sealed override void Draw(in WorldTime time) { - if (!Enabled) return; + if (!Enabled) + { + return; + } if (BeforeDraw(in time)) { - foreach (var actor in _filter) + foreach (ActorRef actor in _filter) { Draw(in actor, time); } @@ -41,4 +47,4 @@ public sealed override void Draw(in WorldTime time) } protected abstract void Draw(in ActorRef actor, in WorldTime time); -} \ No newline at end of file +} diff --git a/src/Hexecs/Actors/Systems/DrawSystem2.cs b/src/Hexecs/Actors/Systems/DrawSystem2.cs index e0c3a43..5c79ec5 100644 --- a/src/Hexecs/Actors/Systems/DrawSystem2.cs +++ b/src/Hexecs/Actors/Systems/DrawSystem2.cs @@ -24,15 +24,21 @@ protected virtual void AfterDraw(in WorldTime time) /// /// Время мира /// Если возвращает false, то обновление не происходит - protected virtual bool BeforeDraw(in WorldTime time) => true; + protected virtual bool BeforeDraw(in WorldTime time) + { + return true; + } public sealed override void Draw(in WorldTime time) { - if (!Enabled) return; + if (!Enabled) + { + return; + } if (BeforeDraw(in time)) { - foreach (var actor in _filter) + foreach (ActorRef actor in _filter) { Draw(in actor, time); } @@ -42,4 +48,4 @@ public sealed override void Draw(in WorldTime time) } protected abstract void Draw(in ActorRef actor, in WorldTime time); -} \ No newline at end of file +} diff --git a/src/Hexecs/Actors/Systems/DrawSystem3.cs b/src/Hexecs/Actors/Systems/DrawSystem3.cs index 5655877..948c9cc 100644 --- a/src/Hexecs/Actors/Systems/DrawSystem3.cs +++ b/src/Hexecs/Actors/Systems/DrawSystem3.cs @@ -25,15 +25,21 @@ protected virtual void AfterDraw(in WorldTime time) /// /// Время мира /// Если возвращает false, то обновление не происходит - protected virtual bool BeforeDraw(in WorldTime time) => true; + protected virtual bool BeforeDraw(in WorldTime time) + { + return true; + } public sealed override void Draw(in WorldTime time) { - if (!Enabled) return; + if (!Enabled) + { + return; + } if (BeforeDraw(in time)) { - foreach (var actor in _filter) + foreach (ActorRef actor in _filter) { Draw(in actor, time); } @@ -43,4 +49,4 @@ public sealed override void Draw(in WorldTime time) } protected abstract void Draw(in ActorRef actor, in WorldTime time); -} \ No newline at end of file +} diff --git a/src/Hexecs/Actors/Systems/ParallelSystem.cs b/src/Hexecs/Actors/Systems/ParallelSystem.cs index 22f0c64..33c0edc 100644 --- a/src/Hexecs/Actors/Systems/ParallelSystem.cs +++ b/src/Hexecs/Actors/Systems/ParallelSystem.cs @@ -34,15 +34,20 @@ public ParallelSystem( public bool TryGetSystem([NotNullWhen(true)] out T? system) where T : class, IUpdateSystem { - foreach (var exists in _systems) + foreach (IUpdateSystem exists in _systems) { - if (exists is not T expected) continue; + if (exists is not T expected) + { + continue; + } system = expected; + return true; } system = null; + return false; } @@ -56,16 +61,17 @@ public void Update(in WorldTime time) } ActorContext IUpdateSystem.Context => Context; + ActorContext IParallelJob.Context => Context; - + void IParallelJob.Execute(int workerIndex, int workersCount) { - var skip = workerIndex * _batchSize; - var batch = _systems.AsSpan(skip, _batchSize); + int skip = workerIndex * _batchSize; + Span batch = _systems.AsSpan(skip, _batchSize); - foreach (var updateSystem in batch) + foreach (IUpdateSystem updateSystem in batch) { updateSystem.Update(_currentTime); } } -} \ No newline at end of file +} diff --git a/src/Hexecs/Actors/Systems/UpdateSystem.cs b/src/Hexecs/Actors/Systems/UpdateSystem.cs index e986b3f..33f0ae0 100644 --- a/src/Hexecs/Actors/Systems/UpdateSystem.cs +++ b/src/Hexecs/Actors/Systems/UpdateSystem.cs @@ -47,9 +47,12 @@ protected ContextLogger Log public abstract void Update(in WorldTime time); [MethodImpl(MethodImplOptions.AggressiveInlining)] - private ContextLogger CreateLogger() => Context - .GetRequiredService() - .CreateContext(GetType()); + private ContextLogger CreateLogger() + { + return Context + .GetRequiredService() + .CreateContext(GetType()); + } ActorContext IUpdateSystem.Context => Context; -} \ No newline at end of file +} diff --git a/src/Hexecs/Actors/Systems/UpdateSystem1.cs b/src/Hexecs/Actors/Systems/UpdateSystem1.cs index d4a0ee9..ec1b61e 100644 --- a/src/Hexecs/Actors/Systems/UpdateSystem1.cs +++ b/src/Hexecs/Actors/Systems/UpdateSystem1.cs @@ -41,20 +41,27 @@ protected virtual void AfterUpdate(in WorldTime time) /// /// Время мира /// Если возвращает false, то обновление не происходит - protected virtual bool BeforeUpdate(in WorldTime time) => true; + protected virtual bool BeforeUpdate(in WorldTime time) + { + return true; + } public sealed override void Update(in WorldTime time) { if (Enabled) { - var length = Filter.Length; + int length = Filter.Length; + if (length > 0) { - if (!BeforeUpdate(in time)) return; + if (!BeforeUpdate(in time)) + { + return; + } if (_parallelWorker == null) { - foreach (var actor in Filter) + foreach (ActorRef actor in Filter) { Update(in actor, in time); } @@ -76,17 +83,18 @@ public sealed override void Update(in WorldTime time) void IParallelJob.Execute(int workerIndex, int workersCount) { - var start = workerIndex * _currentBatchSize; - var length = _currentLength; + int start = workerIndex * _currentBatchSize; + int length = _currentLength; if ((uint)start < (uint)length) { - var batch = workerIndex == workersCount + ActorFilter.SkipTakeEnumerator batch = workerIndex == workersCount ? Filter.Skip(start) : Filter.Skip(start, _currentBatchSize); - ref readonly var currentTime = ref _currentTime; - foreach (var actor in batch) + ref readonly WorldTime currentTime = ref _currentTime; + + foreach (ActorRef actor in batch) { Update(in actor, in currentTime); } @@ -94,4 +102,4 @@ void IParallelJob.Execute(int workerIndex, int workersCount) } ActorContext IParallelJob.Context => Context; -} \ No newline at end of file +} diff --git a/src/Hexecs/Actors/Systems/UpdateSystem2.cs b/src/Hexecs/Actors/Systems/UpdateSystem2.cs index 2e552e3..fe88ff1 100644 --- a/src/Hexecs/Actors/Systems/UpdateSystem2.cs +++ b/src/Hexecs/Actors/Systems/UpdateSystem2.cs @@ -41,20 +41,27 @@ protected virtual void AfterUpdate(in WorldTime time) /// /// Время мира /// Если возвращает false, то обновление не происходит - protected virtual bool BeforeUpdate(in WorldTime time) => true; - + protected virtual bool BeforeUpdate(in WorldTime time) + { + return true; + } + public sealed override void Update(in WorldTime time) { if (Enabled) { - var length = Filter.Length; + int length = Filter.Length; + if (length > 0) { - if (!BeforeUpdate(in time)) return; + if (!BeforeUpdate(in time)) + { + return; + } if (_parallelWorker == null) { - foreach (var actor in Filter) + foreach (ActorRef actor in Filter) { Update(in actor, in time); } @@ -76,17 +83,18 @@ public sealed override void Update(in WorldTime time) void IParallelJob.Execute(int workerIndex, int workersCount) { - var start = workerIndex * _currentBatchSize; - var length = _currentLength; - + int start = workerIndex * _currentBatchSize; + int length = _currentLength; + if ((uint)start < (uint)length) { - var batch = workerIndex == workersCount + ActorFilter.SkipTakeEnumerator batch = workerIndex == workersCount ? Filter.Skip(start) : Filter.Skip(start, _currentBatchSize); - ref readonly var currentTime = ref _currentTime; - foreach (var actor in batch) + ref readonly WorldTime currentTime = ref _currentTime; + + foreach (ActorRef actor in batch) { Update(in actor, in currentTime); } @@ -94,4 +102,4 @@ void IParallelJob.Execute(int workerIndex, int workersCount) } ActorContext IParallelJob.Context => Context; -} \ No newline at end of file +} diff --git a/src/Hexecs/Actors/Systems/UpdateSystem3.cs b/src/Hexecs/Actors/Systems/UpdateSystem3.cs index 7c87590..6b0240c 100644 --- a/src/Hexecs/Actors/Systems/UpdateSystem3.cs +++ b/src/Hexecs/Actors/Systems/UpdateSystem3.cs @@ -43,20 +43,27 @@ protected virtual void AfterUpdate(in WorldTime time) /// /// Время мира /// Если возвращает false, то обновление не происходит - protected virtual bool BeforeUpdate(in WorldTime time) => true; + protected virtual bool BeforeUpdate(in WorldTime time) + { + return true; + } public sealed override void Update(in WorldTime time) { if (Enabled) { - var length = Filter.Length; + int length = Filter.Length; + if (length > 0) { - if (!BeforeUpdate(in time)) return; + if (!BeforeUpdate(in time)) + { + return; + } if (_parallelWorker == null) { - foreach (var actor in Filter) + foreach (ActorRef actor in Filter) { Update(in actor, in time); } @@ -78,17 +85,18 @@ public sealed override void Update(in WorldTime time) void IParallelJob.Execute(int workerIndex, int workersCount) { - var start = workerIndex * _currentBatchSize; - var length = _currentLength; + int start = workerIndex * _currentBatchSize; + int length = _currentLength; if ((uint)start < (uint)length) { - var batch = workerIndex == workersCount + ActorFilter.SkipTakeEnumerator batch = workerIndex == workersCount ? Filter.Skip(start) : Filter.Skip(start, _currentBatchSize); - ref readonly var currentTime = ref _currentTime; - foreach (var actor in batch) + ref readonly WorldTime currentTime = ref _currentTime; + + foreach (ActorRef actor in batch) { Update(in actor, in currentTime); } @@ -96,4 +104,4 @@ void IParallelJob.Execute(int workerIndex, int workersCount) } ActorContext IParallelJob.Context => Context; -} \ No newline at end of file +} diff --git a/src/Hexecs/Assets/Asset.cs b/src/Hexecs/Assets/Asset.cs index a9f68f2..de74b30 100644 --- a/src/Hexecs/Assets/Asset.cs +++ b/src/Hexecs/Assets/Asset.cs @@ -16,7 +16,7 @@ namespace Hexecs.Assets; public static Asset Empty { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => new(null!, AssetId.Empty); + get => new Asset(null!, AssetId.Empty); } /// @@ -122,19 +122,28 @@ public override string ToString() /// Ассет для сравнения /// Возвращает true, если ассеты равны; иначе false [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(Asset other) => Id == other.Id && ReferenceEquals(Context, other.Context); + public bool Equals(Asset other) + { + return Id == other.Id && ReferenceEquals(Context, other.Context); + } /// /// Проверяет равенство с другим объектом. /// /// Объект для сравнения /// Возвращает true, если объект является ассетом и равен текущему; иначе false - public override bool Equals(object? obj) => obj is Asset other && Equals(other); + public override bool Equals(object? obj) + { + return obj is Asset other && Equals(other); + } /// /// Вычисляет хеш-код ассета на основе его идентификатора. /// - public override int GetHashCode() => HashCode.Combine(Id); + public override int GetHashCode() + { + return HashCode.Combine(Id); + } /// /// Оператор равенства для ассетов. @@ -143,7 +152,10 @@ public override string ToString() /// Второй ассет /// Возвращает true, если ассеты равны; иначе false [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(in Asset left, in Asset right) => left.Equals(right); + public static bool operator ==(in Asset left, in Asset right) + { + return left.Equals(right); + } /// /// Оператор неравенства для ассетов. @@ -152,7 +164,10 @@ public override string ToString() /// Второй ассет /// Возвращает true, если ассеты не равны; иначе false [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(in Asset left, in Asset right) => !left.Equals(right); + public static bool operator !=(in Asset left, in Asset right) + { + return !left.Equals(right); + } #endregion @@ -165,7 +180,10 @@ public override string ToString() /// Ассет для преобразования /// Возвращает true, если ассет не пустой; иначе false [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator bool(in Asset asset) => !asset.IsEmpty; + public static implicit operator bool(in Asset asset) + { + return !asset.IsEmpty; + } /// /// Неявное преобразование ассета в идентификатор ассета. @@ -173,7 +191,10 @@ public override string ToString() /// Ассет для преобразования /// Идентификатор ассета [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator AssetId(in Asset asset) => asset.Id; + public static implicit operator AssetId(in Asset asset) + { + return asset.Id; + } #endregion -} \ No newline at end of file +} diff --git a/src/Hexecs/Assets/AssetComponentRef.cs b/src/Hexecs/Assets/AssetComponentRef.cs index 85660f6..b05c1e5 100644 --- a/src/Hexecs/Assets/AssetComponentRef.cs +++ b/src/Hexecs/Assets/AssetComponentRef.cs @@ -8,7 +8,7 @@ public readonly struct AssetComponentRef public static AssetComponentRef Empty { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => new(); + get => new AssetComponentRef(); } public bool IsEmpty @@ -28,8 +28,14 @@ internal AssetComponentRef(AssetComponentPool pool, int index) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ref T Unwrap() => ref _pool.GetByIndex(_index); + public ref T Unwrap() + { + return ref _pool.GetByIndex(_index); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator bool(in AssetComponentRef componentRef) => !componentRef.IsEmpty; -} \ No newline at end of file + public static implicit operator bool(in AssetComponentRef componentRef) + { + return !componentRef.IsEmpty; + } +} diff --git a/src/Hexecs/Assets/AssetId.cs b/src/Hexecs/Assets/AssetId.cs index a578e08..e727460 100644 --- a/src/Hexecs/Assets/AssetId.cs +++ b/src/Hexecs/Assets/AssetId.cs @@ -23,7 +23,7 @@ namespace Hexecs.Assets; public static AssetId Empty { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => new(EmptyId); + get => new AssetId(EmptyId); } /// @@ -61,7 +61,7 @@ internal AssetId(uint value) public override string ToString() { - return AssetMarshal.TryGetDebugContext(out var context) + return AssetMarshal.TryGetDebugContext(out AssetContext? context) ? context.GetDescription(this) : IsEmpty ? StringUtils.EmptyValue @@ -82,36 +82,66 @@ public Asset Unwrap(AssetContext context) #region Equality [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(AssetId other) => Value == other.Value; + public bool Equals(AssetId other) + { + return Value == other.Value; + } - public override bool Equals(object? obj) => obj is AssetId other && Equals(other); + public override bool Equals(object? obj) + { + return obj is AssetId other && Equals(other); + } - public override int GetHashCode() => HashCode.Combine(Value); + public override int GetHashCode() + { + return HashCode.Combine(Value); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(in AssetId left, in AssetId right) => left.Value == right.Value; + public static bool operator ==(in AssetId left, in AssetId right) + { + return left.Value == right.Value; + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(in AssetId left, in AssetId right) => left.Value != right.Value; + public static bool operator !=(in AssetId left, in AssetId right) + { + return left.Value != right.Value; + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator <(in AssetId left, in AssetId right) => left.Value < right.Value; + public static bool operator <(in AssetId left, in AssetId right) + { + return left.Value < right.Value; + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator >(in AssetId left, in AssetId right) => left.Value > right.Value; + public static bool operator >(in AssetId left, in AssetId right) + { + return left.Value > right.Value; + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator <=(in AssetId left, in AssetId right) => left.Value <= right.Value; + public static bool operator <=(in AssetId left, in AssetId right) + { + return left.Value <= right.Value; + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator >=(in AssetId left, in AssetId right) => left.Value >= right.Value; + public static bool operator >=(in AssetId left, in AssetId right) + { + return left.Value >= right.Value; + } #endregion #region Implicit [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator bool(in AssetId asset) => asset.IsNotEmpty; + public static implicit operator bool(in AssetId asset) + { + return asset.IsNotEmpty; + } #endregion -} \ No newline at end of file +} diff --git a/src/Hexecs/Assets/AssetMarshal.cs b/src/Hexecs/Assets/AssetMarshal.cs index f758555..d28212e 100644 --- a/src/Hexecs/Assets/AssetMarshal.cs +++ b/src/Hexecs/Assets/AssetMarshal.cs @@ -5,19 +5,33 @@ namespace Hexecs.Assets; public static class AssetMarshal { - public static ushort GetComponentId() where T : struct, IAssetComponent => AssetComponentType.Id; + public static ushort GetComponentId() where T : struct, IAssetComponent + { + return AssetComponentType.Id; + } - public static ushort GetComponentId(Type componentType) => AssetComponentType.GetId(componentType); + public static ushort GetComponentId(Type componentType) + { + return AssetComponentType.GetId(componentType); + } - public static Type GetComponentType(ushort componentId) => AssetComponentType.GetType(componentId); + public static Type GetComponentType(ushort componentId) + { + return AssetComponentType.GetType(componentId); + } public static ref T GetMutableComponent(in Asset asset) where T : struct, IAssetComponent { - var pool = asset.Context.GetComponentPool(); + AssetComponentPool? pool = asset.Context.GetComponentPool(); + + AssetId assetId = asset.Id; + + if (pool == null) + { + AssetError.ComponentNotFound(assetId); + } - var assetId = asset.Id; - if (pool == null) AssetError.ComponentNotFound(assetId); return ref pool.Get(assetId); } @@ -25,6 +39,7 @@ public static ref T GetMutableComponent(in Asset asset) public static bool TryGetDebugContext([NotNullWhen(true)] out AssetContext? assetContext) { assetContext = WorldDebug.World?.Assets; + return assetContext != null; } -} \ No newline at end of file +} diff --git a/src/Hexecs/Assets/AssetRef1.cs b/src/Hexecs/Assets/AssetRef1.cs index fa870b6..0fa9efb 100644 --- a/src/Hexecs/Assets/AssetRef1.cs +++ b/src/Hexecs/Assets/AssetRef1.cs @@ -20,7 +20,7 @@ namespace Hexecs.Assets; public static AssetRef Empty { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => new(null!, AssetId.Empty, ref Unsafe.NullRef()); + get => new AssetRef(null!, AssetId.Empty, ref Unsafe.NullRef()); } /// @@ -67,7 +67,10 @@ public ref readonly T Get() } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Has() where T : struct, IAssetComponent => Context.HasComponent(Id); + public bool Has() where T : struct, IAssetComponent + { + return Context.HasComponent(Id); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool IsRef(out AssetRef asset) where T : struct, IAssetComponent @@ -75,44 +78,74 @@ public bool IsRef(out AssetRef asset) where T : struct, IAssetComponent return Context.TryGetAssetRef(Id, out asset); } - public override string ToString() => Context == null - ? StringUtils.EmptyValue - : Context.GetDescription(Id); + public override string ToString() + { + return Context == null + ? StringUtils.EmptyValue + : Context.GetDescription(Id); + } #region Equality [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(Asset other) => Id == other.Id && ReferenceEquals(Context, other.Context); + public bool Equals(Asset other) + { + return Id == other.Id && ReferenceEquals(Context, other.Context); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(AssetRef other) => Id == other.Id && ReferenceEquals(Context, other.Context); + public bool Equals(AssetRef other) + { + return Id == other.Id && ReferenceEquals(Context, other.Context); + } - public override bool Equals(object? obj) => obj switch + public override bool Equals(object? obj) { - Asset asset => asset.IsRef(out var expected) && Equals(expected), - _ => false - }; + return obj switch + { + Asset asset => asset.IsRef(out AssetRef expected) && Equals(expected), + _ => false + }; + } - public override int GetHashCode() => HashCode.Combine(Id); + public override int GetHashCode() + { + return HashCode.Combine(Id); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(in AssetRef left, in AssetRef right) => left.Equals(right); + public static bool operator ==(in AssetRef left, in AssetRef right) + { + return left.Equals(right); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(in AssetRef left, in AssetRef right) => !left.Equals(right); + public static bool operator !=(in AssetRef left, in AssetRef right) + { + return !left.Equals(right); + } #endregion #region Implicit [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator bool(in AssetRef asset) => !asset.IsEmpty; + public static implicit operator bool(in AssetRef asset) + { + return !asset.IsEmpty; + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator AssetId(in AssetRef asset) => asset.Id; + public static implicit operator AssetId(in AssetRef asset) + { + return asset.Id; + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator Asset(in AssetRef asset) => new(asset.Context, asset.Id); + public static implicit operator Asset(in AssetRef asset) + { + return new Asset(asset.Context, asset.Id); + } #endregion -} \ No newline at end of file +} diff --git a/src/Hexecs/Assets/AssetRef2.cs b/src/Hexecs/Assets/AssetRef2.cs index 21c8d1d..b1c7b46 100644 --- a/src/Hexecs/Assets/AssetRef2.cs +++ b/src/Hexecs/Assets/AssetRef2.cs @@ -22,7 +22,7 @@ namespace Hexecs.Assets; public static AssetRef Empty { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => new(null!, AssetId.Empty, ref Unsafe.NullRef(), ref Unsafe.NullRef()); + get => new AssetRef(null!, AssetId.Empty, ref Unsafe.NullRef(), ref Unsafe.NullRef()); } /// @@ -103,45 +103,78 @@ public override string ToString() #region Equality [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(Asset other) => Id == other.Id && ReferenceEquals(Context, other.Context); + public bool Equals(Asset other) + { + return Id == other.Id && ReferenceEquals(Context, other.Context); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(AssetRef other) => Id == other.Id && ReferenceEquals(Context, other.Context); + public bool Equals(AssetRef other) + { + return Id == other.Id && ReferenceEquals(Context, other.Context); + } - public override bool Equals(object? obj) => obj is Asset other && Id == other.Id; + public override bool Equals(object? obj) + { + return obj is Asset other && Id == other.Id; + } - public override int GetHashCode() => HashCode.Combine(Id); + public override int GetHashCode() + { + return HashCode.Combine(Id); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(in AssetRef left, in AssetRef right) => left.Equals(right); + public static bool operator ==(in AssetRef left, in AssetRef right) + { + return left.Equals(right); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(in AssetRef left, in AssetRef right) => !left.Equals(right); + public static bool operator !=(in AssetRef left, in AssetRef right) + { + return !left.Equals(right); + } #endregion #region Implicit [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator bool(in AssetRef asset) => !asset.IsEmpty; + public static implicit operator bool(in AssetRef asset) + { + return !asset.IsEmpty; + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator AssetId(in AssetRef asset) => asset.Id; + public static implicit operator AssetId(in AssetRef asset) + { + return asset.Id; + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator Asset(in AssetRef asset) => new(asset.Context, asset.Id); + public static implicit operator Asset(in AssetRef asset) + { + return new Asset(asset.Context, asset.Id); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator AssetRef(in AssetRef actor) => new( - actor.Context, - actor.Id, - ref actor._component1); + public static implicit operator AssetRef(in AssetRef actor) + { + return new AssetRef( + actor.Context, + actor.Id, + ref actor._component1); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator AssetRef(in AssetRef actor) => new( - actor.Context, - actor.Id, - ref actor._component2); + public static implicit operator AssetRef(in AssetRef actor) + { + return new AssetRef( + actor.Context, + actor.Id, + ref actor._component2); + } #endregion -} \ No newline at end of file +} diff --git a/src/Hexecs/Assets/AssetRef3.cs b/src/Hexecs/Assets/AssetRef3.cs index ecfa2fd..cd52682 100644 --- a/src/Hexecs/Assets/AssetRef3.cs +++ b/src/Hexecs/Assets/AssetRef3.cs @@ -24,7 +24,7 @@ namespace Hexecs.Assets; public static AssetRef Empty { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => new(null!, AssetId.Empty, ref Unsafe.NullRef(), ref Unsafe.NullRef(), ref Unsafe.NullRef()); + get => new AssetRef(null!, AssetId.Empty, ref Unsafe.NullRef(), ref Unsafe.NullRef(), ref Unsafe.NullRef()); } /// @@ -79,13 +79,22 @@ internal AssetRef(AssetContext context, AssetId id, ref T1 component1, ref T2 co } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public AssetRef AsRef() where T : struct, IAssetComponent => Context.GetAssetRef(Id); + public AssetRef AsRef() where T : struct, IAssetComponent + { + return Context.GetAssetRef(Id); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ref readonly T Get() where T : struct, IAssetComponent => ref Context.GetComponent(Id); + public ref readonly T Get() where T : struct, IAssetComponent + { + return ref Context.GetComponent(Id); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Has() where T : struct, IAssetComponent => Context.HasComponent(Id); + public bool Has() where T : struct, IAssetComponent + { + return Context.HasComponent(Id); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool IsRef(out AssetRef asset) where T : struct, IAssetComponent @@ -93,80 +102,127 @@ public bool IsRef(out AssetRef asset) where T : struct, IAssetComponent return Context.TryGetAssetRef(Id, out asset); } - public override string ToString() => Context == null - ? StringUtils.EmptyValue - : Context.GetDescription(Id); + public override string ToString() + { + return Context == null + ? StringUtils.EmptyValue + : Context.GetDescription(Id); + } #region Equality [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(Asset other) => Id == other.Id && ReferenceEquals(Context, other.Context); + public bool Equals(Asset other) + { + return Id == other.Id && ReferenceEquals(Context, other.Context); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(AssetRef other) => Id == other.Id && ReferenceEquals(Context, other.Context); + public bool Equals(AssetRef other) + { + return Id == other.Id && ReferenceEquals(Context, other.Context); + } - public override bool Equals(object? obj) => obj is Asset other && Id == other.Id; + public override bool Equals(object? obj) + { + return obj is Asset other && Id == other.Id; + } - public override int GetHashCode() => HashCode.Combine(Id); + public override int GetHashCode() + { + return HashCode.Combine(Id); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(in AssetRef left, in AssetRef right) => left.Equals(right); + public static bool operator ==(in AssetRef left, in AssetRef right) + { + return left.Equals(right); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(in AssetRef left, in AssetRef right) => !left.Equals(right); + public static bool operator !=(in AssetRef left, in AssetRef right) + { + return !left.Equals(right); + } #endregion #region Implicit [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator bool(in AssetRef asset) => !asset.IsEmpty; + public static implicit operator bool(in AssetRef asset) + { + return !asset.IsEmpty; + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator AssetId(in AssetRef asset) => asset.Id; + public static implicit operator AssetId(in AssetRef asset) + { + return asset.Id; + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator Asset(in AssetRef asset) => new(asset.Context, asset.Id); + public static implicit operator Asset(in AssetRef asset) + { + return new Asset(asset.Context, asset.Id); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator AssetRef(in AssetRef actor) => new( - actor.Context, - actor.Id, - ref actor._component1); + public static implicit operator AssetRef(in AssetRef actor) + { + return new AssetRef( + actor.Context, + actor.Id, + ref actor._component1); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator AssetRef(in AssetRef actor) => new( - actor.Context, - actor.Id, - ref actor._component2); + public static implicit operator AssetRef(in AssetRef actor) + { + return new AssetRef( + actor.Context, + actor.Id, + ref actor._component2); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator AssetRef(in AssetRef actor) => new( - actor.Context, - actor.Id, - ref actor._component3); - + public static implicit operator AssetRef(in AssetRef actor) + { + return new AssetRef( + actor.Context, + actor.Id, + ref actor._component3); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator AssetRef(in AssetRef actor) => new( - actor.Context, - actor.Id, - ref actor._component1, - ref actor._component2); + public static implicit operator AssetRef(in AssetRef actor) + { + return new AssetRef( + actor.Context, + actor.Id, + ref actor._component1, + ref actor._component2); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator AssetRef(in AssetRef actor) => new( - actor.Context, - actor.Id, - ref actor._component1, - ref actor._component3); + public static implicit operator AssetRef(in AssetRef actor) + { + return new AssetRef( + actor.Context, + actor.Id, + ref actor._component1, + ref actor._component3); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator AssetRef(in AssetRef actor) => new( - actor.Context, - actor.Id, - ref actor._component2, - ref actor._component3); + public static implicit operator AssetRef(in AssetRef actor) + { + return new AssetRef( + actor.Context, + actor.Id, + ref actor._component2, + ref actor._component3); + } #endregion -} \ No newline at end of file +}