Skip to content

Multiblock Structures ​

A multiblock structure is a "contraption" that players build out of blocks. You write its shape and coordinates into a definition file at plugins/EmakiStructure/multiblocks/<id>.yml, where the file name is the structure id (a mismatch is rejected on load). Once a player assembles that shape and interacts with it (most often by right-clicking a block), the plugin checks the blocks one by one and, if they match, runs the actions you configured in trigger.actions (send a message, give experience, etc.)

Definition format ​

yaml
version: 1                    # only 1 is supported: older reports version_outdated, newer version_unsupported
id: "teleporter"              # must match the file name, otherwise rejected (id_mismatch)

shape:
  allow_rotation: true        # default true; whether rotation matching is allowed
  core_block: [4, 1, 4]       # optional: core block relative coordinate (trigger anchor)
  blocks:
    - pos: [4, 1, 4]
      block: "minecraft:obsidian"
    - pos: [4, 2, 4]
      block: "minecraft:ender_eye"       # states via minecraft:...[state=value]
    - pos: [5, 1, 4]
      block: "craftengine-myns:console"  # custom block: source-rawId, states not allowed
    - pos: [6, 1, 4]
      furniture: "itemsadder:myplugin:chair"  # furniture member; mutually exclusive with block

trigger:
  targets: "any"              # any (any member) / specific (positions below) / all (all members)
  positions:                  # required when targets=specific
    - [4, 1, 4]
  actions: |                  # CoreLib action pipeline lines, run one per line
    send_message "&aPortal activated!"
    action giveexp amount=10

cooldown:                     # optional
  global: "0"                 # shared across players for this structure; 0 = none, supports 30s/5m
  per_player: "0"             # per player per structure

condition: "permission=teleport.use"   # optional trigger precondition (CoreLib condition syntax)

When the plugin loads each file it runs the checks below; any failure rejects the file or skips that entry, and the console always reports the file and entry index:

  • Every member declares exactly one of block or furniture; coordinates are non-negative, inside the size, and unique
  • furniture prefixes are limited to itemsadder: / oraxen: / nexo: / craftengine:
  • block starting with minecraft: may carry block states; any other prefix is treated as a custom block id and must not carry states
  • Invalid targets, specific without positions, or no valid members (blocks_empty) reject the whole file
  • Mismatched id, a version other than 1, and parse failures also reject the file
  • On duplicate ids the later definition is not loaded (duplicate_id)

Commands ​

  • /ems multiblock export <id> [force]: export the current selection as a layout; an existing id needs force (already_exists)
  • /ems multiblock place <id> [facing]: place manually (vanilla blocks / custom blocks / furniture), then run forming detection; up to 5 failing entries are reported
  • /ems multiblock list: list definitions with instance statistics
  • /ems multiblock validate <id>: validate the world shape once; a failure downgrades that instance to incomplete (verification_failed)

Trigger flow ​

  1. The player interaction hits the structure region (or an anchor candidate)
  2. Incremental shape detection decides whether the shape is assembled: only changed blocks are checked (no full-map scan), chunk changes are debounced (detection.debounce), and cold-hit anchor inference is bounded by detection.max_cold_checks
  3. The condition is evaluated as a CoreLib condition group (the whole group must pass) and the cooldown is checked — taken from the definition's own cooldown node, falling back to config.yml's cooldown.global / cooldown.per_player
  4. MultiblockTriggerEvent is published synchronously (non-cancellable, on the thread that handled the interaction; on Folia, the region thread owning the clicked block)
  5. trigger.actions lines run through the CoreLib action pipeline

With retrigger_on_reform: false (default), a destroyed structure that is reassembled only becomes an active instance again — it does not re-fire, so players cannot farm rewards by rebuilding it over and over

Incremental detection settings ​

These keys all live in the detection section of Configuration: sweep_interval (low-frequency fallback sweep, 0 disables and must be ≥ 30s when enabled), instance_limit (per definition per player in-progress cap), instance_ttl (lifetime for unchanged instances), and sample_recheck (low-frequency sampling of active instances, off by default)