Bot releases are hidden (Show)
World.TrimExcess
does not trim Recycled-Entities.Buffer
namespace, might break references.Dangerous
methods for setting and getting recycled ids.ScheduleParallelInlineChunkQuery
for scheduling ChunkJobs
more effectively and to determine dependencies.World.IsAlive(EntityReference);
.Full Changelog: https://github.com/genaray/Arch/compare/1.2.7...1.2.8
Published by genaray about 1 year ago
Add
and Remove
operations.Entity
now implements IComparable<Entity>
Entity
or EntityReference
for IsAlive
now returns false.BitSet
s were vectorized for faster checks (especially when there many registered components)ComponentType
is now slimmer and blittable (just pure data, no managed types in it anymore).ComponentRegistry
and ArrayRegistry
- can now be used to register components native aot-wise.DangerousUtilities
to access arch internals. Used especially by Arch.Extended.Arch.LowLevel
is now a dependencyThanks to @reeseschultz , @Hertzole, @DrSmugleaf for several contributions! <3
Published by genaray about 1 year ago
Thanks to @DrSmugleaf, @nathanrw , @mikhail-dcl , @clibequilibrium for several contributions! <3
Published by genaray over 1 year ago
CommandBuffer
do now clear correctlyDebug.Asserts
to several places to aid developmentWorld.Range
which did not set componentsWorld.Add(entity,cmp)
which did not set component either.ComponentTypes
inside ComponentRegistry
are now offset by +1 to fix a hash related issueQuery._any
now works correctly for larger bitsets > 32.TryGet
and TryGetRef
methods.EntityReference
to `Entity´.World.AddOrGet<T>
to ensure components on entities.Huge thanks to @DrSmugleaf and @nathanrw for bug fixes and contributions! :)
Published by genaray over 1 year ago
PURE_ECS
compatibilityEntityReference.IsAlive()
returning true in certain scenarios where the entity was clearly dead or not valid anymore.Thanks to @DrSmugleaf and @nathanrw for fixing several warnings and bugs! :)
Published by genaray over 1 year ago
CommandBuffer
operations were now fixed and do record Add and Sets correctly.CommandBuffer
resizes its internal arrays now correctly.World.Add
, World.AddRange
, World.RemoveRange
were fixed, they created wrong archetypes with doubled components in some cases.Arch.Core.Extensions
in
and ref
modifiers for many operations because of performance reasons (most used structs are small enough to be copied and thus more efficient).World.Remove
.EntityInfoStore
which acts as an storage for Entity
meta data and offers an unified API to access those data.Thanks to @DrSmugleaf for the PRs and fixing the compatibility with #define pure_ecs and nullable issues :)
Thanks to @Donaut for the EntityInfoDictionary
and its integration! :)
Published by genaray over 1 year ago
EntityInfo
dictionary and a crash sooner or later.QueryDescription
did not set its value correctly, this was now fixed as well.BitSet.None
, which now works correctly with large amounts of components.EntityExtension
methods.Entity.Set
now uses default valuesCommandBuffer
methods now make use of default values.World.Clear()
was introduced and clears the whole world.World.GetEntities(Span<Entity> ...);
was introduced as an alternative to lists, soon all the available API will make use of spans.ComponentRegistry
features a method to register a ComponentType
, therefore the user can register custom types.ComponentRegistry.Add(ComponentType);
Arch tries to support so called managed structs. However, this is not always fully possible due to compatibility with a type-based API. And the existing C# Marshal methods are not always able to recognize managed structs and determine their size.
Therefore, a method has now been added to the ComponentRegister to allow the user to register components independently. He can specify the size himself and thus it is now also possible to add all managed structs.
public struct ManagedStruct{ public List<int> SomeInts{ get; set; } }
// Register
var componentType = new ComponentType(ComponentRegistry.Size, typeof(ManagedStruct), 8, false); // 8 = Size in bytes of the managed struct.
ComponentRegistry.Add(componentType);
// Use
var entity = world.Create(new ManagedStruct());
Thanks to @DrSmugleaf for the PRs and fixing the compatibility with #define pure_ecs
:)
Published by genaray over 1 year ago
QueryArchetypeEnumerator
throws an exception that was caused due to inaccurate poolingentity.Add(cmp)
now works exactly as world.Add(in entity, cmp)
doesComponentRegistry
now features several methods to modify registered components for hot reloadingThanks to @stgeorge and @clibequilibrium for discovering bugs and other small missing features :)
Published by genaray over 1 year ago
.Add
or .Remove
.Destroy
,Set
,Add
and Remove
operations by targeting a range of entities using QueryDescription.Until now, destroying entities or changing their component structure has always been a costly endeavor.
This is mainly due to the Archetype and Chunk architecture itself.
Bulk operations are now changing that. By means of these you can address all entities of a certain structure, which is significantly faster.
var query = new QueryDescription().WithAll<Player>();
world.Set(in query, new Position(), new Transform()); // Sets components for all entities fitting the query.
world.Add(in query, new KillTag(), new DropItems(),..); // Every single entity fitting the queryDescription will receive those components
world.Remove<Velocity, Defence>(in query);
world.Destroy(in query);
Many thanks to @Pheubel and @stgeorge for contributions and issues :)
Published by genaray almost 2 years ago
References<...>
and EntityReferences<...>
are now called Components<...>
and EntityComponents<....>
World.TrimExcess()
can now be called regularly to release unused memory and resources.World.Reference(in entity)
or entity.Reference()
return a EntityReference
used to reference entities.World.Destroy
is now slightly fasterusing var world = World.Create();
var entity = world.Create(_entityGroup);
var reference = world.Reference(entity); // This should be stored in your component ( entity.Reference() is also available. )
// Checks if the entity is the same as before by comparing the version and its id
if(reference.IsAlive()) {
var cmps = reference.Entity.Get(...);
}
Big thanks to @stgeorge , @Pheubel and @RoyAwesome for your bug discoverys and enhancements ! :)
Published by genaray almost 2 years ago
HPQuery
and HPEQuery
, aswell as their parallel counterparts are now called InlineQuery
, InlineEntityQuery
e.g.Index, GetArray, GetSpan, GetFirst
to improve performance and reduce boilerplate code.world.CountEntities
to... count entities which will be targeted by a query.var transform = (object)new Transform { X = 10, Y = 10 };
_entity.Set(transform);
var tramsformReference = (Transform)_entity.Get(typeof(Transform));
// Non generic additional methods
_entity.SetRange(...);
_entity.Has(...);
_entity.HasRange(...);
_entity.Get(...);
_entity.GetRange(...);
_entity.Add(...);
_entity.AddRange(...);
_entity.Remove(...);
_entity.RemoveRange(....);
foreach (var chunk in _world.Query(in _queryDescription).GetChunkIterator())
{
var refs = chunk.GetFirst<Transform, Velocity>(); // or chunk.GetSpan<Transform, Velocity>(out var trans, out var velos);
foreach (var entity in chunk) // New iteration, automatically iterates backwards over all valid chunk entities.
{
ref var pos = ref Unsafe.Add(ref refs.t0, entity);
ref var vel = ref Unsafe.Add(ref refs.t1, entity);
pos.X += vel.X;
pos.Y += vel.Y;
}
}
Published by genaray almost 2 years ago
World
can now be modified during queries using world.Create
, world.Destroy
, world.Set
, world.Add
, world.Remove
.CommandBuffer
-API is available which combines the previous ones.QueryDescription
now features a new API to reduce boilerplate : var desc = new QueryDescription().WithAll<Position, Velocity>...
.Arch.Samples
which provides a small usage sample with Arch and Monogame :)You no longer need several CommandBuffers, but a single one. The syntax is now much simpler.
var entity = world.Create<Transform, Rotation, int>();
var bufferedEntity = commandBuffer.Create(new ComponentType[] {typeof(Transform), typeof(Rotation), typeof(int) }); // Later also generic overloads to get rid of arrays.
commandBuffer.Set(in entity, new Transform{ X = 20, Y = 20});
commandBuffer.Add(in entity, new Ai());
commandBuffer.Set(in bufferedEntity, new Transform{ X = 20, Y = 20});
commandBuffer.Add(in bufferedEntity, new Ai());
commandBuffer.Playback();
Many thanks to @andreakarasho for fixes and new features ! :)
Published by genaray almost 2 years ago
PURE_ECS
preprocessor variable for utilizing pure ecs paradigmaEntity.Null
will not anymore create a new null entity each time its acessedComponentType
is now required for several operations to provide additional component data and to prevent lookupsWorld.Id
is now a int and not limited to 255 anymoreWorld
, Archetype
and Chunk
methods internal for a better workflow and less headacheWorld
will internally track entities and some meta data for faster lookup speed and less dictionarysArchetype
and Chunk
are now slimmer and act as pure containers without mapping entities and wasting space.Theres a PURE_ECS
preprocessor variable now which sets an entity to exactly one integer and disables all existing entity extension methods. This way the ECS can be accessed by a "pure ecs" mindset, thus more entities fit into one chunk and less unnecessary ballast is dragged around. This may only work with forks since the nugget package version will not have that flag enabled.
Entities are now tracked in one single dictionary inside the world, this one stores archetype and chunk index data to provide instand acess. Compared to previous versions only one single lookup is now required instead of multiple ones, therefore the lookup speed increased by a lot.
Previous version:
Method | Amount | Mean | Error | StdDev | Allocated |
---|---|---|---|---|---|
WorldEntityQuery | 10000 | 513.765 us | 297.3252 us | 16.2974 us | - |
WorldEntityQuery | 100000 | 5,032.846 us | 2,116.4383 us | 116.0091 us | - |
WorldEntityQuery | 1000000 | 50,894.500 us | 1,944.0534 us | 106.5601 us | - |
Current version :
Method | Amount | Mean | Error | StdDev | CacheMisses/Op | Allocated |
---|---|---|---|---|---|---|
WorldEntityQuery | 10000 | 147.660 us | 13.2838 us | 0.7281 us | 746 | - |
WorldEntityQuery | 100000 | 1,726.959 us | 3,058.5935 us | 167.6518 us | 11,761 | - |
WorldEntityQuery | 1000000 | 20,419.798 us | 4,491.2760 us | 246.1820 us | 90,624 | - |
@andreakarasho thanks for pointing out issues with commandbuffers and the entity tweaks ! :)
Published by genaray almost 2 years ago
Fixed the acessability of CreationBuffer
and ModificationBuffer
constructors, thanks @andreakarasho ! :)
You may now use them like this...
var creationBuffer = new CreationBuffer(world, 1024); <- Initial capacity, not total capacity
world.ParallelQuery(in desc, (in Entity en) => {
var entity = creationBuffer.Create(group);
entity.Set<Explosion>(...);
entity.Set<Position>(...);
});
creationBuffer.Playback(); // Must happen after a queries on the mainthread.
or this...
var buffer = new ModificationBuffer(world, 1024);
world.ParallelQuery(in desc, (in Entity en) => {
var modifiedEntity = buffer.Modify(in en);
buffer.Set(...);
});
buffer.Playback();
Published by genaray almost 2 years ago
Several new features were added in this release, especially gameplay relevant features to ease development.
With the previous query API you could not target exclusive entity architectures.
This now has changed.
var exclusiveGroup = new[] { typeof(Transform), typeof(Rotation) };
var query = new QueryDescription { Exclusive = exclusiveGroup }; // Only targets entities with EXACTLY those components.
world.Query(in query, (in Entity en) => {}); // Only queries entities with "Transform" and "Rotation", no entities with other components.
Huge thanks to @MindSwipe for the contribution of the exclusive queries ! :)
Due to the iteration mechanism it was not possible to the world or the entity itself during queries. Now theres a way for exactly those purposes, called "Buffers". They "buffer" operations to play them back after a query.
There 4 specialised buffers, one for each operation :
CreationBuffer
- A buffer which records creation commandsModificationBuffer
- A Buffer which records set operationsStructuralBuffer
- A buffer which records structural operationsDestructionBuffer
- A buffer which records destroy operationsA small example :
var creationBuffer = new CreationBuffer(world, 1024); <- Initial capacity, not total capacity
world.ParallelQuery(in desc, (in Entity en) => {
var entity = creationBuffer.Create(group);
entity.Set<Explosion>(...);
entity.Set<Position>(...);
});
creationBuffer.Playback(); // Must happen after a queries on the mainthread.
They are all thread safe and can be used with parallel queries.
The parallel queries were extended by a few methods like...
world.ParallelQuery(in desc, (in Entity en ) => {});
...
Published by genaray almost 2 years ago
Lots of new generic overloads for world
, Chunk
, Archetype
and Entity
. To ease the development for the enduser and to operate on entities more efficient by batching calls.
All of the types above received .Has<T0...T9>
, .Get<T0...T9>
, .Set<T0...T9>
, .Add<T0...T9>
and .Remove<T0...T9>
methods. The world also received world.Create<T0...T9>
as an alternative to the world.Create(Type[])
call.
Using generic overloads instead of multiple single calls is way more efficient and faster.
var entity = world.Create(archetype);
entity.Set(new Transform());
entity.Set(new Movement());
ref var t = ref entity.Get<Transform>();
ref var m = ref entity.Get<Movement>();
becomes
var entity = world.Create(new Transform(), new Movement());
var refs = entity.Get<Transform, Movement>();
Published by genaray almost 2 years ago
ComponentIdToArrayIndex
was a dictionary inside Chunk
and is now a lookup table insteadPublished by genaray almost 2 years ago
Type[]
arrays are now mappd to their specific Archetype
by a unique hashTransform, Rotation
& Rotation, Transform
are handled the sameWorld
now features all entity related methods and EntityExtensions
just forward them for easier API usage.World
,Archetype
, Chunk
are now divded into partial classes/structs by features to give a better overview.WorldTest
and ArchetypeTest
Structural changes move entities from one to another archetype. It is used to remove and add components to entities during runtime.
This should never happen during a query.
world.Add<T>(in entity, new T());
world.Remove<T>(in entity);
entity.Add<T>(new T());
entity.Remove<T>();
Published by genaray almost 2 years ago
Fixed a bug where queries not targeting any entities would throw a NullReferenceException
#11.
Thanks @MindSwipe for the discovery and fix of this bug ! :)
Published by genaray almost 2 years ago
Fixed a bug ( #9 ) where similar structured archetypes could exist next to each other, aswell as a similar bug for queries.
Big thanks at @MindSwipe and his PR #10 for noticing and fixing this bug :)