- Updated iteration algorithm to reduce code size and improve adaptability to bitset filling.
- Removed explicit alignment from
Allocator. Allocations are naturally aligned by size anyway.
SizeOfUnmanagedreturning inconsistent values between Mono and .NET.- Fixed default value invalidation (#12).
- Fixed incorrect allocator rollbacks and clearing of small allocations.
- Ordering support for
Systemsregistration methods. - Implicitly excluded components in
WorldConfig. These components are automatically added
to theExcludefilter in all queries unless explicitly included. - Automatic cloning of deep pointers and their data when an entity is cloned.
IInject<T>is now contravariant.- Renamed
IAutoFree<T>toIAuto<T>. - Improved
QueryCacheupdate efficiency.
SizeOfUnmanagedon .NET 5+ could fail when no size cache preserved. Added a reflection fallback.- Fixed an issue in
AllocatorSchemaGeneratorwhen a type contained a pointer to a primitive. - Fixed an issue with
AllocatorPointerFieldwhen a type contained nested wrapper structs.
Stabilization of the new architecture.
- Built-in
Systemswith customizable method running. - Polyfills for NativeAOT support.
IAutoFree<T>component interface to automatically free allocator pointers when the component is removed from an entity.Peekback(frames)method toMassiveWorldto access previousWorldstates. Can be used to impelemnt interpolation.
Allocatoris now unamanged and unified.
- Read-only operations and queries no longer cause internal component IDs to be assigned. Component IDs for masks are now assigned on set modification rather than when requesting a set.
- Thread-safety of
QueryCachepool.
Breaking storage changes.
SparseSets are replaced with hierarchicalBitSets.- Iteration reworked to use bit scans and boolean operations on the entities in each pool of interest.
- A lot of internal changes.
- Renamed
Entityidentifier toEntifier. - Renamed
EntitiestoEntifiers. - Renamed
SetRegistrytoSets. - Renamed
FilterRegistrytoFilters. - Renamed
AllocatorRegistrytoAllocators. Destroy()no longer throws when called with a dead entity.- Replaced
MassiveAssertwith individual exceptions. World.Set()now throws if the component has no associated data.- Renamed
World.Filter()toWorld.GetFilter(). - Made
Worldact as aViewto reduce boilerplate.
- New rich
Entitystruct with a clean syntax:entity.IsAliveentity.Add<Enemy>()entity.Destroy()- etc.
- Iteration over rich entities:
- using
world.ForEach((Entity entity, ref Player player, ...) => ...)queries. - using
foreach (var entity in world.Include<Player>().Entities())enumerators.
- using
StoreNegativeattribute for storing a complementary set of entities to optimize exclusion filtering:world.Exclude<Dead>.ForEach(...);- Negation in all contexts that use component types:
world.Include<Not<Dead>>.ForEach(...); // Acts like Exclude<Dead>entity.Add<Not<Dead>>(); // Removes Dead component
Allocator, enabling fast rollbacks and serialization for collections inside components, and allowing external tools to plug directly into the data pipeline of theWorld.
- Renamed data sets based on their usage:
- Renamed
ResettingDataSettoUnmanagedDataSet. - Renamed
SwappingDataSettoManagedDataSet.
- Renamed
- Renamed
AsserttoMassiveAssert. - Reworked
default(Entity)behaviour:- Entity ID is now stored without offset.
- Alive entities start with version 1.
- Entities with version 0 are now considered dead.
ViewandFilterViewsometimes choose and use not optimal minimal set.
DefaultValueattribute to customize the reset value for unmanaged components.
- Renamed
ForEachExtratoForEach, making it just another overload. - Renamed
MaxIdtoUsedIdsinEntitiesfor consistency withSparseSet.
PageSizeattribute to override the default page size for a data set of the specified type.
- Replaced the
IStablemarker interface with aStableattribute.
BREAKING CHANGE: Major renaming, groups removal.
- Renamed
Registryclass toWorld. - Changed sets API:
- Renamed
Assign(id)toAdd(id). - Renamed
Unassign(id)toRemove(id). - Renamed
IsAssigned(id)toHas(id). - Renamed
Assign(id, data)toSet(id, data). Add(id)andRemove(id)returnstrueif the component is added or removed andfalseif it is already present or not there.
- Renamed
- Added assertions for negative arguments in some methods.
Clone()andCopyTo(other)methods toSparseSet,DataSet<T>andWorld.
- Groups.
- Assertions for numerous execution paths.
Destroy,Assign,Unassign,HasandClonemethods now disallow passing dead entities or IDs.Filter.Emptystatic property has been moved toFilterRegistryand is now non-static.
Entities.HasHolesworked incorrectly forPacking.WithPersistentHoles.
- Empty type optimization (tags) now only applies to value types, instead of any type without fields.
- Renamed
TrimmedFiltertoReducedFiltedand tweak some internal method names. - Reworked
TypeIdentifierandGenericLookup. - Optimize
FilterView.ForEach()methods for cases where a minimal set is one of the selected data sets. - Moved serialization to a separate package to eliminate unsafe code from the core library.
PageSequencenow usePagestruct to iterate.MassiveRegistrynow saves first empty forMassiveEntitieson creation.
- IL2CPP stripping for
ICopyable<T>.
Iteration stability, sets customization, groups rework, performance improvements and more.
- Copy, move, and swap customization for data sets.
DynamicFilterfor builder-like style when working with non-generic filtering.TrimmedFilter, which removes the leading set from included ones, optimizing iteration.- New packing option
WithPersistentHoles.
- Renamed
PackingModetoPacking. Packingnow dynamically changes for the iteration leader,
ensuring each unique entity appears only once during iteration in most cases,
or in all cases when using the new packing option.- Hide setters in data structures. Added full-state assignment API.
- Renamed
IdsSourcetoPackedSet. - Renamed
IManaged<T>toICopyable<T>. Now used also for entity components cloning. - Renamed
NonOwningGrouptoGroup.
OwningGroupfor SoA access. It may return in some form in the future.GroupView. Groups are now used directly as is.GroupPage,GroupPageSequenceandIOwnSelector.- Runtime/Utils folder.
RegistryReflectionExtensions. Reflection methods remain directly accessible.
Il2CppSetOptionwas not applied correctly.
PackingModetoEntities.PackingModenow can be changed at runtime both forEntitiesandSparseSet.
GroupPagenow returnsEntry, containing both in-page index and ID.
Alivespan property fromEntities. Use enumerator instead.- Delegate parameter from
Entities.CreateMany.
Clearmethod forEntities.ClearandClear<T>extension methods forRegistry.- Enumerator for
Group.
- Renamed
IncludeandExcludeproperties toIncludedandExcluded.
This change affects filters, groups, and some variables.
AsIdsextension method for groups. Use the new enumerator instead.
Non-generic API for a better IL2CPP experience.
- Non-generic version of the
Getmethod forGroupRegistry, making it the primary version. GroupPageSequenceandGroupPagetypes to support working with owning groups in a non-generic manner.- Enumerator for
SparseSetandEntities. PageSizeproperty toRegistry.
Entities.AfterCreatednow returns anintinstead of anEntity.- Renamed
RegistryConfig.DataPageSizetoPageSize. - Group serialization adjusted to align with the new non-generic primary storage.
- Non-owning groups were not functioning when no included sets were present.
Now they default to observing
Entities.
Major devirtualization and other optimizations.
- Fourth generic parameter for all Views.
Groupclass, replacing theIGroupinterface.IdsSourceclass, replacing theIIdsSourceinterface.
- Replaced
IFilterand other filters withFilter. - Replaced
IGroupandIOwningGroupwithGroupandOwningGroupclasses. - Increased default page size from 1024 to 16384 (except
MassiveRegistry, which remains 1024).
IGroup,IFilter, andIIdsSourceinterfaces.SetCapacityparameter; now defaults to 0 across the board.
- Replaced
ArraySegmentwith direct array usage to improve performance.
PageSequencereturned zero-length page in specific cases.- Non-serialized sets and groups not being cleared after deserialization.
- Forgot to serialize the pointer to the next hole in the sparse set.
- Removed unnecessary resizes during deserialization to reduce allocations.
Major serialization rework and addition of reflection toolset.
- RegistrySerializer no longer requires manual setup and works automatically in most cases. Customization remains available.
- Renamed
IDataSetSerializertoIDataSerializerwith slight API modifications.
- Support for
Typeargument in addition to generic ones for:- ISetFactory.CreateAppropirateSet(Component)
- SetRegistry.Get(Component)
- GroupRegistry.Get(Include,Exclude,Own)
- Methods to work with raw data for
IDataSet. - Non-generic
IPagedArrayinterface forPagedArray<T>.
Create<T>()andCreateEntity<T>()now do not initialize data, aligning withAssign<T>()behavior.
FullStabilityoption for Registry.
Remove some abstractions and add some minor things.
Compact()method to sparse set, which removes all holes from the packed array.DefaultPackingModefield intoRegistryConfig.
- Renamed
IGroup.SettoIGroup.MainSet.
MassiveDataSetBase, leaving onlyMassiveDataSetandMassiveManagedDataSet.ISet,IReadOnlySet,IDataSet<T>andIReadOnlyDataSet<T>interfaces.
Sparse set mods rework.
- Renamed
IndexingMode.PackedtoPackingMode.Continuous. - Replaced
IndexingMode.DirectwithPackingMode.WithHoles. The new behavior creates holes in the packed array on Unassign(), which are reused during Assign(). Unlike the previous version, this approach naturally tends toward storage compaction over time.
Major stability update.
IndexingModefor sparse sets, that allows to choose between packed (indirect) and direct storaging.IndexingMode.Packedrepresents the previous behavior of sets and is the default. Even whenIndexingModeisPacked, now you can delete and create entities much more freely during iteration.IStablemarker interface for components, that must be stored withIndexingMode.Direct.First(),FirstEntity(),Destroy(),Count()extension methods for views.
IEntityAction.Applynow returns bool and can break from iteration.- Renamed all "Dense" stuff to "Packed".
- Massives now sync only the current frame capacity during saving. This will allow more gradual memory allocation.
- Divided
Assign<T>()into two distinct overloads - with data initialization and without it. This will allow the sets to be used as objects pools. - Order of groups to more common pattern
Group<Include, Exclude, Owned>.
Devirtualize usages for better inlining and performance.
- Replaced
ISetandIReadOnlySetwithSparseSet. - Replaced
IDataSet<T>andIReadOnlyDataSet<T>withDataSet<T>. - Replaced
IRegistrywithRegistry. - Replaced
IEntitieswithEntities.
IEntitiesandIRegistryinterfaces.
Refactoring and some API change.
- Renamed registry
Components<T>extension method toDataSet<T>. - Renamed registry
Any<T>extension method toSet<T>.
Minor API renaming, but major up. None the less.
- Renamed
IViewmethods. - Renamed
InvokerstoActions.
- Renamed
EntityFillInvokerandEntityFillEntitiesInvokertoFillIdsInvokerandFillEntitiesInvoker.
- Removed final bits of unsafe code from the project.
- Id enumerators for the views.
Include()andExclude()extension methods for basicView. That simplifies querying.
- Major redesign of the views API for ease of use and extensibility.
Fill()extension methods fromIRegistry. Views still have them.
- Added funky bitwise stuff into filters, so now they are working 20% faster.
Fill()extension methods forIRegistryto populate the result list with filtered ids and entities.
- Removed
SetRegistryparameter fromGet()method inFilterRegistryandGroupRegistry. Now it is proper dependency. - Reworked protected
Registryctor to fit API changes.
MassiveGroupRegistryhas been removed, and nowMassiveRegistryis responsible for saving and rollbacking groups.
- Set selectors now return distinct sets. This is useful when the user duplicates generic arguments. We can't prevent this from happening at compile time, so now at least it doesn't affect runtime.
- Items sorting in
GenericLookupnow works with full type names instead of type names hashes, which eliminates possible problems related to hash collisions.
ActionRefdelegates similar toEntityActionRef, but without id parameter.ForEach()andForEachExtra()extension methods overloads withActionRefandActionRefExtraparameters forIView.
Clone()extension method forIRegistryto clone entities.
Fill()extension method forIViewto populate the result list with filtered ids.
- Replaced
IRegistryparameter in views ctors with fields initialization.