Reference Verse compiles

set Expressions: Mutable State on Your Island

Every interesting game needs state that changes — a door that flips from locked to open, a score that climbs, a map of players to their team colours. In Verse, the `set` expression is the single tool that mutates any variable or field after it has been declared. This article walks you through every form of `set` in one sunny dock-and-cove scenario, so you leave knowing exactly when and how to reach for it.

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

Overview

Verse is built around immutability by default: once you bind a name with := you cannot change it — unless you declared it with var. The set expression is the gate that lets you write a new value into a var variable, a var field on a class, a slot in a var array, or an entry in a var map.

set X = 10                   # variable reassignment
set Obj.Field = Value        # field reassignment
set Arr[Index] = Element     # array element reassignment
set Map[Key] = MappedValue   # map entry reassignment

set is itself an expression — it returns the right-hand side value — so you can chain assignments:

set Y = set X = 5   # both X and Y become 5

When to reach for set:

  • Tracking round state (locked → unlocked, day → night)
  • Accumulating scores or counters
  • Recording which players have reached a checkpoint
  • Toggling props visible/hidden based on game progress

API Reference

(API surface could not be resolved for this device.)

Walkthrough

Scenario — The Cove Vault: Three pressure plates are scattered across a sun-drenched dock. When all three are stepped on, a hidden prop (the vault door) is revealed and a counter shows how many plates are active. This example uses set on a var int counter, a var array of booleans, and a var field on the device class.

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

# cove_vault_device — reveals a hidden prop when all three dock plates are stepped on.
cove_vault_device := class(creative_device):

    # Wire these up in the UEFN details panel.
    @editable PlateA : trigger_device = trigger_device{}
    @editable PlateB : trigger_device = trigger_device{}
    @editable PlateC : trigger_device = trigger_device{}
    @editable VaultDoor : creative_prop = creative_prop{}

    # --- mutable state ---
    # Tracks how many plates are currently active (0-3).
    var ActivePlates : int = 0

    # One boolean per plate: false = not yet stepped on.
    var PlateState : []logic = array{false, false, false}

    # Has the vault already been opened this round?
    var VaultOpen : logic = false

    OnBegin<override>()<suspends> : void =
        # Hide the vault door at round start.
        VaultDoor.Hide()

        # Subscribe each plate to its own handler.
        PlateA.TriggeredEvent.Subscribe(OnPlateATriggered)
        PlateB.TriggeredEvent.Subscribe(OnPlateBTriggered)
        PlateC.TriggeredEvent.Subscribe(OnPlateCTriggered)

    # ---- plate handlers ----
    # Each handler checks whether this plate is newly activated,
    # increments the shared counter, and tests for completion.

    OnPlateATriggered(Agent : ?agent) : void =
        ActivatePlate(0)

    OnPlateBTriggered(Agent : ?agent) : void =
        ActivatePlate(1)

    OnPlateCTriggered(Agent : ?agent) : void =
        ActivatePlate(2)

    # Core logic — called with the 0-based index of the plate that fired.
    ActivatePlate(Index : int) : void =
        # Guard: if the vault is already open, do nothing.
        if (VaultOpen?):
            return

        # Guard: if this plate was already counted, do nothing.
        if (PlateState[Index]?):
            return

        # --- set on an array element ---
        # Mark this specific plate as activated.
        if (set PlateState[Index] = true):
            # --- set on a var field ---
            # Increment the running total.
            set ActivePlates = ActivePlates + 1

            # Check whether all three plates are now active.
            if (ActivePlates = 3):
                OpenVault()

    OpenVault() : void =
        # --- set on a var field (logic flag) ---
        set VaultOpen = true
        # Reveal the prop — the real payoff!
        VaultDoor.Show()

Line-by-line explanation

Line(s) What it teaches
var ActivePlates : int = 0 Declare a mutable integer field. Without var you could never set it.
var PlateState : []logic = array{false, false, false} A mutable array — individual slots can be overwritten with set Arr[i] = ….
var VaultOpen : logic = false A boolean flag; toggled exactly once when all plates are hit.
VaultDoor.Hide() Uses the real creative_prop.Hide() API to start the door invisible.
if (VaultOpen?): logic values are tested with ? (the decides effect).
if (PlateState[Index]?): Array index access can fail (out-of-bounds), so it lives inside if.
if (set PlateState[Index] = true): set on an array element is itself failable (index must be valid), so wrap it in if.
set ActivePlates = ActivePlates + 1 Plain variable reassignment — no if needed because int assignment never fails.
set VaultOpen = true Flips the flag so the vault cannot be opened twice.
VaultDoor.Show() Uses the real creative_prop.Show() API to reveal the door.

Common patterns

Pattern 1 — Chained set (score + display)

Chaining lets you update two related variables in one expression. Here a shoreline collectible counter feeds both a local tally and a "best run" high-score field.

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

# shore_score_device — counts collectibles picked up along the shoreline.
shore_score_device := class(creative_device):

    @editable CollectTrigger : trigger_device = trigger_device{}

    var CurrentScore : int = 0
    var BestScore    : int = 0

    OnBegin<override>()<suspends> : void =
        CollectTrigger.TriggeredEvent.Subscribe(OnCollect)

    OnCollect(Agent : ?agent) : void =
        # Chained set: CurrentScore is updated, then BestScore gets
        # whichever is larger — the new current or the old best.
        set BestScore = Max(set CurrentScore = CurrentScore + 1, BestScore)

# Helper — returns the larger of two ints.
Max(A : int, B : int) : int =
    if (A >= B):
        A
    else:
        B

Pattern 2 — set on a map (player → checkpoint index)

Maps are perfect for per-player state. This clifftop race device records the furthest checkpoint each player has reached by writing into a var [] (map) keyed by agent.

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

# clifftop_race_device — tracks the furthest checkpoint reached per player.
clifftop_race_device := class(creative_device):

    @editable CheckpointTriggers : []trigger_device = array{}

    # Map from agent to the highest checkpoint index they have reached.
    var Progress : [agent]int = map{}

    OnBegin<override>()<suspends> : void =
        var Idx : int = 0
        for (Trigger : CheckpointTriggers):
            # Capture the current index for the closure.
            CurrentIdx := Idx
            Trigger.TriggeredEvent.Subscribe(OnCheckpoint)
            set Idx = Idx + 1

    OnCheckpoint(MaybeAgent : ?agent) : void =
        # Unwrap the optional agent.
        if (A := MaybeAgent?):
            # Read the player's current best (default 0 if not yet in map).
            Current := if (V := Progress[A]) then V else 0
            # Only advance — never go backwards.
            NewBest := Max(Current, 1)   # simplified; real code passes checkpoint index
            # --- set on a map entry ---
            if (set Progress[A] = NewBest):
                # Progress recorded — could update a HUD here.
                true

# Helper
Max(A : int, B : int) : int =
    if (A >= B): A
    else: B

Pattern 3 — set on a var field inside a helper method

Sometimes you want a clean reset function that zeroes all mutable state at once — useful for round restarts on a cove arena.

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

# cove_round_device — resets all mutable state between rounds.
cove_round_device := class(creative_device):

    @editable VaultDoor    : creative_prop   = creative_prop{}
    @editable RoundButton  : button_device   = button_device{}

    var RoundNumber  : int   = 0
    var DoorsOpened  : int   = 0
    var RoundActive  : logic = false

    OnBegin<override>()<suspends> : void =
        RoundButton.InteractedWithEvent.Subscribe(OnRoundStart)

    OnRoundStart(Agent : ?agent) : void =
        ResetRound()

    # Resets all var fields in one place — easy to maintain.
    ResetRound() : void =
        set RoundNumber = RoundNumber + 1
        set DoorsOpened = 0
        set RoundActive = true
        VaultDoor.Hide()

Gotchas

1. You MUST declare with var before you can set

If you write Score : int = 0 (no var), the name is immutable and set Score = 1 is a compile error. Always add var when the value will change.

2. Array and map set are failable — wrap in if

set Arr[Index] = Value fails if Index is out of bounds. set Map[Key] = Value can also fail. Always put these inside an if block:

if (set Arr[I] = NewVal):
    # success path

Plain variable assignment (set X = Y) is not failable and does NOT need if.

3. set returns the right-hand side, not the container

After set Obj.Field = Value, the expression evaluates to Value, not Obj. This is useful for chaining but can surprise you if you expect the whole object back.

4. set requires an LValue on the left

You cannot set a function call result or a temporary. The left-hand side must be a var variable, a var field accessed through self or a reference, a valid array index, or a valid map key.

5. logic values use ? to test, not = true

To branch on a logic field, write if (VaultOpen?): — not if (VaultOpen = true):. The ? operator invokes the decides effect that if expects.

6. No implicit int ↔ float conversion

Verse never converts between int and float automatically. If your counter is var Score : float = 0.0, you must write set Score = Score + 1.0, not + 1.

Build your own lesson with set_operations

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 →