Chronicle Prefabs

October 21, 2021









Chronicle World Data

Before we dive into prefabs, here's a quick look at how I've set up some of the data formats for Chronicle. Objects, worlds, and prefabs are all saved in xml. (Note: I recently discovered https://miro.com, so there’s a good amount of diagrams made using that in this post).

In the first image, you can see a high-level view of the format of a world. The world contains a list of object file references plus instance deltas to that file reference. The instance deltas contain component edits, additions, and removals compared to the object reference. It's handy to still be able to make changes to the actual objects and have those changes automatically show up in worlds without ever editing them again, provided changes are made to components that still exist on the instanced object in the world.


Here’s a super simple world with all 3 cases; no delta, attributes delta, and new components delta. (The second image on the left is how it looks in editor): TestExample1.crWorld

It can get a little verbose given how the xml is generated from the reflection system, but it gets the job done and is fairly easy to read, which is always helpful when debugging an issue. On the first object, the overrides section contains just empty sections for each component on the object since it has no deltas. I always write out each component type to make applying the deltas to the file reference a bit easier for component adds and / or removals from either the instance or the referenced object. Next, the car object has some attribute deltas for its transform and physics components. The rifle object has the most override information as it had 2 components added to the instance plus some attribute deltas for its transform.

What is a Prefab?

Prefab is the term I’m using for a reusable collection of objects. It’s very similar to a world in structure, except it stores all object transforms as deltas so that, if the prefab is moved in a world, all objects contained in it can be moved with it while maintaining their relative positions. The other big difference is a prefab doesn’t really exist in the runtime. It’s really just a tools / data container that isn’t meant to be used as a stand alone. After in-game world loading is complete, any information about prefabs it contains are lost as all the objects contained in a prefab are now owned and updated by the world. As such, there is no runtime reason to keep information about a prefab, except for maybe debugging purposes to track down a problematic object.

Prefab Structure

When I started working on prefabs, my first goal for how it should look in a world was something like this diagram.

The topmost delta would contain things like the prefab's world position, added / removed objects, and object position changes on the instance. Then, you could have per-object instance deltas for each object in the prefab stack on top of instance deltas in the prefab file itself. Everything below that is pretty much exactly like world data.


I thought this approach would give me a lot of flexibility editing prefabs on a per instance level in worlds while propagating changes to prefab files to those instances. In the end, I found it difficult to get the multiple levels of instance deltas to the objects to work in a clean way. To make that part work, I think I'll need to revisit how I’m creating these object deltas, but that's not something I want to spend time refactoring at this moment. So: I’ll add it to the list!


Ultimately, I pivoted to something a little less flexible but more achievable for my current goals.

In this diagram, you can see I’ve dropped the top layer of instance deltas and the prefab file reference is to the side of the instance. I decided to embed the prefab instance into the world itself. When a prefab instance is saved, it doesn’t calculate a delta to it’s prefab file reference, but instead saves out as if it was a stand alone prefab file while also writing out it’s prefab file reference. With this approach, we lose the ability to automatically pick up changes to the base prefab file, but—because the reference is remembered—we can always reload the prefab instance from that and manually re-apply any deltas to the instance if needed.


In the below example, you can see what a prefab saved into a world looks like: TestExample.crWorld

REsults

What was the goal of all this? To make building worlds / levels easier and quicker. Before, I was only able to place and manipulate one object at a time, which can get pretty tedious when building out, for instance, a dungeon with a dozen rooms. So, to test all of this work, I built out some room and hallway prefabs from the assets in Quaternius • Ultimate Modular Ruins Pack.

Then, with a few variations of each, I was able to quickly build out a simple dungeon in a fraction of the time it would have taken me before.

To further demonstrate the usefulness of this in editing worlds, here's a somewhat sped up video showing how to remove a window plus add a hallway and new room.

Although lacking the abilities to adjust a prefab's position in the 3D view-port and set a prefab's pivot position, editing a level is still much faster than before.

And to show it all works at runtime as well, here's a quick run through of the dungeon using a first person character controller.

Next Time

Thanks for reading another one of my posts about Chronicle! I hope you’re finding these informative.

My current focus is on building out the size and functionality of worlds in Chronicle, so my next goal is some basic terrain authoring. This included dividing up the world for streaming purposes so I can build bigger, bigger worlds without having all things in memory all the time.