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.