Skip to main content

Race

Competitive race builder

The /lasers race command tree lets an admin assemble a ready-to-run competitive event in their own world — a series of published LasersEnigma puzzles arranged into a multi-copy race, with timing, scoreboard and ranking handled automatically. No command blocks, no buttons in the world, no hand-wired transition logic.

Concepts

Build

A build is a named, persisted competitive event. It carries its configuration (ordered levels, players per copy, number of copies, exit teleporters) and — once generated — the structure placed in the world. Several builds can coexist on a server.

A build is mono-world: its origin is captured in a single world the first time generate is run, and every subsequent operation stays in that world.

Build state machine

  • DRAFT — configuration only, nothing in the world.
  • GENERATINGgenerate in progress; the placement is written incrementally.
  • GENERATED — copy #1 and the spawn are placed. The admin defines the exit teleporters with the wand; each one placed appears in the world as a spinning gold triangle.
  • CONTINUINGcontinue in progress.
  • COMPLETE — every copy is placed. Ready to host runs.
  • GENERATION_FAILED / CONTINUATION_FAILED — terminal failure states (admin abort, exception, or server crash mid-operation). The world holds a partial placement that must be cleaned up with reset confirm (or delete confirm). On plugin startup, any surviving GENERATING is flipped to GENERATION_FAILED and any surviving CONTINUING to CONTINUATION_FAILED, so an interrupted operation surfaces as an explicit failure instead of a silently-dirty state.

Any state can additionally carry an in-flight lock (locked_by = admin UUID) while a destructive or generating operation is running. The lock is cleared unconditionally at plugin startup.

Run

A run is one execution of an event, identified by a 1-based run_index per build. Each start <name> increments the index and opens a new RUNNING run; any previously RUNNING run is flipped to CANCELLED.

A run ends in FINISHED (every group finished naturally) or CANCELLED (next start, stop, or reset / delete confirm). Run history is preserved by run_indexresults <name> [run] browses any past run.

Run groups

A run group is one SAS-locked group within a run. Each group has its own status (PENDING_STARTRUNNINGFINISHED), its own start time, and its own current level. Members are persisted by UUID so a group survives logouts and deaths.

Workflow

1. Create and configure the build

/lasers race create <name>

Opens an empty DRAFT. Build names cannot collide with reserved literal subcommands (create, delete, list, edit, addLevel, generate, continue, start, stop, reset, tp, results, confirm).

/lasers race edit <name>

Opens the builder menu. Header shows: state, level count, players per copy, copies count, exit-teleporters X/N, ready-to-do-next hint. From the menu:

  • Add a level by name (autocompleted from the website catalog). The schematic is downloaded and validated on add.
  • Reorder / remove levels via a timeline-style list.
  • Set players per copy (solo / duo / trio) — fixed for the whole build.
  • Set the number of copies (1–100).
  • Get exit-teleporter wand (available after generate).

Exit teleporters are not set here. The levels are not yet in the world. They are defined in step 3 with the wand.

⚠ Level-name tab-completion for /lasers race addLevel <name> <levelName> is fetched from the Lasers-Enigma website asynchronously, so the list is empty the first time you trigger it. Delete the space before <levelName> then type it again to refresh the suggestions.

2. Generate the test copy

/lasers race generate <name>

The build origin is the admin's position the moment generate runs, and the whole structure (spawn + every copy) is pasted from there along X+ and Z+. There is no undo, and the footprint check below only detects registered LasersEnigma Areas and other race builds — it does not detect arbitrary world structures (vanilla builds, plain block ranges). Stand far away from any existing build before running the command, or you will silently overwrite it.

The admin stands in a large open area and runs the command. The tool:

  • Takes the build's lock and transitions to GENERATING.
  • Captures the admin's current location as the build's mono-world origin and spawn anchor.
  • Validates the full footprint (spawn + all N copies) does not overlap any existing LasersEnigma Area or other race build. On conflict, a chat message names the conflicting element and gives a clickable sample XYZ point. This validation does not cover arbitrary world structures (vanilla builds, plain blocks) — only registered Areas and race builds.
  • Preloads and ticket-locks every chunk overlapping the footprint.
  • Pastes the level series once (copy #1), in order, with an action-bar progress.
  • Builds the spawn: a small structure sized for all N copies, with copy #1's SAS door, detection box, and a public spawn anchor. No buttons, no command blocks.
  • Commits every placement row right after the corresponding Bukkit operation — a mid-generate crash leaves a recoverable state.
  • Transitions to GENERATED, releases the lock, and chats the admin the next step.

3. Define exit teleporters with the wand

Open the builder menu → click "Get exit-teleporter wand". The admin receives a named item whose display name embeds the build name (so multi-build admins can tell their wands apart).

For each level of copy #1, the admin teleports to the spawn anchor (/lasers race tp <name>), walks through the spawn, into the SAS, out to a level, behind the victory door, and right-clicks with the wand. The tool:

  • Detects which level of copy #1 the admin is standing in.
  • Stores the absolute block coordinates of the trigger (world + x/y/z) for copy #1. No facing is stored — the marker spins on its own axis. The rows for copies 2..N are written later by continue, which replicates copy #1's teleporters to every copy.
  • If the admin is not inside any level: translated error listing the levels still undefined, with a clickable hint to /lasers race tp <name>.

Each placed teleporter is materialised in the world by a spinning gold triangle — a GOLD_BLOCK marker made of an ItemDisplay anchor carrying three BlockDisplay sides — so the admin and the players can see exactly where the level-completion trigger is. The marker re-spawns automatically when its chunk loads, and is removed when the build is reset, deleted or regenerated.

Once every exit teleporter is set, copy #1 is fully wired. The admin can walk through it manually, or /lasers race start <name> (with a SAS-locked group) to test the chrono and scoreboard.

4. Generate the remaining copies

/lasers race continue <name>

Takes the lock, transitions to CONTINUING, re-validates the footprint for copies 2..N, preloads chunks, replicates the level series and SAS structure copy by copy, registers the new Areas in the runtime cache, and transitions to COMPLETE. The event is ready.

5. Run the event

Player flow

/lasers race list → see available events
/lasers race tp <name> → reach the spawn anchor (or auto-resume mid-race)
→ walk into a free SAS
→ wait for the SAS door to close
→ race level by level
/lasers race results <name> [run] [page]
→ view final times

Admin flow

/lasers race start <name>

Opens a new run (run_index = previous + 1); cancels any previously RUNNING run; promotes every PENDING_START group to RUNNING and teleports them simultaneously to level 1; starts the per-group chronos; appears the per-player race sidebar.

A SAS that locks after start (late joiners) becomes a RUNNING group of the current run immediately, with its own start_at_ms and an automatic teleport to level 1 — no further admin action required.

/lasers race stop <name>

Ends the current run early: it is flipped to CANCELLED (preserved in the history), every player still inside — racing or waiting in a SAS airlock — is sent back to the spawn anchor, and the airlock doors are reopened. The build stays GENERATED / COMPLETE, so a fresh start can open a new run right away. Unlike reset confirm, the world structure is left untouched.

Resume mechanic

A copy stays reserved for its group for the whole run. A player who leaves (uses /spawn, dies and respawns, logs off, or runs tp <name>) automatically returns to their group's current level on next login / respawn / tp. No commands required from the player.

If a member never returns and the group never finishes naturally, the admin can /lasers race stop <name> to end the run and send everyone back to the spawn (the build stays ready for another start), or /lasers race reset <name> confirm to additionally wipe the structure back to DRAFT.

The sidebar shows progression (current level), not time:

  • Top 15 groups by current level.
  • A personal row for the viewer if their group is outside the top.
  • Title: <build name> #<run index>.

Final times are persisted per run and queried via /lasers race results <name> [run] [page] — runnable by anyone, at any time, for any past run.

6. Edit a generated build

The admin can change configuration via the builder menu except while a run is RUNNING (translated error in that case — wait for the run to finish, or reset confirm to cancel it).

On a GENERATED / COMPLETE build, a mutating click (change players per copy, change copies count, reorder or remove a level) opens a chat-clickable yes/no confirm popup. The menu stays in pending state (further mutating clicks are refused with a translated "edit pending" message) until the admin answers:

  • YES → the tool runs the same cleanup as reset confirm (pre-cleanup teleport, block removal, ticket release) and re-runs generation from scratch. All exit teleporters must be redefined afterwards.
  • NO → the mutation is discarded; the build is unchanged.

If regeneration fails (e.g. a footprint conflict newly introduced), the build is left clean in DRAFT and the admin re-runs generate <name> after fixing the conflict.

7. Reset or delete

There is no separate cancel command. Two flows cover the cleanup space, both protected by the same confirm two-step with a chat-clickable hint that pre-fills the exact confirm command:

CommandEffect
/lasers race delete <name>On clean DRAFT, drops the config immediately. Otherwise: chat-clickable hint.
/lasers race delete <name> confirmPre-cleanup teleport (to origin), wipe the world structure, delete the configuration and the entire run history.
/lasers race reset <name>On clean DRAFT, translated error (nothing to reset). Otherwise: chat-clickable hint.
/lasers race reset <name> confirmPre-cleanup teleport (to spawn anchor), wipe the world structure, send the build back to DRAFT. Preserves the level list, players per copy, copies count and the run history.

The confirm token is intentionally not suggested in tab-completion — it is surfaced only through the chat hints, so destructive operations stay a deliberate action while keeping the autocompletion tree clean.

8. Crash / interruption recovery

If the server crashes between two commits during generate or continue, the build is left with a partial placement record. On plugin startup, any surviving GENERATING is flipped to GENERATION_FAILED and any surviving CONTINUING to CONTINUATION_FAILED, so the interruption surfaces as an explicit failure state; an admin chat hint suggests /lasers race reset <name> confirm (or delete <name> confirm) to clean them up. The cleanup service tolerates a partial placement record — every block actually placed is tracked, every block not placed is simply absent from the record.

What runs when (runtime diagram)

The race runtime is event-driven (Bukkit listeners) plus three scheduled tasks — no per-tick command block layer, no spawn buttons, no command-block logic. The tasks are RaceSasTask (SAS detection, every 10 ticks), RaceExitTeleporterDetectionTask (level-transition trigger, every 2 ticks) and ExitTeleporterRotationTask (visualization animation, every 4 ticks).

Key behaviours behind the diagram:

  • RaceTransitionListener (on RaceExitTeleporterCrossedEvent) resolves the crossed level's exit teleporter, teleports the player to the next level — or to the spawn anchor on the last level, after recording the result row — and updates current_level_order_index. When every member of a group has crossed the last level, the group becomes FINISHED, its copy is freed, the scoreboard is dropped and a group-finish broadcast is sent.
  • RaceExitTeleporterDetectionTask scans every online player every 2 ticks (< 100 ms latency), looks their feet block up in an O(1) map of teleporter coordinates, and fires the crossing event with a per-player debounce — standing still re-fires only after stepping off and back on.
  • RaceSasTask iterates every COMPLETE build with a free copy, checks each SAS detection box for the right number of non-spectator players, and on a match closes the IRON_DOOR, reserves the copy and persists a RUNNING group (if a run is open) or a PENDING_START group otherwise. Spectators are skipped; inactive builds early-out.
  • ExitTeleporterRotationTask spins every placed gold triangle and doubles as the display registry's self-cleanup heartbeat: entries whose root entity is gone (chunk unloaded, manual removal) are unregistered.

Per-player scoreboard lifecycle

TransitionWhen
AppliedOn SAS lock — every member of the freshly-locked group. On start <name> — every member of every group in the wave. On resume — the rejoining member.
RestoredOn PlayerQuitEvent — the leaving player's default scoreboard. On group FINISHED — every member of the finished group. On run CANCELLED (next start, stop, reset / delete confirm) — every member of every cancelled group. On plugin disable — every online member of every RUNNING group.

Command reference

All under /lasers race. Verb-first convention — the build name is always after the verb, never at the root. Admin-only (lasers.admin) except list, tp <name> and results <name> [run] [page], which are open to any player.

See /lasers race commands for the full table.

See also