Pyrite64 Prefab System: Object Instantiation and UUID Management Explained

Pyrite64's prefab system uses stable 64-bit UUIDs for template definitions and ephemeral 32-bit UUIDs for instantiated objects, linked via a uuidPrefab property that enables per-instance overrides while maintaining data reuse.

The Pyrite64 prefab system, implemented in the HailToDodongo/pyrite64 repository, provides a robust mechanism for creating reusable object templates in Nintendo 64 development. By separating the persistent prefab definition from runtime instances through a dual-UUID architecture, the system enables efficient asset management while allowing per-instance customization through property overrides.

Core Architecture of the Pyrite64 Prefab System

Prefab Definition and Global UUIDs

At the heart of the system lies the Prefab class defined in src/project/scene/prefab.h. Each prefab maintains a global 64-bit UUID stored via PROP_U32(uuid) alongside an Object instance that serves as the template data. This template contains the default transform (position, rotation, scale), component configurations, and other properties that define the prefab's behavior.

The UUID generation relies on Utils::Hash::randomU64(), ensuring that each prefab receives a unique, stable identifier that persists across project saves and loads. As noted in the source comments, changing these ID mappings would break existing saved scenes and prefabs, emphasizing the critical role of UUID stability in the asset pipeline.

Serialization and Asset Storage

The Prefab class implements serialize() and deserialize() methods in src/project/scene/prefab.cpp to handle persistence. During serialization, the method writes both the prefab's UUID and the serialized Object data into JSON format. The save() method then writes this JSON to disk at assets/<name>.prefab, establishing the asset file format that the engine uses to reload prefab definitions.

Object Instantiation and UUID Generation

Creating Prefabs from Existing Objects

The Scene class in src/project/scene/scene.cpp provides createPrefabFromObject() to convert existing scene objects into reusable prefabs. When invoked, this method generates a new random 64-bit UUID using Utils::Hash::randomU64() and creates a new Prefab instance containing the object's current state. This establishes the template that future instances will reference.

Instantiating Prefabs in Scenes

Runtime instantiation occurs through Scene::addPrefabInstance(), also located in src/project/scene/scene.cpp. This method performs several critical operations:

  1. Retrieves the prefab using AssetManager::getPrefabByUUID() from src/project/assetManager.h
  2. Generates a fresh 32-bit UUID for the new instance via Utils::Hash::randomU32()
  3. Copies transform data from the prefab's template object
  4. Establishes the prefab link by setting obj->uuidPrefab.value = prefab->uuid.value

This dual-UUID approach—64-bit for the prefab definition, 32-bit for the instance—enables the AssetManager to maintain a global lookup table while allowing the Scene to track individual object instances efficiently.

Property Overrides and Instance Customization

Once instantiated, objects can override prefab properties without affecting the template. The Object class stores a property override map (<property-id → GenericValue>) that shadows the prefab's default values. When addPrefabInstance() creates a new instance, it automatically adds override entries for transform properties (pos, rot, scale), enabling immediate per-instance editing.

The property system, defined in src/utils/prop.h, uses macros like PROP_U32 to create properties with deterministic hash-based IDs generated via Utils::Hash::crc64(name). This ensures that property identifiers remain consistent across compilation units, enabling reliable serialization and override resolution.

Build Pipeline Integration

During the build process, src/build/prefabBuilder.cpp processes prefab instances for the Nintendo 64 target. The builder checks obj->uuidPrefab to identify prefab-linked objects and retrieves the corresponding template data from prefab->obj. This integration ensures that prefab definitions are properly resolved and baked into the final ROM, maintaining the relationship between instances and their templates while optimizing for the target hardware.

Summary

  • Pyrite64's prefab system uses a dual-UUID architecture with stable 64-bit identifiers for prefab templates and ephemeral 32-bit UUIDs for runtime instances.
  • Prefab definitions are stored in assets/<name>.prefab files via JSON serialization, with UUIDs generated using Utils::Hash::randomU64() in src/project/scene/scene.cpp.
  • Instantiation occurs through Scene::addPrefabInstance(), which creates new objects with unique 32-bit UUIDs and establishes prefab links via the uuidPrefab property.
  • Property overrides allow instances to customize transform data and components without affecting the template, utilizing the generic property system defined in src/utils/prop.h.
  • Build integration in src/build/prefabBuilder.cpp resolves prefab links during compilation for Nintendo 64 targets.

Frequently Asked Questions

How does Pyrite64 generate UUIDs for prefabs versus object instances?

Pyrite64 uses Utils::Hash::randomU64() to generate 64-bit UUIDs for prefab definitions when calling Scene::createPrefabFromObject(), ensuring stable, globally unique identifiers for templates. For individual object instances created via Scene::addPrefabInstance(), the system generates 32-bit UUIDs using Utils::Hash::randomU32(), allowing efficient scene-level tracking while maintaining the link to the parent prefab through the uuidPrefab property.

What is the relationship between a prefab and its instances in Pyrite64?

Each prefab instance maintains a reference to its template through the uuidPrefab property, which stores the 64-bit UUID of the source prefab. When instantiated via Scene::addPrefabInstance(), the new object copies the transform data from the prefab's template object but receives its own unique 32-bit UUID for scene management. This architecture allows instances to override specific properties without modifying the shared prefab template, enabling both data reuse and per-instance customization.

How does property overriding work in the Pyrite64 prefab system?

Property overriding utilizes the generic property system defined in src/utils/prop.h. When an instance overrides a property, it adds an entry to its internal override map (<property-id → GenericValue>), which shadows the prefab's default value during serialization and runtime. The PROP_… macros generate deterministic property IDs using Utils::Hash::crc64(name), ensuring consistent identification across the engine. When Scene::addPrefabInstance() creates a new instance, it automatically establishes override entries for transform properties, allowing immediate editing of position, rotation, and scale.

Where are prefab files stored and how are they loaded in Pyrite64?

Prefab definitions are serialized to JSON and saved to disk at assets/<name>.prefab via the Prefab::save() method in src/project/scene/prefab.cpp. The Prefab::serialize() method writes the prefab's 64-bit UUID and the serialized template object data to JSON, while deserialize() restores these fields when loading. At runtime, AssetManager::getPrefabByUUID() in src/project/assetManager.h retrieves prefab instances from the asset table using their stable 64-bit UUIDs, enabling the scene to instantiate objects while maintaining the link to the original template.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →