I’m not in love with how ECS worlds are created. I come from a web developer background and often use human-readable config files for detailing high-level flows. I’m exploring this concept for Unity ECS, bouncing early ideas off our community before pursuing a prototype.
The idea is simple:
Step 1: Write an ECS world’s groups and systems in a text file
Step 2: Reference the file via some “ECSWorldGenerator” monobehavior
Step 3: In the mono’s Start() method, parse the file to construct the intended ECS world.
Step 4: Trigger the initialization of the created ECS world, business as usual.
What are the benefits?
Human-readable for better version control and rapid development iteration.
Easily iterate on multiple worlds
Easily isolate ECS world per scene, or using DontDestroyOnLoad for cross-scene persistence
What would this text file look like?
A few simple rules:
The file name is the world name
One name per line
Each name must exactly match the respective class / struct
Tabs for denoting hierarchy
double forward slash for single line comments
@ for denoting a file path for nesting config files
This is a simple draft. I have additional ideas for more templating options such as conditionals and injecting groups / systems into included partials.
Instead of a text file, it could just be a ScriptableObject with a reorderable list (just so we don’t have to deal with names/strings)
But my concern is I don’t think that would work well with third parties, or anything that can optionally come as a package really. If you add a plugin to your project, you’ll have no choice but to manually add all of that plugin’s systems to your config file in the correct order, or else things won’t work. It’s a problem we don’t have with [UpdateBefore/After/InGroup]
Maybe there would be ways for third parties to define some sort of “systems setup prefab” that can be added to the aforementionned scriptableObject
That’s where “@/path/to/SystemBundle.txt” comes into play. Granted, you’d need to do that per standardized system group, but I could see a high level “include” syntax that would automatically inject systems from a different config file by matching system groups. To avoid confliction between system names, namespace can be included in the text line. The process would become: import 3rd party code, add a single ‘include’ line into the ECS World configs which need the imported code, and you’re done. Good catch.
That might work better. Wouldn’t be as easy when using a text editor, but you could modify things directly inside the Unity Editor. Not sure what the list would be consisting of, because direct references to types could prove troublesome when adding or removing code.
An updated example MyGameWorld.txt (I’ve changed some syntax)
I don’t quite have what you are looking for, but I think it is a lot closer and may be a good starting point for you.
It really lets you mix and match explicit and automatic workflows for maximum compatibility.
The only thing I haven’t figured out how to do cleanly yet is replace a system with a custom optimized version when other systems depend on attribute ordering around it. For example, I have two possible alternative implementations for LocalToParentSystem. One of them is always faster and deterministic. The other is a lot faster, but only under heavy hierarchy workloads so only some projects will benefit. If everything uses explicit ordering, this isn’t an issue. But I haven’t figured out how to ensure compatibility for people who rely on attribute-based ordering.
Took a peak and yeah that’s fairly close. How do you handle setting up multiple worlds on the fly? With my concept you’d simply add another ECSWorldGenerator mono component onto some GO, then throw a second config file into it. If systems need access to another world they’d just query for the components, filter, then cache the desired reference.
Also, does your framework handle adding/removing worlds based on scene?
I suppose another interesting idea would be an ability to query if a third party package is included and what version it is per world. Also some sort of ‘include once’ syntax when mixing several config files. This could prove useful when injecting a third party config doesn’t play well with a some other third party config injection. And if a world’s config file becomes a massive blob of conditionals because of dependency hell, it’s best to manually inject particular groups or systems in the order desirable.
Additionally if I were to stick with text files I’d target an extension like: MyGameWorld.ecsw
Honestly? I don’t. That hasn’t been a use case I encountered yet. With that said, if you find yourself at a dead-end with the public framework API, let me know. If the issue is something I can resolve on my end, I will probably treat it as a high-priority bug. The 0.4.2 patch release was actually a similar incident where I needed to expose a parameter to make Netcode compatibility possible.
I do not have any out-of-the-box feature for such. If I need a vastly different set and order of systems to run for a given scene, I typically use my hierarchical system culling functionality to control that based on the active scene.