sexta-feira, 17 de abril de 2026

UEFN Verse: agent and player classes

In this article, I will cover the agent and player classes, as well as review the concepts of inheritance and casting.

The agent class is a subclass of entity. It represents entities that act in the game, which can be NPCs or players.

The player class is a subclass of agent. It represents a human player in the game.

According to the concepts of inheritance, a subclass inherits the properties of its superclass (parent class). It is as if it accumulates the types of its superclasses.

For example, an instance of the player class is also an agent and an entity. Therefore, it can be referenced by a field whose type is a superclass, such as agent. 

In UEFN, interactions with devices are performed by agents, which can be NPCs or players. To determine whether the agent that interacted with a device is a player, we can use casting to convert a reference of type agent to player. If the cast succeeds, the referenced instance is a player.
HandleItemPickedUp(Agent:agent):void=
    if ( Player := player[Agent] ):

After casting, the player reference allows access to fields and methods that are specific to the player class.

Para ver o casting em ação, vamos criar um dispositivo que referencia um trigger device. Quando o trigger for acionado, vamos usar casting para testar se foi um player que ativou o trigger ou NPC. Se for um jogador, será ligado uma luz verde. Se for um NPC, será uma luz vermelha.

Open Verse Explorer, right-click on the project name, and select the option Add new Verse file to project.

In Device Name put agent_check_device and click the Create Empty button.

Copy the Verse code below into the agent_check_device file:

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

agent_check_device := class(creative_device):

    @editable
    TriggerDevice : trigger_device = trigger_device{}

    @editable
    GreenLight : customizable_light_device = customizable_light_device{}

    @editable
    RedLight : customizable_light_device = customizable_light_device{}

    OnBegin<override>()<suspends>:void =
        TriggerDevice.TriggeredEvent.Subscribe(OnTriggered)

    OnTriggered(MaybeAgent : ?agent) : void =
        if (Agent := MaybeAgent?):
            GreenLight.TurnOff()
            RedLight.TurnOff()

            if (Player := player[Agent]):
                GreenLight.TurnOn()
            else:
                RedLight.TurnOn()

The agent_check_device contains one trigger_device and two customizable_light_device.

In the OnTriggered function, the parameter is of type ?agent (option agent), since the TriggerDevice can be triggered by Verse code without any agent interaction. First, we check if it was triggered by an agent, and then determine whether the agent is a player or an NPC.

Save the file and compile the Verse code using the Verse > Compile Verse Code option from the UEFN menu.

Acess the Content Drawer e add the agent_check_device to the level. Then add one Trigger Device, two Customizable Light Devices and one Wildlife Spawner Device

Select the Trigger Device at the level and check the option Triggered by Creatures.

Select one of the Customizable Light Devices, rename it to RedLight, set Light Color to red, and uncheck Initial State so the light starts off. Then rename the other light device to GreenLight and apply similar settings using green.


Select the agent_check_device in the level. In the Details panel, select the references to the devices added to the level.


We will use the Wildlife Spawner Device to spawn creatures in the level that can activate the Trigger Device when they pass over it. Select the device and, in Type, choose Random to spawn different types of creatures. Set Spawn Count to 10.


Save the level and click Launch Session to load it in Fortnite. Walk over the Trigger Device to activate the green light. Then try to lure a creature to walk over it and activate the red light.


UEFN Verse: Classes agent e player

Neste artigo, vou falar sobre as classes agent e player, além de revisar os conceitos de herança e casting.

A classe agent é uma subclasse de entity. Ela representa entidades que atuam  no jogo, podendo ser NPCs ou jogadores.

A classe player é uma subclasse de agent. Representa um jogador humano que está na partida.

Conforme os conceitos de herança, uma subclasse herda as propriedades de sua superclasse (classe pai). É como se acumulasse os tipos de suas superclasses. 

Por exemplo, uma instância da classe player também é um agent e é uma entity. Por isso, ela também pode ser referenciada por um campo cujo tipo seja o de uma superclasse, como agent

No UEFN, as interações com dispositivos são realizadas por agentes, que podem ser NPCs ou jogadores. Para verificar se o agente que interagiu com o dispositivo é um jogador, podemos usar casting para tentar converter a referência do tipo agent para uma referência do tipo player. Se o casting for bem-sucedido, significa que a instância referenciada é do tipo player.
HandleItemPickedUp(Agent:agent):void=
    if ( Player := player[Agent] ):

Após o casting, a referência do tipo player permitirá acessar os campos e métodos que pertencem apenas à classe player.

Para ver o casting em ação, vamos criar um dispositivo que referencia um trigger_device. Quando o trigger for acionado, vamos usar casting para verificar se foi um player ou um NPC que o ativou. Se for um jogador, uma luz verde será ligada. Se for um NPC, uma luz vermelha será ligada.

Abra o Verse Explorer, clique com o botão-direito no nome do projeto e escolha a opção Add new Verse file to project.

Em Device Name coloque agent_check_device clique no botão Create Empty.

Copie o código Verse abaixo para o dispositivo agent_check_device:

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

agent_check_device := class(creative_device):

    @editable
    TriggerDevice : trigger_device = trigger_device{}

    @editable
    GreenLight : customizable_light_device = customizable_light_device{}

    @editable
    RedLight : customizable_light_device = customizable_light_device{}

    OnBegin<override>()<suspends>:void =
        TriggerDevice.TriggeredEvent.Subscribe(OnTriggered)

    OnTriggered(MaybeAgent : ?agent) : void =
        if (Agent := MaybeAgent?):
            GreenLight.TurnOff()
            RedLight.TurnOff()

            if (Player := player[Agent]):
                GreenLight.TurnOn()
            else:
                RedLight.TurnOn()

O dispositivo agent_check_device possui um trigger_device e dois customizable_light_device

Na função OnTriggered, o parâmetro é do tipo ?agent (option agent), pois o TriggerDevice pode ser acionado por código Verse sem a interação de um agente. Primeiro, é verificado se o TriggerDevice foi acionado por um agente e, em seguida, é testado se o agente é um player ou NPC.

Salve o arquivo e compile o código Verse usando a opção Verse > Compile Verse Code do menu do UEFN. 

Acesse o Content Drawer e adicione o dispositivo agent_check_device ao nível. Em seguida, adicione também um Trigger Device, dois Customizable Light Devices e um Wildlife Spawner Device

Selecione o Trigger Device no nível e marque a opção Triggered by Creatures.

Selecione um dos Customizable Light Devices, renomeie para RedLight, escolha uma cor vermelha em Light Color e desmarque a opção Initial State para que a luz comece desligada. Renomeie o outro Light Device para GreenLight e faça os ajustes semelhantes usando a cor verde.


Selecione o agent_check_device no nível. Na aba Details, selecione as referências dos dispositivos adicionados ao nível.


Vamos usar o Wildlife Spawner Device para gerar criaturas no nível que poderão ativar o Trigger Device ao passarem sobre ele. Selecione o dispositivo e, em Type, escolha Random para que apareçam tipos diferentes de criaturas. Em Spawn Count, defina 10.


Salve o nível e clique no botão Launch Session para carregá-lo no Fortnite. Passe sobre o Trigger Device para ativar a luz verde. Tente atrair uma criatura para que ela passe sobre o Trigger Device e ative a luz vermelha.



domingo, 29 de março de 2026

UEFN Verse: Logging and Log channel

Log messages can help identify issues in your Verse code. These messages can be viewed in the in-game log tab and in the UEFN Output Log window. 

Logging in Verse requires two classes: log and log_channel.

The log_channel is used only to identify the source of the message. Its name is added to the beginning of the message. 

You need to create a subclass of log_channel at the module scope, that is, outside of classes or functions. The code below shows an example of a log_channel

log_general := class(log_channel){}

The next step is to create an instance of the log class inside a class or function, specifying the log_channel to be used:

LoggerGeneral:log = log{Channel:=log_general}

There are five log levels used to categorize messages: Debug, Verbose, Normal, Warning and Error.

Logs with Debug and Verbose levels appear only in the in-game log tab. They do not appear in the UEFN Output Log.

Logs with Warning and Error levels are displayed in different colors to draw attention.

A default log level can be defined when the log is created: 

LoggerGeneral:log = log{Channel:=log_general, DefaultLevel:=log_level.Warning}

To write to the log, use the Print function of the log class:

LoggerGeneral.Print("Experience started")

You can pass the log level as a parameter:

LoggerGeneral.Print("Data not found", ?Level := log_level.Error)

Another useful piece of information for debugging is the Call Stack, which shows the sequence of function calls leading to the current point in the code. Use the PrintCallStack function from the log class to log the Call Stack. 

LoggerGeneral.PrintCallStack()

To illustrate the use of logging, we will create a device that uses two logs. One will be used for general system messages, and the other for logging messages when buttons are pressed by the player. Different log levels will be used.

Open Verse Explorer, right-click on the project name, and select the option Add new Verse file to project.

In Device Name put log_example_device and click the Create Empty button.

Copy the Verse code below into the log_example_device file:

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

log_general := class(log_channel){}
log_buttons := class(log_channel){}

log_example_device := class(creative_device):

    LoggerGeneral:log = log{Channel:=log_general}
    LoggerButtons:log = log{Channel:=log_buttons, 
                            DefaultLevel := log_level.Warning}

    var BtnWarningCount: int = 0
    var BtnErrorCount: int = 0

    @editable
    ButtonWarning : button_device = button_device{}

    @editable
    ButtonError : button_device = button_device{}

    OnBegin<override>()<suspends>:void=
        ButtonWarning.InteractedWithEvent.Subscribe(ButtonWarningPressed)
        ButtonError.InteractedWithEvent.Subscribe(ButtonErrorPressed)
        LoggerGeneral.Print("Experience started.")

    ButtonWarningPressed(Agent:agent):void=
        set BtnWarningCount += 1
        LoggerButtons.Print("ButtonWarning was pressed {BtnWarningCount} times")

    ButtonErrorPressed(Agent:agent):void=
        set BtnErrorCount += 1
        LoggerButtons.Print("ButtonError was pressed {BtnErrorCount} times", 
                            ?Level := log_level.Error)
        LoggerButtons.PrintCallStack()

The log_example_device contains two button_device instances that are used to log messages when pressed. One button is used for Warning level messages, and the other for Error level messages.

The OnBegin function subscribes the functions to be called on the buttons when they are pressed, and then logs a message using LoggerGeneral.

Save the file and compile the Verse code using the Verse > Compile Verse Code option from the UEFN menu.

Access the Content Drawer and add the log_example_device to the level. Then add two Button Devices to the level. 



Select the log_example_device at the level. In the Details tab, Select the references to the buttons in the level. 


Save the level and click the Launch Session button to load the level in Fortnite. Press the buttons a few times. Then switch to UEFN and check the messages logged in the Output Log.



UEFN Verse: Logging e Log channel

Mensagens escritas no log podem ajudar a identificar problemas no seu código Verse. Estas mensagens podem ser visualizadas na aba de log dentro do jogo e na janela Output Log do UEFN.

Para escrever logs em Verse, você precisa usar duas classes: log e log_channel.

O log_channel é usado apenas para identificar a origem da mensagem. Seu nome é adicionado ao início da mensagem.

É necessário criar uma subclasse de log_channel no escopo de módulo, ou seja, fora de classes ou funções. O código abaixo mostra um exemplo de log_channel:

log_general := class(log_channel){}

O próximo passo é criar uma instância da classe log dentro de uma classe ou função, informando o log_channel que será utilizado:

LoggerGeneral:log = log{Channel:=log_general}

Existem 5 níveis de log que podem ser usados para categorizar a mensagem: Debug, Verbose, Normal, Warning e Error.

Logs com níveis Debug e Verbose aparecem apenas na aba de log dentro do jogo. Eles não aparecem no Output Log do UEFN.

Logs com níveis Warning e Error são exibidos em cores diferentes para chamar mais atenção.

É possível definir um nível padrão para um log no momento de sua criação: 

LoggerGeneral:log = log{Channel:=log_general, DefaultLevel:=log_level.Warning}

Para escrever no log, use a função Print da classe log:

LoggerGeneral.Print("Experience started")

Você pode passar como parâmetro o nível de log da mensagem:

LoggerGeneral.Print("Data not found", ?Level := log_level.Error)

Outra informação útil na análise de problemas é o Call Stack (pilha de chamadas) que mostra as funções chamadas até chegar ao ponto atual do código. Use a função PrintCallStack da classe log para registrar o Call Stack. 

LoggerGeneral.PrintCallStack()

Para ilustrar o uso de logs, vamos criar um dispositivo que utiliza dois logs. Um deles será usado para mensagens gerais do sistema e o outro log será para registrar mensagens quando os botões forem pressionados pelo jogador. Serão usados diferentes níveis de log.

Abra o Verse Explorer, clique com o botão-direito no nome do projeto e escolha a opção Add new Verse file to project.

Em Device Name coloque log_example_device clique no botão Create Empty.

Copie o código Verse abaixo para o dispositivo log_example_device:

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

log_general := class(log_channel){}
log_buttons := class(log_channel){}

log_example_device := class(creative_device):

    LoggerGeneral:log = log{Channel:=log_general}
    LoggerButtons:log = log{Channel:=log_buttons, 
                            DefaultLevel := log_level.Warning}

    var BtnWarningCount: int = 0
    var BtnErrorCount: int = 0

    @editable
    ButtonWarning : button_device = button_device{}

    @editable
    ButtonError : button_device = button_device{}

    OnBegin<override>()<suspends>:void=
        ButtonWarning.InteractedWithEvent.Subscribe(ButtonWarningPressed)
        ButtonError.InteractedWithEvent.Subscribe(ButtonErrorPressed)
        LoggerGeneral.Print("Experience started.")

    ButtonWarningPressed(Agent:agent):void=
        set BtnWarningCount += 1
        LoggerButtons.Print("ButtonWarning was pressed {BtnWarningCount} times")

    ButtonErrorPressed(Agent:agent):void=
        set BtnErrorCount += 1
        LoggerButtons.Print("ButtonError was pressed {BtnErrorCount} times", 
                            ?Level := log_level.Error)
        LoggerButtons.PrintCallStack()

O dispositivo log_example_device possui dois button_device que serão usados para registrar mensagens no log quando forem pressionados. Um botão será usado para mensagens com o nível Warning e o outro para mensagens com o nível Error.

A função OnBegin registra, nos botões, as funções que serão chamadas quando eles forem pressionados e, em seguida, escreve uma mensagem no log usando o LoggerGeneral.

Salve o arquivo e compile o código Verse usando a opção Verse > Compile Verse Code do menu do UEFN. 

Acesse o Content Drawer e adicione o dispositivo log_example_device ao nível. Em seguida, adicione dois Button Devices ao nível. 



Selecione o log_example_device no nível. Na aba Details, selecione as referências aos botões que estão no nível. 


Salve o nível e clique no botão Launch Session para carregar o nível no Fortnite. Pressione os botões algumas vezes. Em seguida, alterne para o UEFN e verifique no Output Log as mensagens registradas.  



quinta-feira, 19 de março de 2026

UEFN Verse: Extension Methods

Methods are functions that belong to a class, just as fields or attributes represent class data, such as variables and constants. This terminology comes from Object-Oriented Programming.

The Verse language allows the creation of extension methods, which are functions that can be added to existing classes without the need for inheritance.

This can be useful when you need to add functionality to classes that cannot be extended, such as player, agent, and team in UEFN.

In addition to classes, extension methods can be used with any type in Verse. The example below adds a function to the int type that calculates the power of a number.

(Base:int).MyPowFunction(Exponent:int):int=
    if (Exponent < 0):
        return 0
    var PowResult: int = 1
    for (Ind := 1..Exponent):
        set PowResult *= Base
    PowResult

Inside the parentheses is a constant of the type being extended. This constant is used in the function body as if it were a parameter.

The following code shows how to use the function:

IntValue := 2
Result := IntValue.MyPowFunction(4)


We will use extension methods to add functionality to the player class in UEFN. To do this, a new class and a map will be used to associate additional fields with a player instance.

Open Verse Explorer, right-click on the project name, and select the option Add new Verse file to project.

In Device Name put extension_device and click the Create Empty button.

Copy the Verse code below into the extension_device file:

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

player_fields := class:
    var Score : int = 0
    var CoinsCollected : int = 0
    var GameLevel : int = 1
    var CoinsPerLevel : int = 3    

extension_device := class(creative_device):

    @editable
    ItemSpawnerArray : []item_spawner_device = array{}

    var PlayerFieldsMap<public> : [player]player_fields  = map{}

    OnBegin<override>()<suspends>:void =
        for(ItemSpawner : ItemSpawnerArray):
            ItemSpawner.ItemPickedUpEvent.Subscribe(HandleCoinCollected)

    HandleCoinCollected(Agent:agent):void=
        if ( Player := player[Agent], Player.CollectCoin[] ) {}

    (Player:player).GetPlayerFields()<decides><transacts>:player_fields=
        if(PlayerFields := PlayerFieldsMap[Player]):
            PlayerFields
        else:
            NewPlayerFields := player_fields{}
            set PlayerFieldsMap[Player] = NewPlayerFields
            NewPlayerFields

    (Player:player).CollectCoin()<decides><transacts>:void=
        PlayerFields := Player.GetPlayerFields[]
        set PlayerFields.CoinsCollected += 1
        set PlayerFields.Score += PlayerFields.GameLevel * 100
        if ( Mod[PlayerFields.CoinsCollected, PlayerFields.CoinsPerLevel] = 0 ):
            set PlayerFields.GameLevel += 1
        Print("Score:{PlayerFields.Score} | GameLevel:{PlayerFields.GameLevel}")

The player_fields class contains the new fields that will be associated with a player instance through the PlayerFieldsMap map.

The extension_device contains an array of item_spawner_device used to store references to the Item Spawners in the level. The OnBegin function registers HandleCoinCollected on each instance in the item_spawner_device array so it is executed when the player collects a coin.

The HandleCoinCollected function receives the agent that collected the coin as a parameter. It is cast to player, and then the CollectCoin extension method created for the player class is called. The if expression is used only as a failure context.

GetPlayerFields is an extension method created for the player class. It returns the player_fields instance associated with the player. If it does not exist yet, a new player_fields instance is created, stored in the map, and returned by the method.

CollectCoin is another extension method for the player class. It retrieves the player_fields instance to update its values. In this example, GameLevel increases every three coins collected, and the score awarded for each coin depends on it.

Save the file and compile the Verse code using the Verse > Compile Verse Code option from the UEFN menu.

Access the Content Drawer and add the constructor_device to the level. Add an Item Spawner Device to the level and, in the Details tab, configure it as shown in the image so that a coin is generated every 3 seconds.


Make copies of the Item Spawner Device by holding Alt and dragging one of the axis arrows on the selected device. In my example, there are four Item Spawners.


Select the extension_device at the level. In the Details tab, add elements to the array and select the Item Spawner Device references for each element.


Save the level and click the Launch Session button to load the level in Fortnite. When a coin is collected, a message is displayed showing the player's current Score and GameLevel.



UEFN Verse: Métodos de extensão

Métodos são as funções que pertencem a uma classe, assim como campos ou atributos representam dados da classe, como variáveis e constantes. Esta nomenclatura começou a ser usada na Programação Orientada a Objetos.

A linguagem Verse permite a criação de métodos de extensão que são funções que podem ser adicionadas a classes existentes sem precisar usar a herança.

Isto pode ser útil quando você precisar adicionar funcionalidade as classes que não podem ser estendidas como player, agent e team do UEFN.

Além de classes, os métodos de extensão podem ser usados em qualquer tipo do Verse. O exemplo abaixo adiciona uma função ao tipo int que calcula a potência de um número:

(Base:int).MyPowFunction(Exponent:int):int=
    if (Exponent < 0):
        return 0
    var PowResult: int = 1
    for (Ind := 1..Exponent):
        set PowResult *= Base
    PowResult

Entre parênteses, há a declaração de uma constante do tipo que está sendo estendido. Esta constante é usada no corpo da função como se fosse um parâmetro.

O código abaixo mostra como a função pode ser usada:

IntValue := 2
Result := IntValue.MyPowFunction(4)


Vamos usar métodos de extensão para adicionar funcionalidades à classe player do UEFN. Para isso, será utilizada uma nova classe e um map para associar novos campos a uma instância de player.

Abra o Verse Explorer, clique com o botão-direito no nome do projeto e escolha a opção Add new Verse file to project.

Em Device Name coloque extension_device clique no botão Create Empty.

Copie o código Verse abaixo para o dispositivo extension_device:

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

player_fields := class:
    var Score : int = 0
    var CoinsCollected : int = 0
    var GameLevel : int = 1
    var CoinsPerLevel : int = 3    

extension_device := class(creative_device):

    @editable
    ItemSpawnerArray : []item_spawner_device = array{}

    var PlayerFieldsMap<public> : [player]player_fields  = map{}

    OnBegin<override>()<suspends>:void =
        for(ItemSpawner : ItemSpawnerArray):
            ItemSpawner.ItemPickedUpEvent.Subscribe(HandleCoinCollected)

    HandleCoinCollected(Agent:agent):void=
        if ( Player := player[Agent], Player.CollectCoin[] ) {}

    (Player:player).GetPlayerFields()<decides><transacts>:player_fields=
        if(PlayerFields := PlayerFieldsMap[Player]):
            PlayerFields
        else:
            NewPlayerFields := player_fields{}
            set PlayerFieldsMap[Player] = NewPlayerFields
            NewPlayerFields

    (Player:player).CollectCoin()<decides><transacts>:void=
        PlayerFields := Player.GetPlayerFields[]
        set PlayerFields.CoinsCollected += 1
        set PlayerFields.Score += PlayerFields.GameLevel * 100
        if ( Mod[PlayerFields.CoinsCollected, PlayerFields.CoinsPerLevel] = 0 ):
            set PlayerFields.GameLevel += 1
        Print("Score:{PlayerFields.Score} | GameLevel:{PlayerFields.GameLevel}")

A classe player_fields contém os novos campos que serão associados a uma instância de player por meio do map PlayerFieldsMap.

O dispositivo extension_device possui um array de item_spawner_device usado para armazenar as referências dos Item Spawner presentes no nível. A função OnBegin registra a função HandleCoinCollected em cada uma das instâncias do array item_spawner_device para ser executada quando o jogador coletar uma moeda. 

A função HandleCoinCollected recebe como parâmetro o agente que coletou a moeda. É feito o cast (conversão) para player e, em seguida, é chamado o método de extensão CollectCoin, criado para a classe player. A expressão if está sendo usada apenas como contexto de falha.

GetPlayerFields é um método de extensão criado para a classe player. Ele retorna a instância de player_fields associada ao player. Caso ainda não exista, uma nova instância de player_fields é criada, armazenada no map e retornada pelo método.

CollectCoin é outro método de extensão criado para a classe player. O método obtém a instância de player_fields para atualizar seus valores. Neste exemplo, o GameLevel aumenta a cada três moedas coletadas. A pontuação obtida ao coletar cada moeda depende do GameLevel

Salve o arquivo e compile o código Verse usando a opção Verse > Compile Verse Code do menu do UEFN. 

Acesse o Content Drawer e adicione o dispositivo extension_device ao nível. Adicione um Item Spawner Device no nível e na aba Details configure conforme a imagem para que uma moeda seja gerada a cada 3 segundos.


Faça cópias do Item Spawner Device usando a tecla Alt e arrastando uma das setas de eixo do dispositivo selecionado. No meu exemplo, utilizei quatro Item Spawners.


Selecione o extension_device no nível. Na aba Details, adicione elementos ao array e selecione as referências aos Item Spawner Devices em cada elemento do array.


Salve o nível e clique no botão Launch Session para carregar o nível no Fortnite. Ao coletar uma moeda, será exibida uma mensagem informando os valores atuais de Score e GameLevel do jogador.



terça-feira, 24 de fevereiro de 2026

UEFN Verse: Constructor and Persistence

In this article I will show how to use a constructor to make it easier to update persisted data.

If you're not yet familiar with persistence using Verse, I recommend reading my previous article:

UEFN Verse: Introduction to Persistence

The best option for persisting player data is by using a class. Within a class, you can group multiple fields and associate an instance of that class with the player in the weak_map. Another advantage of using classes for persistence is that they allow for the addition of fields after the island has been published.

The classes used in persistence need to have the <persistable> and <final> specifiers. The <final> specifier indicate that the class cannot have subclasses.

Another important point is that the class cannot have variables, only constants. The code below is a simple example of a class used for persistence.

player_data := class<final><persistable>:
    Version<public>:int = 1
    PlayerXP<public>:int = 0
    ItemsCollected<public>:int = 0

It's good practice to have a field that indicates the class version. This allows you to detect if a player's data is from an older version and perform a conversion if necessary.

The following line shows the weak_map type variable that associates the player type with the new player_data class. The values ​​of this variable are persisted.

var PlayerDataMap:weak_map(player, player_data) = map{}

Since a class used for persistence cannot have variables, a new instance of the class will need to be created every time the data is updated. We can use a constructor to make this task easier.

A constructor is a type of function that creates an instance of a class. In our example, it will be used to make a copy of an instance, and then we can update only the fields that have been modified.

The code below is for a constructor that takes an instance of player_data as a parameter and returns a new instance with the copied values.

NewPlayerData<constructor>(OldData:player_data)<transacts> := player_data:
    Version := OldData.Version
    PlayerXP := OldData.PlayerXP
    ItemsCollected := OldData.ItemsCollected

Note that the NewPlayerData function does not have a return type using the ":" operator. A constructor function receives an instance of a class using the assignment operator ":=".

A constructor function can be called during the archetype instantiation of a class. In the example below, the goal is to create a new instance of player_data and assign a new value to the ItemsCollected field:

set PlayerDataMap[Player] = player_data:
                ItemsCollected := NewItemsCollected
                NewPlayerData<constructor>(PlayerSavedData)

This is the approach used to update specific fields of a persisted class. In archetype instantiation, the constructor is executed first, making copies of all the data. Then, assignments are made to the fields, such as the ItemsCollected field.

To see these persistence codes in use, let's create an example using an Item Spawner Device. The player will be able to collect items. Each time an item is collected, the ItemsCollected value will be updated. When the player re-enters the experience, the count of collected items will continue from the value where it stopped in the last run.

Open Verse Explorer, right-click on the project name, and select the option Add new Verse file to project.

In Device Name put constructor_device and click the Create Empty button.

Copy the Verse code below into the constructor_device file:

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

player_data := class<final><persistable>:
    Version<public>:int = 1
    PlayerXP<public>:int = 0
    ItemsCollected<public>:int = 0

NewPlayerData<constructor>(OldData:player_data)<transacts> := player_data:
    Version := OldData.Version
    PlayerXP := OldData.PlayerXP
    ItemsCollected := OldData.ItemsCollected

var PlayerDataMap:weak_map(player, player_data) = map{}

constructor_device := class(creative_device):

    @editable  
    ItemSpawnerDevice: item_spawner_device = item_spawner_device{}

    OnBegin<override>()<suspends>:void =
        ItemSpawnerDevice.ItemPickedUpEvent.Subscribe(HandleItemPickedUp)
        for (Player : GetPlayspace().GetPlayers()):
            if:
                not PlayerDataMap[Player]
                set PlayerDataMap[Player] = player_data{}

    HandleItemPickedUp(Agent:agent):void=	
        if: 
            Player := player[Agent]
            PlayerSavedData := PlayerDataMap[Player]
            NewItemsCollected := PlayerSavedData.ItemsCollected + 1
            set PlayerDataMap[Player] = player_data:
                ItemsCollected := NewItemsCollected
                NewPlayerData<constructor>(PlayerSavedData)                
        then:
            Print("Items collected: {NewItemsCollected}")

The OnBegin function subscribes the HandleItemPickedUp function in the ItemPickedUpEvent of the ItemSpawnerDevice. This function will be executed when the player picks up an item. The for loop is used to check if all players in the experience have persisted data. If a player does not have data, a player_data will be created with default values ​​and stored in the PlayerDataMap weak_map.

The HandleItemPickedUp function retrieves the persisted player data and stores it in PlayerSavedData. The new value for the ItemsCollected field is calculated and temporarily stored in NewItemsCollected. The PlayerDataMap weak_map receives a new instance of player_data that was created using the constructor along with the update of the ItemsCollected field.

Save the file and compile the Verse code using the Verse > Compile Verse Code option from the UEFN menu.

Access the Content Drawer and add the constructor_device to the level. Add an Item Spawner Device to the level and, in the Details tab, configure it as shown in the image so that a coin is generated every 3 seconds.


Select the constructor_device at the level. In the Details tab, add the reference to the Item Spawner Device.


Save the level and click the Launch Session button to load the level in Fortnite. Collect some coins. Each time a coin is collected, the saved coin counter will be updated and a message will be displayed with the current counter value.

To simulate local persistence, do not end your UEFN session. In Fortnite, press ESC to exit the current experience without exiting your UEFN session. 


When you re-enter the experience with the same player and collect a coin, the count will continue from the last value that was saved before exiting the experience.

Table of Contents Verse