Releases: EcsRx/ecsrx
Minor fixes for Computed Groups
Thanks to @thejayman for adding a fix for ComputedGroups
incorrectly raising removal events for entities which were not currently being tracked internally.
Observable Group Changes + Dropping .Net Framework Builds
Summary
The high level information here is that we have dropped explicit releases for .Net Framework 4.6 and instead are now just focusing on building netstandard2.0
, in the future we would like to move to net7
but until a lot more frameworks have migrated over to it we are just going to stick with netstandard
.
We have also changed the way ObservableGroup
objects work by separating out the group matching mechanism to a new interface known as an IObservableGroupTracker
which will monitor the groups/entities and then relay onto the ObservableGroup
when there is a change.
This diagram shows the new process, which historically all used to take place within the ObservableGroup
so this makes the object simpler and allows other parts of the system to track group changes.
Other Changes
There are some breaking changes around namespaces for events changing as well as a new wrapper around component interactions on the type called IComponentAccessor
, which reduce the amount of type lookups if you are doing a lot of interactions with component types.
Fixed Regression Issue With `IDisposable` Components
Summary
While this isn't a massive release it does have a few small changes in terms of how component removal is handled.
So first of all a HUGE thanks to DoctorDepthum
on the discord who noticed the regression of the IDisposable
handling of components within entities, this has been rectified now so components with IDisposable
are now correctly disposed.
So just to clarify when you remove a component now, the underlying logic that runs in the ComponentPool
will check if the pool contains reference types, and if so null out the index, and check if the component implements IDisposable
and if so will trigger the disposable logic, then finally release the index for future consumption.
SystemsRx Split From EcsRx
Summary
The high level change for this version is that SystemsRx
is now its own repository within the EcsRx
org, however realistically at a high level you wont notice much difference other than a few package name changes:
EcsRx.Infrastructure.Ninject
->SystemsRx.Infrastructure.Ninject
EcsRx.ReactiveData
->SystemsRx.ReactiveData
EcsRx.MicroRx
->SystemsRx.MicroRx
There is also now a non EcsRx
dependent SystemsRx.Plugins.Computeds
which has base computed types without being dependent upon IGroup
etc. The EcsRx version still exists and builds on top of this allowing you little change in terms of usage.
IEventSystem
Changes
The IEventSystem
now has 2 publish methods, the default one which is backwards compatible is the default Publish<T>
however there is also now a PublishAsync<T>
which will use IThreadHandler
to Run
a new task for it which by default does a Task.Run(...)
for the publish.
IThreadHandler
Changes
The IThreadHandler
now has a Run
method which allows you to just do an arbitrary run of an action via the thread handler (defaulted to Task.Run
).
Moving more into SystemsRx
Summary
Some of these changes actually happened in previous releases but a few things have been moved down into SystemsRx
such as the pooling mechanisms, as they are useful regardless of the ECS aspect of things, so now they can be used without.
Also there have been some changes thanks to @Fijo which makes it easier to include IObservableGroup
objects on the fly in your systems via attributes by using the GroupBinding
plugin.
GroupBinding Plugin
This is optional but if you do want to include multiple IObservableGroup
objects within your systems (such as IManualSystem
) you can do so like this:
[FromComponents(typeof (LevelComponent))] public IObservableGroup LevelAccessor;
[FromComponents(typeof(EnemyComponent))] public IObservableGroup EnemyAccessor;
Which is directly lifted from the Roguelike2d Repository which has some real life usages of this plugin and how it can simplify the system and reduce dev time/boilerplate, there are some other approaches where you can use FromGroup
to pass in an explicit group or just use FromGroup
without a group on systems which implement IGroupedSystem
, and it will take the default group property as its argument.
This also simplifies those usecases for people who were originally using
IManualSystems
before they got moved toSystemsRx
and were left without a simple way to resolve anIObservableGroup
when needed.
Splitting Core Systems/Infrastructure (SystemsRx) from EcsRx
Summary
Currently a lot of the EcsRx features are not directly tied to the ECS paradigm but as they are part of core they come bundled together.
Part of this change is to decouple some of that so there can be a SystemsRx
library which has no notion of EcsRx
which can be used by people who want to have nice infrastructure and DI abstractions, as well as nice simple systems to run logic in a simple way, but don't want to have to worry about using entities and components.
SystemsRx
So this split has now made it so the new library acts as a layer underneath EcsRx
and provides basic System Execution, Infrastructure, DI and common extensions as well as a couple of simple systems such as IManualSystem
and event handling systems, it even supports plugins without needing to worry about the EcsRx
layer.
EcsRx
At the high level EcsRx
hasn't changed much, its just a lot of the core innards have been moved down a layer (and this is mentioned more on front page readme), there are a couple of breaking changes (mentioned in breaking changes document), but for the most part you continue to use the library as you do right now.
Under the hood to use EcsRx
you will be pulling in SystemsRx
but this simplifies things a bit and also lets you run systems outside of the ECS paradigm alongside your ECS related ones, so its best of both worlds.
Fixed issue with Struct Batching
Batching Plugin + Structs
As the issue with structs and batches still seemed to have no real avenue to being resolved other than only allowing blittable types, the decision has been made to just make this a requirement.
If you do not use the batching plugin then your structs (if you use them) can be of any type you want, but if you want to get the performance boost of them all being batched together you need to use blittable types otherwise they cannot be pinned.
Also updated group builder
Added a couple of struct methods to the group builder, this should allow you to use the builder to make groups with struct types in too
Persistence Plugin now available, as well as other helpers
Persistence Plugin
The major thing to talk about is the new persistence plugin which adds the ability to save your entities to and from files (or anywhere else you want), out the box it supports saving and loading from binary files, but there is an example project for how to change that to JSON if you prefer it to be human readable/editable.
As the persistence functionality is built on top of Persistity you can also make use of pipelines for your own needs, like extracting certain data from your game state and persisting it as a save game file, or even sending off metrics to PlayFab etc.
For more info on this look at the example projects and persistity documentation, or feel free to discuss in the discord server.
DI Improvements
There are some new helpers for DI around custom functions on activation as well as being able to specify that your binding should only be used when injecting into a certain type or set of types.
Streamlining Update/Time Checking
As part of the previous update we moved the IObservableScheduler
into the core, but on top of this we have streamlined what it does, so its now IUpdateScheduler
and also implements ITimeTracker
which allows you to get the elapse/total time in a cross platform way.
This would be a minor update but as it breaks the surface API it needs to be a major release.
A new `IBasicSystem` and some group changes and infrastructure movement
This isn't a huge update but there are lots of words explaining whats happened :D
IObservableScheduler
now in core
This was originally brought in as a way to have a streamlined cross platform "EveryUpdate" style notion, as every engine/framework does their update loop differently, so this exposed a way for those events to be fed through in a sane-ish way. So in Unity it may be from a UniRx Observable.EveryUpdate
in MonoGame it may be from a Game.Update
while in a console app it may just be a timer ticking at 60fps.
The point is that this allows plugins to have systems which update according to the host platform but be agnostic of it, so plugin systems no longer need to worry about having platform dependent observables, as historically if you wanted to have a cross platform system your only option really was an IManualSystem
and make some update loop yourself which is not great.
And off the back of this a new basic system has been introduced which wraps up the underlying update mechanism and exposes a simple processing point.
New IBasicSystem
This is basically a cut down IReactToGroupSystem
but the schedule of it is taken care of for you, as in most cases people would just have it default to every update anyway, so in these cases you can just use the normal IBasicSystem
and it will work on any platform and doesnt need the ReactiveSystems
plugin.
This as mentioned above makes plugin development easier as you can at least have a cross platform system without needing other plugins or writing any of your own boilerplate code.
IGroup
and Group
are more in line
This isn't a massive update, but the gist is that IGroup
and Group
have not been on the same page for a while, as IGroup
just exposed component lists to match on, whereas the Group
implementation had that AND predicates built in.
In most cases predicates are the exception, and while they allow you some great flexibility it needs to be more separated, so there is now a GroupWithPredicate
which is basically the same as the old Group
class, and the new Group
class just contains component lookups.
For the most part this wont effect most people, as the helpers/builders have been updated to automatically create the appropriate class for you, however if you had your own classes inherit off Group
and you used predicates in them, you may need to now inherit from GroupWithPredicate
.