Feature Item Naming - bh679/dungeon-train-mc GitHub Wiki
Procedural item naming
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 theItemStackand 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()usedRandom.Range(0, sharedLines.Count - 1), but Unity's intRangeis exclusive on max, so the last entry was silently never picked. The port usesrng.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_NAMEis part of vanillaItemStackserialization — 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.literalstrings — not translatable. Matches vanilla anvil-renamed-item behaviour.