Well, I have finally gotten around to getting my framework up to the latest DOTS again (0.4.0), so I suppose it is as good of time as any to re-evaluate this like I promised a couple months ago.
I will be referencing my framework for a lot of these discussions mostly because it makes it easier to present my points precisely. You can find it here: GitHub - Dreaming381/Latios-Framework: A Unity DOTS framework for my personal projects
DOTS Documentation
I didn’t think the Unity Engine documentation could get any better. It got better. Mobile is an enjoyable experience. Unfortunately, packages haven’t evolved in the same light and the Mathematics APIs still take eons to load.
As for the content in the preview packages, some of them are progressing quite well!
Mathematics
Nothing changed. Docs take forever to load but are useful once they do. I’m still using my own simdFloat3. I still screw up the order of the bits in bitmask from time to time. And this is still my favorite math library by a long shot. I’m guessing this package will get some love again with Burst 1.3?
Burst
Burst is an incredible piece of technology. It made CPU programming fun again. I can go full technical on whatever I care about and not have to worry about the stuff I don’t care much about because it is still Unity and Unity makes a lot of that trivial.
But where I really want to give praise is to the team behind the technology. Everyone on the team who participates on the forums has been helpful, kind, patient, and professional. You guys make some of the other teams at Unity look like a bunch of aimless monkeys. I have mad respect for you guys.
And while I have a ton of things that I would love from Burst, I know you guys have your plates pretty full.
The only nitpick I want to bring is that you removed showing the C# code in the Burst inspector. And now it is way harder for me to find a particular loop in a long and complex job I want to optimize. Can I have that back?
Otherwise, I can’t wait for Burst 1.3!
Collections
Most of my feedback on containers is the same as before. Those things haven’t changed nor have they been better documented. However, I really do like the new features that have been arriving. Words and more unsafe structures are really solving some of the more awkward use cases I run into.
The container I am missing the most is a dictionary implementation. I know there’s NativeHashMap, but sometimes I need a map to be able to grow. I’ve seen some clever solutions where people make a tree with each parent having 32 children.
Jobs
I have very little to say about the Job system. Engine-side is awesome and profiling performance with it seems to have improved for some odd reason. But is the package going to get any new development? Or is it “good enough” for a good while yet?
Entities
A lot has happened here, and I have a lot to talk about.
This is still the coolest ECS I have ever worked with in terms of data organization. I can build games in so many different styles of ECS for any timeline and performance budget.
I can tell you listened regarding World instances and ICustomBootstrap. The API is so much cleaner and more flexible. In BootstrapTools.cs in my framework, I still have to copy code from the Entities package and use reflection. But I did find myself removing hacks and adding new features when I updated the framework. Nice job! I hope you continue to improve it so that I don’t have to copy code or use reflection to access internal types.
However, nothing has been done regarding being able to copy a component from one entity to another based on a ComponentType. I wrote an EntityDataCopyKit.cs file which uses reflection to handle that, as I depend on it for my entity merging system. But this is another hack I don’t want to keep.
In my last post, I asked for ShouldRunSystem to be virtual. While I think it is a good thing by default that Unity make decisions for me, sometimes I want to make better decisions that Unity will never know about. I am currently getting around this in my framework by overriding OnUpdate of ComponentSystemGroup. (SuperSystem.cs) While my solution works, I don’t think what I am doing is the intended solution, so I would like to know what is the intended way to control whether or not a system runs based on data other than EntityQueries?
Bursted ECBs are nice. I need to spend a lot more time understanding their performance characteristics for different scenarios. It is really nice in search algorithms where you have a low number of outputs but a high amount of data to crunch to get those outputs. No complaints there.
The biggest and most exciting innovation in the Entities package is also the most frustrating for me. That’s code gen. [GenerateAuthoringComponent] is awesome for prototyping, except rarely in prototyping do I want to make a file for each component. So that one is counter-intuitive. Entities.ForEach is missing ScheduleSingle. But even more so, I can’t add my own types. If you look at the FindPairs API I have in my physics package, you’ll see I define as the last argument a generic IFindPairsProcessor value. This provides a callback for the jobs that ultimately get scheduled allowing user code to decide what to do with those results. It is similar to Unity.Physics ITriggerEventsJob except this one actually runs in multiple jobs and doesn’t use a custom job type. Anyways, if it looks like that IFindPairsProcessor argument could be replaced with a lambda, that’s because that’s exactly what I want to do! But the code gen code as it exists today is completely internal and not extensible. I would have to copy huge amounts of code to do something similar. Is this what I should do, or is there a better way.
And lastly, Code gen with the lambdas has interfered with another problem I have been trying to solve. I don’t really care if Unity solves the lambda conflicts or the root of the problem itself. But I really want a solution to this.
Currently, if you need an Entity to reference a managed object, you need to use a Class IComponentData. When you use a class IComponentData, whenever you instantiate such an Entity, you generate garbage. I want a component type that can be instantiated and destroyed without generating new garbage endlessly and also be a struct type so that copy by value rules apply. Effectively, I want something in between struct IComponentData and class IComponentData. In my framework, I came up with a solution using IComponent. But really it is just a custom interface not tied to Entities in any way and the only way I make it act as part of the archetype is by using reactive tag components. Of course, this conversion from IComponent to IManagedComponentTag<> for specifying EntityQueries totally breaks with code gen Entities.ForEach.
Ok. So the use cases for my IComponent are small enough that I could deal with not having it as inconvenient as it is. What I can’t live without is my ICollectionComponent. When a NativeContainer needs to be accessed from multiple Systems, the correct home for such data is to be attached to an Entity. Forcing NativeContainers to live in systems is just asking for unnecessary code coupling and not being able to efficiently deal with a dynamic number of NativeContainers. The Overwatch team has been bitten by this. I personally have been bitten by this. And a few people on these forums have been bitten by this. My ICollectionComponent solves that issue and even has this really nice feature of automatically tracking and updating its JobHandles when a user requests it in a JobComponentSystem. But ICollectionComponent is not a true ComponentType either and also relies on reactive tags to affect an Entity’s archetype. It is totally broken with Entities.ForEach.
I don’t care is Unity unlocks code gen, unlocks an API for creating custom ComponentTypes, or borrows my ICollectionComponent implementation and makes it a first-class citizen. This is a blocker for me. I need to be unblocked if I want to push my tech to the next level.
Heck, making Entities.ForEach have an option to use an EntityQuery passed in would get me far enough along that it wouldn’t be painful.
But hey! I would not have built my framework with an Entities dependency if I did not believe that Entities was a solid foundation on which to build. It totally is, and it is so close to being absolutely perfect. I just need a little more extensibility support.
Transforms
Nothing new here. It works. But the conversion system isn’t smart enough to use Scale over NonUniformScale. I wrote a system that corrects it. I’m happy.
Scenes
Please fix the SubScene components and API to use “SubScene” instead of “Scene” in their type, variable, and method names. They get really confusing when working with actual scenes. Otherwise the Scene of SubScenes paradigm is crazy powerful and solves one of classical Unity’s biggest problems in the most elegant way possible.
Hybrid Renderer
HDRP is fixed!
My only complaint now is please at least partially fix this or at least explain what is going on here:
Turning off culling of RenderMeshSystemV2
Otherwise I really like the new instance property system’s engine-side integration. It is fast and clean!
Physics
I love the algorithms. I hate the architecture. If you want the full rant, you can go here: https://github.com/Dreaming381/Latios-Framework/blob/master/Documentation/Physics/README.md
Feel free to borrow anything you like. It’s technical yours anyways.
Audio
I haven’t used this and do not plan on using this until some out-of-the-box ECS API comes along. I may update this section once that happens. Tiny has one, but my framework doesn’t work with Tiny yet because of the many previously discussed issues.
Animation
I still haven’t figured out what is totally going on here yet and whether or not I like it. I think the biggest question I ran into is: What exactly is a ComputeBuffer in Unity? Does it do things on devices that don’t have Compute Shader support? I think that’s what Animation is using to upload the bones, right?
I need a lot more time with this one.
Netcode
My general comments from my first post still apply here. It also isn’t intuitive to me how I would rely on determinism to simulate thousands of entities with rollback without synchronizing all their positions. The simulation is cheap. And I don’t mind doing something custom. I just need some direction here.
Build
I like it. I think assembly code gen integration would go a long ways. I would love to be able to customize the arguments Unity feeds into the compiler for each assembly, as well as intuitively generate and inject new assemblies after the authored assemblies have been built. I’m probably going to try it anyways for my next version of my Burst Generics Patcher. But getting some more official support for such pipelines would be awesome!
DOTS Runtime
I like it. I can’t use it yet because my framework doesn’t support it because it needs reflection to get access to stuff in Entities. Also, what kind of Burst support is there for WebGL? I haven’t been able to figure out what “partially supported” means.
DOTS in General
Again, I really like what’s there (except for Physics). I’m just having trouble extending it with features that I am not aware to be on any roadmap. Extending and replacing modules is going to be critical for this new ecosystem. You have an incredible design that really opens things up. Its immersive. Keep working at fixing those ugly parts and one day the only negative thing I will be able to say will be prefaced by a “Nit:”.
Thanks for reading!
Hopefully you found the helpful and insightful.