# Arquitectura do Cliente ZMMO

> Regras de organização do projecto Unreal `ZMMO` (Content + Source) e tutorial
> de como adicionar gameplay novo seguindo o padrão. **Este documento é
> normativo.** Qualquer estrutura nova no projecto tem de respeitar estas
> regras, ou justificar a excepção por escrito.

Última actualização: 2026-05-11.

> **Extensões da arquitetura** (documentos normativos paralelos, escopo específico):
> - [`ARQUITETURA_SERVER_SELECT.md`](ARQUITETURA_SERVER_SELECT.md) — Server Select, lista de mundos, handoff CharServer↔WorldServer, multi-region, queue, Valkey. Roadmap em 7 fases.
> - [`ARQUITETURA_CHARACTER_MODEL.md`](ARQUITETURA_CHARACTER_MODEL.md) — Stats primários (STR/AGI/VIT/INT/DEX/LUK), classes (Novato → especializações), fórmulas de stats derivados (ATK/MATK/DEF/...), `jobs.yml` data-driven, stat allocation server-side. Espelha rathena.

> **Sumário de mudanças (2026-05-11):** adicionada secção de **temas sazonais
> de UI** (`UI/Themes/`), com tutorial §4.7, regra de "no hard ref a textura
> em widget" em §5 e política de activação em §1.10.

---

## 1. Princípios fundamentais

Estas são as regras que **não negociamos**:

1. **Namespace do projecto.** Todo o conteúdo do jogo vive sob
   `Content/ZMMO/`. Nada de assets soltos na raiz `Content/`.
2. **Organizar por feature, não por tipo de asset.** Não criamos pastas
   `Meshes/`, `Textures/`, `Materials/` no nível alto. O Content Browser já
   filtra por prefixo (`SM_`, `T_`, `M_`...). Pastas existem para refletir
   **domínio de gameplay**.
3. **Self-contained por entidade.** Cada Mob, NPC ou Item vive numa pasta
   própria que contém **todos os seus assets** (malha, animações, materiais,
   texturas, áudio, VFX). Apagar a pasta = remover a entidade do jogo, sem
   referências órfãs espalhadas.
4. **Plano (máximo 3 níveis úteis).** Se está a aninhar mais que isso,
   provavelmente está a organizar errado. Excepção: dentro de uma entidade
   self-contained, sub-pasta `Animations/` é permitida quando o número de
   anims ultrapassa 5–6.
5. **DataTable manda em catálogo, Blueprint manda em comportamento.** Dados
   tabulares (stats, drops, preços, descrições) vão em
   `Content/ZMMO/Data/**/DT_*.uasset`. Comportamento vai em Blueprints
   herdados das bases em `Core/`. Nunca misturar.
6. **Structs e Enums vivem em C++.** Toda `USTRUCT` (row de DataTable
   inclusive) e toda `UENUM` é declarada em `Source/ZMMO/Data/`. Blueprint
   Structs estão **proibidos** — eles corrompem em refactor e não dão tipos
   fortes.
7. **Hierarquia de Entity.** Tudo que vive no mundo herda da mesma raiz:
   `BP_Entity_Base` → (`BP_Player_Base` | `BP_NPC_Base` | `BP_Mob_Base`) →
   instâncias concretas. Espelha a classe C++ `AZMMOEntity` em
   `Source/ZMMO/Game/Entity/`.
8. **Lazy loading via `TSoftObjectPtr`.** Linhas de DataTable e referências
   entre features usam soft pointers. Nada de hard ref para BPs de mob/item a
   partir da DT mestre — caso contrário carregamos o mundo inteiro ao abrir o
   inventário.
9. **`Developers/` e `ExternalContent/` fora do namespace `ZMMO/`.** Não
   entram no cook (`Developers/`) e não poluem o nosso namespace
   (`ExternalContent/` para Fab/Megascans/Marketplace).
10. **Temas de UI são data-driven, não hard-coded.** Widgets não têm hard
    ref para textura/som sazonal — pedem ao `UZMMOThemeSubsystem` via uma
    chave declarada em `EZMMOThemeKey` (C++). Veja §1.10 abaixo para a
    política de activação.

### 1.10. Política de activação de temas

A UI suporta **temas** (`Default`, `Christmas`, `Halloween`, etc.). A escolha
do tema activo segue esta **ordem de precedência** em runtime:

1. **Override de desenvolvimento** (`DefaultGame.ini`, chave `ActiveTheme=`).
   Só lido fora de builds Shipping. Para QA testar Natal em Maio.
2. **Resposta autoritativa do servidor.** Quando o servidor Zeus envia o
   opcode `ServerHello` com `ThemeId`, ele vence. É o único caminho válido
   em produção.
3. **Calendário local do cliente** (`DT_ThemeCalendar`). Fallback antes do
   login (tela de login/character-select aparece antes do servidor falar) e
   se o servidor não enviar `ThemeId`.
4. **`DA_Theme_Default`.** Último recurso. Sempre presente, sempre carregado.

**Por que servidor vence:** MMO precisa ligar Halloween fora da data
canónica, fazer evento-surpresa, A/B test de tema sem patch do cliente.

**Por que data local existe:** sem ela, jogador que abre o jogo em 24 de
Dezembro vê tema Default até autenticar — quebra a magia sazonal.

**Por que .ini só fora de Shipping:** evita que um jogador edite o ficheiro
e force um tema que não devia ter acesso (cosméticos pagos, por exemplo).

---

## 2. Estrutura de pastas

### 2.1. `Clients/ZMMO/Content/`

```
Content/
│
├── ZMMO/                              ← namespace do projecto
│   │
│   ├── Core/                          ← bases que outros assets herdam
│   │   ├── Entity/
│   │   │   ├── BP_Entity_Base.uasset          ← herda AZMMOEntity (C++)
│   │   │   └── BPI_Entity.uasset              ← interface comum
│   │   ├── Player/
│   │   │   └── BP_Player_Base.uasset
│   │   ├── NPC/
│   │   │   └── BP_NPC_Base.uasset
│   │   ├── Mob/
│   │   │   ├── BP_Mob_Base.uasset
│   │   │   ├── BT_Mob_Default.uasset          ← Behavior Tree base
│   │   │   └── BTT_Mob_*.uasset               ← Tasks compartilhadas
│   │   ├── Item/
│   │   │   ├── BP_Item_Base.uasset
│   │   │   └── BPI_Item.uasset
│   │   └── Network/                           ← debug do UZMMOWorldSubsystem
│   │
│   ├── Entities/                      ← TODAS as instâncias concretas
│   │   ├── Players/
│   │   │   └── Classes/
│   │   │       ├── Warrior/
│   │   │       │   ├── BP_Player_Warrior.uasset
│   │   │       │   ├── SK_Warrior.uasset
│   │   │       │   ├── ABP_Warrior.uasset
│   │   │       │   ├── M_Warrior.uasset
│   │   │       │   ├── T_Warrior_*.uasset
│   │   │       │   └── Animations/
│   │   │       ├── Mage/
│   │   │       └── Archer/
│   │   │
│   │   ├── NPCs/
│   │   │   ├── Vendor_Blacksmith/
│   │   │   │   ├── BP_NPC_Blacksmith.uasset
│   │   │   │   ├── SK_Blacksmith.uasset
│   │   │   │   ├── ABP_Blacksmith.uasset
│   │   │   │   └── ...
│   │   │   └── Questgiver_Elder/
│   │   │
│   │   └── Mobs/
│   │       ├── Beasts/                        ← família (organiza, não herda)
│   │       │   ├── Wolf_Gray/                 ← pacote completo do mob
│   │       │   │   ├── BP_Mob_Wolf_Gray.uasset
│   │       │   │   ├── SK_Wolf.uasset
│   │       │   │   ├── PHY_Wolf.uasset
│   │       │   │   ├── M_Wolf.uasset
│   │       │   │   ├── MI_Wolf_Gray.uasset
│   │       │   │   ├── T_Wolf_*.uasset
│   │       │   │   ├── Animations/
│   │       │   │   │   ├── ABP_Wolf.uasset
│   │       │   │   │   ├── AS_Wolf_Skel.uasset
│   │       │   │   │   ├── AM_Wolf_AttackBite.uasset
│   │       │   │   │   └── A_Wolf_{Idle,Run,Hit,Death}.uasset
│   │       │   │   ├── Audio/
│   │       │   │   └── VFX/
│   │       │   ├── Bear_Brown/
│   │       │   └── Boar_Wild/
│   │       ├── Undead/
│   │       ├── Humanoids/
│   │       ├── Dragons/
│   │       └── Bosses/
│   │
│   ├── Data/                          ← apenas DataTables (.uasset)
│   │   ├── Items/
│   │   │   ├── DT_Items_Master.uasset
│   │   │   ├── DT_Items_Weapons.uasset
│   │   │   ├── DT_Items_Armor.uasset
│   │   │   ├── DT_Items_Consumables.uasset
│   │   │   └── DT_ItemDrops.uasset
│   │   ├── Mobs/
│   │   │   ├── DT_Mobs_Master.uasset
│   │   │   └── DT_MobSpawns.uasset
│   │   ├── Players/
│   │   │   ├── DT_Classes.uasset
│   │   │   └── DT_ExpCurve.uasset
│   │   ├── NPCs/
│   │   │   ├── DT_NPCs.uasset
│   │   │   └── DT_Dialogs.uasset
│   │   ├── Abilities/
│   │   │   ├── DT_Abilities.uasset
│   │   │   └── DT_StatusEffects.uasset
│   │   ├── Quests/
│   │   │   ├── DT_Quests.uasset
│   │   │   └── DT_QuestRewards.uasset
│   │   └── World/
│   │       └── DT_Zones.uasset
│   │
│   ├── Items/                         ← assets visuais (modelo/icon dos itens)
│   │   ├── Equipment/
│   │   │   ├── Weapons/
│   │   │   │   ├── Sword_Iron/
│   │   │   │   │   ├── SM_Sword_Iron.uasset
│   │   │   │   │   ├── M_Sword_Iron.uasset
│   │   │   │   │   ├── T_Sword_Iron_*.uasset
│   │   │   │   │   └── T_Icon_Sword_Iron.uasset
│   │   │   │   └── Bow_Hunter/
│   │   │   ├── Armor/
│   │   │   └── Accessories/
│   │   ├── Consumables/
│   │   │   ├── Potion_Health/
│   │   │   └── Potion_Mana/
│   │   ├── Materials/
│   │   └── Quest/
│   │
│   ├── Abilities/                     ← VFX/Cues/Montagens (data fica em Data/)
│   │   ├── Combat/  Buffs/  Heals/  Movement/
│   │   └── Shared/
│   │
│   ├── World/
│   │   ├── Maps/                      ← L_World_Open, L_City_*, L_Dungeon_*
│   │   ├── Instances/
│   │   ├── Environment/               ← Architecture/  Nature/  Props/
│   │   └── Interactables/             ← baús, portas, warps, recursos
│   │
│   ├── Maps/                          ← mapas que NÃO são de mundo
│   │   └── FrontEnd/                  ← L_FrontEnd (boot/menu; GameMode via
│   │                                     World Settings = AZMMOFrontEndGameMode)
│   │
│   ├── UI/                            ← HUD, Login, CharacterSelect, Inventory,
│   │   │                                Chat, Party, Guild, Trade, Quest, Map,
│   │   │                                Shared, Icons
│   │   ├── Shared/                      ← WBPs reutilizáveis (UI_Button_Master,
│   │   │                                   UI_Panel_Master, UI_Spinner_Master,
│   │   │                                   UI_CheckBox_Master, UI_Input_Master)
│   │   ├── FrontEnd/                     ← WBP_PrimaryGameLayout, DA_FrontEndScreenSet,
│   │   │                                   telas refinadas (Boot/Login/… vindas do Forge)
│   │   ├── Fonts/                       ← Font_*/FF_* (Cinzel, Rajdhani)
│   │   ├── CommonUI/Style/              ← estilos CommonUI (espelha o Hyper)
│   │   │   ├── Button/                  ← BSB_* (UCommonButtonStyle)
│   │   │   └── Text/                    ← BST_* (UCommonTextStyle)
│   │   └── Themes/                     ← temas sazonais (data-driven, ver §1.10)
│   │       ├── DA_Theme_Default.uasset         ← sempre carregado, fallback
│   │       ├── DA_Theme_Christmas.uasset
│   │       ├── DA_Theme_Halloween.uasset
│   │       ├── DT_ThemeCalendar.uasset         ← datas → ThemeId (fallback local)
│   │       ├── _Shared/                        ← assets reutilizados entre temas
│   │       ├── Default/                        ← assets do tema base
│   │       │   ├── HUD/   Login/   Inventory/
│   │       │   ├── Audio/ MS_MainMenu.uasset
│   │       │   └── VFX/
│   │       ├── Christmas/                      ← sazonal
│   │       │   ├── HUD/   Login/   Inventory/
│   │       │   ├── Audio/ MS_MainMenu_Christmas.uasset
│   │       │   └── VFX/   NS_Snow.uasset
│   │       └── Halloween/  ...                 ← mesma estrutura
│   ├── Effects/                       ← VFX globais (Niagara)
│   ├── Audio/                         ← Music, Ambient, SFX, Voice
│   ├── Input/                         ← Enhanced Input
│   ├── Cinematics/                    ← Sequencer
│   ├── Movement/                      ← Mounts, Transport
│   ├── Localization/                  ← StringTables
│   └── Debug/                         ← Maps de smoke test
│
├── Developers/                        ← rascunho por dev (não cooka)
│   └── <nick-do-dev>/
├── AutoCreated/                       ← saída CRUA do Zeus UMG Forge (HTML→WBP).
│   └── <batch>/                         Quarentena: refina-se e MOVE p/ ZMMO/UI/
│                                        FrontEnd/ antes de produção (não cooka cru)
├── ExternalContent/                   ← Fab / Megascans / Marketplace
│   ├── Fab/  Megascans/  Marketplace/
├── Collections/
└── __ExternalActors__/  __ExternalObjects__/   ← World Partition (não mexer)
```

### 2.2. `Clients/ZMMO/Source/ZMMO/`

```
Source/ZMMO/
├── ZMMO.Build.cs
├── ZMMO.h
├── ZMMO.cpp
│
├── Game/                              ← gameplay runtime (já existe)
│   ├── Entity/                        ← AZMMOEntity + derivados
│   ├── Controller/                    ← AZMMOPlayerController,
│   │                                    AZMMOFrontEndPlayerController
│   ├── Modes/                         ← GameMode + GameInstance,
│   │                                    AZMMOFrontEndGameMode
│   ├── Network/                       ← UZMMOWorldSubsystem
│   └── UI/                            ← runtime de UI (não é contrato de dados)
│       ├── ZMMOThemeSubsystem.*       ← resolução de tema
│       ├── Widgets/                   ← UUIButton_Base, UUIPanel_Base,
│       │                                UUISpinner_Base, UUICheckBox_Base,
│       │                                UUIInput_Base (variantes Box/Outline/
│       │                                Underline/Search), UUICommonText_Base
│       │                                (EUITextRole → FUIStyle.Text)
│       └── FrontEnd/                  ← infra de navegação CommonUI:
│                                        UUIActivatableScreen_Base,
│                                        UUIBootScreen_Base (1ª tela),
│                                        UUILoginScreen_Base (2ª tela),
│                                        CharServerOpcodes.h (faixa 2000-2099),
│                                        UUIPrimaryGameLayout_Base,
│                                        UUIManagerSubsystem (LocalPlayer),
│                                        UUIFrontEndFlowSubsystem (GameInstance),
│                                        UUIFrontEndScreenSet (UDataAsset)
│
└── Data/                              ← contrato de dados (USTRUCT + UENUM)
    ├── ZMMOData.h                     ← header agregador (opcional)
    ├── Items/
    │   ├── ItemRow.h                  ← FItemRow : public FTableRowBase
    │   └── ItemTypes.h                ← E_ItemType, E_ItemRarity, E_EquipSlot
    ├── Mobs/
    │   ├── MobRow.h                   ← FMobRow
    │   └── MobTypes.h                 ← E_MobFaction, E_MobBehavior
    ├── Players/
    │   ├── ClassRow.h                 ← FClassRow
    │   └── StatBlock.h                ← FStatBlock (HP/MP/Sta/Atk/Def…)
    ├── NPCs/
    │   ├── NPCRow.h
    │   └── DialogRow.h
    ├── Abilities/
    │   ├── AbilityRow.h
    │   └── StatusEffectRow.h
    ├── Quests/
    │   └── QuestRow.h
    ├── UI/
    │   ├── ThemeKeys.h                 ← EZMMOThemeKey (HUD_Frame, Login_BG…)
    │   ├── ThemeRow.h                  ← FThemeEntry (Key → SoftAsset)
    │   ├── ThemeCalendarRow.h          ← FThemeCalendarRow (data → ThemeId)
    │   ├── FrontEndTypes.h             ← EZMMOFrontEndState, EZMMOLobbyPage
    │   └── UILayerTags.h/.cpp          ← GameplayTags nativos UI.Layer.*
    └── World/
        └── ZoneRow.h
```

Regra: **toda DT em `Content/ZMMO/Data/X/`** tem a `Row Structure` definida no
`.h` correspondente em **`Source/ZMMO/Data/X/`**. Espelhamento 1-para-1 nos
nomes das sub-pastas.

O subsystem do tema (`UZMMOThemeSubsystem`) vive em
`Source/ZMMO/Game/UI/` — é gameplay/runtime, não contrato de dados, por isso
não fica em `Data/`.

---

## 3. Convenções de nomenclatura

### 3.1. Pastas

- `PascalCase`, sem espaços, sem acentos.
- Nome no singular para categoria conceitual (`Mob`, `Item`, `Quest`).
- Nome no plural para colecção de instâncias (`Mobs/`, `Items/`, `Quests/`).
- Família de mob/item usa nome temático: `Beasts/`, `Undead/`, `Weapons/`.
- Instância individual usa `Tipo_Variante`: `Wolf_Gray`, `Sword_Iron`,
  `Vendor_Blacksmith`.

### 3.2. Assets (prefixo obrigatório)

| Prefixo | Tipo                              | Exemplo                       |
|---------|-----------------------------------|-------------------------------|
| `BP_`   | Blueprint Class                   | `BP_Mob_Wolf_Gray`            |
| `BPI_`  | Blueprint Interface               | `BPI_Entity`                  |
| `UI_`   | Widget Blueprint (estilo Hyper)   | `UI_Button_Base`, `UI_Inventory_Slot` |
| `ABP_`  | Animation Blueprint               | `ABP_Wolf`                    |
| `BT_`   | Behavior Tree                     | `BT_Mob_Default`              |
| `BTT_`  | Behavior Tree Task                | `BTT_Mob_ChasePlayer`         |
| `BTS_`  | Behavior Tree Service             | `BTS_Mob_FindTarget`          |
| `BTD_`  | Behavior Tree Decorator           | `BTD_Mob_CanSeeTarget`        |
| `BB_`   | Blackboard                        | `BB_Mob_Default`              |
| `SK_`   | Skeletal Mesh                     | `SK_Wolf`                     |
| `SKEL_` | Skeleton                          | `SKEL_Wolf`                   |
| `SM_`   | Static Mesh                       | `SM_Sword_Iron`               |
| `PHY_`  | Physics Asset                     | `PHY_Wolf`                    |
| `M_`    | Material                          | `M_Wolf`                      |
| `MI_`   | Material Instance                 | `MI_Wolf_Gray`                |
| `MF_`   | Material Function                 | `MF_NormalBlend`              |
| `T_`    | Texture                           | `T_Wolf_Diffuse`              |
| `RT_`   | Render Target                     | `RT_MiniMap`                  |
| `Font_` | Font (UFont, Composite)           | `Font_Cinzel`                 |
| `FF_`   | Font Face (UFontFace, Inline)     | `FF_Cinzel_Bold`              |
| `BSB_`  | Common Button Style (UCommonButtonStyle) | `BSB_Button_Transparent` |
| `BST_`  | Common Text Style (UCommonTextStyle)     | `BST_Button`             |
| `NS_`   | Niagara System                    | `NS_Wolf_Death`               |
| `NE_`   | Niagara Emitter                   | `NE_Sparks_Small`             |
| `SC_`   | Sound Cue                         | `SC_Wolf_Growl`               |
| `SW_`   | Sound Wave                        | `SW_Wolf_Growl_01`            |
| `MS_`   | MetaSound Source                  | `MS_AmbientForest`            |
| `MSA_`  | Mix MetaSound Asset               | `MSA_CombatMix`               |
| `A_`    | Animation Sequence                | `A_Wolf_Idle`                 |
| `AM_`   | Animation Montage                 | `AM_Wolf_AttackBite`          |
| `AS_`   | Anim State / Skeleton ref         | `AS_Wolf_Skel`                |
| `IA_`   | Input Action                      | `IA_Move`                     |
| `IMC_`  | Input Mapping Context             | `IMC_Default`                 |
| `DA_`   | Data Asset (PrimaryDataAsset)     | `DA_Quest_FirstSteps`         |
| `DT_`   | Data Table                        | `DT_Items_Master`             |
| `CT_`   | Curve Table                       | `CT_DamageFalloff`            |
| `C_`    | Curve                             | `C_AttackPower`               |
| `L_`    | Level / Map                       | `L_World_Open`                |
| `LS_`   | Level Sequence                    | `LS_OpeningCinematic`         |
| `GE_`   | Gameplay Effect *(se GAS)*        | `GE_StatusBleed`              |
| `GA_`   | Gameplay Ability *(se GAS)*       | `GA_Fireball`                 |
| `GC_`   | Gameplay Cue *(se GAS)*           | `GC_Hit_Blood`                |

### 3.3. C++ (`Source/ZMMO/Data/`)

- Struct: `F<Nome>Row` quando é linha de DataTable. Ex: `FItemRow`, `FMobRow`.
- Struct genérica (não-DT): `F<Nome>`. Ex: `FStatBlock`.
- Enum: `E<Nome>`. Sempre `UENUM(BlueprintType)` e tipado: `enum class EItemType : uint8`.
- Header path espelha a pasta: `Source/ZMMO/Data/Items/ItemRow.h` →
  `#include "Data/Items/ItemRow.h"`.

**Exceção — classes base de UI (widgets):** a família de UI **não** leva o
prefixo `ZMMO` (ao contrário de `AZMMOEntity`/`UZMMOGameInstance`). Classe C++
base de widget = `UUI<Componente>_Base`, sempre `UCLASS(Abstract)` (não
instanciável direto; só os filhos derivam — padrão `_Abstract` do Hyper).
Ex.: `UUIButton_Base`, `UUIPanel_Base`, `UUIProgressBar_Base`.

**Sub-regra — infra de navegação de front-end:** as classes que orquestram a
navegação CommonUI seguem o mesmo prefixo `UUI` (sem `ZMMO`) por coerência com
a família de UI, **mesmo não sendo widgets**. Assim: o layout raiz é
`UUIPrimaryGameLayout_Base` (Abstract, widget), a base de tela é
`UUIActivatableScreen_Base` (Abstract, widget), e os subsistemas de UI são
`UUIManagerSubsystem` (`ULocalPlayerSubsystem`) e `UUIFrontEndFlowSubsystem`
(`UGameInstanceSubsystem`). Atores de gameplay do front-end (GameMode,
PlayerController) **mantêm** o prefixo `AZMMO` — não são UI, espelham
`AZMMOGameMode`: `AZMMOFrontEndGameMode`, `AZMMOFrontEndPlayerController`.

**Regra do UMG (importante):** um Widget Blueprint **não pode** herdar de outro
Widget Blueprint que tenha árvore de widgets (UMG aborta a compilação: "apenas
um deles deve ter árvore"). Portanto a camada abstrata é **só a classe C++**
`UUI<X>_Base`. O WBP concreto (prefixo `UI_`, ver §3.2) herda **direto da
classe C++**: `UUIButton_Base` (C++ Abstract) → `UI_Button_Master` (WBP, árvore
própria). Variantes por feature são **WBPs irmãos** sobre a mesma classe C++
(`UI_Button_<Feature>` : `UUIButton_Base`), cada um com a própria árvore
(montada via `set_widget_tree`) — nunca encadeando WBPs.

---

## 4. Tutoriais

### 4.1. Adicionar um Mob novo (ex: `Wolf_Gray`)

**Pré-requisito:** já existe `FMobRow` em
`Source/ZMMO/Data/Mobs/MobRow.h` e `DT_Mobs_Master` em
`Content/ZMMO/Data/Mobs/`.

1. Criar a pasta `Content/ZMMO/Entities/Mobs/Beasts/Wolf_Gray/`.
2. Importar **todos** os assets do lobo dentro dela:
   - `SK_Wolf`, `SKEL_Wolf`, `PHY_Wolf`.
   - `T_Wolf_Diffuse`, `T_Wolf_Normal`, `T_Wolf_ORM`.
   - `M_Wolf` e a variante `MI_Wolf_Gray`.
   - `Animations/`: `ABP_Wolf`, `AS_Wolf_Skel`, `A_Wolf_*`, `AM_Wolf_*`.
   - `Audio/`: `SC_Wolf_Growl`, `SC_Wolf_Footstep`.
   - `VFX/`: `NS_Wolf_Death`.
3. Criar `BP_Mob_Wolf_Gray` **herdando** de `Core/Mob/BP_Mob_Base`.
4. Atribuir no BP: `SK_Wolf` no Mesh, `ABP_Wolf` no AnimClass,
   `BT_Mob_Default` (ou um BT próprio se necessário) no AIController.
5. Abrir `Content/ZMMO/Data/Mobs/DT_Mobs_Master.uasset`. Adicionar linha
   `Wolf_Gray`:
   - `BlueprintRef` = `BP_Mob_Wolf_Gray` (via `TSoftObjectPtr` — soft).
   - `Stats` = `FStatBlock` com HP/Atk/Def adequados.
   - `Faction` = `EMobFaction::Hostile`.
   - `DropTableRow` = `WolfDrops` (linha em `DT_ItemDrops`).
6. Se for dropar loot novo, abrir `DT_ItemDrops` e adicionar a linha
   `WolfDrops` com array de `FItemRow` ids + chances.

**Regra:** nunca colocar um asset de `Wolf_Gray` fora de
`Entities/Mobs/Beasts/Wolf_Gray/`. Apagar a pasta tem de remover o mob por
inteiro.

### 4.2. Adicionar um Item novo (ex: `Sword_Iron`)

**Pré-requisito:** `FItemRow` em `Source/ZMMO/Data/Items/ItemRow.h`,
`DT_Items_Master` em `Content/ZMMO/Data/Items/`.

1. Criar `Content/ZMMO/Items/Equipment/Weapons/Sword_Iron/`.
2. Importar `SM_Sword_Iron`, texturas `T_Sword_Iron_*`, material
   `M_Sword_Iron`, e o ícone `T_Icon_Sword_Iron`.
3. Abrir `DT_Items_Master`. Adicionar linha `Sword_Iron`:
   - `Type` = `EItemType::Weapon`.
   - `Rarity` = `EItemRarity::Common`.
   - `EquipSlot` = `EEquipSlot::MainHand`.
   - `WorldMesh` = `SM_Sword_Iron` (soft).
   - `Icon` = `T_Icon_Sword_Iron` (soft).
   - `DisplayName`, `Description` via `StringTable` em `Localization/`.

**Sem Blueprint por item.** O item é "data only" — quando precisar de
comportamento especial (ex: poção que cura), criar `BP_Item_Potion_Health`
herdando de `Core/Item/BP_Item_Base` e apontar a coluna `BehaviorClass` da
linha para esse BP. A maioria dos itens **não** tem BP próprio.

### 4.3. Adicionar uma Classe de Player (ex: `Warrior`)

1. Criar `Content/ZMMO/Entities/Players/Classes/Warrior/`.
2. Importar `SK_Warrior`, anims, materiais, etc. (mesmo padrão self-contained
   do mob).
3. Criar `BP_Player_Warrior` herdando de `Core/Player/BP_Player_Base`.
4. Adicionar linha `Warrior` em `DT_Classes`:
   - `BlueprintRef` = `BP_Player_Warrior` (soft).
   - `BaseStats` = `FStatBlock`.
   - `LevelUpStats` = `FStatBlock` (delta por nível).
   - `StartingAbilities` = `TArray<FName>` de ids em `DT_Abilities`.

### 4.4. Adicionar um NPC (ex: `Vendor_Blacksmith`)

1. Criar `Content/ZMMO/Entities/NPCs/Vendor_Blacksmith/` (self-contained).
2. Criar `BP_NPC_Blacksmith` herdando de `Core/NPC/BP_NPC_Base`.
3. Adicionar linha `Vendor_Blacksmith` em `DT_NPCs`:
   - `BlueprintRef` = `BP_NPC_Blacksmith` (soft).
   - `Role` = `ENPCRole::Vendor`.
   - `ShopInventory` = `TArray<FName>` de ids em `DT_Items_Master`.
   - `DialogRoot` = id em `DT_Dialogs`.

### 4.5. Adicionar uma Row Struct em C++

Exemplo: nova struct `FCraftRecipeRow` para receitas de crafting.

1. Criar `Source/ZMMO/Data/Crafting/CraftRecipeRow.h`:

```cpp
#pragma once

#include "CoreMinimal.h"
#include "Engine/DataTable.h"
#include "CraftRecipeRow.generated.h"

USTRUCT(BlueprintType)
struct ZMMO_API FCraftRecipeRow : public FTableRowBase
{
    GENERATED_BODY()

    UPROPERTY(EditAnywhere, BlueprintReadOnly)
    FName OutputItem;

    UPROPERTY(EditAnywhere, BlueprintReadOnly)
    int32 OutputQuantity = 1;

    UPROPERTY(EditAnywhere, BlueprintReadOnly)
    TArray<FName> Ingredients;
};
```

2. Recompilar o módulo `ZMMO`.
3. No editor: `Content/ZMMO/Data/Crafting/` → `Add → Miscellaneous → Data Table`
   → escolher `CraftRecipeRow` como Row Structure → salvar como
   `DT_Crafting_Recipes`.

### 4.6. Conectar uma DataTable a um Blueprint em runtime

```cpp
// Em BP_Mob_Base (ou na sua classe C++ AZMMOMobBase):
//
// UPROPERTY(EditDefaultsOnly, Category="Data")
// TSoftObjectPtr<UDataTable> MobsTable;
//
// UPROPERTY(EditAnywhere, Category="Data")
// FName MobId;
//
// void AZMMOMobBase::BeginPlay()
// {
//     Super::BeginPlay();
//     if (UDataTable* Table = MobsTable.LoadSynchronous())
//     {
//         if (FMobRow* Row = Table->FindRow<FMobRow>(MobId, TEXT("Mob init")))
//         {
//             ApplyStats(Row->Stats);
//             Faction = Row->Faction;
//             DropTableRowId = Row->DropTableRow;
//         }
//     }
// }
```

Regra: o `MobId` é setado pelo `UZMMOWorldSubsystem` quando o servidor envia
o opcode de spawn. O cliente nunca instancia mob "por nome" — sempre via id.

### 4.7. Adicionar um tema sazonal (ex: `Christmas`)

**Pré-requisito:** já existem `EZMMOThemeKey` em
`Source/ZMMO/Data/UI/ThemeKeys.h`, `FThemeEntry` em `ThemeRow.h`, e o
`UZMMOThemeSubsystem` em `Source/ZMMO/Game/UI/`.

1. Criar a pasta `Content/ZMMO/UI/Themes/Christmas/` com sub-pastas que
   espelham as features de UI a substituir: `HUD/`, `Login/`, `Inventory/`,
   `Audio/`, `VFX/`. Não precisa criar sub-pastas para features que o tema
   **não** altera.
2. Importar os assets variantes lá dentro. Manter os **mesmos nomes** que os
   equivalentes em `Themes/Default/` ajuda a comparar:
   - `Themes/Default/HUD/T_HUD_Frame.uasset` ↔
     `Themes/Christmas/HUD/T_HUD_Frame.uasset`.
3. Criar `DA_Theme_Christmas.uasset` em `Content/ZMMO/UI/Themes/` como
   `PrimaryDataAsset` herdando da classe `UZMMOThemeDataAsset` (a classe
   vive em `Source/ZMMO/Game/UI/`).
4. Preencher o `TMap<EZMMOThemeKey, FThemeEntry>` do data asset **apenas com
   as chaves que o tema sobrescreve**. As que ficam vazias caem
   automaticamente para `DA_Theme_Default`.
5. Adicionar linha em `DT_ThemeCalendar`:
   - `ThemeId` = `Christmas`.
   - `StartDate` = `12-15`.
   - `EndDate` = `01-05`.
   - `Priority` = `10` (caso duas datas se sobreponham).
6. No servidor Zeus, quando quiser activar o tema (autoritativo), enviar o
   opcode `ServerHello` com `ThemeId = "Christmas"`. Em ausência disso, o
   cliente usa o calendário do passo 5.

**Adicionar uma chave nova de tema** (ex: tela de loading sazonal):

1. Abrir `Source/ZMMO/Data/UI/ThemeKeys.h` e adicionar o valor ao enum:
   ```cpp
   UENUM(BlueprintType)
   enum class EZMMOThemeKey : uint8
   {
       HUD_Frame,
       Login_Background,
       Login_Logo,
       Inventory_SlotEmpty,
       LoadingScreen,      // <-- nova chave
       MainMenu_Music,
   };
   ```
2. Recompilar o módulo `ZMMO`.
3. Abrir `DA_Theme_Default` no editor e preencher a nova chave **obrigatoriamente**
   (Default tem de ter todas).
4. Preencher nos temas sazonais apenas se quiser substituir.

**Regra de ouro do tema:** widget consome via subsystem, nunca por hard ref.

```cpp
// Em vez de:
// UPROPERTY(EditAnywhere) TObjectPtr<UTexture2D> HudFrameTex;
//
// Faz:
// const UZMMOThemeSubsystem* Theme = GetGameInstance()->GetSubsystem<UZMMOThemeSubsystem>();
// SetBrushFromSoftTexture(Theme->GetTexture(EZMMOThemeKey::HUD_Frame));
```

O subsystem aplica fallback internamente: pergunta ao tema activo; se a
chave não estiver preenchida, devolve a do `Default`.

### 4.8. Adicionar uma tela de front-end (ex: `Login`)

**Pré-requisito:** já existem `UUIActivatableScreen_Base` e
`UUIFrontEndFlowSubsystem` em `Source/ZMMO/Game/UI/FrontEnd/`, o
`WBP_PrimaryGameLayout` e o `DA_FrontEndScreenSet` em
`Content/ZMMO/UI/FrontEnd/`.

Fluxo geral: **Boot → Connecting → Login → ServerSelect → Lobby → EnteringWorld
→ InWorld**. O **Lobby** é o hub principal logado; suas páginas internas
(CharacterSelect, CharacterCreate, Shop, Settings…) são `EZMMOLobbyPage`,
navegadas por um stack CommonUI **dentro** da tela do Lobby — não são estados
de topo do fluxo.

**Rede do pré-login:** o `UUIFrontEndFlowSubsystem` dirige a conexão ao
**`UZeusCharServerSubsystem`** (WebSocket, `CharServerUrl` de Project Settings,
default `ws://127.0.0.1:7100/zeus`) ao entrar em **Boot** — NÃO o
`UZeusNetworkSubsystem` (UDP, world server, usado só no travel
EnteringWorld→InWorld). A tela Boot (`UUIBootScreen_Base`) observa o
CharServer: libera o botão "Iniciar" no `OnConnected`; o clique chama
`UUIFrontEndFlowSubsystem::RequestEnterLogin()` → estado Login. Tela nunca
segura hard-ref de asset de tema (cores via `FUIStyle`; §5).

**Login:** a tela `UUILoginScreen_Base` autentica pelo MESMO WebSocket do
CharServer enviando `C_CHAR_AUTH_REQUEST` (opcode 2000, ver
`CharServerOpcodes.h`) com um token. Escopo atual = **dev**: token `dev:<n>`
aceito pelo `StubTokenValidator` (senha ignorada no stub). `S_CHAR_AUTH_OK`
→ `RequestEnterServerSelect()` → estado ServerSelect; `S_CHAR_AUTH_REJECT`
→ mensagem de erro na própria tela. Auth real (HTTP `/auth/login` + JWT)
fica para tarefa dedicada. "Voltar" → `RequestBack()` (Login→Boot, CharServer
permanece conectado).

1. Prototipar a tela em HTML/CSS em `Tools/Templates/MMO_Widget/` (ou usar os
   templates já existentes).
2. Rodar o Zeus UMG Forge (HTML→UMG). Saída crua: `Content/AutoCreated/<batch>/`.
3. Abrir o `WBP_*` gerado e **reparent** a classe pai para
   `UUIActivatableScreen_Base` (a base é `UCommonActivatableWidget`; o WBP tem
   árvore própria — respeita §3.3, nunca encadeia WBP→WBP).
4. **Reconectar tema:** o Forge gera hard ref de textura (proibido §5).
   Substituir por consumo via `UZMMOThemeSubsystem` por `EZMMOThemeKey` no
   override de `RefreshUIStyle`; remontar botões/painéis com os widgets
   compartilhados (`UI_Button_Master`, `UI_Panel_Master`).
5. **Mover** o asset refinado de `Content/AutoCreated/…` para
   `Content/ZMMO/UI/FrontEnd/` (o cru não cooka).
6. Registrar no `DA_FrontEndScreenSet`: `StateScreens[EZMMOFrontEndState::Login]`
   = soft class do WBP refinado (páginas do Lobby vão no map de
   `EZMMOLobbyPage` da tela de Lobby). Sem registro, o flow faz no-op + log.

**Regra:** uma tela nunca segura hard ref a asset de tema (textura/som/VFX) —
sempre via `UZMMOThemeSubsystem` por `EZMMOThemeKey` (igual §4.7 e §5).

---

## 5. O que **NÃO** fazer

- **Não** criar pastas `Meshes/`, `Textures/`, `Materials/` no nível alto.
- **Não** criar `Blueprint Struct` no editor. Toda struct é C++.
- **Não** referenciar BPs de mob/item com `TObjectPtr<>` (hard ref) a partir
  de DataTables ou Subsystems globais — usar `TSoftObjectPtr<>`.
- **Não** misturar assets de uma entidade com assets de outra. Cada
  Wolf_Gray, Sword_Iron, etc. é uma pasta isolada.
- **Não** colocar nada na raiz `Content/`. Tudo é `Content/ZMMO/...` ou
  `Content/{Developers,AutoCreated,ExternalContent}/...`. `AutoCreated/` é
  quarentena do Zeus UMG Forge: refina-se e **move** para `ZMMO/UI/FrontEnd/`
  antes de produção; o cru não cooka.
- **Não** importar conteúdo do Fab/Megascans directo para dentro de `ZMMO/`.
  Vai sempre para `ExternalContent/` e, se quiser usar, **referencia** dali.
- **Não** colocar dados tabulares em Blueprint (lista hardcoded de itens,
  array de stats no ABP). Move para DataTable.
- **Não** duplicar `FStatBlock` em C++ se já existe — importar de
  `Source/ZMMO/Data/Players/StatBlock.h`.
- **Não** colocar hard ref de textura/som de tema dentro de um Widget
  (`TObjectPtr<UTexture2D> ChristmasFrame` é proibido). Widgets pedem ao
  `UZMMOThemeSubsystem` via `EZMMOThemeKey`. Hard ref a asset de tema
  bloqueia a troca em runtime e quebra a política de fallback. Vale também
  para **telas de front-end** (Boot/Login/ServerSelect/Lobby/…): a saída crua
  do Forge traz hard ref — tem de ser reconectada ao subsystem antes do merge
  (ver §4.8).
- **Não** criar chave de tema "ad-hoc" como `FName("HUD.Frame")`. Toda chave
  é entrada do enum C++ `EZMMOThemeKey`. String literal é proibida — o
  compilador tem de quebrar quando alguém esquecer de adicionar a chave.
- **Não** preencher um tema sazonal com **todas** as chaves só porque o
  Default preenche. Tema sazonal só lista o que **substitui**; o resto cai
  no Default automaticamente.

---

## 6. Excepções permitidas

- Dentro de uma entidade self-contained, sub-pasta `Animations/` é OK quando
  passa de 5–6 anims. O mesmo vale para `Audio/` e `VFX/` próprios da
  entidade.
- `Items/.../Equipment/Weapons/Sword_Iron/` mantém o ícone `T_Icon_*` junto
  do mesh — é a única excepção em que textura e mesh ficam na mesma pasta
  raiz da entidade (porque o ícone é parte do item, não um asset solto).
- Skeleton compartilhado entre variantes (ex: `Wolf_Gray`, `Wolf_Black`)
  pode viver em `Entities/Mobs/Beasts/_Shared/Wolf/` se as variantes
  reutilizarem o mesmo `SK_` e `Animations/`. Pasta começa com `_` para
  ordenar primeiro no Content Browser.

---

## 7. Referências externas

- [Allar UE5 Style Guide](https://github.com/Allar/ue5-style-guide) — base
  das nossas convenções de nomenclatura e estrutura.
- [Epic – Unreal Engine Directory Structure](https://dev.epicgames.com/documentation/en-us/unreal-engine/unreal-engine-directory-structure).
- [Lyra Project Structure](https://github.com/iliags/LyraGameVault/blob/main/Lyra%20Project%20Structure.md)
  — modelo Epic para projecto multiplayer escalável.
- [Hyperdense – UE5 folder structure best practices](https://medium.com/@sarah.hyperdense/ue5-project-folder-structure-and-organization-best-practices-b9e487c330a3).
- [Epic Forum – Using DataTables, Structs and DataAssets for Inventory](https://forums.unrealengine.com/t/using-data-tables-structs-and-data-assets-for-an-inventory/2381408).
- [Epic Forum – Item system: how to structure/store data](https://forums.unrealengine.com/t/item-system-how-to-structure-store-data/2170364).

---

## 8. Como mudar este documento

Este `.md` é a fonte de verdade da arquitectura do cliente. Mudanças
estruturais (nova pasta no nível alto, mudança de convenção de nome, novo
tipo de asset) **precisam de PR alterando este ficheiro primeiro**. Sem PR
neste documento, não se mexe na árvore real.
