Introduction
For my specialization project, I have expanded our in-house engine and editor to allow us to create, save, and iterate on scenes and prefabs through the editor instead of code. This change in workflow allows us to configure scenes and prefabs without recompiling, and also invites other disciplines to do so.
To achieve this, I have created a system for serializing and deserializing components, implemented a separate editor and play state, reworked our GameObject management and the initialization process of GameObjects and components, and more.
To achieve this, I have created a system for serializing and deserializing components, implemented a separate editor and play state, reworked our GameObject management and the initialization process of GameObjects and components, and more.
Background
RockSolid Editor is an application used throughout projects 5-7 to assist the development of our games. It was mostly developed by me and used by all disciplines in our group to debug issues, experiment with lighting and post-processing settings, and verify models, textures, and animations. However, scenes and prefabs have previously been defined in code, with levels being imported from Unreal. This workflow has worked fine but constrains development to the group's programmers.
Motivation
This project aims to change the way we (my group at TGA) create games, specifically our last game, project 8. By expanding the editor to support editing of scenes and prefabs, we can increase our productivity and collaboration using a workflow more similar to that of large-scale game engines.
New features must be easy to understand and use, which is why I've taken inspiration from Unity, an engine we're all more or less familiar with. Assets must also be human-readable and as easy as possible to merge or manually resolve in case of version control conflicts.
New features must be easy to understand and use, which is why I've taken inspiration from Unity, an engine we're all more or less familiar with. Assets must also be human-readable and as easy as possible to merge or manually resolve in case of version control conflicts.
Result
On the surface, the editor doesn't look much different from before, but there are a lot of new features packed under the hood. Let's go through all the new features!

Edit / Play mode
・ Start the editor in edit mode; this loads the scene into an editable state whilst not awakening (most) components.
・ Press play to save and start the scene. Press stop to end the session and return to edit mode.
・ Press play to save and start the scene. Press stop to end the session and return to edit mode.
Hierarchy
・ Drag and drop to reorder GameObjects and their parent/child relationships with validity checks.
・ Drag and drop GameObjects into GameObject or component pointer widgets in the Inspector.
・ Expand and collapse GameObjects to show or hide their children.
・ GameObject context menu to activate/deactivate, rename, and destroy.
・ Icons and colors for specifying GameObject type.
・ Drag and drop GameObjects into GameObject or component pointer widgets in the Inspector.
・ Expand and collapse GameObjects to show or hide their children.
・ GameObject context menu to activate/deactivate, rename, and destroy.
・ Icons and colors for specifying GameObject type.
Prefabs
・ Create Prefab assets from existing GameObjects.
・ Create instances of Prefabs with unique transforms and names.
・ Edit Prefabs in an isolated view.
・ Outdated Prefab instances are updated automatically without disrupting any references.
・ Unpack instances into normal GameObjects without disrupting any references.
・ Create instances of Prefabs with unique transforms and names.
・ Edit Prefabs in an isolated view.
・ Outdated Prefab instances are updated automatically without disrupting any references.
・ Unpack instances into normal GameObjects without disrupting any references.
Scenes
・ Create, save, and load scenes.
・ Save references from one component to another component or GameObject.
・ Robust error handling. Practically impossible to crash the editor when loading a scene or Prefab.
・ Create, save, and load scenes.
・ Save references from one component to another component or GameObject.
・ Robust error handling. Practically impossible to crash the editor when loading a scene or Prefab.
Hierarchy
The Hierarchy window has been improved to feature the current scene and dropdown arrows for expanding and collapsing GameObjects with children.
With the introduction of Prefabs, GameObjects also have an icon and color identifying their type. Blue text indicates a root or part of a Prefab instance. A filled blue cube indicates the Prefab instance root.
With the introduction of Prefabs, GameObjects also have an icon and color identifying their type. Blue text indicates a root or part of a Prefab instance. A filled blue cube indicates the Prefab instance root.


Implementation
In order to achieve the features listed above, I have:
・ Developed a system to easily serialize and deserialize components and user-defined structs.
・ Made it easy to add GUI to your components.
・ Created a system for auto-registering components.
・ Completely reworked how GameObjects and components are created, initialized, and started (or not started if in edit mode)
・ Ability to flag a component type to run in edit mode.
・ Moved GameObjects and renderables from centralized managers into the scenes themselves to allow multiple scenes to be loaded at the same time.
・ Added robust exception handling for loading components, GameObjects, and scenes that disable the component or GameObject, or unload the scene completely and tries loading the previous scene, then a new scene.
・ Ensured that GameObject IDs and component IDs are persistent between sessions.
・ Set up deserialization contexts with rerouted GameObject IDs for deserializing feather-weighted Prefab instances.
・ Made it easy to add GUI to your components.
・ Created a system for auto-registering components.
・ Completely reworked how GameObjects and components are created, initialized, and started (or not started if in edit mode)
・ Ability to flag a component type to run in edit mode.
・ Moved GameObjects and renderables from centralized managers into the scenes themselves to allow multiple scenes to be loaded at the same time.
・ Added robust exception handling for loading components, GameObjects, and scenes that disable the component or GameObject, or unload the scene completely and tries loading the previous scene, then a new scene.
・ Ensured that GameObject IDs and component IDs are persistent between sessions.
・ Set up deserialization contexts with rerouted GameObject IDs for deserializing feather-weighted Prefab instances.
Loading scenes
The process of loading a scene is divided into four stages:
・ Creating GameObjects and components
・ Deserializing components
・ Unpacking Prefab instances
・ Awakening components
This ensures all GameObjects and components exist before deserializing components, and all components have been deserialized before they are awoken.
Deserialize contexts are used when deserializing components of a Prefab instance. They allow feather-weighted instances by rerouting GameObject IDs when deserializing references.
・ Deserializing components
・ Unpacking Prefab instances
・ Awakening components
This ensures all GameObjects and components exist before deserializing components, and all components have been deserialized before they are awoken.
Deserialize contexts are used when deserializing components of a Prefab instance. They allow feather-weighted instances by rerouting GameObject IDs when deserializing references.

Feather-weighted Prefab instances
Prefab instances are feather-weighted in the sense that they don't store any component data. Instead, instance roots store a key to the Prefab asset, and instance parts store an ID referencing their respective Prefab part.
All Prefabs referenced in a scene are embedded into the scene to ensure it can be loaded into its saved state before updating outdated Prefab instances.
All Prefabs referenced in a scene are embedded into the scene to ensure it can be loaded into its saved state before updating outdated Prefab instances.

Updating Prefab instances
When a Prefab instance needs updating, it's not just replaced by a new instance, since that would expire all references to it and cause unnecessarily many changes to the scene file.
Instead, I've put an algorithm in place that shelves the existing GameObjects and their components, and use the updated asset as a template to rebuild the instance using the shelved GameObjects when possible.
Only when no matching GameObject or component is found is a new one created, and leftover GameObjects and components are destroyed when the instance is fully rebuilt.
Instead, I've put an algorithm in place that shelves the existing GameObjects and their components, and use the updated asset as a template to rebuild the instance using the shelved GameObjects when possible.
Only when no matching GameObject or component is found is a new one created, and leftover GameObjects and components are destroyed when the instance is fully rebuilt.

Serialization workflow
Making sure your component is properly serialized and deserialized is easy. All you need to do is override the virtual serialize method and list the component's member variables (without the "my") to a macro. Alternatively, you can serialize your variables manually, but the macro is preferred as it ensures the naming convention is followed.
There's no need to implement a deserialization method, the serialization method is used to deserialize as well.
There's no need to implement a deserialization method, the serialization method is used to deserialize as well.


Serialization output
Serialized GameObjects contain a list of their components. Each component has a data object with user-defined data.

Auto-registering Components
Component types are auto-registered by simply adding the AUTO_REGISTER_COMPONENT macro in the source file of the component. This defines a static object that registers the type to the component registry.
The macro also allows you to specify the location of the component in the add component menu, e.g. "Game/Characters/Player" making it easy to organize large projects.
The macro also allows you to specify the location of the component in the add component menu, e.g. "Game/Characters/Player" making it easy to organize large projects.


Future Work
There are a few more things I'd like to implement for a better user experience, most importantly, an asset window. With this, I want an overview of the game's asset directory and to be able to drag and drop certain assets into the scene or to widgets in Component GUIs, much like the Project window in Unity.
Another useful feature would be transform handles to make it easier to move and rotate the selected GameObject. This was something I had originally planned to do but dropped due to time constraints.
I would also like to have nestled Prefabs. This was something I had planned for and was possible to have up to a point, but I had to put it aside as technical depth increased and time was running short. It's probably not too difficult to implement since I have had it in mind when structuring other things around it.
Lastly, it would be great for Prefab instances to be able to have local overrides.
Another useful feature would be transform handles to make it easier to move and rotate the selected GameObject. This was something I had originally planned to do but dropped due to time constraints.
I would also like to have nestled Prefabs. This was something I had planned for and was possible to have up to a point, but I had to put it aside as technical depth increased and time was running short. It's probably not too difficult to implement since I have had it in mind when structuring other things around it.
Lastly, it would be great for Prefab instances to be able to have local overrides.