Reference Verse compiles

GetPlayerFromAgent: Turning Any Agent Into a Player

Almost every Fortnite device event hands you an `agent` — but many APIs you actually want to call need a `player`. The `GetPlayerFromAgent` function is the one-line bridge between those two types. In this article you'll learn exactly how to use it, why it can fail, and how to handle both outcomes gracefully — all set on a sun-drenched pirate cove where a dockside pressure plate triggers a cannon-fire cinematic just for the player who steps on it.

Updated Examples verified on the live UEFN compiler

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 agent or ?agent and you need a player.
  • Before calling APIs that require a player argument (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:

  1. Place a Trigger Device on the dock — this is the pressure plate.
  2. Place a Cinematic Sequence Device — your cannon-fire sequence.
  3. Place a Teleporter Device pointed at the treasure island.
  4. Create a new Verse device, paste the code below, and wire the three @editable fields 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.

Guides & scripts that use player

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

Build your own lesson with player

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 →