Categories
entity systems Unity3D

ECS for Unity: design notes + next prototype

Recently I’ve been thinking a lot about how a high-quality ECS would appear / present itself within Unity, how it would interact with standard Unity3d game-code at the API level, how it would appear in the Unity Editor, etc. This evening, I had a go at making some of that within Unity itself.

NB: a few weeks ago I made a small Editor Plugin that used Reflection to upgrade and fix some of the core Unity Editor code/GUI. That was practice for what I’m doing here. It’ll hopefully appear on the Asset Store at some point (pending review right now!) – it has the full source unobfuscated, so you can see for yourself both what and how I got it to do its clever bits.

References

Some things to read if you haven’t already:

(that last one is particularly important; working around Unity’s broken Serialization system is a whole mega topic in its own right, and I’ll be largely assuming you already have read up on it. If you don’t know Unity Serialization yet (enough to fear it!) go read that article)

Initial thoughts/plans

There’s been one thought in particular nagging away at me for a while now:

If we’re going to really, truly, genuinely replace Unity’s core scripting architecture (which sucks for game development) with a modern ECS one, then we MUST create a new custom panel for the GUI Editor.

…until / unless we do that, it’s just a Programmers’ Circle Jerk: it loses 90%+ of the audience of Unity developers, people who chose Unity because of the Editor. 1st-class Editor integration is more important than anything else (certainly a lot more important than – say – performance).

Core Unity bugs that got in the way

Unity never repaints windows when Scene changes

If the scene changes, we’ll be looking at a new Entity System (different entities, different components). You would naturally expect that Unity automatically repaints all windows when Unity changes the Scene, right?

Wrong.

(incidentally, this is why it’s also very hard to be sure that a scene has actually loaded when you double-click on it – Unity gives no indication to the user that anything changed, if the Hierarchy for the two Scenes was the same)

Workaround to Unity bug

The undocumented method “EditorWindow.OnDidOpenScene()” which you can override. Amusingly, in Unity 4.5 they “fixed” the “bug” that this was documented; now your only way of discovering it is by finding a Mystical Unity Guru who knows The Secrets of Unity.

ScriptableObject: fundamentally broken

This isn’t even funny any more…

ScriptableObject System.Guid properties are wiped by Unity Serialization

public class EntityID : ScriptableObject
{
public System.Guid GUID = System.Guid.Empty; // this will NEVER be saved by Unity
}

… you have to manually write a serializer and deserializer for System.Guid. Because C# built-in structs weren’t considered important enough to be supported by Unity. WTF!!!??!??

ScriptableObject breaks C#: no constructors allowed, no initialization allowed

We know why: it’s because Unity Serialization is crap.

Unity Serialization requires every class to use a zero-argument constructor and has a bizarre array of hacks to try and restore state.

If – for instance – you need to create a ScriptableObject and guarantee that it gets an internal globally unique ID … you can’t. C# supports it, but Unity removes that support. Joy!

ScriptableObject data loss

New discoveries:

  1. SerializedObjects saved into your scene are automatically deleted whenever you change Scene.
    • …Unity staff apparently felt that developers are too stupid to write code; an info message tells you you “leaked” memory (no, no you didn’t. Unity incorrectly DELETED your non-leaking data)
    • …probably they’re too embarassed to admit that their failure to include Editor UI to show “SerializedObjects in current scene” was causing many projects to accidentally build up masses of invisible objects.
    • …there was a fix for that bug. It would have taken them MINUTES to code it up (I’ve done it myself, seems to work fine?). Or … they could break Unity further. Which option did they go with?
      • (this was probably due to some time pressure at the time; but that’s what CTO’s and Tech Directors are for: to make sure such hacks are then fixed properly shortly afterwards, not brushed under the carpet)
  2. If you mark a SerializedObject as “DontDestroyOnLoad” you discover that bug is even worse. It’s really, really bad:
    1. When you try to change Scene, Unity correctly asks “do you want to save? You have unsaved changes”
    2. …and then whatever you do, Unity deletes your SAVED DATA, using the first bug above.
    3. …looks like the bug isn’t just “deleting data when it shouldn’t”, but “incorrectly implemented DELETE that overrides Unity’s built-in data and scene management”

From Unity forums, this has been around for a good 4 years.

Some Classes

EntityID – with workarounds for core Unity bugs

Here’s the fixed EntityID class from above, with the hacks needed to make up for Unity’s “oh, let’s take C# core features, and break them” attitude.

You need to do this a lot if you work with Unity, sadly…

[csharp]
/**
NOTE: this class is really only 1 line long. Unity problems add 10 lines to it!
*/
public class EntityID : ScriptableObject, ISerializationCallbackReceiver
{
public System.Guid GUID = System.Guid.Empty;

private string _UnityWorkaroundProperty_GUID = System.Guid.Empty.ToString();
public void OnBeforeSerialize()
{
_UnityWorkaroundProperty_GUID = GUID.ToString();
}

public void OnAfterDeserialize()
{
GUID = new System.Guid (_UnityWorkaroundProperty_GUID );
}
}
[/csharp]

Conclusions

I got a basic self-managing EditorWindow interacting, and duplicating the most basic behaviour of the Hierarchy window, but I wasted so much time trying to kick Unity’s awful ScriptableObject into working shape that I got no further than that. Very frustrating.

Here’s a video: