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
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.models/item/<item>.json; an icons/ subfolder is fine too — the icon field in the definition
spells out the full resource location either way.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:
/reload.F3+T to reload.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. ✅ AvailableEvery pack needs a valid pack.mcmeta; a folder missing it is skipped — you’ll see a warning in the log.
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:slaptiedup:shocker_activated tiedup:collar_key_open tiedup:whiptiedup:chain tiedup:collar_key_closeTwo more things to keep in mind:
unequip_sound is optional: if you omit it, the unequip reuses equip_sound.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>.jsonand 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.
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.
| Field | Type | Default | Notes |
|---|---|---|---|
type | string | — | Required. Exactly tiedup:bondage_item_crafting. |
pattern | string[] | — | Required. Grid rows, like a vanilla shaped recipe. |
key | object | — | Required. Maps each pattern symbol to an ingredient. |
result.tiedup_item | RL | — | Required. The bondage-item id (same as the tiedup_items/<item>.json file). |
result.count | int | 1 | Optional output stack size. |
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.
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>.nbtThere are two ways to use one.
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 tentcell_tent ← the prisoner cell tentkidnap_tent_trader ← the trader tentkidnap_fortress ← the larger fortress buildkidnap_outpost ← the smaller outpost buildSo a file at data/<ns>/structures/kidnap_tent.nbt quietly reskins every kidnapper tent in the world.
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:
All of these live in the same data/<ns>/ folder as everything else, so it’s still one pack.
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.
| Content | On the server | On each client | Works 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.
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.
data/<ns>/tiedup_items/ definition and the assets/<ns>/ mesh it
points to.models/gltf/<category>/..glb; tintable textures authored in grayscale (tint reads via
tintable_* materials). ✅ Availablelang/ entry for the display name..ogg will register a new id.
🔧 Manual / tool-gap
pack.mcmeta present and valid, or the pack is silently skipped.default_cape.json + the EF animmodels/animations/ clips)./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.