Overview
In Verse, agent is the broad base type for anything that can act in the world — players, NPCs, and more. player is the narrower type that represents a real human in the session. Most device events (like trigger_device.TriggeredEvent) fire with an ?agent payload because they can be triggered by code as well as by humans.
When you need to do something player-specific — spawn them at a pad, teleport them, register them with a score manager — you must first prove the agent is actually a player. That's exactly what GetPlayerFromAgent does:
GetPlayerFromAgent(Agent : agent) <decides><transacts> : player
It is a failable expression (note <decides>). If the agent is an NPC or the trigger fired from code, it fails and your if block is skipped — no crash, no undefined behaviour, just clean branching.
When to reach for it:
- Any time a device event gives you an
agentor?agentand you need aplayer. - Before calling APIs that require a
playerargument (e.g.player_spawner_device.SpawnPlayer,teleporter_device.Teleport). - When you want to gate logic so only human players — not NPCs — trigger an effect.
API Reference
player
Full public surface, resolved verbatim from the live Epic digest (Verse.digest.verse). Inherited members are merged from agent.
player<native><public> := class<unique><persistent><module_scoped_var_weak_map_key><epic_internal>(agent):
agent
Full public surface, resolved verbatim from the live Epic digest (Verse.digest.verse). Inherited members are merged from entity.
agent<native><public> := class<unique><epic_internal>(entity):
trigger_device
Used to relay events to other linked devices.
Full public surface, resolved verbatim from the live Epic digest (Fortnite.digest.verse). Inherited members are merged from trigger_base_device.
trigger_device<public> := class<concrete><final>(trigger_base_device):
Events (subscribe a handler to react):
| Event | Signature | Description |
|---|---|---|
TriggeredEvent |
TriggeredEvent<public>:listenable(?agent) |
Signaled when an agent triggers this device. Sends the agent that used this device. Returns false if no agent triggered the action (ex: it was triggered through code). |
Methods (call these to make the device act):
| Method | Signature | Description |
|---|---|---|
Trigger |
Trigger<public>(Agent:agent):void |
Triggers this device with Agent being passed as the agent that triggered the action. Use an agent reference when this device is setup to require one (for instance, you want to trigger the device only with a particular agent. |
Trigger |
Trigger<public>():void |
Triggers this device, causing it to activate its TriggeredEvent event. |
Enable |
Enable<public>():void |
Enables this device. |
Disable |
Disable<public>():void |
Disables this device. |
SetMaxTriggerCount |
SetMaxTriggerCount<public>(MaxCount:int):void |
Sets the maximum amount of times this device can trigger. * 0 can be used to indicate no limit on trigger count. * MaxCount is clamped between [0,20]. |
GetMaxTriggerCount |
GetMaxTriggerCount<public>()<transacts>:int |
Gets the maximum amount of times this device can trigger. * 0 indicates no limit on trigger count. |
GetTriggerCountRemaining |
GetTriggerCountRemaining<public>()<transacts>:int |
Returns the number of times that this device can still be triggered before hitting GetMaxTriggerCount. Returns 0 if GetMaxTriggerCount is unlimited. |
SetResetDelay |
SetResetDelay<public>(Time:float):void |
Sets the time (in seconds) after triggering, before the device can be triggered again (if MaxTrigger count allows). |
GetResetDelay |
GetResetDelay<public>()<transacts>:float |
Gets the time (in seconds) before the device can be triggered again (if MaxTrigger count allows). |
SetTransmitDelay |
SetTransmitDelay<public>(Time:float):void |
Sets the time (in seconds) which must pass after triggering, before this device informs other external devices that it has been triggered. |
GetTransmitDelay |
GetTransmitDelay<public>()<transacts>:float |
Gets the time (in seconds) which must pass after triggering, before this device informs other external devices that it has been triggered. |
Walkthrough
Scenario: The Pirate Cove Cannon
You've built a 2D cel-shaded pirate cove. A pressure plate sits on the dock. When a player (not an NPC, not a code trigger) steps on it, a cinematic cannon-fire sequence plays just for them, and they're teleported to the treasure island across the lagoon. NPCs and code-fired triggers are silently ignored.
UEFN scene setup:
- Place a Trigger Device on the dock — this is the pressure plate.
- Place a Cinematic Sequence Device — your cannon-fire sequence.
- Place a Teleporter Device pointed at the treasure island.
- Create a new Verse device, paste the code below, and wire the three
@editablefields in the Details panel.
using { /Fortnite.com/Devices }
using { /Fortnite.com/Game }
using { /Verse.org/Simulation }
# Pirate cove dock: step on the plate → cannon cinematic → teleport to treasure island.
cannon_dock_device := class(creative_device):
# Wire this to the Trigger Device on the dock.
@editable
DockPlate : trigger_device = trigger_device{}
# Wire this to the Cinematic Sequence Device (cannon fire).
@editable
CannonSequence : cinematic_sequence_device = cinematic_sequence_device{}
# Wire this to the Teleporter Device aimed at the treasure island.
@editable
TreasureTeleporter : teleporter_device = teleporter_device{}
OnBegin<override>()<suspends> : void =
# Subscribe to the dock plate. The handler runs every time someone steps on it.
DockPlate.TriggeredEvent.Subscribe(OnDockStepped)
# Called by TriggeredEvent — payload is ?agent (optional agent).
OnDockStepped(MaybeAgent : ?agent) : void =
# Step 1 — unwrap the optional. If nobody triggered it (code-fired), stop here.
if (A := MaybeAgent?):
# Step 2 — prove the agent is a real player, not an NPC.
if (P := player[A]):
# Step 3 — play the cannon cinematic for this specific player.
CannonSequence.Play(P)
# Step 4 — teleport them to the treasure island.
TreasureTeleporter.Teleport(P)```
### Line-by-line explanation
| Lines | What's happening |
|---|---|
| `@editable` fields | Expose the three placed devices to the Details panel so you can wire them without touching code. |
| `DockPlate.TriggeredEvent.Subscribe(OnDockStepped)` | Registers `OnDockStepped` as the callback. Every step fires it. |
| `OnDockStepped(MaybeAgent : ?agent)` | `TriggeredEvent` is `listenable(?agent)` — the payload is *optional*, so the parameter type must be `?agent`. |
| `if (A := MaybeAgent?)` | Unwraps the optional. If the trigger fired from code with no agent, `MaybeAgent` is `false` and we bail cleanly. |
| `if (P := GetPlayerFromAgent(A))` | The failable cast. Succeeds only for human players. NPCs fall through silently. |
| `CannonSequence.Play(P)` | Plays the cinematic *for that player* — the agent-overload targets a specific participant. |
| `TreasureTeleporter.Teleport(P)` | Sends only that player across the lagoon. |
## Common patterns
### Pattern 1 — Spawn a player at a custom pad on trigger
A second pressure plate on the treasure island respawns only the triggering player at the cove's spawn pad (useful for a reset mechanic).
```verse
using { /Fortnite.com/Devices }
using { /Fortnite.com/Game }
using { /Verse.org/Simulation }
# Respawn the triggering player at the cove spawn pad.
respawn_plate_device := class(creative_device):
@editable
ResetPlate : trigger_device = trigger_device{}
@editable
CoveSpawnPad : player_spawner_device = player_spawner_device{}
OnBegin<override>()<suspends> : void =
ResetPlate.TriggeredEvent.Subscribe(OnResetStepped)
OnResetStepped(MaybeAgent : ?agent) : void =
if (A := MaybeAgent?):
if (P := GetPlayerFromAgent(A)):
# SpawnPlayer requires a player, not just an agent.
CoveSpawnPad.SpawnPlayer(P)
Pattern 2 — Limit the trigger to one use per player, then disable it
The cannon should only fire once per session. After the first real player steps on it, disable the plate and use SetMaxTriggerCount to cap future code-side triggers too.
using { /Fortnite.com/Devices }
using { /Fortnite.com/Game }
using { /Verse.org/Simulation }
# One-shot cannon plate: fires once for a real player, then locks out.
one_shot_cannon_device := class(creative_device):
@editable
DockPlate : trigger_device = trigger_device{}
@editable
CannonSequence : cinematic_sequence_device = cinematic_sequence_device{}
OnBegin<override>()<suspends> : void =
# Allow exactly one trigger from this point forward.
DockPlate.SetMaxTriggerCount(1)
DockPlate.TriggeredEvent.Subscribe(OnFirstStep)
OnFirstStep(MaybeAgent : ?agent) : void =
if (A := MaybeAgent?):
if (P := GetPlayerFromAgent(A)):
CannonSequence.Play(P)
# Disable so no one else can fire it.
DockPlate.Disable()
Pattern 3 — Delayed transmit: show a cinematic, then teleport after a pause
Use SetTransmitDelay on a second trigger to create a gap between the cannon blast and the teleport, so the sequence has time to play.
using { /Fortnite.com/Devices }
using { /Fortnite.com/Game }
using { /Verse.org/Simulation }
# Cannon fires, waits 4 seconds, then teleports the player.
delayed_cannon_device := class(creative_device):
@editable
DockPlate : trigger_device = trigger_device{}
@editable
DelayRelay : trigger_device = trigger_device{}
@editable
CannonSequence : cinematic_sequence_device = cinematic_sequence_device{}
@editable
TreasureTeleporter : teleporter_device = teleporter_device{}
OnBegin<override>()<suspends> : void =
# The relay trigger will wait 4 s before signalling downstream devices.
DelayRelay.SetTransmitDelay(4.0)
DockPlate.TriggeredEvent.Subscribe(OnDockStepped)
DelayRelay.TriggeredEvent.Subscribe(OnDelayFired)
OnDockStepped(MaybeAgent : ?agent) : void =
if (A := MaybeAgent?):
if (P := GetPlayerFromAgent(A)):
# Play cinematic immediately.
CannonSequence.Play(P)
# Fire the relay with this agent so the delay fires for them.
DelayRelay.Trigger(P)
OnDelayFired(MaybeAgent : ?agent) : void =
if (A := MaybeAgent?):
if (P := GetPlayerFromAgent(A)):
TreasureTeleporter.Teleport(P)
Gotchas
1. GetPlayerFromAgent is failable — always wrap it in if
GetPlayerFromAgent has the <decides> effect, meaning it can fail. Calling it outside an if (or other failable context) is a compile error. Always write:
if (P := GetPlayerFromAgent(A)):
# safe to use P here
Never assume the agent is a player — NPCs, AI creatures, and code-fired triggers all produce non-player agents.
2. The TriggeredEvent payload is ?agent, not agent
trigger_device.TriggeredEvent is typed listenable(?agent). Your handler parameter must be ?agent. Forgetting the ? is a type mismatch compile error. Unwrap with if (A := MaybeAgent?) before passing to GetPlayerFromAgent.
3. Don't confuse agent overloads with player overloads
Many devices have two overloads — one taking agent, one taking player. cinematic_sequence_device.Play(Agent:agent) and teleporter_device.Teleport(Agent:agent) both accept agent, so you could skip the cast there — but player_spawner_device.SpawnPlayer(Player:player) requires a player. Casting early with GetPlayerFromAgent keeps your code consistent and future-proof.
4. SetMaxTriggerCount clamps between 0 and 20
Passing a value outside [0, 20] is silently clamped. Use 0 to mean unlimited. Check GetTriggerCountRemaining() if you need to know how many fires are left.
5. No StringToMessage — use a <localizes> function for text
If you ever want to display a player's name or a status string in a UI widget, you cannot pass a raw string where a message is expected. Declare a localizes helper:
StatusText<localizes>(S : string) : message = "{S}"
Then pass StatusText("Cannon fired!") wherever a message parameter is required.