Overview
The lock_device wraps any UEFN door asset and exposes six methods that cover every state transition a door can have:
- Lock / Unlock / ToggleLocked — control whether the door can be opened by a player.
- Open / Close / ToggleOpened — physically swing the door regardless of lock state (useful for scripted cinematics or auto-doors).
Reach for lock_device whenever you need scripted door control: a vault that opens only after a puzzle is solved, a jail cell that slams shut when a player enters, a treasure room that unlocks after all enemies are defeated, or an auto-sliding door triggered by proximity.
Important:
lock_deviceonly works with props/assets that have a door component attached. A plain static mesh will not respond.
API Reference
lock_device
Used to customize the state and accessibility of doors.
lock_deviceonly works with assets that have a door attached.
Full public surface, resolved verbatim from the live Epic digest (Fortnite.digest.verse).
lock_device<public> := class<concrete><final>(creative_device_base):
Methods (call these to make the device act):
| Method | Signature | Description |
|---|---|---|
Lock |
Lock<public>(Agent:agent):void |
Locks the door. Agent is the instigator of the action. |
Unlock |
Unlock<public>(Agent:agent):void |
Unlocks the door. Agent is the instigator of the action. |
ToggleLocked |
ToggleLocked<public>(Agent:agent):void |
Toggles between Lock and Unlock. Agent is the instigator of the action. |
Open |
Open<public>(Agent:agent):void |
Opens the door. Agent is the instigator of the action. |
Close |
Close<public>(Agent:agent):void |
Closes the door. Agent is the instigator of the action. |
ToggleOpened |
ToggleOpened<public>(Agent:agent):void |
Toggles between Open and Close. Agent is the instigator of the action. |
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. |
hud_message_device
Used to show custom HUD messages to one or more
agents.
Full public surface, resolved verbatim from the live Epic digest (Fortnite.digest.verse).
hud_message_device<public> := class<concrete><final>(creative_device_base):
Events (subscribe a handler to react):
| Event | Signature | Description |
|---|---|---|
ShowMessageEvent |
ShowMessageEvent<public>:listenable(agent) |
Called when a Message has been Shown on-screen. Returns an Agent if it was Shown on a specified Agent's screen. |
HideMessageEvent |
HideMessageEvent<public>:listenable(agent) |
Called when a Message has been Hidden on-screen. Returns an Agent if it was Hidden from a specified Agent's screen. |
ClearAllMessagesEvent |
ClearAllMessagesEvent<public>:listenable(agent) |
Called when all queued Messages from all players that are affected by this HUD Message Device have been cleared. |
Methods (call these to make the device act):
| Method | Signature | Description |
|---|---|---|
Show |
Show<public>(Agent:agent):void |
Shows the currently set HUD Message on Agents screen. Will replace any previously active message. Use this when the device is setup to target specific agents. |
Show |
Show<public>():void |
Shows the currently set Message HUD message on screen. Will replace any previously active message. |
Hide |
Hide<public>():void |
Hides the HUD message. |
Hide |
Hide<public>(Agent:agent):void |
Hides the currently set HUD Message on Agents screen. Use this when the device is setup to target specific agents. |
Show |
Show<public>(Agent:agent, Message:message, ?DisplayTime:float |
Displays a Custom message to a specific Agent that you define.Setting DisplayTime to 0.0 will display the HUD message persistently.If not defined, or less than 0.0 the message will show for the time set on the device. |
Show |
Show<public>(Message:message, ?DisplayTime:float |
Displays a Custom message that you define for all PlayersSetting DisplayTime to 0.0 will display the HUD message persistently.If not defined, or less than 0.0 the message will show for the time set on the device. |
SetDisplayTime |
SetDisplayTime<public>(Time:float):void |
Sets the time (in seconds) the HUD message will be displayed. 0.0 will display the HUD message persistently. |
GetDisplayTime |
GetDisplayTime<public>()<transacts>:float |
Returns the time (in seconds) for which the HUD message will be displayed. 0.0 means the message is displayed persistently. |
SetText |
SetText<public>(Text:message):void |
Sets the Message to be displayed when the HUD message is activated. Text is clamped to 150 characters. |
ClearAllMessages |
ClearAllMessages<public>():void |
Clears all queued Messages from all players that are affected by this HUD Message Device. |
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):
Walkthrough
The Scenario
A cel-shaded pirate cove. A heavy vault door blocks the treasure room. Two pressure-plate triggers are hidden on the dock — both must be stepped on (in any order) before the vault unlocks and swings open. A HUD message guides the player through each step.
Level Setup
- Place a lock_device on your vault door asset. In its Details panel set Starts Locked = true, Starts Open = false.
- Place two trigger_devices (
PlateAandPlateB) as pressure plates on the dock. Set Trigger Activation = Player, Max Trigger Count = 1 each. - Place a hud_message_device (
HUD). Set Display Time = 3.0 s, Target = Triggering Player.
The Code
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
# Localised message helper — Verse requires `message` not raw strings
PirateHint<localizes>(S : string) : message = "{S}"
pirate_vault_device := class(creative_device):
# ── Editable device references ──────────────────────────────────────
@editable VaultDoor : lock_device = lock_device{}
@editable PlateA : trigger_device = trigger_device{}
@editable PlateB : trigger_device = trigger_device{}
@editable HUD : hud_message_device = hud_message_device{}
# ── Internal state ───────────────────────────────────────────────────
var PlateATriggered : logic = false
var PlateBTriggered : logic = false
# ── Lifecycle ────────────────────────────────────────────────────────
OnBegin<override>()<suspends> : void =
# Subscribe to both pressure plates
PlateA.TriggeredEvent.Subscribe(OnPlateATriggered)
PlateB.TriggeredEvent.Subscribe(OnPlateBTriggered)
# Greet the first player to load in (broadcast version — no agent)
HUD.Show(PirateHint("Find the two hidden dock plates to open the vault!"))
# ── Plate A handler ──────────────────────────────────────────────────
OnPlateATriggered(MaybeAgent : ?agent) : void =
if (A := MaybeAgent?):
set PlateATriggered = true
HUD.Show(A, PirateHint("Plate A — activated! Find the second plate."))
CheckVaultCondition(A)
# ── Plate B handler ──────────────────────────────────────────────────
OnPlateBTriggered(MaybeAgent : ?agent) : void =
if (A := MaybeAgent?):
set PlateBTriggered = true
HUD.Show(A, PirateHint("Plate B — activated! Find the second plate."))
CheckVaultCondition(A)
# ── Vault logic ──────────────────────────────────────────────────────
CheckVaultCondition(Agent : agent) : void =
if (PlateATriggered? and PlateBTriggered?):
# Both plates pressed — unlock then open the vault door
VaultDoor.Unlock(Agent)
VaultDoor.Open(Agent)
HUD.Show(Agent, PirateHint("The vault is open — claim your treasure!"))
Line-by-Line Explanation
| Lines | What's happening |
|---|---|
@editable VaultDoor : lock_device |
Wires the Verse class to the placed lock_device in the level. Without @editable the identifier is unknown at runtime. |
@editable PlateA/B : trigger_device |
The two dock pressure plates. |
@editable HUD : hud_message_device |
The floating pirate hint UI. |
PlateA.TriggeredEvent.Subscribe(OnPlateATriggered) |
Registers our handler; the event fires with ?agent (an optional agent). |
HUD.Show(PirateHint(...)) |
Broadcasts to all players. Uses the Show() no-agent overload. |
if (A := MaybeAgent?) |
Safely unwraps the ?agent; required before passing to any method that expects a concrete agent. |
HUD.Show(A, PirateHint(...)) |
Shows the message only on that player's screen. |
VaultDoor.Unlock(Agent) |
Removes the lock — the door can now be opened. |
VaultDoor.Open(Agent) |
Physically swings the door open, with Agent as the instigator. |
Common patterns
Pattern 1 — Toggle a jail cell door when a player re-enters a trigger
A guard shack trigger toggles the cell open/closed each time it fires — great for a repeating patrol mechanic.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
CellHint<localizes>(S : string) : message = "{S}"
jail_toggle_device := class(creative_device):
@editable CellDoor : lock_device = lock_device{}
@editable GuardTrigger: trigger_device = trigger_device{}
@editable HUD : hud_message_device = hud_message_device{}
OnBegin<override>()<suspends> : void =
GuardTrigger.TriggeredEvent.Subscribe(OnGuardTriggered)
OnGuardTriggered(MaybeAgent : ?agent) : void =
if (A := MaybeAgent?):
# ToggleOpened swings the door open if closed, or closed if open
CellDoor.ToggleOpened(A)
HUD.Show(A, CellHint("The cell door shifts..."))
Key call: ToggleOpened(Agent) — one call handles both directions, no extra state variable needed.
Pattern 2 — Lock a door after a player passes through (one-way gate)
A clifftop gate lets a player through, then locks behind them so they cannot backtrack.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
GateHint<localizes>(S : string) : message = "{S}"
one_way_gate_device := class(creative_device):
@editable CliffGate : lock_device = lock_device{}
@editable PassTrigger : trigger_device = trigger_device{}
@editable HUD : hud_message_device = hud_message_device{}
OnBegin<override>()<suspends> : void =
# Allow only one pass — after that the trigger disables itself
PassTrigger.SetMaxTriggerCount(1)
PassTrigger.TriggeredEvent.Subscribe(OnPlayerPassed)
OnPlayerPassed(MaybeAgent : ?agent) : void =
if (A := MaybeAgent?):
CliffGate.Open(A)
# Brief pause so the player can walk through
Sleep(1.5)
CliffGate.Close(A)
CliffGate.Lock(A)
HUD.Show(A, GateHint("The gate locks behind you. No turning back!"))
Key calls: Open → Sleep → Close → Lock — a sequential async chain inside a <suspends> context. SetMaxTriggerCount(1) ensures the trigger fires exactly once.
Pattern 3 — HUD countdown then auto-close a treasure room
After the vault opens, a timed HUD message warns the player, then the door slams shut automatically.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
TimerHint<localizes>(S : string) : message = "{S}"
treasure_timer_device := class(creative_device):
@editable TreasureDoor : lock_device = lock_device{}
@editable EnterTrigger : trigger_device = trigger_device{}
@editable HUD : hud_message_device = hud_message_device{}
OnBegin<override>()<suspends> : void =
EnterTrigger.SetMaxTriggerCount(1)
EnterTrigger.TriggeredEvent.Subscribe(OnEnterTreasure)
OnEnterTreasure(MaybeAgent : ?agent) : void =
if (A := MaybeAgent?):
TreasureDoor.Unlock(A)
TreasureDoor.Open(A)
# Show a persistent warning (DisplayTime 0.0 = persistent)
HUD.Show(A, TimerHint("You have 10 seconds before the vault seals!"), ?DisplayTime := 0.0)
Sleep(10.0)
HUD.Hide(A)
TreasureDoor.Close(A)
TreasureDoor.Lock(A)
HUD.Show(A, TimerHint("The vault has sealed. Escape with your loot!"))
Key calls: HUD.Show(Agent, Message, ?DisplayTime := 0.0) for a persistent message, HUD.Hide(Agent) to clear it, then Close + Lock to seal the room.
Gotchas
1. Lock and Open are independent states
Lock/Unlock controls accessibility; Open/Close controls physical position. A door can be locked AND open at the same time (it stays open but a player cannot close it). Always call Unlock before Open if you want the player to be able to interact with it afterward.
2. ?agent must be unwrapped before use
TriggeredEvent sends ?agent (an optional). Passing it directly to VaultDoor.Unlock(MaybeAgent) is a compile error because the method expects agent, not ?agent. Always unwrap:
if (A := MaybeAgent?):
VaultDoor.Unlock(A)
3. message is not a plain string
Every hud_message_device method that takes text expects the message type, not a string. Declare a localizer helper at module scope:
MyText<localizes>(S : string) : message = "{S}"
There is no StringToMessage function — the <localizes> specifier is the only way.
4. lock_device needs a door asset
The device silently does nothing if attached to a plain static mesh. In UEFN, choose a prop from the Content Browser that has a door component (look for assets tagged Door in the Creative prop library).
5. Sequential async calls require <suspends>
Chaining Open → Sleep → Close only works inside a function marked <suspends> (like OnBegin) or a spawned coroutine. Event handler methods are not <suspends> by default — if you need async behaviour inside a handler, spawn a helper:
OnPlateTriggered(MaybeAgent : ?agent) : void =
if (A := MaybeAgent?):
spawn { RunDoorSequence(A) }
RunDoorSequence(Agent : agent)<suspends> : void =
VaultDoor.Open(Agent)
Sleep(5.0)
VaultDoor.Close(Agent)
VaultDoor.Lock(Agent)
6. SetMaxTriggerCount clamps to [0, 20]
Passing a value outside that range is silently clamped. Use 0 for unlimited triggers.