Skip to content

Packaging

A TiedUp! content add-on is two halves in one folder: a datapack (data/) that holds the item definitions, and a resourcepack (assets/) that holds everything you can see or hear — meshes, animations, icons, lang, and sound references. You need both. A datapack-only add-on has no model to render; a resourcepack-only add-on has no item to attach the model to.

data/ — the datapack

Item definition JSON: regions, locks, components, the path to the mesh. Loaded server-side on /reload. This is the gameplay contract. ✅ Available

assets/ — the resourcepack

The .glb mesh (texture baked in), EF-JSON animation clips, the inventory icon + its PNG, lang/, and sounds.json. Loaded client-side. ✅ Available

The item definition’s model field is just a resource location — it points across the split into the resourcepack. If the assets/ half is missing (for example, a client that didn’t install it), the item still exists server-side but renders nothing.

Your pack can ship any of the content types below — drop the file in the right folder and it’s picked up, no registration step. You only include the folders you actually use; a pack that’s just a recipe is fine, and so is one that’s just a room theme.

A complete add-on for one namespace <ns> and one item <item>:

<addon>/
├── pack.mcmeta ← standard MC pack metadata (see below)
├── data/
│ └── <ns>/
│ ├── tiedup_items/<item>.json ← item definition (the datapack contract)
│ ├── tiedup_furniture/<piece>.json ← furniture definition (if any)
│ ├── recipes/<name>.json ← crafting recipe (if any — see Recipes below)
│ ├── skins/<npc-type>/<skin>.json ← NPC skin definition (if any)
│ ├── tiedup_npc_names/<pool>.json ← NPC name pool (if any)
│ ├── dialogue/<file>.json ← NPC dialogue lines
│ ├── tiedup_room_themes/<theme>.json ← kidnapper-camp room looks
│ ├── synced_actions/<action>.json ← reaction / co-op action definitions
│ ├── tiedup/living_motions/<motion>.json ← animation bindings (advanced — pair with assets)
│ ├── tiedup/armatures/<armature>.json ← skeleton data (advanced — pair with assets)
│ └── structures/<name>.nbt ← a built structure (see Structures below)
└── assets/
└── <ns>/
├── models/gltf/<category>/<item>.glb ← the mesh, baked texture inside
├── animmodels/animations/<clip>.json ← EF-JSON animation clips
├── models/item/<icon>.json ← inventory icon model
├── textures/item/<icon>.png ← the icon sprite
├── textures/entity/<…>/<skin>.png ← NPC skin texture (if any)
├── lang/en_us.json ← display name / tooltips
└── sounds.json ← sound aliases (references only — see below)

A few layout notes:

  • <category> is a free-form folder you choose (shipped examples: binds/, gags/, collars/). It’s purely organisational — the model field carries the full path.
  • The icon model is a plain vanilla item model. The built-in items put it directly under models/item/<item>.json; an icons/ subfolder is fine too — the icon field in the definition spells out the full resource location either way.
  • EF-JSON clips go under animmodels/animations/, referenced by name from the item’s living_motions / on_equip bindings. The on_equip / on_unequip one-shot is now server-fired (so a worn item on an NPC also animates on remote clients); authoring the binding is unchanged — see Item JSON → animations.

The icon is an ordinary item/generated model pointing at your sprite:

{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "<ns>:item/<icon>"
}
}

Drop your pack folder (or .zip) into:

.minecraft/config/tiedup/packs/<your-addon>/

The mod auto-creates that folder on first run and registers every pack inside it for both sides: the assets/ half is served to the client as a resource pack, the data/ half to the server as a datapack — the same physical folder serves both. No need to split your pack across .minecraft/resourcepacks/ and a world’s datapacks/. ✅ Available

Packs here are loaded as forced (required = true): always enabled, non-removable, and pinned to the top of the stack so your content wins over lower packs.

Loading-timing caveats to know:

  • A data pack dropped while a world is already open is only picked up on the next world load or /reload.
  • Resources dropped at runtime need F3+T to reload.
  • On a dedicated server, your data/ definitions — items, furniture, living motions, custom armatures — are sent to every client automatically when they join and on each /reload, so a client doesn’t need the data/ half itself. The assets/ half (meshes, textures, sounds, animation files) is not sent over the network: install it on each client too, or the item exists but renders nothing. The single-folder layout handles authoring; getting the visual assets onto each player is still up to you. ✅ Available

Every pack needs a valid pack.mcmeta; a folder missing it is skipped — you’ll see a warning in the log.

Sounds: reference only, you can’t register new ones

Section titled “Sounds: reference only, you can’t register new ones”

Equip / unequip sound bindings live under the item’s animations block:

{
"animations": {
"equip_sound": "tiedup:collar_put",
"unequip_sound": "tiedup:collar_key_open"
}
}

Reference a vanilla sound (e.g. minecraft:block.chain.place) or one of the mod’s registered events:

tiedup:electric_shock tiedup:collar_put tiedup:slap
tiedup:shocker_activated tiedup:collar_key_open tiedup:whip
tiedup:chain tiedup:collar_key_close

Two more things to keep in mind:

  • These sounds are client-only / local — there’s no network packet, so on a server only the player performing the equip hears them.
  • unequip_sound is optional: if you omit it, the unequip reuses equip_sound.

Recipes — ship a crafting recipe with your pack ✅ Available

Section titled “Recipes — ship a crafting recipe with your pack ”

Because your pack’s data/ half is a datapack, you can ship a crafting recipe right next to the item definition. Drop a recipe file at:

data/<ns>/recipes/<name>.json

and it’s loaded automatically on /reload — there’s no separate registration step. The mod now ships built-in survival recipes for its own items, so they’re craftable, not creative-only; your pack’s items can be too.

Which recipe type you use depends on which kind of item you’re targeting.

A data-driven bondage item (the tiedup_items/ kind)

Section titled “A data-driven bondage item (the tiedup_items/ kind)”

A bondage item isn’t a normal registered item — every one shares a single underlying item, differentiated by data. So a vanilla { "item": …, "count": … } result can’t point at it. Use the mod’s recipe type instead:

{
"type": "tiedup:bondage_item_crafting",
"pattern": ["S", "S", "S"],
"key": {
"S": { "item": "minecraft:string" }
},
"result": {
"tiedup_item": "<ns>:<item_id>"
}
}

The tiedup_item id is the same id as the item definition file — e.g. tiedup:ropes for tiedup_items/ropes.json. pattern and key work exactly like a vanilla shaped recipe.

FieldTypeDefaultNotes
typestringRequired. Exactly tiedup:bondage_item_crafting.
patternstring[]Required. Grid rows, like a vanilla shaped recipe.
keyobjectRequired. Maps each pattern symbol to an ingredient.
result.tiedup_itemRLRequired. The bondage-item id (same as the tiedup_items/<item>.json file).
result.countint1Optional output stack size.

A real registered item (the mod’s tools)

Section titled “A real registered item (the mod’s tools)”

The mod’s tool items — the whip, lockpick, keys, and friends — are ordinary registered items, so they take a plain vanilla recipe with an { "item": … } result:

{
"type": "minecraft:crafting_shaped",
"pattern": [" X ", " X ", " # "],
"key": {
"#": { "item": "minecraft:blaze_rod" },
"X": { "item": "minecraft:blaze_powder" }
},
"result": {
"item": "tiedup:<id>",
"count": 1
}
}

minecraft:crafting_shapeless works the same way — list ingredients instead of a pattern + key.

Structures — ship a build that generates in the world ✅ Available

Section titled “Structures — ship a build that generates in the world ”

You can ship a structure — an actual in-game build — as a single .nbt file. Make it the normal way: place a structure block in a creative world, save your build to it, and grab the resulting .nbt. Drop it at:

data/<ns>/structures/<name>.nbt

There are two ways to use one.

Easiest — replace a build the mod already uses

Section titled “Easiest — replace a build the mod already uses”

Give your .nbt the same name as a structure the mod already generates, and your version takes over: kidnapper camps then spawn with your build instead of the default. Nothing else to author — no extra files, no config. Just match the name and drop it in.

The built-in structures you can override by name:

kidnap_tent ← the main kidnapper tent
cell_tent ← the prisoner cell tent
kidnap_tent_trader ← the trader tent
kidnap_fortress ← the larger fortress build
kidnap_outpost ← the smaller outpost build

So a file at data/<ns>/structures/kidnap_tent.nbt quietly reskins every kidnapper tent in the world.

A brand-new structure that generates on its own

Section titled “A brand-new structure that generates on its own”

To add a build that isn’t a replacement — one that places itself in the world — ship the world-generation files that tell the game where and how often to place it, alongside the .nbt:

  • the structure itself,
  • a structure set (the placement rules — spacing, rarity),
  • and a biome entry (which biomes it’s allowed to spawn in).

All of these live in the same data/<ns>/ folder as everything else, so it’s still one pack.

Does it work in multiplayer? ✅ Available

Section titled “Does it work in multiplayer? ”

Yes — with one rule to remember: a pack is not shared automatically. Install it on the server and on each player’s client. The game doesn’t push the whole pack to players for you.

What the server does send automatically are the definitions behind your content — the custom items, furniture, animation bindings, recipes, NPC names and skins. That’s why the gameplay and the right behaviour just work for everyone: the rules travel.

What the server doesn’t send are the visual files in assets/ — 3D models, textures, the animation files themselves. Those are never pushed over the network. Each player needs the assets/ half of your pack locally, or your custom item shows up but renders blank / untextured.

And some content is server-only — it never needs to be on a client at all.

ContentOn the serverOn each clientWorks in MP
Custom items / furniture (definitions)(sent automatically)
Recipes(sent automatically)
Animation & armature data(sent automatically)
NPC names(sent automatically)
NPC skin definitions(see note)
Visual files (.glb, textures, animation files)(install locally)
Structures
Dialogue
Room themes

The short version: put the whole pack on the server, and put the assets/ half on every client. Do both and everything works.

License caveat — replace the dev biped before shipping

Section titled “License caveat — replace the dev biped before shipping”

This caveat is about the base biped rig assets, not your add-on. As long as your add-on’s own .glb meshes, textures, animations, and sounds are original (or properly licensed) work, the add-on itself is yours to distribute under whatever terms you choose.

  1. Both halves present — a data/<ns>/tiedup_items/ definition and the assets/<ns>/ mesh it points to.
  2. Model path uses models/gltf/<category>/.
  3. Texture baked into the .glb; tintable textures authored in grayscale (tint reads via tintable_* materials). ✅ Available
  4. Icon + PNG shipped (don’t rely on the missing default), and a lang/ entry for the display name.
  5. Sounds reference real registered sound ids — no custom .ogg will register a new id. 🔧 Manual / tool-gap
  6. pack.mcmeta present and valid, or the pack is silently skipped.
  7. No Epic Fight assets in a release build — replace the whole gitignored EF dev-only block first (four biped meshes + default_cape.json + the EF animmodels/animations/ clips).
  8. /reload (data) and F3+T (resources) to verify in-game.

See Your First Item for the end-to-end walkthrough, and Tools & setup for getting Blender + the addon ready.