Planned / Not yet available
So you never build against something that doesn’t work, here’s the honest list of limitations. All verified against the mod’s code.
Not authorable yet ❌ Planned
Section titled “Not authorable yet ”- Pets — 4 hardcoded blocks; models/textures/scale are baked into Java. Not data-driven.
- OBJ models — paths are hardcoded; a resourcepack can only override an existing shipped path’s texture/geometry, not register a new OBJ.
- Mob-initiated coop (AI auto-initiate) — a reusable AI goal exists and is correct, but it is attached to no mob. Today coop actions only ever start when a player presses the coop keybind (default V) — see Coop actions. There is no datapack hook to give a mob the goal, so this is not authorable: giving an NPC the ability to auto-start a takedown requires Java.
- Custom (non-biped) armatures — a datapack armature at
data/<ns>/tiedup/armatures/<name>.jsonloads & validates, but nothing renders a non-biped skeleton (every entity falls back to the biped), and the addon can’t export the required schema. Experimental / manual-only — the loadable schema is documented below for the few who script it by hand. - New movement styles —
movement_styleis a fixed enum (WADDLE/SHUFFLE/HOP/CRAWL); you can’t add one from JSON. - New sound events — sounds are bound at mod init; add-ons can only reference already-registered
events, not register a new
.oggid. - Unified
tiedup_packs/loader — design only; not built.
Works with caveats ⚠️ Partial
Section titled “Works with caveats ”- Gameplay-event one-shots are wired, but their default clips are EMPTY. The
synced-action system is shipping and server-authoritative: capture,
enslave, recapture, punish, hurt, struggle (one merged event), lockpick-fail, leash-yank and death
fire at their server call sites and broadcast to every viewer — each binds to a shipped
synced_actions/def (leash_yankanddeathare self-role defs, their clip ids unauthored placeholders). The default clips are shared: the four capture flows usereaction.restrain.{initiator,target}, hurt+lockpick usereaction.flinch, struggle usesreaction.struggle. But TiedUp ships only placeholder clip ids (tiedup:reaction.restrain.initiator,tiedup:reaction.flinch, …) with no authored clip, so they resolve to the empty animation — the trigger fires and the gameplay runs, but you see no pose. 🔧 Manual / tool-gap The system is available and authorable today; the default visuals need an artist (or a datapack binding the events to clips you have authored). The takedown coop clips are unauthored in the same way. - Body-altering pose visuals are not rendered yet. Four pose effects are wired to gameplay but
not drawn: the dog/floor crawl pose (
pose_type: DOG), the pet-bed lying/sleeping pose, hiding the wearer’s arms under a full wrap/latex enclosure (hides_arms), and hiding the held item in those poses. The gameplay around them applies — lowered camera/leash, immobilization, movement style — but the third-person figure still renders as a normal standing biped, so these poses are not visible to onlookers yet. First-person mitten hiding is unaffected and still works. - Server-side animation effects (
apply_effect,damage_entity, serverplay_sound) only fire in singleplayer — they are dead on dedicated servers. 🖥️ Client / singleplayer only - Inert component fields — these parse but have no effect:
shock.damage,gagging.comprehension,choking.air_drain_per_tick/non_lethal_for_master,blinding.overlay,adjustable.min/max/step,gps.public_tracking. escape_difficulty(top-level) is only used when the item has noresistancecomponent.iconis effectively required — an item omitting it renders the missing-texture sprite.
Manual steps / tool gaps 🔧 Manual / tool-gap
Section titled “Manual steps / tool gaps ”- Meshes need Blender’s built-in glTF exporter, not the EF-JSON addon (which is animations-only).
- The
constructorblock must be hand-added to every animation JSON. - Custom armature JSON and OBJ can’t be exported by the bundled addon.
Custom (non-biped) armatures: experimental ⚠️ Partial
Section titled “Custom (non-biped) armatures: experimental ”The id of an armature is its namespace:path derived from the file location — a file at
data/mymod/tiedup/armatures/quadruped.json registers as mymod:quadruped. The scanned directory
is tiedup/armatures, so the tiedup/ segment is part of the path, not the namespace. The
built-in tiedup:biped is hardcoded in Java and is not loaded from a datapack; custom ids must
not collide with it.
{ "description": "Four-legged pet creature armature", "root_joint": "Root", "joints": { "Root": { "id": 0, "parent": null, "translation": [0.0, 0.0, 0.0], "rotation": [0.0, 0.0, 0.0, 1.0], "children": ["Torso"] }, "Torso": { "id": 1, "parent": "Root", "translation": [0.0, 12.0, 0.0], "rotation": [0.0, 0.0, 0.0, 1.0], "children": [] } }}Top-level fields:
| Field | Type | Req? | Notes |
|---|---|---|---|
description | string | optional | Free text; defaults to "". |
root_joint | string | required | Must be a key in joints, and that joint must have parent: null. |
joints | object | required | Map of joint name → joint object. Must be non-empty. |
Each joint object:
| Field | Type | Req? | Notes |
|---|---|---|---|
id | int | required | Joint ids must be unique and contiguous 0..N-1 (N = number of joints). |
parent | string | null | required | null only for the root; every other joint needs a declared parent. |
translation | [x, y, z] | required | Local translation relative to the parent, in blocks (Minecraft Y-up). |
rotation | [x, y, z, w] | required | Local rotation quaternion, xyzw order (JOML). Identity = [0, 0, 0, 1]. |
children | string array | optional | Child joint names. Order is significant — it fixes the bone index. Defaults to []. |
Each file is validated at load; the first failure is logged with a WARN and that one file is
skipped — the rest of the batch still loads. The checks:
root_jointexists injointsand hasparent: null.- Joint ids are unique and exactly cover
0..N-1(no gaps, no duplicates). - Joint count is at or below the engine cap.
- Every
parent(except the root’snull) and everychildrenentry names a declared joint. - Parent/child links are bidirectional: if
AlistsBinchildren, thenB.parentmust beA. - The hierarchy is a single tree rooted at
root_joint— every joint is reachable from the root exactly once (cycles, orphans, and detached subtrees are all rejected). - Each joint object’s key in the map must equal its own
name.
A malformed file (wrong types, missing required field, bad array length) is caught the same way:
skipped with a WARN, batch continues.
For the joint names of the built-in biped (the skeleton everything actually renders against today), see Bones & regions.