Skip to content

Feature Item Naming

Brennan Hatton edited this page May 17, 2026 · 1 revision

Procedural item naming

Since: v0.191.0 — PR #237

Naturally-spawned weapons, tools, shields, and armor now roll a procedurally-composed display name at chest/pot generation time. "Doombringer of Dreams, Wraith of Iron Blade", "Pope of Cherry Grove Hoofs", "Supreme World Overlord of TechnoBlade" — all rolled deterministically from the same (world seed, carriage index, slot) mix as durability and enchantment, so the same chest at the same world seed always produces the same named loot.

Ports the original Unity DungeonTrain SharedLines weighted-text system into a data-driven Minecraft mod implementation. Twenty original Unity-era word pools (Title Prefix, Title Post-Prefix, Food, Places, Animals, Names, Math, Music, Discord People, Colors, Feelings, Wholesome Things, Inclusion, Titles, Technology, Materials → split between real & fantasy) plus 11 Minecraft-themed pools (Animals, Structures, Lore, TechnoBlade, Minigames, Dimensions, Enchantments, Hostile Mobs, Biomes, Events, Potions/Effects, Skins, Streamers, Villager Professions, Music Discs) — ~1,400 entries total across 33 pools.

Crafted items stay vanilla-named: the hook is wired into ContainerContentsRoller.rollItemStack, which is the single entry point for items spawned into Dungeon Train containers and decorated pots. Crafting tables, anvils, trading, and entity drops follow vanilla paths and aren't touched.

What gets named

Coverage is data-driven via JSON selector files mapping item tags to chain configs:

Item kind Item tag Selector file
Swords minecraft:swords naming/selectors/sword.json
Axes minecraft:axes naming/selectors/axe.json
Pickaxes minecraft:pickaxes naming/selectors/pickaxe.json
Shovels minecraft:shovels naming/selectors/shovel.json
Hoes minecraft:hoes naming/selectors/hoe.json
Helmets minecraft:head_armor naming/selectors/helmet.json
Chestplates minecraft:chest_armor naming/selectors/chestplate.json
Leggings minecraft:leg_armor naming/selectors/leggings.json
Boots minecraft:foot_armor naming/selectors/boots.json
Shields dungeontrain:shields (custom tag containing minecraft:shield) naming/selectors/shield.json

Adding new item kinds (custom mod weapons, future vanilla item types) is purely a data-side change — drop a selector JSON, no Java edits required.

Naming probability

Not every namable item gets a name — most stay vanilla. The gate runs at applyName time:

Item state Probability of getting a name
Plain (no enchantments) 30%
Enchanted 50%

When the gate fires, the chain config picks one of two name profiles based on enchantment state:

  • Plain → weapon_name_short — a single "Title of X" combination, e.g. "Princess of Iron".
  • Enchanted → weapon_name_full — up to four chained title combinations (1.0, 0.4, 0.75, 0.2 chance for segments 1–4), e.g. "Doombringer of Dreams, Wraith of Diamond. Mother of Trains".

Enchanted names read longer / more elaborate, giving a visible rarity gradient even before you mouse over to see the enchant list.

Composition

Each rolled name is built segment-by-segment from a chain that references other chains and pools:

weapon_name_full
└─ title_combinations  (segment 1, chance 1.0)
└─ title_combinations  (segment 2, chance 0.4, joined by " ")
└─ title_combinations  (segment 3, chance 0.75, joined by ", ")
└─ title_combinations  (segment 4, chance 0.2, joined by ". ", newline)

title_combinations itself is a chain:

title_combinations
└─ title_prefix         (segment 1, chance 1.0)  ← always a title
└─ weighted of-X pool   (segment 2, chance 1.0, joined by " of ")
   ├─ original pools (~80%): title_post_prefix, food, titles, places, animals, names, ...
   └─ MC pools (~20%):       mc_biomes, mc_technoblade, mc_lore, mc_dimensions, ...

Material context

The "material" reference in a name resolves to the actual material of the item at compose time, not a random pick. The chain material_or_element rolls 50/50 between:

  • dungeontrain:context/item_material — a virtual ref that reads from the ItemStack and returns the vanilla material prefix (Wood, Stone, Iron, Gold, Diamond, Netherite, Leather, Chainmail, Turtle)
  • dungeontrain:elements — a 14-entry pool of fantasy materials (Mithril, Fire, Crystal, The Night, Runes, etc.)

So "Princess of Iron Blade" on an iron sword has its material grounded in the item's actual type; "Princess of Mithril Blade" on the same iron sword is a fantasy roll. Both feel correct.

Item-type synonym slot

After the name composes, a synonym matching the item's kind is added with weighted placement:

Placement Weight Example
None 65% Princess of Iron
End (space) 30% Princess of Iron Blade
Start (space) 4% Blade Princess of Iron
Start ("X of …") 1% Blade of Princess of Iron

84 synonyms across 10 item kinds, tagged per item type so a sword can only roll Blade/Sword/Great Sword/Cleaver/Saber/Edge/Reaver/Skewer — never Trousers. Each item kind has 8–10 synonyms ranging from formal (Bardiche, Cuirass, Targe, Aegis) to whimsical (Brain-Bucket, Stocking-Things, Foot-Mittens, Wood-Wrecker).

MC content weights

Of the "of X" picks, ~20% land in Minecraft-themed pools. Within MC:

MC pool Weight in chain % of MC slot
mc_biomes 0.043 15.6%
mc_technoblade 0.038 13.8% — TechnoBlade family + 21 epithets
mc_dimensions 0.025 9.1%
mc_hostile_mobs 0.024 8.7%
mc_animals 0.023 8.4%
mc_structures 0.023 8.4%
mc_lore 0.023 8.4% — Herobrine, creepypasta lore
mc_minigames 0.021 7.6%
mc_villager_professions 0.016 5.8%
mc_events 0.013 4.7%
mc_skins 0.009 3.3%
mc_music_discs 0.008 2.9%
mc_potions_effects 0.004 1.5%
mc_enchantments 0.003 1.1%
mc_streamers 0.002 0.7%

Data layout

src/main/resources/data/dungeontrain/naming/
├── pools/                     # 33 word lists (~1,400 entries)
│   ├── title_prefix.json       (99 entries — original 45 + 54 added)
│   ├── title_post_prefix.json  (34)
│   ├── animals.json            (23)
│   ├── colors.json             (27)
│   ├── elements.json           (14 fantasy materials)
│   ├── type_synonyms.json      (84, tagged per item kind)
│   ├── mc_technoblade.json     (21, incl. Potato King)
│   ├── mc_biomes.json          (26)
│   ├── mc_lore.json            (20)
│   └── ... (24 more)
├── chains/                    # 4 composition recipes
│   ├── title_combinations.json     (Title Prefix + " of " + weighted pool pick)
│   ├── material_or_element.json    (50/50 real-material vs fantasy)
│   ├── weapon_name_short.json      (plain — single combination)
│   └── weapon_name_full.json       (enchanted — up to 4 chained combinations)
├── selectors/                 # 10 item-tag → chain mappings
└── tags/items/shields.json    # custom dungeontrain:shields containing minecraft:shield

Implementation notes

Two off-by-one bugs from the original Unity SharedLines.cs are deliberately fixed in the port:

  • Weighted pick — Unity's PickSharedLine() compared the random target against the cumulative weight before adding the current weight, so it returned the previous entry. The port adds first, then compares, so the chosen ref matches the rolled weight slice. (NameComposer.pickWeighted)
  • Uniform pick — Unity's GetSharedLine() used Random.Range(0, sharedLines.Count - 1), but Unity's int Range is exclusive on max, so the last entry was silently never picked. The port uses rng.nextInt(size) which is [0, size) — every entry is reachable.

Determinism uses the existing mix(localPos, worldSeed, carriageIndex, slot, SALT_NAME) pattern with a new salt constant, isolating name rolls from the durability/enchantment salts so toggling one doesn't shift the other's outcome.

The dungeontrain:context/item_material virtual ref is special-cased inside the composer — it short-circuits chain/pool lookup and reads the stack's item path prefix (netherite_, diamond_, chainmail_, ..., longest-prefix-first to avoid gold collision with golden_). Returns an empty string for items without a vanilla material prefix (vanilla shields, custom mod items, blocks like written_book) so the segment skips cleanly.

Compatibility

  • Sable: naming only writes to DataComponents.CUSTOM_NAME; no physics, collision, or rendering paths touched. Safe on Sable ships and carriages.
  • Multiplayer: CUSTOM_NAME is part of vanilla ItemStack serialization — syncs to clients with no custom packet work.
  • Save format: no schema changes. Existing chests retain their previously-rolled (unnamed) contents; only chests generated post-v0.191.0 roll through the naming gate.
  • Locale: generated names are stored as literal Component.literal strings — not translatable. Matches vanilla anvil-renamed-item behaviour.

Clone this wiki locally