{"id":3555,"date":"2015-04-25T21:57:12","date_gmt":"2015-04-25T20:57:12","guid":{"rendered":"http:\/\/t-machine.org\/?p=3555"},"modified":"2015-04-25T22:39:59","modified_gmt":"2015-04-25T21:39:59","slug":"ecs-for-unity-design-notes-next-prototype","status":"publish","type":"post","link":"http:\/\/new.t-machine.org\/index.php\/2015\/04\/25\/ecs-for-unity-design-notes-next-prototype\/","title":{"rendered":"ECS for Unity: design notes + next prototype"},"content":{"rendered":"<p>Recently I&#8217;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.<\/p>\n<p>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&#8217;m doing here. It&#8217;ll hopefully appear on the Asset Store at some point (pending review right now!) &#8211; it has the full source unobfuscated, so you can see for yourself both <em>what<\/em> and <em>how<\/em> I got it to do its clever bits.<\/p>\n<p><!--more--><\/p>\n<h2>References<\/h2>\n<p>Some things to read if you haven&#8217;t already:<\/p>\n<ul>\n<li><a href=\"https:\/\/grovecodeblog.wordpress.com\/2015\/04\/02\/using-scriptableobject-for-data-objects-in-unity-scenes\/\">Sampsa&#8217;s post on the missing documentation for Unity&#8217;s ScriptableObject<\/a> (follow him <a href=\"http:\/\/twitter.com\/snlehton\">@snlehton<\/a>)\n<li><a href=\"http:\/\/t-machine.org\/index.php\/2014\/10\/05\/towards-a-unity3d-ecs-what-gui-what-features\/\">Mockups of GUI we might want in Unity3D for managing an Entity System<\/a>\n<li><a href=\"http:\/\/t-machine.org\/index.php\/2014\/03\/08\/data-structures-for-entity-systems-contiguous-memory\/\">High-performance, low-level memory management for Entity System implementation<\/a> &#8211; we won&#8217;t be doing this immediately, but it&#8217;s a precursor to some of the things I&#8217;ll end up doing here.\n<li><a href=\"http:\/\/t-machine.org\/index.php\/2014\/12\/22\/unitys-failure-as-an-entity-system-example-1-selecting-things\/\">A single worked-example of where Unity&#8217;s built-in architecture makes it much harder to write games than if you were using a modern Entity System<\/a>\n<li>Lucas Meijer&#8217;s (<a href=\"https:\/\/twitter.com\/lucasmeijer\/\">@lucasmeijer<\/a>) post on official Unity blog about<a href=\"http:\/\/blogs.unity3d.com\/2014\/06\/24\/serialization-in-unity\/\">Serialization in Unity &#8211; what is it, how it works under the hood, and how you fix it when it breaks\/has missing features<\/a>\n<\/ul>\n<p>(that last one is particularly important; working around Unity&#8217;s broken Serialization system is a whole mega topic in its own right, and I&#8217;ll be largely assuming you already have read up on it. If you don&#8217;t know Unity Serialization yet (enough to fear it!) go read that article)<\/p>\n<h2>Initial thoughts\/plans<\/h2>\n<p>There&#8217;s been one thought in particular nagging away at me for a while now:<\/p>\n<blockquote><p>\nIf we&#8217;re going to really, truly, genuinely replace Unity&#8217;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.\n<\/p><\/blockquote>\n<p>&#8230;until \/ unless we do that, it&#8217;s just a Programmers&#8217; 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 &#8211; say &#8211; performance).<\/p>\n<h2>Core Unity bugs that got in the way<\/h2>\n<h3>Unity never repaints windows when Scene changes<\/h3>\n<p>If the scene changes, we&#8217;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?<\/p>\n<p>Wrong.<\/p>\n<p>(incidentally, this is why it&#8217;s also very hard to be sure that a scene has actually loaded when you double-click on it &#8211; Unity gives no indication to the user that anything changed, if the Hierarchy for the two Scenes was the same)<\/p>\n<h4>Workaround to Unity bug<\/h4>\n<p>The undocumented method &#8220;EditorWindow.OnDidOpenScene()&#8221; which you can override. Amusingly, in Unity 4.5 they &#8220;fixed&#8221; the &#8220;bug&#8221; that this was documented; now your only way of discovering it is by finding a Mystical Unity Guru who knows The Secrets of Unity.<\/p>\n<h3>ScriptableObject: fundamentally broken<\/h3>\n<p>This isn&#8217;t even funny any more&#8230;<\/p>\n<h4>ScriptableObject System.Guid properties are wiped by Unity Serialization<\/h4>\n<p>public class EntityID : ScriptableObject<br \/>\n{<br \/>\npublic System.Guid GUID = System.Guid.Empty; \/\/ this will NEVER be saved by Unity<br \/>\n}<\/p>\n<p>&#8230; you have to manually write a serializer and deserializer for System.Guid. Because C# built-in structs weren&#8217;t considered important enough to be supported by Unity. <em>WTF!!!??!??<\/em><\/p>\n<h4>ScriptableObject breaks C#: no constructors allowed, no initialization allowed<\/h4>\n<p>We know why: it&#8217;s because Unity Serialization is crap.<\/p>\n<p>Unity Serialization requires every class to use a zero-argument constructor and has a bizarre array of hacks to try and restore state.<\/p>\n<p>If &#8211; for instance &#8211; you need to create a ScriptableObject and guarantee that it gets an internal globally unique ID &#8230; you can&#8217;t. C# supports it, but Unity removes that support. Joy!<\/p>\n<h4>ScriptableObject data loss<\/h4>\n<p>New discoveries:<\/p>\n<ol>\n<li>SerializedObjects saved into your scene are automatically deleted whenever you change Scene.\n<ul>\n<li>&#8230;Unity staff apparently felt that developers are too stupid to write code; an info message tells you you &#8220;leaked&#8221; memory (no, no you didn&#8217;t. Unity incorrectly DELETED your non-leaking data)\n<li>&#8230;probably they&#8217;re too embarassed to admit that their failure to include Editor UI to show &#8220;SerializedObjects in current scene&#8221; was causing many projects to accidentally build up masses of invisible objects.\n<li>&#8230;there was a fix for that bug. It would have taken them MINUTES to code it up (I&#8217;ve done it myself, seems to work fine?). Or &#8230; they could break Unity further. Which option did they go with?\n<ul>\n<li>(this was probably due to some time pressure at the time; but that&#8217;s what CTO&#8217;s and Tech Directors are for: to make sure such hacks are then fixed properly shortly afterwards, not brushed under the carpet)<\/ul>\n<\/ul>\n<li>If you mark a SerializedObject as &#8220;DontDestroyOnLoad&#8221; you discover that bug is even worse. It&#8217;s really, really bad:\n<ol>\n<li>When you try to change Scene, Unity correctly asks &#8220;do you want to save? You have unsaved changes&#8221;\n<li>&#8230;and then whatever you do, Unity deletes your SAVED DATA, using the first bug above.\n<li>&#8230;looks like the bug isn&#8217;t just &#8220;deleting data when it shouldn&#8217;t&#8221;, but &#8220;incorrectly implemented DELETE that overrides Unity&#8217;s built-in data and scene management&#8221;\n<\/ol>\n<\/ol>\n<p>From Unity forums, <a href=\"http:\/\/forum.unity3d.com\/threads\/editorwindow-loses-reference-of-scriptableobject-on-play-mode.107831\/\">this has been around for a good 4 years<\/a>.<\/p>\n<h2>Some Classes<\/h2>\n<h2>EntityID &#8211; with workarounds for core Unity bugs<\/h2>\n<p>Here&#8217;s the fixed EntityID class from above, with the hacks needed to make up for Unity&#8217;s &#8220;oh, let&#8217;s take C# core features, and break them&#8221; attitude.<\/p>\n<p>You need to do this a lot if you work with Unity, sadly&#8230;<\/p>\n<p>[csharp]<br \/>\n \/**<br \/>\n NOTE: this class is really only 1 line long. Unity problems add 10 lines to it!<br \/>\n *\/<br \/>\npublic class EntityID : ScriptableObject, ISerializationCallbackReceiver<br \/>\n{<br \/>\n\tpublic System.Guid GUID = System.Guid.Empty;<\/p>\n<p>\tprivate string _UnityWorkaroundProperty_GUID = System.Guid.Empty.ToString();<br \/>\n\tpublic void OnBeforeSerialize()<br \/>\n\t{<br \/>\n\t_UnityWorkaroundProperty_GUID = GUID.ToString();<br \/>\n\t}<\/p>\n<p>\tpublic void OnAfterDeserialize()<br \/>\n\t{<br \/>\n\t\tGUID = new System.Guid (_UnityWorkaroundProperty_GUID );<br \/>\n  }<br \/>\n}<br \/>\n[\/csharp]<\/p>\n<h2>Conclusions<\/h2>\n<p>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&#8217;s awful ScriptableObject into working shape that I got no further than that. Very frustrating.<\/p>\n<p>Here&#8217;s a video:<\/p>\n<p><iframe loading=\"lazy\" width=\"640\" height=\"390\" src=\"https:\/\/www.youtube.com\/embed\/SFCzy0u8wLc\" frameborder=\"0\" allowfullscreen><\/iframe><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Recently I&#8217;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 [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[60,67],"tags":[],"_links":{"self":[{"href":"http:\/\/new.t-machine.org\/index.php\/wp-json\/wp\/v2\/posts\/3555"}],"collection":[{"href":"http:\/\/new.t-machine.org\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/new.t-machine.org\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/new.t-machine.org\/index.php\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"http:\/\/new.t-machine.org\/index.php\/wp-json\/wp\/v2\/comments?post=3555"}],"version-history":[{"count":10,"href":"http:\/\/new.t-machine.org\/index.php\/wp-json\/wp\/v2\/posts\/3555\/revisions"}],"predecessor-version":[{"id":3565,"href":"http:\/\/new.t-machine.org\/index.php\/wp-json\/wp\/v2\/posts\/3555\/revisions\/3565"}],"wp:attachment":[{"href":"http:\/\/new.t-machine.org\/index.php\/wp-json\/wp\/v2\/media?parent=3555"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/new.t-machine.org\/index.php\/wp-json\/wp\/v2\/categories?post=3555"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/new.t-machine.org\/index.php\/wp-json\/wp\/v2\/tags?post=3555"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}