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
OnBeginbodies 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:
cove_helpers.verse— the shared module with two helper functions.cove_challenge_start.verse— the device placed at the clifftop dock that callsStartChallenge.cove_challenge_finish.verse— the device placed at the shore checkpoint that callsCompleteChallenge.
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.FailureEventis alistenable(?agent)— the agent is optional. Always unwrap withif (Agent := MaybeAgent?):before calling anyagent-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 int↔float 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).