Overview
In Verse, text is stored in the string type — letters, numbers, punctuation, spaces, even emojis. Every string carries a .Length member that tells you how many UTF-8 code units it contains. There is no separate string-length device: length is a built-in property you read off any string value with a dot, exactly like "Hello".Length.
The game problem it solves is validation and formatting. On a sunny island cove you might have a sign-in terminal where players type a codename: too short and it looks empty, too long and it overflows your 2D cel-shaded banner. Reading .Length lets you gate a granter, light a signal, or pick which localized message to show — all driven by how much text the player supplied.
One subtlety to keep in your back pocket: .Length counts code units, not visible characters. "José".Length is 5 (the accented é takes two units) while "Jose".Length is 4. For ASCII names they match; for fancy text they don't. We'll return to this in Gotchas.
API Reference
(API surface could not be resolved for this device.)
Walkthrough
The scene: a wooden sign-in post on a cove dock. A player walks up and hits a button to "claim" their spot. We read the player's platform name, check its .Length, and react: names that are too short get a warning message, good-length names light up a billboard with a welcome and trigger a prop mover / vault — here modeled as an item_granter_device that hands the player a celebratory item.
We declare the placed devices as @editable fields, subscribe to the button in OnBegin, and do all the length logic in the handler.
using { /Fortnite.com/Devices }
using { /Fortnite.com/Characters }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/UI }
using { /UnrealEngine.com/Temporary/SpatialMath }
cove_signin := class(creative_device):
# The button the player presses to claim their spot on the cove.
@editable
ClaimButton : button_device = button_device{}
# The billboard sign that shows the welcome / warning text.
@editable
WelcomeSign : hud_message_device = hud_message_device{}
# Hands the player a celebratory item when their name fits.
@editable
RewardGranter : item_granter_device = item_granter_device{}
# Localized text helpers (a message param needs a localized value).
TooShort<localizes>(S : string) : message = "Name too short: {S}"
WelcomeMsg<localizes>(S : string) : message = "Welcome aboard, {S}!"
OnBegin<override>()<suspends> : void =
# React each time a player interacts with the sign-in button.
ClaimButton.InteractedWithEvent.Subscribe(OnClaim)
OnClaim(Agent : agent) : void =
# Read the player's display name off their character/agent.
if (Player := player[Agent]):
Name := Player.GetFortCharacter[].GetAgent[].GetName[]
OnNameChecked(Agent, Name)
OnNameChecked(Agent : agent, Name : string) : void =
# .Length is the number of UTF-8 code units in the string.
Len := Name.Length
if (Len < 3):
# Too short — show a warning on the sign, no reward.
WelcomeSign.Show(Agent, TooShort(Name))
else:
# Good length — welcome them and hand out the reward.
WelcomeSign.Show(Agent, WelcomeMsg(Name))
RewardGranter.GrantItem(Agent)
Line by line:
- The four
@editablefields let you drop the real placed devices into these slots in the UEFN Details panel. Without theclass(creative_device)wrapper, callingClaimButton.Something()would fail with Unknown identifier. TooShortandWelcomeMsgare<localizes>functions. Amessageparameter (whatShowexpects) needs a localized value — you cannot pass a rawstring, and there is noStringToMessage. These helpers wrap the interpolated string into amessage.OnBeginsubscribesOnClaimto the button'sInteractedWithEventso it runs every press.- In
OnClaimwe unwrap theagentinto aplayerwithplayer[Agent], then dig out the name.GetName[]returns astring. OnNameCheckedis where.Lengthearns its keep:Name.Lengthgives anint, we branch on it, and drive the sign (Show) and granter (GrantItem) with the result. Note the length lives entirely in Verse — no extra device required.
Common patterns
Pattern 1 — Clamp overly long names before display. If the name is longer than the sign can hold, slice the string down using a subrange, then show the trimmed version. .Length tells us whether trimming is needed.
using { /Fortnite.com/Devices }
using { /Fortnite.com/Characters }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/UI }
name_trimmer := class(creative_device):
@editable
NameButton : button_device = button_device{}
@editable
Sign : hud_message_device = hud_message_device{}
Label<localizes>(S : string) : message = "{S}"
OnBegin<override>()<suspends> : void =
NameButton.InteractedWithEvent.Subscribe(OnPress)
OnPress(Agent : agent) : void =
if (Player := player[Agent], Name := Player.GetFortCharacter[].GetAgent[].GetName[]):
var Display : string = Name
# If longer than 8 code units, keep only the first 8.
if (Name.Length > 8):
if (Cut := Name[0..7]):
set Display = Cut
Sign.Show(Agent, Label(Display))
Pattern 2 — Gate a checkpoint by minimum length. A cliff-top gate (an item_granter_device standing in for the vault reward) only opens if the codename meets a minimum. Empty strings have .Length of 0.
using { /Fortnite.com/Devices }
using { /Fortnite.com/Characters }
using { /Verse.org/Simulation }
codename_gate := class(creative_device):
@editable
EnterButton : button_device = button_device{}
@editable
GateGranter : item_granter_device = item_granter_device{}
OnBegin<override>()<suspends> : void =
EnterButton.InteractedWithEvent.Subscribe(OnEnter)
OnEnter(Agent : agent) : void =
if (Player := player[Agent], Name := Player.GetFortCharacter[].GetAgent[].GetName[]):
# Require at least 4 code units before granting entry.
if (Name.Length >= 4):
GateGranter.GrantItem(Agent)
Pattern 3 — Compare against a fixed target string's length. A treasure sign hides a password; the player is only "close" if their guess matches the secret's length exactly. Both strings expose .Length.
using { /Fortnite.com/Devices }
using { /Fortnite.com/Characters }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/UI }
length_hint := class(creative_device):
@editable
GuessButton : button_device = button_device{}
@editable
HintSign : hud_message_device = hud_message_device{}
Secret : string = "coconut"
RightLen<localizes>() : message = "Right length! Keep guessing."
WrongLen<localizes>() : message = "Wrong length, try again."
OnBegin<override>()<suspends> : void =
GuessButton.InteractedWithEvent.Subscribe(OnGuess)
OnGuess(Agent : agent) : void =
if (Player := player[Agent], Guess := Player.GetFortCharacter[].GetAgent[].GetName[]):
# Compare the two .Length values as ints.
if (Guess.Length = Secret.Length):
HintSign.Show(Agent, RightLen())
else:
HintSign.Show(Agent, WrongLen())
Gotchas
.Lengthcounts code units, not characters."José".Lengthis5,"Jose".Lengthis4. For plain ASCII names they agree, but accents, emojis, and other multi-byte glyphs count as more than one. Don't assume.Lengthequals what the player sees on screen..Lengthis anint. Verse never auto-converts int↔float, so if you ever need to compute a float ratio from it you must convert explicitly. Comparisons like< 3,>= 4, and=are all int operations.- You cannot pass a
stringwhere amessageis required. Devices likehud_message_device.Showtake a localizedmessage. Wrap your text in a<localizes>helper (Label<localizes>(S:string):message = "{S}") and passLabel(Name)— there is noStringToMessage. - Slicing a string is failable.
Name[0..7]is a subrange that can fail if the range is invalid, so it must be used inside anif(if (Cut := Name[0..7]):). Only trim after you've confirmed with.Lengththat the string is long enough. - Unwrap the agent first. Button/trigger handlers give you an
agent; get theplayerwithplayer[Agent]and read the name via the failableGetName[]— all inside anif, since any step can fail. - Empty strings are length
0, not a failure. An empty codename""still has a valid.Lengthof0; guard your minimums explicitly rather than relying on the read to fail.