Voltar ao Blog

Corrigindo a Opção Ausente "Clear Player Data" no Fortnite Creative: Resets em Verse e Recuperação de Estado com Backend Customizado

Publicado em 19 de julho de 2026
Corrigindo a Opção Ausente "Clear Player Data" no Fortnite Creative: Resets em Verse e Recuperação de Estado com Backend Customizado

Em resumo

Este artigo aborda como contornar o bug da opção ausente de "Clear Player Data" no Fortnite Creative e UEFN através de versionamento de schema manual em Verse. Também detalha como configurar opções locais de persistência no editor para acelerar o ciclo de playtest. Por fim, apresenta o uso de backends externos como o [horizOn](https://horizon.pm) para superar as restrições nativas de persistência de dados em plataformas fechadas.

Seu mapa mais recente do Fortnite Creative ou UEFN está pronto. Você refatorou sua economia, redesenhou seu sistema de classes e otimizou seu gameplay loop. Mas, na hora de publicar, você se depara com um pesadelo que quebra a engine: a opção "Press Triangle to Clear Player Data" desapareceu da tela de confirmação de publicação. Você está encurralado. Seus jogadores estão carregando o mapa com dados de persistência desatualizados, causando stack overflows instantâneos, quest lines quebradas e incompatibilidades de estado (state mismatches) que travam o jogo.

Este problema exato tem atormentado criadores nos fóruns de desenvolvedores da Epic, onde a ausência repentina do botão de reset deixa os usuários sem um mecanismo via UI para limpar estados de produção obsoletos. Quando o schema dos dados de persistência do jogador muda, o backend da Epic tenta mapear os dados serializados antigos para as suas novas estruturas. Se o seu código não for projetado para lidar com essas propriedades incompatíveis de forma elegante, você vai inutilizar (brickar) o estado do jogo para 100% dos jogadores que retornarem.

Neste tutorial, vamos nos aprofundar nos contornos técnicos para esse bug. Mostraremos como construir um sistema robusto de versionamento de schema em Verse, configurar as opções locais do UEFN para limpar estados de teste e explorar como backends externos customizados podem libertar você das limitações de persistência de plataformas fechadas.

A Causa Raiz: Por que Schemas Falham em Upgrades de Versão

No Fortnite Creative e no Unreal Editor for Fortnite (UEFN), os dados persistentes são armazenados na infraestrutura de banco de dados da Epic usando estruturas weak_map. Uma weak_map vincula uma instância de jogador (player) a uma classe customizada marcada com o especificador <persistable>. Ao contrário dos bancos de dados relacionais SQL ou documentais tradicionais, a camada de armazenamento da Epic não executa uma pipeline de migração formal quando você lança uma atualização. Em vez disso, ela tenta desserializar qualquer payload binário existente no cloud save do jogador para a definição atual da classe Verse.

Quando você deleta uma variável, renomeia uma propriedade ou altera um tipo (por exemplo, mudando um campo de int para float), o desserializador encontra uma incompatibilidade. Dependendo da gravidade da alteração, essa divergência de schema resulta em um de três modos de falha:

  • Falhas Silenciosas (Silent Failures): O runtime atribui valores padrão (default) às propriedades modificadas, apagando o progresso de qualquer forma, mas sem crashar.
  • Corrupção de Estado (State Corruption): A aplicação lê estados de memória inválidos ou encontra estruturas de dados inesperadas, disparando erros de lógica em outras partes do código.
  • Crashes Graves em Runtime (Severe Runtime Crashes): O mapa falha ao carregar ou a Verse VM interrompe a execução porque não consegue descompactar o mapa persistente.

Quando o botão "Clear Player Data" do console de publicação desaparece, você perde a capacidade de limpar os dados globalmente. Se um desenvolvedor fizer alterações fundamentais no layout de seus dados salvos, o jogo fica quebrado.

A Solução Manual: Versionamento de Schema dentro do Verse

Como você não pode contar com o portal de publicação da Epic para limpar os dados, é necessário implementar um fallback em nível de software. A estratégia é direta: introduzir um rastreador de versão diretamente em suas classes persistíveis. Ao comparar a versão salva do jogador com a versão ativa da aplicação no início da sessão, você pode identificar saves desatualizados e sobrescrevê-los com valores padrão.

Aqui está uma implementação em Verse pronta para produção que configura uma camada de persistência com controle de versão.

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

# A simple persistable class representing our player save schema.
# Note: Classes tagged with <persistable> can only contain certain types like int, float, string, and maps.
player_save_data := class<persistable>:
    # The SchemaVersion tracks which generation of player data this struct belongs to.
    SchemaVersion : int = 0
    GoldCount : int = 0
    XP : int = 0
    HasCompletedTutorial : int = 0  # Using int as a boolean flag representation for older Verse constraints

# The persistence manager device handles loading, validating, and migrating player data.
persistence_manager_device := class(creative_device):

    # By updating this value in the Editor, we force a schema migration next time the game runs.
    @editable
    TargetSchemaVersion : int = 2

    # Map to store player data in memory
    var PlayerDataMap : weak_map(player, player_save_data) = map{}

    # Initialize the persistence logic for a joining player
    InitializePlayer(Player : player) : void =
        # Check if the player already has persistent data
        if (ExistingData := PlayerDataMap[Player]):
            # If the stored version is older than our target version, trigger a manual reset
            if (ExistingData.SchemaVersion < TargetSchemaVersion):
                Print("Data version mismatch. Local: {ExistingData.SchemaVersion}, Target: {TargetSchemaVersion}. Resetting player data.")
                ResetPlayerData(Player)
            else:
                Print("Loaded existing player data. Version: {ExistingData.SchemaVersion}")
        else:
            # If no data exists, initialize a new record with the current version
            Print("No player data found. Initializing new record.")
            ResetPlayerData(Player)

    # Re-initializes a player's record with default values at the current version
    ResetPlayerData(Player : player) : void =
        NewData := player_save_data:
            SchemaVersion := TargetSchemaVersion
            GoldCount := 0
            XP := 0
            HasCompletedTutorial := 0

        # Save the freshly initialized data block to the persistence map
        if (set PlayerDataMap[Player] = NewData):
            Print("Successfully saved fresh persistent data block.")

Desconstruindo o Script de Versionamento

Este padrão se baseia em uma validação precoce dentro do método InitializePlayer. A lógica passo a passo funciona da seguinte forma:

  1. A Verificação de Entrada (Entry Check): Quando um jogador entra, o sistema consulta o PlayerDataMap em busca de uma instância existente de player_save_data.
  2. A Avaliação de Versão (Version Assessment): Se um estado de save existir, a engine verifica sua propriedade SchemaVersion.
  3. O Gatilho de Migração (Migration Trigger): Se SchemaVersion for menor do que a propriedade @editable TargetSchemaVersion do dispositivo, o script chama ResetPlayerData(Player).
  4. Sobrescrita de Estado (State Overwrite): ResetPlayerData constrói uma nova instância de player_save_data configurada com o novo TargetSchemaVersion e atualiza a map.

Ao incrementar manualmente o TargetSchemaVersion na configuração do seu dispositivo dentro do UEFN, você força uma limpeza de dados para todos os jogadores na inicialização da próxima sessão, tornando irrelevante o botão ausente na UI da Epic.

Procedimento de Teste Passo a Passo

Para validar com segurança este script de migração em seu ciclo de playtest, siga estes passos sequenciais:

  1. Arraste seu persistence_manager_device customizado para o viewport do seu nível no UEFN.
  2. No painel Details do UEFN, defina o TargetSchemaVersion inicial como 1.
  3. Inicie uma sessão de jogo, acumule alguma pontuação ou ouro e encerre o jogo.
  4. De volta ao editor, atualize o campo TargetSchemaVersion no dispositivo de 1 para 2.
  5. Inicie a sessão novamente. Observe a saída do console log: 'Data version mismatch. Local: 1, Target: 2. Resetting player data.'
  6. Verifique se o ouro e a progressão do seu jogador foram resetados de forma limpa, sem crashar a Verse VM.

Configurações de Desenvolvimento Local: Ignorando Arquivos de Save Durante a Iteração

Embora o versionamento de código em runtime resolva problemas em servidores de produção (live servers), ele adiciona uma fricção indesejada durante o playtesting local. Mudar manualmente o número da versão dentro do UEFN toda vez que você modifica uma feature em andamento é tedioso. Para otimizar seu processo de debugging, você pode ignorar completamente a persistência local através das configurações do seu editor.

Siga estes passos para desabilitar a persistência local:

  1. No UEFN, navegue até Island Settings no painel Outliner.
  2. Busque pela subseção User Options - Game Rules.
  3. Localize a opção Enable Persistence e desabilite-a.
  4. Se estiver testando loops multiplayer localmente, abra as Editor Preferences, vá para o menu In-Game Play e localize a caixa de seleção Clear Local Saved Data On Launch. Marcar essa opção garante que cada simulação comece com um cache vazio.

No entanto, os desvios locais não simulam cenários de produção. Embora o tempo de iteração em testes possa cair de 45 segundos para menos de 5 segundos com o cache de persistência desabilitado, você deve executar pelo menos um ciclo de staging completo com a persistência habilitada antes de lançar a versão de produção (pushing live). É aqui que os obstáculos de conexão podem se acumular. Setups de playtest locais são conhecidos por conflitos de drivers, fazendo com que desenvolvedores percam tempo precioso diagnosticando drivers de rede do Unreal Engine durante timeouts de inicialização de sessão do UEFN.

Limitações de Persistência Nativas do UEFN

Usar a camada de persistência nativa do Verse traz restrições arquiteturais significativas. Mesmo quando as opções de limpeza em nuvem (cloud-clear) funcionam perfeitamente, os desenvolvedores estão limitados por restrições rígidas da plataforma:

  • Orçamento de Armazenamento (Storage Budgets): Os blocos de dados persistíveis são limitados a 12KB por jogador por sessão. Exceder esse limite impede que o estado seja salvo.
  • Apenas Tipos Primitivos: Você não pode serializar classes customizadas que não estejam marcadas com <persistable>, nem pode armazenar referências a game objects (como creative_device ou atores dinâmicos).
  • Sem Consultas Externas: O sistema da Epic é uma caixa-preta completa. Você não pode consultar dados de jogadores a partir de um dashboard externo, auditar estados de usuários em busca de exploits ou migrar bancos de dados dinamicamente.
  • Gargalos de Telemetria: Projetar dashboards de analytics complexos no UEFN é altamente limitado pelos limites de comprimento de strings. Por exemplo, os desenvolvedores lutam constantemente com restrições ao superar o limite de 32 caracteres para nomes de eventos de dispositivos de analytics do UEFN.

Para minijogos casuais, esses limites são gerenciáveis. Mas para RPGs persistentes complexos, shooters live-ops ou títulos multiplataforma, depender exclusivamente da persistência proprietária de ciclo fechado bloqueia seu caminho de escalabilidade.

A Alternativa do Arquiteto: Estados de Banco de Dados Externos com horizOn

Para construir um jogo escalável que não seja limitado por bugs de UI específicos da plataforma ou tamanhos de dados proprietários, os desenvolvedores estão recorrendo a arquiteturas de backend externas. Em vez de armazenar estados de jogo nos memory maps locais do Verse, seu projeto UEFN pode se comunicar com um banco de dados externo usando o módulo http_client no Verse.

Essa abordagem oferece controle total sobre o ciclo de save do jogador. Quando você precisa limpar dados de persistência do jogador, não precisa procurar por um botão ausente no console da Epic ou fazer o push de uma atualização de código. Você pode simplesmente rodar um script administrativo de banco de dados ou clicar em um único botão no seu painel de controle do backend para limpar, migrar ou corrigir (patch) as tabelas dos jogadores.

Construir isso por conta própria exige a configuração de load balancers, sharding de banco de dados e gerenciamento de certificados SSL — facilmente 4 a 6 semanas de trabalho. Com o horizOn, esses serviços de backend vêm pré-configurados, permitindo que você publique seu jogo em vez de se preocupar com infraestrutura.

Ao rotear os estados dos jogadores através do horizOn, seu código Verse se torna um cliente simples que lê e grava estados através de endpoints REST limpos:

# Pseudocode showing HTTP-based state synchronization with [horizOn](https://horizon.pm)
sync_manager_device := class(creative_device):

    # Send player progress to [horizOn](https://horizon.pm) endpoint
    SavePlayerState(Player : player, SaveData : player_save_data) : void =
        # In a real environment, you construct a JSON payload and dispatch it
        # via the Verse http_client. This bypasses the 12KB local persistence limit.
        RequestURL := "https://api.horizon.pm/v1/players/{GetPlayerID(Player)}/state"
        Print("Dispatching persistent payload to [horizOn](https://horizon.pm) at: {RequestURL}")
        
        # This keeps the server-side payload lightweight (under 240 bytes) 
        # while securing long-term storage off the Fortnite engine.

Este setup desvincula completamente seu gameplay loop dos bugs físicos de backend da plataforma. Se um patch quebrar a compatibilidade do seu save local, você pode disparar uma migração de schema direcionada no seu banco de dados horizOn em tempo real, com zero interrupção no servidor do jogo em produção (live game server). Você evita o risco de quebrar servidores de produção por conta de pequenos ajustes estruturais.

Melhores Práticas para Gerenciamento de Persistência de Estado de Jogo

Quer você prefira os maps nativos do Verse ou aproveite uma arquitetura de servidor externa, manter um ciclo de vida de persistência estável é vital para jogos multiplayer. Siga estes princípios para proteger os estados dos jogadores:

  1. Implemente Versionamento Implícito Cedo: Sempre inclua um inteiro SchemaVersion no layout inicial de seus dados salvos. Mesmo se você não planeja modificar seu schema, ter a chave de versão desde o primeiro dia evita corrupção catastrófica de dados no futuro.
  2. Imponha Regras de Validação de Estado: Ao ler o estado carregado, valide os limites de cada atributo. Se a quantidade de ouro salva de um jogador for negativa ou exceder o limite estrutural do seu map, resete essa propriedade específica para evitar exploits na economia.
  3. Minimize a Frequência de Saves: Gravar na nuvem é custoso. Em vez de atualizar o banco de dados a cada moeda coletada, agrupe seus writes em lotes (batch). Dispare os saves durante marcos importantes, como a finalização da partida, level-up do jogador ou quando o jogador sai da sessão.
  4. Construa Estruturas de Fallback Limpas: Nunca permita que uma leitura com falha impeça um jogador de entrar no jogo. Se o payload de persistência falhar ao desserializar, recorra imediatamente a uma estrutura de estado padrão (default).
  5. Desacople o Código de Gameplay da Lógica de Armazenamento: Mantenha suas consultas de armazenamento isoladas em um dispositivo gerenciador de persistência dedicado. Seus dispositivos de armas, progressão e UI devem consultar este gerenciador em vez de fazer chamadas diretas ao data map.

Próximos Passos

Depender da UI do console da Epic para gerenciar migrações de estado críticas é um padrão de design arriscado. Quando a opção "Clear Player Data" falha, o versionamento em runtime dentro do Verse funciona como sua primeira linha de defesa. No entanto, se o seu jogo exige saves de alta frequência, telemetria complexa ou controle administrativo completo, migrar seu banco de dados para um backend dedicado é a solução definitiva.

Pronto para escalar seu backend multiplayer? Experimente o horizOn gratuitamente ou confira os API docs.


Fonte: clear players data button in creative 1