Skip to content

Encounters

Encounters are Journey’s framework for instanced, per-player (or per-party) gameplay set-pieces — dungeons, boss fights, puzzles, scripted sequences. Each player who walks into an encounter gets their own runtime instance with its own spawned mobs, fake blocks, and phase state. Other players see nothing (or only the participants see the action, depending on the visibility tier).

New in Beta 2   Authored via an in-game visual editor or hand-edited JSON.

Per-player instances

Each player who triggers an encounter gets their own runtime state. Other players nearby see nothing.

Signal-wired elements

27 built-in element types emit named signals that sibling elements listen for. Activate, deactivate, transition phase, run a script — all declarative JSON.

Multi-phase progression

Phase definitions gate which elements are active, drive signal listeners, and switch fake block sets as the encounter unfolds.

In-game visual editor

/journey editor new <name> hands you a 9-tool hotbar to place, wire, and phase encounters without editing JSON by hand.


An encounter is a JSON blueprint pinned to a world location. When a player steps inside the activation radius, Journey spins up a private instance just for them (and their party), ticks it for as long as they’re in range, and tears it down when they complete it, die, or walk away. Inside the instance, you have elements — configurable objects like spawners, objectives, barriers, timers — that emit and listen for signals to wire up custom behavior.

There are two flavors:

  • Per-player (default) — the owner and their party see their own instance. Everyone else sees nothing.
  • Shared persistent — one global instance visible to everyone in range. Useful for persistent world events, world bosses, or ambient gameplay.

FieldTypeDefaultDescription
nameString""Display name
descriptionString[][]Lore lines
iconIconReuses the task system icon type
origin{x,y,z}{0,0,0}World position; activation radius is centered here
radiusDouble30.0Proximity activation radius. Players are dropped out at radius * 2
dimensionString"minecraft:overworld"Dimension resource location
elementsElement[][]Members of the encounter
phasesObjectnullPhase map. First key is the entry phase.
resetResetConfigmode ∈ cooldown / one_time / daily / always, plus cooldown_ticks
rewardsRewardConfig[]nullEach { type, data }. Only type == "command" is implemented today
blocksMap{}Encounter-level fake blocks, visible regardless of phase
visibilityString"all"Default visibility tier for spawned entities
persistentBooleanfalseIf true, the instance isn’t auto-destroyed on range exit
persistent_modeString"shared""shared" or "per_player"
blueprintsObjectnullReusable bundles: spawn tables, loot tables, item blueprints, dialogues, sound packs, command pools, reward packs, variables

The ID is derived from the file basename (e.g. stone_tower.jsonjourney:stone_tower).

FieldTypeNotes
nameStringDisplay name
durationLongPhase duration in ticks. Drives on_duration_expire transitions
active_elementsString[]Whitelist of element IDs active in this phase. Falls back to each element’s active_in_phases list when null
transitionsPhaseTransition[]Outbound transitions
blocksMapPhase-only fake blocks (additive to the encounter-level blocks)
FieldNotes
targetPhase name, or complete / success / completed / failure / failed
on_signalSignal pattern listened for while this is the current phase
on_duration_expireFires when elapsed phase ticks meet the phase duration
on_all_objectives_completeFires when every active objective element with required = true is complete

Elements emit named signals. Other elements (and phase definitions) listen for those signals and react. Wiring is declarative JSON — no code, no scripts needed for most cases.

Each element’s signals list is a set of {on, action, target?, data?} entries. When a matching signal arrives, Journey performs the action.

ActionEffect
activateResolve target, activate it
deactivateResolve target, deactivate it
emitRe-emit a signal whose name comes from data.signal
transitionRequest a phase transition to target
scriptRun data.script through a Molang runtime
store_setSet a key in the encounter data store
store_increment / _decrement / _multiplyNumeric mutators
store_toggleBoolean toggle
anything elseFalls through to the element for type-specific actions (go_to_point, start_wave, set_stage, etc.)

Signal patterns are "sourceId:signalName" strings:

  • wave_1:all_dead — match source and name exactly
  • all_dead — match any source for that name
  • wave_1:* — match any signal from that source
  • *:entity_killed — match any source for that name
{
"elements": [
{
"id": "wave_1",
"type": "wave_spawner",
"signals": [
{ "on": "all_dead", "action": "activate", "target": "boss_door" }
]
},
{
"id": "boss_door",
"type": "barrier",
"initially_active": true,
"signals": [
{ "on": "objective_complete", "action": "deactivate", "target": "boss_door" },
{ "on": "boss:entity_killed", "action": "transition", "target": "victory" }
]
},
{ "id": "boss", "type": "spawner" }
],
"phases": {
"fight": { "transitions": [ { "target": "victory", "on_signal": "boss_dead" } ] },
"victory": { }
}
}

When every wave 1 entity dies, the boss door deactivates. When the boss’s entity_killed signal fires, the encounter transitions to the victory phase. Done — all declarative JSON.


A definition with a non-empty phases map becomes phased — the first key is the entry phase. Each phase has its own active element whitelist, its own fake blocks, and its own outbound transitions.

Phase transitions can target another phase by name, or use the special targets below:

  • complete / success / completed → the encounter finishes and distributes rewards
  • failure / failed → the encounter is destroyed without running rewards
  • Any other name → enters that phase
"phases": {
"wave_1": { "duration": 600, "active_elements": ["spawner_1"], "transitions": [ { "target": "wave_2", "on_signal": "all_dead" } ] },
"wave_2": { "duration": 600, "active_elements": ["spawner_2"], "transitions": [ { "target": "boss", "on_signal": "all_dead" } ] },
"boss": { "active_elements": ["boss_spawner"],
"transitions": [ { "target": "victory", "on_signal": "boss_dead" },
{ "target": "failed", "on_duration_expire": true } ] },
"victory": { }
}

Wave 1, wave 2, boss fight, victory (or fail on time-out). Four phases, each with its own active element whitelist, gated by signal and duration.


Encounter entities can be hidden from non-participants using the visibility field on each element (or on the encounter as a default). Four values are supported:

TierBehavior
"all"Everyone in the world sees the entity. Fine for ambient set dressing, but not for participant-only mobs.
"eligible" / "party"Only the owner and their party see the entity. Other players in the same area see nothing.
"none"Nobody sees the entity except admins. Useful for trigger helpers and invisible logic elements.

When a managed encounter mob dies, its item and XP drops inherit the same viewer set — only participants can see or pick them up. Mobs with "all" visibility fall through to vanilla loot rules.


Two persistence modes encoded by persistent and persistent_mode:

ModeBehavior
persistent: falseDefault. Per-player instances, destroyed when the owner walks away or disconnects.
persistent: true, persistent_mode: "per_player"Per-player instances that stay alive (but stop updating) when the owner walks away.
persistent: true, persistent_mode: "shared"One global instance visible to everyone in range. Created automatically at server start. Never auto-destroyed.

PathMechanism
ProximityAutomatic — players within radius activate non-shared definitions.
Persistent shared (auto-start)Server start creates instances for persistent && persistent_mode == "shared".
Admin command/journey encounter start <id> [player]
Editor Test toolEditor hotbar slot 7.
Molang (inside an active encounter)Scripts running inside an encounter can activate / deactivate elements, request phase transitions, emit signals, and mutate the data store.
Tasks / NPCs / dialogues / zonesNo direct API today — shell out to /journey encounter start from a command reward or script.

The editor is invoked through /journey editor subcommands (requires journey.command.admin / OP level 3). It’s the fastest way to author encounters without hand-writing JSON.

SubcommandBehavior
new <name>Start a new editor session at the player’s position. Names must match ^[a-zA-Z0-9_:.-]+$.
edit <name>Open an existing definition for editing. Autocompletes from all loaded definitions.
cancelDiscard pending changes, revert blocks, restore player state.
saveSave and exit (equivalent to hotbar slot 8).

When you start an editor session, Journey captures your current gamemode, inventory, and position, flips you to creative, and hands you a 9-tool hotbar. save and cancel both restore everything.

The editor ships a full suite of sub-editors:

  • Encounter-level settings (origin, radius, dimension, reset, persistence)
  • Phase editor (phases, transitions, active element whitelists)
  • Signal wiring editor and wiring list browser
  • Element shape editor (custom shape overrides)
  • Blueprint editors: dialogue blueprints, command pools, item blueprints, loot tables, reward packs, sound packs, spawn tables, variable definitions
  • Interactable sub-editors: NPC preset picker, stage editor, visual state editor
  • Wave editor for wave_spawner elements
  • Element type picker

All encounter commands require journey.command.admin (OP level 3 fallback).

SubcommandBehavior
start <id> [player]Force-start an encounter for self or named player. Still respects cooldown.
stop <instanceId>Destroy an instance by UUID
list [definitions|active]List loaded definitions or all active instances
info <id>Print origin, radius, dimension, element list, phase list, reset config
reloadRe-scan encounter definitions
reset [id]Destroy and re-create the calling player’s matching active encounter(s)
debugToggle signal bus debug echo for the calling player
SubcommandBehavior
new <name>Start a new editor session
edit <name>Open an existing definition
cancelDiscard and restore
saveSave and exit

Two distinct reward concepts:

On completion, the encounter’s rewards list runs only for the owner, only if they’re still online. Currently only command rewards are implemented — the {player} placeholder is substituted and the command runs with suppressed output. Other reward types parse without error but are silently skipped.

Encounter mob drops inherit the mob’s visibility set, so only participants see and can pick up the drops. This works for both item drops and experience orbs.


Each instance owns a key-value data store seeded from blueprints.variables and mutated by signal-wiring store_* actions. The store uses type coercion driven by variable definitions (string, int, double, bool). This is the canonical way to share state between elements without relying on per-element custom data.


  • Player disconnect mid-encounter — all instances for that player are destroyed, including per-player persistent ones.
  • Player walks away — destroyed outside radius * 2, except for persistent_mode == "per_player" which only stops updating.
  • Missing element type — logged as a warning and skipped; the encounter still runs without that element.
  • Element with both position and offset set — absolute position wins.

  • Prefer signal wiring over hardcoded phase transitions. on_signal transitions pair well with emitter elements (wave spawner, objective, sequence).
  • Use the data store for cross-element state. store_set / store_increment wiring actions are more robust than chaining custom-data mutations through scripts.
  • Start with persistent: false. Per-player scoping is the default for a reason; escalate only when you genuinely need a global instance.
  • Run the editor “Test” tool frequently. Hot-iterate without leaving creative.
  • Split content into blueprint bundles. Reusable spawn tables, loot tables, and dialogue blueprints scale cleanly across encounters.
  • Namespace element ids. Prefer wave_1_spawner over spawner1 to avoid collisions when copy-pasting phases.