[Febuary 2024] Full ECS Stack Review
Hi everyone,
If you aren’t familiar with this format, every so often I make a big post discussing my thoughts on the Unity ECS ecosystem and all of its parts. This feedback is specifically addressed to the folks at Unity.
Very little has changed since my last review. To avoid sounding like a pessimistic broken record, I am going to limit myself to one positive and one negative of each feature. If you are looking for a more exhaustive list of critical feedback, I keep a list of items here that I periodically update.
General Feeling
Entities 1.X feels abandoned. It feels like you are all moving too slow. It feels like you are all focusing on the next big 2.0 that is going to break all of our projects and have tons of use-case oversights.
Lately, I’ve been seeing more people use asmref into packages. I’ve been seeing more people fork the packages. And I’ve seen people not willing to invest in that quit ECS altogether. And the reason is simple. The ECS packages are plagued by tons of small issues, such as missing APIs, or mistake-prone designs, or little bugs that aren’t getting fixed and in public releases in any timely manner.
If you assigned one developer each month to engage in the community, especially those who have asmref modifications or forks, and tackle exclusively the low-hanging fruits that can be fixed within a day each, you could easily do monthly releases with fat changelogs and remove all doubts that you are working on making things better while 95%+ of your team continues to do whatever it is you are doing right now. Rotate which developer is assigned to this task each month. Or make it every two weeks if one month is too long.
But if you can’t even make that work, consider having a repo out on GitHub that can accept pull requests. It doesn’t need a perfect mirror or all the fancy processes. Git is pretty good at converting full folder replacements into small diffs of the actual changes. It only takes a few minutes to sync things. But it could potentially save you some time by allowing a streamlined process to bring in user changes quickly.
Note: I am intentionally ignoring the 2023/Unity 6 compatibility, because I don’t believe it should have been that difficult. If there were significant complications, you should write about it so that us users can respect the technical debt achievements.
My Biggest Pain Point
My last biggest pain point was with AudioClip.GetData() inside a baker. This has finally been fixed! Granted, I had to find one of the couple of audio folks at Unity on the forums and get their attention, only for you all to brag about the fix in your announcement post here. Either that was an internal stress factor exacerbated by silo-ing, or there was some shady company politics being put on display. But hey, it is fixed, and I am pretty happy about that.
Of course, you had to create another major problem in the process, which was completely throw out one of your most unique features of your ECS. You had true per-platform determinism baked into your design, and now you are getting rid of it while leaving in the artifacts of its design (sortKey of ECB). Why?
It isn’t like you couldn’t solve subscene streaming a different way. Why not pre-allocate entities in the target world with shared components representing the scene being streamed in? And timing could be negotiated by a server once all players are loaded so that streaming could be made compatible with a lockstep network architecture. Why am I the one proposing this?
Mathematics
Package development has become alive again. Admittedly, I missed the update in my last review, but it is a pleasant surprise to see.
My criticism for this one is minor. There is no math.select for boolean types.
Burst
It seems like you are mostly focused on bugfixes and stability and supporting platforms. As much as I like new features, I do believe these things are important. As always, I have a crazy amount of respect for your team.
I was going to make a comment how I heard much less about problems with Burst, but then I ran into a few of my own that I had to work around. One was that the intrinsic guards throw build errors if they wrap the call site instead of directly inside the method. Another was that byte-sized enums could cause Burst to fail to compile some things, especially if they are used as function arguments to some instance method of a struct. I’ve also had a couple of situations where the cache got stale and Burst was running older versions of the job, which made debugging a little annoying.
These things are infrequent though, so I just encourage you to keep doing what you are doing, because I probably still wouldn’t be hanging out around here if it weren’t for what you do.
Collections
I benchmarked JobsUtility.ThreadIndex, and it is much faster than I originally anticipated. This opened the door to a big optimization I made recently where I needed to pool allocations per-thread.
This might be more of a job thing, but I really want to be able to have a dynamic number of containers inside some jobs. Not like thousands, mind you. But a good example of this would be an array of DynamicComponentTypeHandles.
Jobs
I’ve been seeing much better scheduling behavior of jobs recently. Maybe that’s a coincidence, but the compaction on worker threads is awesome!
Currently, I believe the job system is holding Unity back a bit. It is kinda bad at phased parallelism. I want to be able to schedule one parallel job that has multiple phases, perhaps a dynamic number of phases. I have algorithms where scheduling 40 jobs is faster than a single job, but it hits the main thread harder than I would like.
I fully acknowledge that this is a tough problem. But from the few hints you’ve provided, it sounds like you may have some ideas on how to fix this.
Entities Baking
I haven’t had subscenes cause crashes for a while now, at least not without it being my own fault. I find subscenes to be somewhat pleasant to work with.
As much as I want to complain about iteration by not having Burst, I suspect you are banking on CoreCLR to fix that. So instead, I am going to discuss an issue I have seen zero progress on. Baking is very bad at inside-out relationships. If an authoring GameObject belongs to a group, and all entities baked from that group should have a component, that is really hard to do right now, if not straight-up impossible. The group could be based on the hierarchy, or a serialized list, or some other thing. One of the challenges with this is that there is no way to just bake a GameObject, independent of its components. Well, there is, but it is internal to the Entities package.
Entities Editor
The exceptions are pretty much gone! Yay!
Why are the inspectors and windows not customizable? Why do I need access to internals to write inspectors for runtime components, especially blob assets? Why can I not define a custom tree of entities that the hierarchy window can display?
Entities Runtime
I believe a lot of the powerful performance features of Entities is severely underutilized. Some of that is due to the myriad of little API gaps, but I think a lot of that simply comes from developers not diving deep enough to learn them. But the fact that every year I find new ways to use some of these features shows just how powerful this is.
I’ve already discussed my determinism concern, so instead, my criticism will be focused on type handles. I’m getting really annoyed with having to cache handles to aspect lookups or structs that bundle type handles together. These things are necessary for advanced 3rd-party libraries that need to provide a good API.
Why can’t SystemAPI work with aspect handles and lookups? Why can’t we implement an interface that SystemAPI operates on to generate custom bundles of handles? I could also argue that maybe handles shouldn’t be cached to begin with, but that’s a deep rabbit hole.
Scenes
I don’t know when this happened, but the rules around scenes and scene streaming is much more consistent and predictable than when I last had to investigate them.
With that said, they are still extremely poorly documented, and what documentation there is tends to be a bit hand-wavy on the critical details.
Transforms
The Transform Helpers are really nice when you need them.
But Transforms in general are really wasteful of chunk space and calculations. The Child buffer is especially bad.
Graphics
MaterialMeshInfo’s new range mode is actually really awesome at runtime! This was a feature I didn’t see coming but is a really nice surprise once we got it. Unfortunately, I had to completely rework the baking mess to make full use of this new feature correctly, but the runtime is pretty clean.
If you didn’t know, I have been doing a lot of innovating with what is effectively my rewrite of Entities Graphics in my framework. It is faster in every way, has many more features, and is more stable than vanilla Entities Graphics. As an outsider hearing all the news indirectly, I am only left to assume your team barely exists and you need all the help you can get. All I ask is that you do not try to reinvent the wheels I have already invented. Instead, take what I have if you want it, and if you need help understanding, then start a conversation with me!
Physics
The little hidden algorithms in this package are good. The convex hull builder and GJK algorithms are well-constructed. And recently, I’ve been able to make sense of some of the wisdom behind the contact generation algorithms.
My biggest complaint with this package was never with the algorithms, but always with the general architecture. I had always assumed this was mostly just a “me” problem of wanting something more flexible. And that has been why I have been building my own solution that borrows from Unity Physics low-level algorithms.
However, recently I have been putting together some comparisons between my framework and vanilla Unity packages. I now understand the performance complaints I keep hearing about. It is bad, like shockingly bad. And I believe the culprit is the general architecture.
I plan to bring these comparisons into the spotlight in a couple of weeks, but if you want an early look at it, here’s the commit you should check out: Add physics trigger comparison · Dreaming381/LatiosFrameworkMiniDemos@b82c007 · GitHub
Character Controller
For all the reasons that people choose to use my framework in Unity Transforms compatibility mode, this package is by far the number one reason. People really like it.
Personally, I haven’t been able to dig deep into it since it is so tightly coupled to Unity Physics. If there were some lower-level APIs or functionality that was independent, I could maybe provide more critique.
NetCode
I’ve made comments about how I don’t believe NetCode and DOTS are where they need to be where the networking architecture of NetCode makes the best use of DOTS capabilities. Despite several conversations I have had behind the scenes, I’m still not convinced it is there.
I’m convinced at this point that it is not sufficient for my own needs without significant modifications to the package that I really don’t want to invest in right now. But I’m also getting close to the point where I need some kind of networking solution to keep a project of mine moving in the right direction.
The positive is that I have had conversations directly with members of the NetCode team, which I can’t say for many of the other teams here.
DSPGraph
Despite being abandoned at this point, the package is still working. And now that the audio crash in subscenes is gone, people are using my tech built on top of it. It is one of the most-used features according to my most recent survey.
Final Thoughts
User trust is serious concern right now. I’d like to see Unity make strides to invest in trust both short and long term. I’m currently working on a comparison project between my framework and vanilla Unity ECS, and the results so far make Unity look far worse than I expected.
Please feel free to reach out to me via these forums, Discord, or publicly in this thread. I want to discuss. I want this tech to move in a direction where I don’t feel like I am being further and further isolated as if you all are secretly plotting to get rid of me. It has been a rough past few weeks. Things can get better, but it starts with communication. We need more of it!
For everyone who did decide to read this wall of text (unity or not), thanks for making it all the way to the bottom. If you have comments or questions, feel free to reply to this thread and share them!