Custom items are a common goal for new mod authors, but they're one of the hardest things to do because the game uses the item spritesheet index as the ID. That means IDs need to fit within the spritesheet's max size, and mods can't avoid conflicts with other mods without complex workarounds like Json Assets and Dynamic Game Assets (which add their own problems and limitations).
This proposal solves that by giving each item a string UniqueKey
, and allowing custom
spritesheets per item. That also avoids needing to check item types in most code, since there's no
longer any possible ID overlap.
Goals
This proposal aims to...
- minimize changes needed in the game code where possible;
- maximize compatibility with existing content packs where possible;
- allow item keys anywhere that currently uses the parent sheet index;
- let mods add items without Harmony or complex frameworks;
- let mods add any number of custom items without key or sprite index conflicts.
Changes to C# code
Item class
The Item
class has two new fields:
name | type | description |
---|---|---|
ParentSheet |
Texture2D |
The spritesheet texture to draw (e.g. Game1.objectSpriteSheet for a vanilla object). |
UniqueKey |
string |
A globally unique string key for the item, like radish_salad (vanilla item) or Pathoschild.ExampleMod_watermelon (mod item). This is assumed to only contain characters [a-zA-Z_.] , so it can be used in fields delimited with spaces/slashes/commas, filenames, etc. |
The ParentSheetIndex
field is unchanged, except that it targets ParentSheet
instead of a global texture (which would be the same for vanilla items).
Creating items
Creating an item would be the same as before, except that it'd take the key instead of the spritesheet index. For example:
new Object("634", 1); // 634 = unique key for apricot (see changes to data assets below)
new Object("Pathoschild.ExampleMod_watermelon", 1);
new Furniture("groovy_chair", Vector2.Zero);
The game would ideally provide a method to get any item by its key too (which would enable things like sending non-object items through the mail):
Item item = Game1.getItemByKey("groovy_chair");
Item references
Most item references would use the key instead. For example:
old code | new code |
---|---|
item.ParentSheetIndex == 848 |
item.UniqueKey == "848" |
IsNormalObjectAtParentSheetIndex(item, 74) |
item.UniqueKey == "74" |
!item.bigCraftable && item.ParentSheetIndex == this.wantedIndex |
item.UniqueKey == this.wantedKey |
item is Boots && item.ParentSheetIndex == 505 |
item.UniqueKey == "rubber_boots" |
Changes to data assets
Assets which define an item
This section applies to:
Data/BigCraftablesInformation
Data/Boots
Data/ClothingInformation
Data/Crops
Data/Fish
Data/FruitTrees
Data/Furniture
Data/Hats
Data/ObjectInformation
Data/weapons
These all have two new fields:
field | description |
---|---|
ParentSheetIndex |
(optional for objects) The item's index in the spritesheet. (For Data/ObjectInformation only: defaults to the unique key if numeric, else 0.) |
ParentSheet |
(optional) The item spritesheet's asset name under Maps . Defaults to the vanilla spritesheet for that item type. |
Data/ObjectInformation
is identical for vanilla items, while custom items can use the new fields:
"634": "Apricot/50/15/Basic -79/Apricot/A tender little fruit with a rock-hard pit.",
"Pathoschild.ExampleMod_watermelon": "Watermelon/300/10/Basic -79/Watermelon/Takes 28 days to grow. Plant in summer./3/Pathoschild.ExampleMod_objectSprites"
Unfortunately non-objects can't use the same trick, since their unique keys would overlap with
object keys. These have a unique key based on the name instead. For example, in Data/Furniture
:
"groovy_chair": "Groovy Chair/chair/-1/-1/4/750/82"
Assets which reference an item
These now reference the unique key instead of the parent sheet index. Since those are the same for objects, many assets are unchanged.
For example, here's from Data/NPCDispositions
with one custom item:
Universal_Like: "-2 -7 -26 -75 -80 72 395 613 634 635 636 637 638 724 459 Pathoschild.ExampleMod_watermelon"