Reference Verse compiles

Lost at Sea: detect_player_leave Lifecycle Cleanup

Down in the Deeps, a disconnect is a ledger problem: a diver who vanishes mid-round takes un-banked relics with them and leaves ghost entries in every [player]-keyed map. This lesson wires `GetPlayspace().PlayerRemovedEvent()` into a cleanup handler that returns the leaver's relics to the round ledger and removes their map entries safely — using the option-returning lookup pattern from West Coves as the one safe door into the map.

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

Overview

The Detect Player Leave device (Verse type: player_left_device) raises a single listenable event — PlayerLeftEvent — whenever a player exits the session. Drop one into your level, reference it from a creative_device, and subscribe to that event in OnBegin. From that moment on, every departure triggers your handler.

When to reach for it:

  • Seal a vault or close a gate when the player who was guarding it leaves.
  • Award bonus loot to surviving players when an opponent disconnects.
  • Log or persist a player's progress before they fully exit.
  • Trigger a cinematic or ambient sound at the clifftop cove when the last player leaves a zone.

Because the event fires after the player has already left, you cannot interact with their character — but you still receive the agent reference for stat lookups, map cleanup, and team-logic decisions.

API Reference

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

Walkthrough

Scenario: A sun-drenched clifftop cove holds a glowing treasure vault. One player is assigned as the Vault Guardian. The moment that guardian leaves the island — rage-quit, disconnect, or session end — the vault door slams shut, a warning billboard flashes, and every remaining player hears the alarm. We use PlayerLeftEvent to detect the departure and IsReferenced on a companion Player Reference device to check whether the leaver was specifically the guardian.

using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }

# Localisation helper — message params must be <localizes>
VaultMessage<localizes>(S : string) : message = "{S}"

clifftop_vault_manager := class(creative_device):

    # A Player Reference device pre-configured to track the Vault Guardian
    @editable
    GuardianReference : player_reference_device = player_reference_device{}

    # A Mutator Zone or Trigger that represents the vault door being "sealed"
    @editable
    VaultSealTrigger : trigger_device = trigger_device{}

    # A Billboard device to flash the warning message
    @editable
    WarningBoard : billboard_device = billboard_device{}

    # Called once when the island starts
    OnBegin<override>()<suspends> : void =
        # Subscribe: whenever any player leaves the session, call OnPlayerLeft
        GetPlayspace().PlayerRemovedEvent().Subscribe(OnPlayerLeft)

    # Handler — fires each time a player leaves the session
    OnPlayerLeft(LeavingAgent : agent) : void =
        # Check: was the leaver the designated Vault Guardian?
        GuardianAgent := GuardianReference.GetAgent()
        if (GuardianAgent = LeavingAgent):
            # Guardian is gone — seal the clifftop vault immediately
            VaultSealTrigger.Trigger()
            # Flash the billboard with a localized warning
            WarningBoard.SetText(VaultMessage("⚠ The Guardian has left — Vault Sealed!"))```

**Line-by-line breakdown:**

| Lines | What's happening |
|---|---|
| `@editable LeaveDetector` | Binds the placed Detect Player Leave device so Verse can subscribe to it. |
| `@editable GuardianReference` | Binds a Player Reference device that the designer has pointed at the Guardian player slot. |
| `@editable VaultSealTrigger` | A Trigger device whose "Triggered" output is wired to the vault door's close animation. |
| `@editable WarningBoard` | A Billboard device that displays text to all players. |
| `LeaveDetector.PlayerLeftEvent.Subscribe(OnPlayerLeft)` | Registers our handler  from this point every player departure calls `OnPlayerLeft`. |
| `OnPlayerLeft(LeavingAgent : agent)` | The handler receives the departing player as an `agent`. |
| `GuardianReference.IsReferenced[LeavingAgent]` | Uses the failable `<decides>` method inside an `if`  succeeds only if the leaver is the tracked guardian. |
| `VaultSealTrigger.Trigger()` | Fires the trigger, closing the vault door. |
| `WarningBoard.SetText(...)` | Updates the billboard with a localized `message` value. |

## Common patterns

### Pattern 1 — Count remaining players and end the game when the island empties

Use `PlayerLeftEvent` to decrement a counter; when it hits zero, trigger a game-over sequence at the dock.

```verse
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }

dock_session_manager := class(creative_device):

    @editable
    LeaveDetector : player_left_device = player_left_device{}

    # An End Game device placed at the sunny dock
    @editable
    GameEnder : end_game_device = end_game_device{}

    # Mutable player count — updated as players leave
    var ActivePlayerCount : int = 0

    OnBegin<override>()<suspends> : void =
        # Snapshot current player count at game start
        AllPlayers := GetPlayspace().GetPlayers()
        set ActivePlayerCount = AllPlayers.Length
        LeaveDetector.PlayerLeftEvent.Subscribe(OnPlayerLeft)

    OnPlayerLeft(LeavingAgent : agent) : void =
        set ActivePlayerCount = ActivePlayerCount - 1
        if (ActivePlayerCount <= 0):
            # Last player left the cove — end the session
            GameEnder.Activate(LeavingAgent)

Key point: GetPlayspace().GetPlayers() gives the count at start; we decrement on each PlayerLeftEvent. When the dock is empty, end_game_device.Activate wraps the session.


Pattern 2 — Persist a stat snapshot the moment a player leaves

Capture the player's score (via a linked player_counter_device) before they fully exit, so the leaderboard stays accurate.

using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }

shore_stat_saver := class(creative_device):

    @editable
    LeaveDetector : player_left_device = player_left_device{}

    # A Stat Tracker device that has been counting this player's fish caught
    @editable
    FishCounter : stat_tracker_device = stat_tracker_device{}

    # A Billboard to display the last recorded score at the shore
    @editable
    ScoreBoard : billboard_device = billboard_device{}

    ScoreLabel<localizes>(N : int) : message = "Last leaver caught {N} fish!"

    OnBegin<override>()<suspends> : void =
        LeaveDetector.PlayerLeftEvent.Subscribe(OnPlayerLeft)

    OnPlayerLeft(LeavingAgent : agent) : void =
        # Read the current tracked stat value before the player is gone
        LastScore := FishCounter.GetStatValue()
        ScoreBoard.SetText(ScoreLabel(LastScore))

Key point: stat_tracker_device.GetStatValue() returns an int — no conversion needed. We call it synchronously inside the handler before the session cleans up the player's data.


Pattern 3 — Check if the leaver was the tracked guardian using IsReferenced

A focused snippet showing IsReferenced as a guard clause — useful whenever you only care about one specific player leaving, not the whole lobby.

using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }

cove_guardian_check := class(creative_device):

    @editable
    LeaveDetector : player_left_device = player_left_device{}

    @editable
    GuardianRef : player_reference_device = player_reference_device{}

    # Cinematic sequencer to play the "guardian gone" cutscene at the cove
    @editable
    GuardianGoneCinematic : cinematic_sequence_device = cinematic_sequence_device{}

    OnBegin<override>()<suspends> : void =
        LeaveDetector.PlayerLeftEvent.Subscribe(OnPlayerLeft)

    OnPlayerLeft(LeavingAgent : agent) : void =
        # IsReferenced<decides> — only enters the if-block for the tracked player
        if (GuardianRef.IsReferenced[LeavingAgent]):
            GuardianGoneCinematic.Play()

Key point: IsReferenced is a <decides> method — call it inside if (...) with bracket syntax [LeavingAgent], not parentheses. It silently fails (no runtime error) for every other leaver.

Gotchas

1. The agent is already gone — don't try to move or damage them

By the time PlayerLeftEvent fires, the player's character has been removed from the world. Calling character-manipulation APIs (teleport, damage, etc.) on the LeavingAgent will silently fail or throw a runtime error. Use the agent only for identity checks (IsReferenced) or stat reads.

2. IsReferenced uses bracket syntax, not parentheses

IsReferenced is marked <decides>, meaning it can fail. Always call it inside an if expression using square brackets:

# CORRECT
if (MyRef.IsReferenced[LeavingAgent]):
    ...
# WRONG — won't compile
if (MyRef.IsReferenced(LeavingAgent)):
    ...

3. SetText requires a <localizes> message, not a raw string

Billboard's SetText takes a message type. Declare a helper function with <localizes> and pass that — you cannot pass a plain string literal directly:

# CORRECT
MyLabel<localizes>(S : string) : message = "{S}"
Board.SetText(MyLabel("Vault Sealed"))
# WRONG — compile error
Board.SetText("Vault Sealed")

4. PlayerLeftEvent fires for ALL players — filter when you need specifics

If your logic only applies to one player (the guardian, the host, a VIP), always gate your handler with IsReferenced or a stored agent comparison. Without a filter, every departure — including spectators and late-joiners — triggers your logic.

5. int ↔ float is never automatic

GetStatValue() returns int. If you need it as a float (e.g., for a timer calculation), cast explicitly: Float(GetStatValue()). Verse will not coerce types silently.

Guides & scripts that use fort_playspace

Step-by-step tutorials that put this object to work.

Build your own lesson with fort_playspace

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 →