Como dominar o Asset Stripping no Unreal Engine Dedicated Server (Passo a passo)
Você inicia seu Unreal Engine dedicated server recém-compilado, esperando um processo leve e headless. Você faz um memory profile e lá estão eles: milhares de objetos UMaterial, UTexture e USoundWave ocupando a RAM do seu servidor.
A documentação oficial afirma que um servidor headless não renderiza visuais. Então, por que seu servidor está acumulando megabytes de dados de textura?
Todo desenvolvedor indie conhece o momento em que os custos de hosting começam a ameaçar o projeto. Quando uma máquina bare-metal só consegue hospedar 10 instâncias do seu jogo em vez de 50 devido ao memory bloat, sua arquitetura de backend está comprometida.
Neste mergulho técnico, vamos dissecar como o unreal engine dedicated server asset stripping realmente funciona, por que ghost assets permanecem na memória e como você pode arquitetar seu C++ e Blueprints para erradicá-los completamente.
A Anatomia de um "Ghost Asset" em um Dedicated Server
Para corrigir o problema, você deve entender o que o Unreal Automation Tool (UAT) faz ao realizar o cook para o target Server.
Quando um desenvolvedor vê UTexture ou UMaterial em um perfil de memória de servidor, a primeira suposição é que o engine falhou no stripping. Isso é apenas parcialmente verdade.
O Unreal Engine separa os assets em duas partes:
- O UObject Wrapper: Metadados, propriedades e dados de reflexão.
- O Bulk Data: A carga pesada real (pixels comprimidos DXT para texturas, vertex buffers para meshes, dados PCM para áudio).
Ao cozinhar um dedicated server, o cooker remove com sucesso o bulk data. Os dados de renderização somem. No entanto, o wrapper UObject permanece.
Se um Blueprint Class Default Object (CDO) tem uma hard reference para uma UTexture2D, o servidor precisa instanciar o UObject UTexture2D para satisfazer o sistema de reflexão e evitar crashes. Mesmo que o bulk data tenha sido removido e a textura ocupe apenas 1KB em vez de 10MB, o overhead de instanciar 50.000 desses UObjects resulta em um memory bloat significativo e sobrecarga no Garbage Collection.
Áudio e Partículas seguem a mesma lógica?
Sim. Se você tiver uma hard reference para um USoundCue ou UNiagaraSystem, o servidor carregará o UObject. Os dados pesados de áudio PCM são removidos, mas o objeto existe.
Com sistemas de partículas, isso é perigoso. Se houver lógica de CPU (como simulações Niagara complexas), o servidor pode executar o tick dessa lógica se não for configurado corretamente, consumindo CPU e memória.
Passo 1: Profiling do Memory Bloat do Servidor
Antes de mexer no código, você precisa de números. Você não otimiza o que não mede.
Inicie seu dedicated server com os argumentos:
-LLM -LLMCSV -memoryprofiler
No console do servidor, execute:
memreport -full
Procure por Obj List no arquivo .memreport. Você verá algo como:
Class UTexture2D: 1452 Objects, 1.25 MB
Class UMaterial: 840 Objects, 0.85 MB
Class USoundWave: 620 Objects, 0.45 MB
Embora 2.5MB pareça pouco, o alinhamento de memória e as dependências em cascata podem inflar um servidor de 150MB para mais de 600MB.
Confira nossa análise sobre arquitetura de servidores zero-waste.
Passo 2: Cortando Hard References com Soft Pointers
A causa principal de ghost assets são hard references. Se seu ACharacter tem um hard pointer para um retrato de UI, o servidor carregará esse asset.
A solução em C++: TSoftObjectPtr
Substitua referências visuais/áudio por soft references. Elas armazenam apenas o caminho do asset; o UObject só é carregado ao chamar LoadSynchronous() ou usar o Streamable Manager.
RUIM: Hard Reference (Carrega no Servidor)
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "UI")
UTexture2D* HeroPortrait;
BOM: Soft Reference (Servidor Limpo)
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "UI")
TSoftObjectPtr<UTexture2D> HeroPortraitSoft;
Passo 3: Forçando NeedsLoadForServer
Você pode ignorar componentes visuais sobrescrevendo NeedsLoadForServer.
bool UMyVisualCustomizationComponent::NeedsLoadForServer() const
{
return false; // Garante que o componente seja removido da memória do servidor
}
Passo 4: Stripping via Configuração
No DefaultEngine.ini, exclua diretórios do cook:
[/Script/UnrealEd.ProjectPackagingSettings]
+DirectoriesToNeverCook=(Path="UI/Widgets")
No YourGameServer.Target.cs, desative o áudio engine:
bDisableAudio = true;
Melhores Práticas
- Separar Meshes de Colisão de Visuais: Use um
UStaticMeshsimples para o servidor. - Auditar Construction Scripts: Use
Switch Has Authoritypara evitar que o servidor instancie visuais. - Isolar Data Assets: Separe stats (servidor/cliente) de visuais (apenas cliente).
- Automatizar Profiling no CI/CD: Verifique a memória em cada build.
Escalando seu Backend
Reduzir o footprint do servidor de 800MB para 180MB permite hospedar 4-5 vezes mais instâncias, cortando custos de AWS ou Google Cloud.
Orquestrar esses servidores é difícil. Com horizOn, esses serviços vêm pré-configurados. Foque no seu jogo enquanto o horizOn cuida do auto-scaling global.
Conclusão
O asset stripping no Unreal Engine depende da sua arquitetura. Usando soft pointers e separando dados visuais, você obtém a performance necessária para o multiplayer.
Pronto para escalar? Teste o horizOn grátis ou veja nossa documentação da API.