Reference Verse compiles

Sea-Stack Pillars: your shared helper module

Seven lessons into the Coastal Race, your timing logic, array lookups, and debug prints are scattered across files like flotsam after a storm. This lesson extracts them into ONE shared module — RaceHelpers, with FormatTime, SafeIndex, and RaceLog — that every later lesson in the West Coves imports with a single using{} line. It is the module-building skill from Barnaby's North Jungle lessons, promoted into the SOLID layering habit the rest of the island runs on.

Updated Examples verified on the live UEFN compiler
Watch the Knotshared_helper_module in ~90 seconds.

Overview

A shared helper module is a Verse module block (or a folder whose name becomes a module) that holds functions, constants, and types you want to call from more than one creative_device on your island. Instead of copy-pasting the same "reset the timer and award points" logic into five different devices, you write it once in the module and import it everywhere.

When to reach for it:

  • You have two or more devices that need to run the same sequence of API calls (e.g., start a timer, play a cinematic, then teleport the winner).
  • You want to enforce consistent game rules — every scoring moment goes through the same function, so tweaking the formula is a one-line change.
  • Your OnBegin bodies are growing past ~30 lines and you want to name the intent clearly.

The sunny cove scenario: players dive off a clifftop dock, swim through a glowing underwater arch, and surface at a shore checkpoint. A pressure plate triggers the challenge. A shared module handles the "challenge started" and "challenge completed" logic — starting the countdown timer, playing the cinematic fanfare, awarding score, and teleporting the winner back to the dock — so both the start device and the finish device call the same helpers.

API Reference

(API surface could not be resolved for this device.)

Walkthrough

We'll build three files:

  1. cove_helpers.verse — the shared module with two helper functions.
  2. cove_challenge_start.verse — the device placed at the clifftop dock that calls StartChallenge.
  3. cove_challenge_finish.verse — the device placed at the shore checkpoint that calls CompleteChallenge.

File 1 — cove_helpers.verse (the shared module)

using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }

# Folder name = module name: cove_helpers
# Any device in the project can `using { cove_helpers }` to access these.
cove_helpers := module:

    # Starts the cove challenge for an agent:
    # resets + starts the timer, plays the intro cinematic.
    StartChallenge(Agent : agent,
                   ChallengeTimer : timer_device,
                   IntroCinematic : cinematic_sequence_device) : void =
        ChallengeTimer.Reset(Agent)
        ChallengeTimer.Start(Agent)
        IntroCinematic.Play(Agent)

    # Completes the cove challenge for an agent:
    # stops the timer, awards score, plays the win cinematic, teleports back to dock.
    CompleteChallenge(Agent : agent,
                      ChallengeTimer : timer_device,
                      Scorer : score_manager_device,
                      WinCinematic : cinematic_sequence_device,
                      DockTeleporter : teleporter_device) : void =
        ChallengeTimer.Reset(Agent)
        Scorer.Activate(Agent)
        WinCinematic.Play(Agent)
        DockTeleporter.Teleport(Agent)

Line-by-line explanation

Line What it does
cove_helpers := module: Declares the module. Because this file lives in a folder called cove_helpers, UEFN maps the folder to this module name automatically.
StartChallenge(...) Plain Verse function — no class, no @editable. Takes live device references passed in by the caller.
ChallengeTimer.Reset(Agent) Calls timer_device.Reset(Agent:agent) — resets the countdown for this specific player.
ChallengeTimer.Start(Agent) Calls timer_device.Start(Agent:agent) — begins the countdown.
IntroCinematic.Play(Agent) Calls cinematic_sequence_device.Play(Agent:agent) — plays the splash-entry sequence for that player.
CompleteChallenge(...) Stops the timer, grants points, plays the win fanfare, teleports the player back to the dock.
Scorer.Activate(Agent) Calls score_manager_device.Activate(Agent:agent) — awards the configured point value to the agent.
DockTeleporter.Teleport(Agent) Calls teleporter_device.Teleport(Agent:agent) — sends the player directly to the dock teleporter's location.

File 2 — cove_challenge_start.verse (clifftop dock device)

This creative_device is placed at the pressure plate on the dock. When a player steps on it, it calls the shared StartChallenge helper.

using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { cove_helpers }

cove_challenge_start := class(creative_device):

    # Wire these in the UEFN Details panel
    @editable
    DockTimer : timer_device = timer_device{}

    @editable
    IntroCinematic : cinematic_sequence_device = cinematic_sequence_device{}

    # Called once when the island starts
    OnBegin<override>()<suspends> : void =
        # The trigger_device / pressure plate fires an agent event;
        # here we simulate that with a damage_volume at the dock edge.
        DockVolume.AgentEntersEvent.Subscribe(OnPlayerEntersDock)

    @editable
    DockVolume : damage_volume_device = damage_volume_device{}

    # Handler: player stepped onto the dock launch zone
    OnPlayerEntersDock(Agent : agent) : void =
        # Delegate all setup logic to the shared helper
        StartChallenge(Agent, DockTimer, IntroCinematic)

File 3 — cove_challenge_finish.verse (shore checkpoint device)

Placed at the glowing arch at the shore. When a player surfaces through it, CompleteChallenge fires.

using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { cove_helpers }

cove_challenge_finish := class(creative_device):

    @editable
    DockTimer : timer_device = timer_device{}

    @editable
    Scorer : score_manager_device = score_manager_device{}

    @editable
    WinCinematic : cinematic_sequence_device = cinematic_sequence_device{}

    @editable
    DockTeleporter : teleporter_device = teleporter_device{}

    @editable
    FinishVolume : damage_volume_device = damage_volume_device{}

    OnBegin<override>()<suspends> : void =
        FinishVolume.AgentEntersEvent.Subscribe(OnPlayerReachesShore)

    OnPlayerReachesShore(Agent : agent) : void =
        CompleteChallenge(Agent, DockTimer, Scorer, WinCinematic, DockTeleporter)

Both devices share zero duplicated logic. Changing the scoring formula or swapping the cinematic means editing cove_helpers.verse once.


Common patterns

Pattern 1 — Disabling the finish zone until the challenge is active

Use damage_volume_device.Disable() to prevent players from cheating by running straight to the shore.

using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }

cove_gate_controller := class(creative_device):

    @editable
    StartVolume : damage_volume_device = damage_volume_device{}

    @editable
    FinishVolume : damage_volume_device = damage_volume_device{}

    OnBegin<override>()<suspends> : void =
        # Shore checkpoint is OFF until the challenge begins
        FinishVolume.Disable()
        StartVolume.AgentEntersEvent.Subscribe(OnChallengeBegins)

    OnChallengeBegins(Agent : agent) : void =
        # Now the finish zone is live for everyone
        FinishVolume.Enable()
        # Optionally re-disable after a window using timer SuccessEvent

Pattern 2 — Teleporting the player back to the dock on timer failure

If the countdown expires before the player reaches shore, teleport them back and reset.

using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }

cove_timeout_handler := class(creative_device):

    @editable
    ChallengeTimer : timer_device = timer_device{}

    @editable
    DockTeleporter : teleporter_device = teleporter_device{}

    @editable
    DockSpawner : player_spawner_device = player_spawner_device{}

    OnBegin<override>()<suspends> : void =
        ChallengeTimer.FailureEvent.Subscribe(OnTimerFailed)

    # FailureEvent sends ?agent — must unwrap before use
    OnTimerFailed(MaybeAgent : ?agent) : void =
        if (Agent := MaybeAgent?):
            # Send them back to the dock start
            DockTeleporter.Teleport(Agent)
            ChallengeTimer.Reset(Agent)

Key point: timer_device.FailureEvent is a listenable(?agent) — the agent is optional. Always unwrap with if (Agent := MaybeAgent?): before calling any agent-typed API.

Pattern 3 — Tracking the challenge winner with player_reference_device

Record which player completed the cove challenge fastest so a leaderboard hologram can display them.

using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }

cove_winner_tracker := class(creative_device):

    @editable
    FinishVolume : damage_volume_device = damage_volume_device{}

    @editable
    WinnerReference : player_reference_device = player_reference_device{}

    @editable
    Scorer : score_manager_device = score_manager_device{}

    OnBegin<override>()<suspends> : void =
        FinishVolume.AgentEntersEvent.Subscribe(OnPlayerFinished)
        # React whenever the tracked winner changes
        WinnerReference.AgentUpdatedEvent.Subscribe(OnWinnerUpdated)

    OnPlayerFinished(Agent : agent) : void =
        # Register this agent as the current winner
        WinnerReference.Register(Agent)
        # Award score
        Scorer.Activate(Agent)

    OnWinnerUpdated(NewWinner : agent) : void =
        # The hologram on player_reference_device now shows the new winner automatically
        # You could also play a fanfare here
        WinnerReference.Activate()

Gotchas

1. Module functions receive device references — they don't own @editable fields

A plain module function cannot declare @editable fields. Those belong to creative_device classes. Pass your placed devices as parameters to module functions, as shown in the walkthrough. Trying to put @editable inside a module block is a compile error.

2. timer_device.FailureEvent and SuccessEvent send ?agent, not agent

Both events are listenable(?agent). Your handler signature must be (MaybeAgent : ?agent) and you must unwrap: if (Agent := MaybeAgent?):. Forgetting the ? causes a type mismatch compile error.

3. cinematic_sequence_device.Play(Agent) requires the device set to a specific player mode

Play() (no argument) works when the device is set to Everyone. Play(Agent:agent) requires the device to be set to a mode other than Everyone in the Details panel. Mismatching these silently does nothing at runtime.

4. score_manager_device.Activate(Agent) respects the Activating Team setting

If you set Activating Team to a specific team in the Details panel, only agents on that team will have their score updated. If you're calling it from a shared helper and scores aren't registering, check the device's team filter first.

5. Module using imports must be in every file that references the module's symbols

Adding using { cove_helpers } in cove_challenge_start.verse does NOT make it available in cove_challenge_finish.verse. Each file needs its own using directive.

6. damage_volume_device.SetDamage clamps between 1 and 500

If you repurpose a damage_volume_device purely as a trigger zone (no actual damage), set its Damage Per Second to 1 in the Details panel and rely on AgentEntersEvent for logic — or set it to 0 damage in the panel (the SetDamage API clamps to 1 minimum, but the panel allows 0).

7. No intfloat auto-conversion

If you pass a score delta as an int to a function expecting float (or vice versa), Verse will not coerce it. Use explicit casts: Float(MyInt) or Int[MyFloat] (the latter is failable).

Build your own lesson with shared_helper_module

Generate a personalized, step-by-step lesson plan built around this object — grounded in this exact reference and our compile-verified knowledge base.

Build a lesson →