Skip to content

Instantly share code, notes, and snippets.

@dpogue
Created September 26, 2024 22:56
Show Gist options
  • Save dpogue/75a9aa780e88234d5dd523eb92154808 to your computer and use it in GitHub Desktop.
Save dpogue/75a9aa780e88234d5dd523eb92154808 to your computer and use it in GitHub Desktop.

Plasma Object IDs

Background

The 2003 version of the Plasma engine used by the original version of Uru handled all object references by comparing object names. Comparing object names essentially means stepping through each letter of the name and comparing them one at a time until you find a mismatch or reach the end of the name. That's generally quick enough, but imagine doing that for every single reference between objects in an Age and it starts to become a performance bottleneck.

For Myst V, Cyan developer Colin Bonstead came up with the idea of assigning every object in a PRP file a numeric ID. That changes references from needing to do N comparisons (where N is the number of letters in the object name) to 1 comparison.

These numeric IDs are computed at 3DS Max export time by sorting all the objects alphabetically and assigning IDs sequentially.

The Problem

As fans adding content to existing files, we run into a problem. If we add a new object, we need to assign it an object ID. The engine wants objects to be sorted alphabetically, which means our new object might need to be in the middle of the list of object IDs, which means we need to re-number all the object IDs for objects with names that come later in the alphabet. Doing this means updating all the places that reference those other objects, including references in other PRP files. This quickly becomes a nightmare.

If all the references are not updated, then you have references in other files pointing to objects that are no longer the one they expect. The results of this can range from wrong textures being applied to outright crashes due to bad data.

Adding to the confusion here, Cyan's Internal client has extra code that falls back to string comparison lookups if the numeric reference doesn't match. But this code is removed in External clients (and has also been removed in H'uru Internal clients, specifically to make it easier to identify Object ID problems earlier).

The Solution (ish)

Ideally, entire Ages get exported as a single batch step. This was Cyan's process, where the entirety of the game content was re-exported from 3DS Max as part of their client build system. For Ages built with korman, this is also the easiest option.

It's more complicated when the change involves adding to existing content that we don't have source files for, or content that has multiple source files for disparate systems (such as clothing items).

Right now, the most reliable way to fix these problems is to "round-trip" the data using libHSPlasma. libHSPlasma allows opening the data files for an entire Age and recalculting the object IDs across all the files and then saving them out again. It is very important to ensure this process happens, specifically for new clothing items, to avoid issues.

Retrospective on Recent Issues

  1. New additions to Fan02 and Mysterium shirts were created and merged.
  2. There were issues with the new Fan02 and Mysterium additions due to Object ID mismatches against the base clothing files (which provide the meshes for T-shirts). It's possible this was due to generating the files against one set of content and then copying them into another set (i.e., building against H'uru content and dropping into OpenUru content).
  3. The new bracelet was created in 3DS Max and exported (which probably referenced objects in the base clothing files at the time of export).
  4. To resolve point 2, all the GlobalClothing files were round-tripped and object IDs reassigned.
  5. The bracelets were merged.
  6. Because the bracelets were exported before point 4, but merged after point 4, they now have bad references due to the object ID reassignements.
  7. All the clothing items were round-tripped again, and only the bracelet files had changes, which have now been merged.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment