Experimenting with shorter Entity Systems articles
This post is an experiment: rather than write massive, heavily-edited articles, I’m writing “shallow” versions first, which takes me only an hour or so. Then I’m saving the in-depth, detailed versions of each topic for future subscribers to my own Unity3D Entity System. This way I can cover a lot more topics in the same amount of time, and I suspect most people will get all they need without the deep dives I used to do.
Let me know what you think – @t_machine_org
The Unity bug that deleted my game prototype
A few days ago, I fired up my Unity3d test project for the new Entity System. All the data was serialized into Unity’s scene, everything was fine. I was expecting to see all my “registered” components (that are saved directly into the scene) exactly as they were last time:
Instead … I got this. Why, Unity – WHY?
On further inspection, Unity’s serialization system had stabbed me in the back: it combined data from two different situations (which is blatantly wrong and should be impossible – although since Unity has failed to document it … who knows what contracts it promises to uphold internally?). I’d like to know why…but the Unity Editor won’t tell me (they don’t let us see this data).
But I don’t really know what happened. Even with extensive logging, Unity lacks a solid debugger – and most of Unity’s code here runs BEFORE your debugger starts or AFTER your debugger stops. Any Unity bugs here are happening inside the invisible, opaque, known-to-be-buggy, Unity startup/shutdown routines. ARGH!
Software … has BUGS! OMGWTFBBQ!
Unity has bugs. Lots of bugs. So does all software. So what?!
Some (many?) of Unity’s many bugs sit in mission-critical parts of the engine. Rumour suggests that’s not because the devs are unaware of them – quite the opposite! – but because they’re too hard to fix. Any mistake in the fix, and it might cause more harm than the original bug (because these systems are so core).
This in itself suggests Unity’s internal dev teams maybe lacked a culture of TDD in the early days. My impression was that they do significant TDD now (yes? no?) but if it only arrived recently, then much of their code might be weakly tested or even untestable. i.e.: I try not to be too hard on them here, even when I’m suffering and there’s no help to be had.
In particular with Serialization: Unity doesn’t allow anyone to see what the bugs are. The Serialization system (along with some other super-critical-data-corrupting-bastard-evil-features of Unity – like the Undo system) has no API to let people outside of Unity corp see WTF it’s doing.
And we know it has bugs. But we can only guess at them, and how to workaround them. Unless you have a million dollars spare and can afford to purchase source-code access…?
Incidentally, this is why it is standard in the games industry to demand source-code access to your game-engine. This is non-negotiable. It has always been a black mark against Unity in professional / experienced gamedev teams that they are so secretive about their source code. It would be fine if they had a high-quality, Automatically Tested, well-documented accurate API, etc – but they don’t.
I have an idea … a new feature for my Entity System
At this point, I’ve already accidentally built quite a lot of the pieces of a debugger for fixing Unity itself. I’m recording the exact data, I’m storing it in memory in raw bytes (which sidesteps all the bugs in Unity’s undocumented serialization layers), and I’m displaying live data-visualizations in human-readable pretty colours, etc.
Enter: the Entity Systems Journal.
What’s a Journal?
If you don’t know, and you care about programming that involves data or storage, read this:
In the event of a system crash or power failure, such file systems can be brought back online quicker with lower likelihood of becoming corrupted.
What’s an Entity System Journal?
As many people have noticed, while experimenting with Entity Systems for their games, an ES is very easy to integrate with Event-driven programming.
You’re changing raw data which has no side-effects; that makes it very easy to write generic code that automatically converts every “change” into an “Event object” that the rest of your app / game can programmatically inspect.
With an ES, we’re going to use a Journal to record exactly what happened to your entire game-state, at all times, and in all places.
Journals in AAA Gamedev
To be clear: in an abstract sense this is nothing new, games have been doing “journalling” (But not calling it that!) since the 1990’s, when it was discovered to be a very effective way of making multiplayer / internet games run reliably while sending minimal data over slow network connections. Read about the early RTS implementations (Anything from Patt Wyatt’s blog, or the old Ensemble Studios gamasutra piece about 10,000 archers IIRC).
What makes this a little different is that we’re going to be a lot more … explicit … about it. Our Entity Journal will come with its own cross-platform API that’s easy to write tools for.
a.k.a. “lessons learned in software design and architecture over many years and from standing on the shoulders of giants”
- The API itself might be best expressed using one of the API’s we’re already using to access and/or manage data elsewhere
- aka: the “don’t screw-up like XML version 1 screwed up” rule; XML (a data langage) invented a second language to describe its data. Until they woke up one day and said WAIT A MINUTE … WE ALREADY HAVE A DATA LANGUAGE!
- Whatever first-class objects exist in the API need to be few, simple, and generic
- Journals are a bit like Entity Systems: the simpler the API, the more robust and easier to optimize performance – and re-use with all the world’s generic data
- The Journal is a lot like Quake3’s networking compression; however we build it, it OUGHT to be compatible with that when finished
- i.e. once this is implemented, it ought to be re-usable “in server mode” with almost no code changes to provide a multi-host non-uniform distributed event log and playback system. “ought to”.
- From a tools perspective, we want to click on any Journal event and see the exact state of the entire Game at that point in time
- Game Debugging … on steroids. BECAUSE WE CAN, THAT’S WHY
- …which’ll destroy C#’s crappy Garbage Collector.
- So we’d better be aggressive about using weak references and/or converting “old” data into “summary” data, and dumping the data itself
- Just like an FS Journal, the ES Journal should allow us to reconstruct our entire game data at any point in time, so that we never, ever lose data, no matter how many bugs in Unity we encounter
- Unity: your refusal to debug and TEST your own frickin’ “undo” implementation? Yeah. I’m looking at YOU!
- Make a stupid mistake in your game-code and accidentally delete critical stuff while in Editor? Not done a git-commit recently? NO WORRIES! GO BACK IN TIME AND RELOAD IT! YEAH!
- Find a bug in the Entity System itself? (shock! Horror! But also: guaranteed to happen) … well, we’ve got you covered ;)
- …(which leads to the next point)
- This absolutely unfailingly guaranteeably … must not have any bugs in it.
- Unit Tests FTW
- This is our equivalent to Unity’s Serialization: everything will rely upon the assumption that “the Journal will take care of it”, making the Journal our weakest link / most critical code
- KISS: the simpler we keep the implementation AND the API, the more confident we can be that it works at all times in all situations
Yeah, well … that’s going to be a much longer article (or three!)
Want more? Want to support this ES in future?
…Sign up here to be kept up-to-date on the project’s upcoming Kickstarter / Patreon / whatever-it-ends-up-beign (if you’re already signed up, it won’t add you again)
3 replies on “Journalling for #entitySystems: #unity3d corrupted my scene; I’ve built a debugger for Unity!”
Why do you need an explicit journalling? Is there any reason other than stepping around unity-specific problems?
If all the changes are a result of processors being run on the system’s data, it should be enough to just save all the tables at the start of the frame. Playback is just a matter of reverting to one of the previously saved gamestates and just (re)run the processors one by one or in debugger’s step mode. Even user input will be covered as long as it is implemented via ECS and goes through the tables.
Even for a multiplayer game, it is relatively easy to compare the two gamestates (that are noting more than sets of tables) and find the difference that needs to be sent to a client.
Just wanted to drop by and say I’m following your progress with much interest and anticipation. I’ll definitely chip in on the kickstarter/patreon, really want to see this happen.
@Ilya – mostly this is about “if you keep every version of every table, you’ll run out of memory very quickly” combined with “make the API trivially easy to use and re-use throughout the codebase”. So … the aim is to take some of the techniques from journalling (as opposed to versioning) and get a good compromise.
But, TBH, Versioning might have been a clearer way to describe it – the only real reason to be interested in journalling specifically is the performance (storage space) aspects.