Is your feature request related to a problem? Please describe.
I have all of my System
s set up as ScriptableObject
s. One major upside is that I can configure my System
s in the Unity editor; instead of having to screw around with dependency injection, I just add some fields. It's very designer-friendly, which is good because I don't expect to be a solo dev forever.
There are disadvantages, however. Chief among them is that the ScriptableObject
life cycle is more complicated than that of a plain C# object (like System
s usually are). It's difficult to simply construct a system and throw it away like I regularly do in my test suite. I work around this by heavily using IInitializeSystem
and ITeardownSystem
. Problem solved; now I don't need to figure out when exactly Awake()
, OnEnable()
, OnDestroy()
, or OnDisable()
are called (and on which systems).
A related disadvantage is that I can't initialize systems with constructors; generally, this is where you would run logic that needs to be done before Initialize()
, like setting up Collector
s or Group
s. I set those objects up in Initialize()
...and then hit a weird bug in my code.
I needed to create some Entity
s within Initialize()
. This worked fine. However, I expected them to be tracked by a Collector
on the first frame of execution; this didn't happen because the Entity
s were being created before the Collector
was, so my customized ReactiveSystem
didn't notice them.
This wouldn't have happened if I could guarantee that there was some kind of set up phase that occurred before any Entity
was created.
Describe the solution you'd like
Simple; an IPreInitializeSystem
that looks something like this:
public interface IPreInitializeSystem
{
void PreInitialize(IContexts contexts);
}
By convention, System
s in Entitas have a unary constructor that takes a Contexts
as an argument. The system might then store the Contexts
and use it to create Group
s or Collector
s (like in ReactiveSystem
s). Since I can't use constructors, this interface would be the next best thing.
The interface takes an IContexts
because Contexts
is usually generated in each project; the expectation is that you would cast it inside your implementation of PreInitialize()
.
There's a secondary advantage, too. Since my ScriptableSystem
s can't use constructors, I have to pass around a singleton with a Contexts
everywhere. This interface would eliminate that need, simplifying the process of implementing System
s as ScriptableObject
s.
I don't know what use IPreInitializeSystem
would have in POCO-based System
s, but I can't see it getting in the way. It doesn't place any more burden on the developer than the other phases. Game devs are creative, I'm sure you'll figure something out.
Describe alternatives you've considered
See the first three paragraphs.
Additional context
I'm still using vanilla Entitas but I figured Redux would benefit from this idea, hence my feature request.