Reference Devices compiles

player_reference_device: Track, Display, and React to Any Player

The `player_reference_device` is your island's "spotlight" — it locks onto one agent, tracks a chosen stat (eliminations, score, time), fires events when that stat changes, and can project a hologram of the tracked player. Whether you're building a leaderboard, a most-wanted system, or a winner's podium, this device is the glue between raw game data and visual or logical reactions.

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

Overview

The player_reference_device solves a specific problem: you need to remember which player did something important and react whenever their stats change. Place one on your island, point it at a player with Register, and it becomes a live feed — signaling TrackedStatChangedEvent every time the tracked stat ticks up, AgentUpdatedEvent when the stored agent changes, and ActivatedEvent when you call Activate (which also ends the round). You can read the current stat with GetStatValue, check whether a particular agent is the one being tracked with IsReferenced, and retrieve the stored agent with GetAgent.

Reach for this device when you need:

  • A leaderboard that re-sorts as scores change
  • A most-wanted / bounty system that highlights the leading player
  • A winner's podium that shows the champion's hologram at round end
  • Any logic that must react to a specific player's stat in real time

API Reference

player_reference_device

Used to relay agent statistics to other devices and agents. Can transmit statistics such as elimination count, eliminated count, or scores when certain conditions are met. Can also project a hologram of the agent and display text that can be altered in various positions and curvatures.

Full public surface, resolved verbatim from the live Epic digest (Fortnite.digest.verse).

player_reference_device<public> := class<concrete><final>(creative_device_base):

Events (subscribe a handler to react):

Event Signature Description
ActivatedEvent ActivatedEvent<public>:listenable(agent) Signaled when this device is activated. Sends the agent stored in the device.
TrackedStatChangedEvent TrackedStatChangedEvent<public>:listenable(agent) Signaled when a stat tracked by this device is updated. Sends the agent stored in the device.
AgentUpdatedEvent AgentUpdatedEvent<public>:listenable(agent) Signaled when the agent tracked by this device is updated. Sends the new agent stored in the device.
AgentUpdateFailsEvent AgentUpdateFailsEvent<public>:listenable(agent) Signaled when the agent tracked by this fails to be updated. Sends the agent that attempted to be stored in this device.
AgentReplacedEvent AgentReplacedEvent<public>:listenable(agent) Signaled when the agent tracked by this device is replaced. Sends the new agent stored in the device.

Methods (call these to make the device act):

Method Signature Description
Enable Enable<public>():void Enables this device.
Disable Disable<public>():void Disables this device.
Activate Activate<public>():void Ends the round/game.
Register Register<public>(Agent:agent):void Registers Agent as the agent being tracked by this device.
Clear Clear<public>():void Clears the state of this device.
IsReferenced IsReferenced<public>(Agent:agent)<transacts><decides>:void Is true when Agent is the player being referenced by the device.
GetAgent GetAgent<public>():?agent Returns the agent currently referenced by the device.
GetStatValue GetStatValue<public>():int Returns the stat value that this device is currently tracking

Walkthrough

Scenario: Most-Wanted Bounty Board

A player steps on a pressure plate. Your Verse device registers them as the "most wanted" player on a player_reference_device. Every time that player's elimination count increases, a HUD message announces the new count. If a different player steps on the plate, the reference is replaced. When the tracked player's eliminations reach 5, the device activates (ending the round/game).

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

# Localizer helper — player_reference_device.Activate needs no message,
# but hud_message_device does.
bounty_device := class(creative_device):

    # Wire up in the UEFN Details panel
    @editable
    BountyReference : player_reference_device = player_reference_device{}

    @editable
    RegistrationPlate : trigger_device = trigger_device{}

    @editable
    AnnouncementHUD : hud_message_device = hud_message_device{}

    # How many eliminations trigger the round end
    EliminationGoal : int = 5

    OnBegin<override>()<suspends> : void =
        # Subscribe to the pressure plate — when any player steps on it,
        # register them as the most-wanted agent.
        RegistrationPlate.TriggeredEvent.Subscribe(OnPlateTriggered)

        # React every time the tracked stat (set to Eliminations in device
        # settings) changes for the registered agent.
        BountyReference.TrackedStatChangedEvent.Subscribe(OnStatChanged)

        # React when the stored agent is successfully swapped out.
        BountyReference.AgentUpdatedEvent.Subscribe(OnAgentUpdated)

        # React when an agent update fails (e.g., device is disabled).
        BountyReference.AgentUpdateFailsEvent.Subscribe(OnAgentUpdateFailed)

    # Called when a player steps on the plate.
    # TriggeredEvent sends ?agent, so we unwrap it.
    OnPlateTriggered(MaybeAgent : ?agent) : void =
        if (A := MaybeAgent?):
            # Check if this agent is already the one being tracked.
            # IsReferenced is a <decides> function — use it inside an if.
            if (BountyReference.IsReferenced[A]):
                # Already the most-wanted; nothing to do.
                AnnouncementHUD.SetText(AlreadyTrackedMsg())
            else:
                # Register the new agent as most-wanted.
                BountyReference.Register(A)

    # Called when the tracked stat changes.
    # The event sends the stored agent (not ?agent — it's a plain agent).
    OnStatChanged(TrackedAgent : agent) : void =
        CurrentStat := BountyReference.GetStatValue()
        # Announce the new elimination count via HUD.
        AnnouncementHUD.SetText(EliminationCountMsg(CurrentStat))

        # If the goal is reached, activate the device (ends the round).
        if (CurrentStat >= EliminationGoal):
            BountyReference.Activate()

    # Called when the stored agent is successfully replaced.
    OnAgentUpdated(NewAgent : agent) : void =
        AnnouncementHUD.SetText(NewBountyMsg())

    # Called when an update attempt fails.
    OnAgentUpdateFailed(FailedAgent : agent) : void =
        AnnouncementHUD.SetText(UpdateFailedMsg())

    # --- Localized message helpers ---
    AlreadyTrackedMsg<localizes>() : message = "Already the most-wanted!"
    NewBountyMsg<localizes>() : message = "New most-wanted player registered!"
    UpdateFailedMsg<localizes>() : message = "Could not update the most-wanted player."
    EliminationCountMsg<localizes>(Count : int) : message = "Most-wanted eliminations: {Count}"

Line-by-line explanation

Lines What's happening
@editable BountyReference Wires the placed player_reference_device into Verse via the Details panel.
RegistrationPlate.TriggeredEvent.Subscribe(OnPlateTriggered) Listens for any player stepping on the trigger.
BountyReference.TrackedStatChangedEvent.Subscribe(OnStatChanged) Fires whenever the tracked stat (configured in device settings) ticks up for the stored agent.
BountyReference.AgentUpdatedEvent.Subscribe(OnAgentUpdated) Fires when Register succeeds and the stored agent changes.
BountyReference.AgentUpdateFailsEvent.Subscribe(OnAgentUpdateFailed) Fires when a Register call is rejected (e.g., device disabled).
if (BountyReference.IsReferenced[A]) IsReferenced is <decides>, so it must live inside an if — it succeeds only when A is the currently stored agent.
BountyReference.Register(A) Stores A as the tracked agent; triggers AgentUpdatedEvent on success.
BountyReference.GetStatValue() Returns the current integer value of the tracked stat.
BountyReference.Activate() Ends the round/game — use this as your win condition trigger.
<localizes> helpers hud_message_device.SetText requires a message type; raw strings won't compile.

Common patterns

Pattern 1 — Enable/Disable and GetAgent for a conditional spotlight

Only allow registration during a specific phase. After the phase ends, disable the device and retrieve the stored agent to drive downstream logic (e.g., spawn a trophy).

using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }

spotlight_phase_device := class(creative_device):

    @editable
    Spotlight : player_reference_device = player_reference_device{}

    @editable
    PhaseTimer : timer_device = timer_device{}

    @editable
    RegistrationPlate : trigger_device = trigger_device{}

    @editable
    AnnouncementHUD : hud_message_device = hud_message_device{}

    OnBegin<override>()<suspends> : void =
        # Start with the device enabled so registrations are accepted.
        Spotlight.Enable()
        RegistrationPlate.TriggeredEvent.Subscribe(OnPlateTriggered)
        PhaseTimer.SuccessEvent.Subscribe(OnPhaseEnd)

    OnPlateTriggered(MaybeAgent : ?agent) : void =
        if (A := MaybeAgent?):
            Spotlight.Register(A)

    OnPhaseEnd(MaybeAgent : ?agent) : void =
        # Lock the spotlight — no new registrations accepted.
        Spotlight.Disable()

        # Retrieve whoever is currently stored.
        if (StoredAgent := Spotlight.GetAgent()?):
            # StoredAgent is now a plain agent — use it for downstream logic.
            AnnouncementHUD.SetText(SpotlightWinnerMsg())
        else:
            AnnouncementHUD.SetText(NoOneRegisteredMsg())

    SpotlightWinnerMsg<localizes>() : message = "Phase over — spotlight winner locked in!"
    NoOneRegisteredMsg<localizes>() : message = "Phase over — nobody stepped up!"

Pattern 2 — AgentReplacedEvent and Clear for a rotating bounty

In a rotating bounty system, the most-wanted player changes every 30 seconds. Use Clear to wipe the current reference and AgentReplacedEvent to react when a new agent takes over.

using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }

rotating_bounty_device := class(creative_device):

    @editable
    BountyRef : player_reference_device = player_reference_device{}

    @editable
    RotationPlate : trigger_device = trigger_device{}

    @editable
    AnnouncementHUD : hud_message_device = hud_message_device{}

    OnBegin<override>()<suspends> : void =
        BountyRef.AgentReplacedEvent.Subscribe(OnBountyReplaced)
        RotationPlate.TriggeredEvent.Subscribe(OnRotationTriggered)

    OnRotationTriggered(MaybeAgent : ?agent) : void =
        if (A := MaybeAgent?):
            # Wipe the old reference first, then register the new agent.
            # Clear resets state; Register then fires AgentReplacedEvent
            # because an agent was previously stored.
            BountyRef.Clear()
            BountyRef.Register(A)

    # AgentReplacedEvent fires when the stored agent is swapped
    # (i.e., a previous agent existed and was replaced).
    OnBountyReplaced(NewAgent : agent) : void =
        AnnouncementHUD.SetText(NewBountyMsg())

    NewBountyMsg<localizes>() : message = "The bounty has a new target!"

Pattern 3 — ActivatedEvent for a winner's podium

When Activate is called (either from Verse or a sequencer), ActivatedEvent fires and sends the stored agent. Use this to trigger a podium animation or cinematic.

using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }

podium_device := class(creative_device):

    @editable
    WinnerRef : player_reference_device = player_reference_device{}

    @editable
    WinButton : button_device = button_device{}

    @editable
    PodiumHUD : hud_message_device = hud_message_device{}

    OnBegin<override>()<suspends> : void =
        WinnerRef.ActivatedEvent.Subscribe(OnWinnerActivated)
        WinButton.InteractedWithEvent.Subscribe(OnButtonPressed)

    OnButtonPressed(MaybeAgent : ?agent) : void =
        if (A := MaybeAgent?):
            # Register this player as the winner, then activate.
            WinnerRef.Register(A)
            WinnerRef.Activate()  # Fires ActivatedEvent AND ends the round.

    # ActivatedEvent sends the stored agent as a plain agent (not ?agent).
    OnWinnerActivated(Winner : agent) : void =
        # The hologram on the device will display the winner automatically
        # if "Show Player Details" is enabled in device settings.
        PodiumHUD.SetText(WinnerAnnouncementMsg())

    WinnerAnnouncementMsg<localizes>() : message = "We have a winner! Check the podium!"

Gotchas

1. ActivatedEvent vs. Activate() — they're not the same thing

Activate() is a method you call that ends the round/game AND signals ActivatedEvent. ActivatedEvent is the event you subscribe to in order to react when activation happens (whether triggered by your Verse code or by a sequencer). Don't confuse calling Activate() with subscribing to ActivatedEvent — you need both if you want to trigger the end and react to it.

2. Event handler signatures — agent vs. ?agent

All five events on player_reference_device send a plain agent (not ?agent). This is different from many other devices (like trigger_device.TriggeredEvent) that send ?agent. Your handler signatures must match:

# CORRECT for player_reference_device events:
OnStatChanged(TrackedAgent : agent) : void = ...

# WRONG — will not compile:
OnStatChanged(MaybeAgent : ?agent) : void = ...

3. IsReferenced is <decides> — use it inside if

IsReferenced is a failable expression. You cannot call it in a void context or assign its result. Always use it as an if condition:

# CORRECT:
if (BountyReference.IsReferenced[A]):
    # A is the tracked agent

# WRONG — compile error:
BountyReference.IsReferenced(A)  # missing <decides> context

Note the bracket syntax IsReferenced[A] — this is the standard Verse pattern for calling <decides> functions inside if.

4. GetAgent returns ?agent — always unwrap

GetAgent() returns an optional. If no agent has been registered yet (or Clear was called), it returns false. Always unwrap:

if (StoredAgent := WinnerRef.GetAgent()?):
    # safe to use StoredAgent here

5. Localized text for HUD messages

hud_message_device.SetText requires a message type, not a raw string. Declare a <localizes> helper for every string you want to display. There is no StringToMessage function in Verse.

6. AgentUpdatedEvent vs. AgentReplacedEvent

  • AgentUpdatedEvent fires whenever the stored agent changes to a new value — including the first registration when no agent was stored before.
  • AgentReplacedEvent fires only when an agent that was already stored is replaced by a different one. Use AgentReplacedEvent for "swap" logic and AgentUpdatedEvent for any change including first registration.

7. The device must be placed and wired via @editable

You cannot construct a player_reference_device in Verse with player_reference_device{} and expect it to work as a real device. It must be placed in the UEFN level and referenced via an @editable field. The = player_reference_device{} in the field declaration is only a default placeholder so the class compiles — always assign the real placed device in the Details panel.

Device Settings & Options

The player_reference_device User Options panel in the UEFN editor — every setting you can tune.

Player Reference Device settings and options panel in the UEFN editor
Player Reference Device — User Options in the UEFN editor

Build your own lesson with player_reference_device

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 →