Skip to content

ID Preservation (Registry)

The Registry system tracks created objects with persistent UUIDs, enabling cross-session identification and integration with external tools.

Overview

When you create objects (units, graphics, sounds, techs, effects), the Registry:

  1. Assigns a unique UUID to each created object
  2. Maps UIDs to current integer IDs
  3. Enables export to JSON for external tools
  4. Tracks dependencies between objects

Why UUIDs?

Integer IDs can change:

  • If you add objects, existing IDs might shift
  • Different DAT versions have different ID ranges
  • Sharing mods requires ID awareness

UUIDs provide stable identity:

  • Always unique
  • Persist across sessions
  • Can be used to find objects even if IDs change

Accessing the Registry

python
workspace = GenieWorkspace.load("input.dat")
registry = workspace.registry

Registering Objects

Objects are automatically registered when created through managers:

python
# Automatically registered
unit = workspace.unit_manager.create("Hero")
print(f"UUID: {registry.get_uuid_for_unit(unit.id)}")

graphic = workspace.graphic_manager.add_graphic("hero.slp")
print(f"UUID: {registry.get_uuid_for_graphic(graphic.id)}")

Manual Registration

You can also manually register existing objects:

python
# Register an existing unit for tracking
registry.register_unit("MyArcher", id=4)

Looking Up by UUID

python
# Get ID from UUID
unit_id = registry.get_id_by_uuid("units", "abc-123-uuid")

# Use in operations
if unit_id:
    unit = workspace.unit_manager.get(unit_id)

JSON Export

Export registry data for external tools (like AoE2ScenarioParser):

python
# Export to JSON file
registry.export_json("registry.json")

The JSON contains:

json
{
  "units": [
    {"uuid": "abc-123", "id": 500, "name": "Hero"},
    {"uuid": "def-456", "id": 501, "name": "Elite Hero"}
  ],
  "graphics": [
    {"uuid": "ghi-789", "id": 6000, "name": "hero_attack.slp"}
  ],
  "sounds": [...],
  "techs": [...],
  "effects": [...]
}

External tools can read this to understand what was created and at what IDs.


Bulk Registration

Register all existing objects in the DAT file:

python
# Register all existing objects (marks them as "existing" vs "created")
registry.register_existing_objects(workspace)

This is useful for:

  • Full validation of all references
  • Building a complete object map
  • Migration/comparison tools

Integration with AoE2ScenarioParser

The Registry was designed to work with AoE2ScenarioParser for scenario editing:

python
# In your mod script
workspace = GenieWorkspace.load("input.dat")

# Create custom units
hero = workspace.unit_manager.create("Hero", unit_id=1000)
hero.hit_points = 200

# Export registry
workspace.registry.export_json("my_mod_registry.json")
workspace.save("my_mod.dat")

# In scenario parser script, you can read the registry
# to know which IDs correspond to your custom units

Dependency Tracking

The Registry can track dependencies between objects:

python
# When you assign a graphic to a unit, that's a dependency
unit.standing_graphic_1 = graphic.id

# The registry knows unit depends on graphic
# This helps with:
# - Ensuring referenced objects exist
# - Export ordering
# - Deletion safety checks

Session vs Existing Objects

The Registry distinguishes between:

  • Session-created: Objects you created in this session
  • Existing: Objects that were already in the DAT file

This enables selective validation:

python
# Validate only session-created objects (faster)
issues = workspace.validator.validate_all_references(
    workspace, 
    validate_existing=False  # Only check new stuff
)

# Validate everything (slower but thorough)
issues = workspace.validator.validate_all_references(
    workspace,
    validate_existing=True
)

Best Practices

Export Registry for Complex Mods

python
# At the end of your mod script
workspace.registry.export_json("my_mod_registry.json")

Use Meaningful Names

python
# Names are stored in registry and help identify objects
unit = workspace.unit_manager.create("EliteLongbowman")  # Clear name
# vs
unit = workspace.unit_manager.create("u1")  # Unhelpful

Check UUID Collisions

If importing from multiple sources:

python
# UUIDs should never collide, but if using custom UUIDs:
existing_uuid = registry.get_uuid_for_unit(some_id)
if existing_uuid:
    print(f"ID {some_id} already tracked as {existing_uuid}")

Released under the MIT License.