Skip to content

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>.json loads & 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 stylesmovement_style is 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 .ogg id.
  • 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_yank and death are self-role defs, their clip ids unauthored placeholders). The default clips are shared: the four capture flows use reaction.restrain.{initiator,target}, hurt+lockpick use reaction.flinch, struggle uses reaction.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, server play_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 no resistance component.
  • icon is 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 constructor block 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:

FieldTypeReq?Notes
descriptionstringoptionalFree text; defaults to "".
root_jointstringrequiredMust be a key in joints, and that joint must have parent: null.
jointsobjectrequiredMap of joint name → joint object. Must be non-empty.

Each joint object:

FieldTypeReq?Notes
idintrequiredJoint ids must be unique and contiguous 0..N-1 (N = number of joints).
parentstring | nullrequirednull only for the root; every other joint needs a declared parent.
translation[x, y, z]requiredLocal translation relative to the parent, in blocks (Minecraft Y-up).
rotation[x, y, z, w]requiredLocal rotation quaternion, xyzw order (JOML). Identity = [0, 0, 0, 1].
childrenstring arrayoptionalChild 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_joint exists in joints and has parent: 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’s null) and every children entry names a declared joint.
  • Parent/child links are bidirectional: if A lists B in children, then B.parent must be A.
  • 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.