SMAPI - Stardew Modding API

SMAPI - Stardew Modding API

971k Downloads

Manage unique IDs for custom content

Pathoschild opened this issue ยท 2 comments

commented

SMAPI mods can't avoid unique ID conflicts when adding custom items/content (which will be possible with #255). Provide a way to get unique IDs that are guaranteed not to conflict with other mods or when loading different saves.

(Split from #173.)

Requirements

  • A mod must not reuse another mod's IDs (e.g. two mods adding a crop with ID=1000).
  • A mod must always use the same ID for an item (so their content can be read from the save file).
  • Saves must be portable โ€” if you load a save, it should work even if different IDs were assigned.
  • Saves must be robust โ€” players must be able to remove a mod that added custom content without breaking their saves.
commented

Proposed implementation

Assume a PineappleMod mod adds a custom pineapple crop. Here's how the unique ID could be handled:

  1. Mod requests a unique ID for key Pineapple:

    int id = content.GetID(ContentType.Crop, "pineapple");

    SMAP internally assigns a unique internal key like PineappleMod::Crop::Pineapple, and saves the key/ID mapping in an app data file. Generated IDs should be high enough to avoid conflicts with future vanilla items.

  2. Mod injects the item data into ObjectInformation.xnb, Crops.xnb, and the texture file with that ID using the content events (#255).

  3. Right before data is serialised to the save file, SMAPI changes the item ID to 0 (weed) and sets the name to SMAPI/PineappleMod::Crop::Pineapple/1097/Pineapple (containing the internal key, assigned ID, and full item name).

  4. After save, SMAPI switches the item back to normal based on that string.
    [...]

  5. When loading an arbitrary save file, SMAPI reads the custom items in the save file and does one of four things for each one:

    • If the mod which added the item isn't loaded, leave the item as-is (in weed form) to avoid errors.
    • Else if the item has an unknown key, register it with the given ID. (If the former ID conflicts with an assigned ID, change it.) Then unweed the item.
    • Else if the item's former ID doesn't match the ID currently assigned to that key, transparently change the item's ID to match the assigned ID before unweeding the item. (This avoids issues with mods having already saved the assigned ID, e.g. in their Entry methods.)
    • Else SMAPI simply unweeds the item based on that string.

With this approach...

  • Custom items don't break your save files. If you have custom items but stop using SMAPI or the mod that added them, your save will work fine; you'll just have some strangely-named weeds.
  • You can load arbitrary save files, even if they have different custom IDs, and SMAPI will transparently map IDs over.

Note that is a low-level API โ€” the goal is to let mods add custom items without conflicting with each other, not to facilitate custom item behaviour. Mods will still need to handle that themselves. Simplifying that will be for a higher-level API in a future SMAPI version.

commented

On further thought, this approach is unnecessarily complicated for mods. Even if SMAPI provides the IDs, each mod then needs to calculate the target area in the spritesheet to patch. This also introduces a lot of edge cases when dealing with ID collisions.

Replaced by an alternative approach in #315.