diff --git a/.mcp.json b/.mcp.json new file mode 100644 index 0000000..e12937c --- /dev/null +++ b/.mcp.json @@ -0,0 +1,15 @@ +{ + "mcpServers": + { + "nwiro": + { + "type": "http", + "url": "http://localhost:5353/mcp" + }, + "hyperpro": + { + "type": "http", + "url": "http://localhost:5354/mcp" + } + } +} \ No newline at end of file diff --git a/ARQUITETURA.md b/ARQUITETURA.md new file mode 100644 index 0000000..700dbd0 --- /dev/null +++ b/ARQUITETURA.md @@ -0,0 +1,630 @@ +# 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. + +> **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 +│ │ +│ ├── UI/ ← HUD, Login, CharacterSelect, Inventory, +│ │ │ Chat, Party, Guild, Trade, Quest, Map, +│ │ │ Shared, Icons +│ │ └── 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) +│ └── / +├── 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 +│ ├── Modes/ ← GameMode + GameInstance +│ └── Network/ ← UZMMOWorldSubsystem +│ +└── 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) + └── 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` | +| `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: `FRow` quando é linha de DataTable. Ex: `FItemRow`, `FMobRow`. +- Struct genérica (não-DT): `F`. Ex: `FStatBlock`. +- Enum: `E`. 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_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`. O Widget +Blueprint que herda usa prefixo de asset `UI_` (ver §3.2): `UI_Button_Base` +(abstrato) → `UI_Button_Master` → `UI_Button_`. + +--- + +## 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` 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` 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 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 MobsTable; +// +// UPROPERTY(EditAnywhere, Category="Data") +// FName MobId; +// +// void AZMMOMobBase::BeginPlay() +// { +// Super::BeginPlay(); +// if (UDataTable* Table = MobsTable.LoadSynchronous()) +// { +// if (FMobRow* Row = Table->FindRow(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` 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 HudFrameTex; +// +// Faz: +// const UZMMOThemeSubsystem* Theme = GetGameInstance()->GetSubsystem(); +// 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`. + +--- + +## 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,ExternalContent}/...`. +- **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 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. +- **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. diff --git a/Config/DefaultGame.ini b/Config/DefaultGame.ini index 97b1be6..39991e1 100644 --- a/Config/DefaultGame.ini +++ b/Config/DefaultGame.ini @@ -1,3 +1,26 @@ [/Script/EngineSettings.GeneralProjectSettings] ProjectID=FC3E256F43B2AFD43009F4949B0814BE ProjectName=Third Person Game Template + +; ----------------------------------------------------------------------------- +; ZMMO Theme subsystem (see Source/ZMMO/Game/UI/ZMMOThemeSubsystem.h and +; ARQUITETURA.md §1.10 / §4.7). +; +; - DefaultThemeAsset is the fallback theme (must define every EZMMOThemeKey). +; - ThemeRegistry maps ThemeId -> seasonal DA_Theme_* asset. +; - CalendarTable points to DT_ThemeCalendar (FThemeCalendarRow rows). +; - UIStyleTable points to DT_UI_Styles (FUIStyleRow rows): tokens de estilo +; (cores/fontes/dimensões) keyed por ThemeId; linha "Default" é o fallback. +; - DevThemeOverride forces a theme in non-Shipping builds only. Keep commented +; in production. +; +; Paths use the /Game prefix (cooked Content namespace). Uncomment after the +; assets are actually created in the editor. +; ----------------------------------------------------------------------------- +[/Script/ZMMO.ZMMOThemeSubsystem] +;DefaultThemeAsset=/Game/ZMMO/UI/Themes/DA_Theme_Default.DA_Theme_Default +;+ThemeRegistry=(("Christmas", "/Game/ZMMO/UI/Themes/DA_Theme_Christmas.DA_Theme_Christmas")) +;+ThemeRegistry=(("Halloween", "/Game/ZMMO/UI/Themes/DA_Theme_Halloween.DA_Theme_Halloween")) +;CalendarTable=/Game/ZMMO/UI/Themes/DT_ThemeCalendar.DT_ThemeCalendar +UIStyleTable=/Game/ZMMO/Data/UI/DT_UI_Styles.DT_UI_Styles +;DevThemeOverride=Christmas diff --git a/Content/ZMMO/Abilities/Buffs/.gitkeep b/Content/ZMMO/Abilities/Buffs/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Content/ZMMO/Abilities/Combat/.gitkeep b/Content/ZMMO/Abilities/Combat/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Content/ZMMO/Abilities/Heals/.gitkeep b/Content/ZMMO/Abilities/Heals/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Content/ZMMO/Abilities/Movement/.gitkeep b/Content/ZMMO/Abilities/Movement/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Content/ZMMO/Abilities/Shared/.gitkeep b/Content/ZMMO/Abilities/Shared/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Content/ZMMO/Audio/Ambient/.gitkeep b/Content/ZMMO/Audio/Ambient/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Content/ZMMO/Audio/Music/.gitkeep b/Content/ZMMO/Audio/Music/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Content/ZMMO/Audio/SFX/Combat/.gitkeep b/Content/ZMMO/Audio/SFX/Combat/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Content/ZMMO/Audio/SFX/Footsteps/.gitkeep b/Content/ZMMO/Audio/SFX/Footsteps/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Content/ZMMO/Audio/SFX/UI/.gitkeep b/Content/ZMMO/Audio/SFX/UI/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Content/ZMMO/Audio/Voice/.gitkeep b/Content/ZMMO/Audio/Voice/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Content/ZMMO/Cinematics/.gitkeep b/Content/ZMMO/Cinematics/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Content/ZMMO/Core/Entity/.gitkeep b/Content/ZMMO/Core/Entity/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Content/ZMMO/Core/Item/.gitkeep b/Content/ZMMO/Core/Item/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Content/ZMMO/Core/Mob/.gitkeep b/Content/ZMMO/Core/Mob/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Content/ZMMO/Core/NPC/.gitkeep b/Content/ZMMO/Core/NPC/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Content/ZMMO/Core/Network/.gitkeep b/Content/ZMMO/Core/Network/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Content/ZMMO/Core/Player/.gitkeep b/Content/ZMMO/Core/Player/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Content/ZMMO/Data/Abilities/.gitkeep b/Content/ZMMO/Data/Abilities/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Content/ZMMO/Data/Items/.gitkeep b/Content/ZMMO/Data/Items/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Content/ZMMO/Data/Mobs/.gitkeep b/Content/ZMMO/Data/Mobs/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Content/ZMMO/Data/NPCs/.gitkeep b/Content/ZMMO/Data/NPCs/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Content/ZMMO/Data/Players/.gitkeep b/Content/ZMMO/Data/Players/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Content/ZMMO/Data/Quests/.gitkeep b/Content/ZMMO/Data/Quests/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Content/ZMMO/Data/UI/DT_UI_Styles.uasset b/Content/ZMMO/Data/UI/DT_UI_Styles.uasset new file mode 100644 index 0000000..4c4af14 Binary files /dev/null and b/Content/ZMMO/Data/UI/DT_UI_Styles.uasset differ diff --git a/Content/ZMMO/Data/World/.gitkeep b/Content/ZMMO/Data/World/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Content/ZMMO/Debug/BP/.gitkeep b/Content/ZMMO/Debug/BP/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Content/ZMMO/Debug/Maps/.gitkeep b/Content/ZMMO/Debug/Maps/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Content/ZMMO/Debug/Materials/.gitkeep b/Content/ZMMO/Debug/Materials/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Content/ZMMO/Effects/Abilities/.gitkeep b/Content/ZMMO/Effects/Abilities/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Content/ZMMO/Effects/Environment/.gitkeep b/Content/ZMMO/Effects/Environment/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Content/ZMMO/Effects/Shared/.gitkeep b/Content/ZMMO/Effects/Shared/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Content/ZMMO/Effects/UI/.gitkeep b/Content/ZMMO/Effects/UI/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Content/ZMMO/Entities/Mobs/Beasts/.gitkeep b/Content/ZMMO/Entities/Mobs/Beasts/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Content/ZMMO/Entities/Mobs/Bosses/.gitkeep b/Content/ZMMO/Entities/Mobs/Bosses/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Content/ZMMO/Entities/Mobs/Dragons/.gitkeep b/Content/ZMMO/Entities/Mobs/Dragons/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Content/ZMMO/Entities/Mobs/Humanoids/.gitkeep b/Content/ZMMO/Entities/Mobs/Humanoids/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Content/ZMMO/Entities/Mobs/Undead/.gitkeep b/Content/ZMMO/Entities/Mobs/Undead/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Content/ZMMO/Entities/NPCs/.gitkeep b/Content/ZMMO/Entities/NPCs/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Content/ZMMO/Entities/Players/Classes/Archer/Animations/.gitkeep b/Content/ZMMO/Entities/Players/Classes/Archer/Animations/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Content/ZMMO/Entities/Players/Classes/Mage/Animations/.gitkeep b/Content/ZMMO/Entities/Players/Classes/Mage/Animations/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Content/ZMMO/Entities/Players/Classes/Warrior/Animations/.gitkeep b/Content/ZMMO/Entities/Players/Classes/Warrior/Animations/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Content/ZMMO/Input/Actions/.gitkeep b/Content/ZMMO/Input/Actions/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Content/ZMMO/Input/Mappings/.gitkeep b/Content/ZMMO/Input/Mappings/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Content/ZMMO/Input/Modifiers/.gitkeep b/Content/ZMMO/Input/Modifiers/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Content/ZMMO/Items/Consumables/.gitkeep b/Content/ZMMO/Items/Consumables/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Content/ZMMO/Items/Equipment/Accessories/.gitkeep b/Content/ZMMO/Items/Equipment/Accessories/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Content/ZMMO/Items/Equipment/Armor/.gitkeep b/Content/ZMMO/Items/Equipment/Armor/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Content/ZMMO/Items/Equipment/Weapons/.gitkeep b/Content/ZMMO/Items/Equipment/Weapons/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Content/ZMMO/Items/Materials/.gitkeep b/Content/ZMMO/Items/Materials/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Content/ZMMO/Items/Quest/.gitkeep b/Content/ZMMO/Items/Quest/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Content/ZMMO/Localization/.gitkeep b/Content/ZMMO/Localization/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Content/ZMMO/Movement/Mounts/.gitkeep b/Content/ZMMO/Movement/Mounts/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Content/ZMMO/Movement/Transport/.gitkeep b/Content/ZMMO/Movement/Transport/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Content/ZMMO/UI/CharacterSelect/.gitkeep b/Content/ZMMO/UI/CharacterSelect/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Content/ZMMO/UI/Chat/.gitkeep b/Content/ZMMO/UI/Chat/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Content/ZMMO/UI/Fonts/Cinzel/FF_Cinzel_Bold.uasset b/Content/ZMMO/UI/Fonts/Cinzel/FF_Cinzel_Bold.uasset new file mode 100644 index 0000000..a2c35d6 Binary files /dev/null and b/Content/ZMMO/UI/Fonts/Cinzel/FF_Cinzel_Bold.uasset differ diff --git a/Content/ZMMO/UI/Fonts/Cinzel/FF_Cinzel_ExtraBold.uasset b/Content/ZMMO/UI/Fonts/Cinzel/FF_Cinzel_ExtraBold.uasset new file mode 100644 index 0000000..15858d3 Binary files /dev/null and b/Content/ZMMO/UI/Fonts/Cinzel/FF_Cinzel_ExtraBold.uasset differ diff --git a/Content/ZMMO/UI/Fonts/Cinzel/FF_Cinzel_Regular.uasset b/Content/ZMMO/UI/Fonts/Cinzel/FF_Cinzel_Regular.uasset new file mode 100644 index 0000000..5996164 Binary files /dev/null and b/Content/ZMMO/UI/Fonts/Cinzel/FF_Cinzel_Regular.uasset differ diff --git a/Content/ZMMO/UI/Fonts/Cinzel/FF_Cinzel_SemiBold.uasset b/Content/ZMMO/UI/Fonts/Cinzel/FF_Cinzel_SemiBold.uasset new file mode 100644 index 0000000..8ec0fc7 Binary files /dev/null and b/Content/ZMMO/UI/Fonts/Cinzel/FF_Cinzel_SemiBold.uasset differ diff --git a/Content/ZMMO/UI/Fonts/Rajdhani/FF_Rajdhani_Bold.uasset b/Content/ZMMO/UI/Fonts/Rajdhani/FF_Rajdhani_Bold.uasset new file mode 100644 index 0000000..880f980 Binary files /dev/null and b/Content/ZMMO/UI/Fonts/Rajdhani/FF_Rajdhani_Bold.uasset differ diff --git a/Content/ZMMO/UI/Fonts/Rajdhani/FF_Rajdhani_Medium.uasset b/Content/ZMMO/UI/Fonts/Rajdhani/FF_Rajdhani_Medium.uasset new file mode 100644 index 0000000..3410d15 Binary files /dev/null and b/Content/ZMMO/UI/Fonts/Rajdhani/FF_Rajdhani_Medium.uasset differ diff --git a/Content/ZMMO/UI/Fonts/Rajdhani/FF_Rajdhani_Regular.uasset b/Content/ZMMO/UI/Fonts/Rajdhani/FF_Rajdhani_Regular.uasset new file mode 100644 index 0000000..dd5b32e Binary files /dev/null and b/Content/ZMMO/UI/Fonts/Rajdhani/FF_Rajdhani_Regular.uasset differ diff --git a/Content/ZMMO/UI/Fonts/Rajdhani/FF_Rajdhani_SemiBold.uasset b/Content/ZMMO/UI/Fonts/Rajdhani/FF_Rajdhani_SemiBold.uasset new file mode 100644 index 0000000..5d4acd9 Binary files /dev/null and b/Content/ZMMO/UI/Fonts/Rajdhani/FF_Rajdhani_SemiBold.uasset differ diff --git a/Content/ZMMO/UI/Guild/.gitkeep b/Content/ZMMO/UI/Guild/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Content/ZMMO/UI/HUD/.gitkeep b/Content/ZMMO/UI/HUD/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Content/ZMMO/UI/Icons/.gitkeep b/Content/ZMMO/UI/Icons/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Content/ZMMO/UI/Inventory/.gitkeep b/Content/ZMMO/UI/Inventory/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Content/ZMMO/UI/Login/.gitkeep b/Content/ZMMO/UI/Login/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Content/ZMMO/UI/Map/.gitkeep b/Content/ZMMO/UI/Map/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Content/ZMMO/UI/Party/.gitkeep b/Content/ZMMO/UI/Party/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Content/ZMMO/UI/Quest/.gitkeep b/Content/ZMMO/UI/Quest/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Content/ZMMO/UI/Shared/.gitkeep b/Content/ZMMO/UI/Shared/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Content/ZMMO/UI/Themes/Christmas/Audio/.gitkeep b/Content/ZMMO/UI/Themes/Christmas/Audio/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Content/ZMMO/UI/Themes/Christmas/HUD/.gitkeep b/Content/ZMMO/UI/Themes/Christmas/HUD/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Content/ZMMO/UI/Themes/Christmas/Inventory/.gitkeep b/Content/ZMMO/UI/Themes/Christmas/Inventory/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Content/ZMMO/UI/Themes/Christmas/Login/.gitkeep b/Content/ZMMO/UI/Themes/Christmas/Login/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Content/ZMMO/UI/Themes/Christmas/VFX/.gitkeep b/Content/ZMMO/UI/Themes/Christmas/VFX/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Content/ZMMO/UI/Themes/Default/Audio/.gitkeep b/Content/ZMMO/UI/Themes/Default/Audio/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Content/ZMMO/UI/Themes/Default/HUD/.gitkeep b/Content/ZMMO/UI/Themes/Default/HUD/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Content/ZMMO/UI/Themes/Default/Inventory/.gitkeep b/Content/ZMMO/UI/Themes/Default/Inventory/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Content/ZMMO/UI/Themes/Default/Login/.gitkeep b/Content/ZMMO/UI/Themes/Default/Login/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Content/ZMMO/UI/Themes/Default/VFX/.gitkeep b/Content/ZMMO/UI/Themes/Default/VFX/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Content/ZMMO/UI/Themes/Halloween/Audio/.gitkeep b/Content/ZMMO/UI/Themes/Halloween/Audio/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Content/ZMMO/UI/Themes/Halloween/HUD/.gitkeep b/Content/ZMMO/UI/Themes/Halloween/HUD/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Content/ZMMO/UI/Themes/Halloween/Inventory/.gitkeep b/Content/ZMMO/UI/Themes/Halloween/Inventory/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Content/ZMMO/UI/Themes/Halloween/Login/.gitkeep b/Content/ZMMO/UI/Themes/Halloween/Login/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Content/ZMMO/UI/Themes/Halloween/VFX/.gitkeep b/Content/ZMMO/UI/Themes/Halloween/VFX/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Content/ZMMO/UI/Themes/_Shared/.gitkeep b/Content/ZMMO/UI/Themes/_Shared/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Content/ZMMO/UI/Trade/.gitkeep b/Content/ZMMO/UI/Trade/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Content/ZMMO/World/Environment/Architecture/.gitkeep b/Content/ZMMO/World/Environment/Architecture/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Content/ZMMO/World/Environment/Nature/.gitkeep b/Content/ZMMO/World/Environment/Nature/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Content/ZMMO/World/Environment/Props/.gitkeep b/Content/ZMMO/World/Environment/Props/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Content/ZMMO/World/Instances/.gitkeep b/Content/ZMMO/World/Instances/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Content/ZMMO/World/Interactables/.gitkeep b/Content/ZMMO/World/Interactables/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Content/ZMMO/World/Maps/.gitkeep b/Content/ZMMO/World/Maps/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Scripts/import_fonts.py b/Scripts/import_fonts.py new file mode 100644 index 0000000..fccdadb --- /dev/null +++ b/Scripts/import_fonts.py @@ -0,0 +1,90 @@ +""" +import_fonts.py — Importa as fontes Aurora Arcana para o cliente ZMMO. + +Cria (UFontFace, loading policy = Inline; .ttf embutido no .uasset): + Content/ZMMO/UI/Fonts/Cinzel/ FF_Cinzel_Regular | _SemiBold | _Bold | _ExtraBold + Content/ZMMO/UI/Fonts/Rajdhani/ FF_Rajdhani_Regular | _Medium | _SemiBold | _Bold + +Source dos .ttf: Tools/Templates/Zeus_Widget/shared/assets/fonts/ (source-of-truth, +não duplicar — UFontFace importa como Inline e embute o .ttf no .uasset). + +Nota: Typeface/TypefaceEntry/FontData NÃO são expostos ao Python (UE 5.7), então +a Composite Font (Font_Cinzel/Font_Rajdhani) não é criada por script. Como o +FUIStyleText usa um peso fixo por papel, o FSlateFontInfo referencia o FF_* direto. + +Idempotente. Como rodar: + - Editor: console Python -> exec(open(r"f:/.../Scripts/import_fonts.py").read()) + - Ou via MCP nwiro execute_python. +""" + +import os +import unreal + +SRC_DIR = r"f:/ZeusProject/Tools/Templates/Zeus_Widget/shared/assets/fonts" +DEST_ROOT = "/Game/ZMMO/UI/Fonts" + +FAMILIES = { + "Cinzel": [ + ("Regular", "Cinzel-Regular.ttf"), + ("SemiBold", "Cinzel-SemiBold.ttf"), + ("Bold", "Cinzel-Bold.ttf"), + ("ExtraBold", "Cinzel-ExtraBold.ttf"), + ], + "Rajdhani": [ + ("Regular", "Rajdhani-Regular.ttf"), + ("Medium", "Rajdhani-Medium.ttf"), + ("SemiBold", "Rajdhani-SemiBold.ttf"), + ("Bold", "Rajdhani-Bold.ttf"), + ], +} + +asset_tools = unreal.AssetToolsHelpers.get_asset_tools() + + +def import_font_face(ttf_path, dest_pkg_path, asset_name): + task = unreal.AssetImportTask() + task.filename = ttf_path + task.destination_path = dest_pkg_path + task.destination_name = asset_name + task.replace_existing = True + task.automated = True + task.save = True + task.factory = unreal.FontFileImportFactory() + + asset_tools.import_asset_tasks([task]) + + full = "{}/{}".format(dest_pkg_path, asset_name) + face = unreal.load_asset(full) + if face is None: + unreal.log_error("[import_fonts] FALHOU import: {}".format(full)) + return False + + try: + face.set_editor_property("loading_policy", unreal.FontLoadingPolicy.INLINE) + unreal.EditorAssetLibrary.save_asset(full) + except Exception as e: + unreal.log_warning("[import_fonts] loading_policy INLINE falhou em {}: {}".format(full, e)) + + unreal.log_warning("[import_fonts] OK {} (class={})".format(full, type(face).__name__)) + return True + + +def main(): + unreal.log_warning("[import_fonts] === inicio ===") + ok = 0 + total = 0 + for family, weights in FAMILIES.items(): + dest_pkg = "{}/{}".format(DEST_ROOT, family) + for weight_name, ttf in weights: + total += 1 + ttf_path = os.path.join(SRC_DIR, ttf).replace("\\", "/") + if not os.path.isfile(ttf_path): + unreal.log_error("[import_fonts] .ttf nao encontrado: {}".format(ttf_path)) + continue + asset_name = "FF_{}_{}".format(family, weight_name) + if import_font_face(ttf_path, dest_pkg, asset_name): + ok += 1 + unreal.log_warning("[import_fonts] === fim: {}/{} faces ===".format(ok, total)) + + +main() diff --git a/Source/ZMMO/Data/Abilities/AbilityRow.h b/Source/ZMMO/Data/Abilities/AbilityRow.h new file mode 100644 index 0000000..1d69f7c --- /dev/null +++ b/Source/ZMMO/Data/Abilities/AbilityRow.h @@ -0,0 +1,84 @@ +#pragma once + +#include "CoreMinimal.h" +#include "Engine/DataTable.h" +#include "AbilityRow.generated.h" + +class UTexture2D; +class UAnimMontage; +class UNiagaraSystem; +class USoundBase; + +UENUM(BlueprintType) +enum class EAbilityCategory : uint8 +{ + Combat UMETA(DisplayName = "Combat"), + Buff UMETA(DisplayName = "Buff"), + Heal UMETA(DisplayName = "Heal"), + Movement UMETA(DisplayName = "Movement"), + Passive UMETA(DisplayName = "Passive") +}; + +UENUM(BlueprintType) +enum class EAbilityTarget : uint8 +{ + Self UMETA(DisplayName = "Self"), + Single UMETA(DisplayName = "Single Target"), + Area UMETA(DisplayName = "Area"), + Cone UMETA(DisplayName = "Cone"), + Line UMETA(DisplayName = "Line") +}; + +USTRUCT(BlueprintType) +struct ZMMO_API FAbilityRow : public FTableRowBase +{ + GENERATED_BODY() + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Ability") + FText DisplayName; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Ability", meta = (MultiLine = true)) + FText Description; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Ability") + EAbilityCategory Category = EAbilityCategory::Combat; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Targeting") + EAbilityTarget TargetMode = EAbilityTarget::Single; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Targeting") + float Range = 500.f; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Targeting", meta = (EditCondition = "TargetMode == EAbilityTarget::Area || TargetMode == EAbilityTarget::Cone")) + float Radius = 200.f; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Cost") + int32 ManaCost = 0; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Cost") + int32 StaminaCost = 0; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Timing") + float CastTime = 0.f; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Timing") + float Cooldown = 1.f; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Effect") + int32 BaseDamage = 0; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Effect") + FName StatusEffectRow; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Visuals") + TSoftObjectPtr Icon; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Visuals") + TSoftObjectPtr CastMontage; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Visuals") + TSoftObjectPtr CastVFX; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Audio") + TSoftObjectPtr CastSound; +}; diff --git a/Source/ZMMO/Data/Abilities/StatusEffectRow.h b/Source/ZMMO/Data/Abilities/StatusEffectRow.h new file mode 100644 index 0000000..42da702 --- /dev/null +++ b/Source/ZMMO/Data/Abilities/StatusEffectRow.h @@ -0,0 +1,51 @@ +#pragma once + +#include "CoreMinimal.h" +#include "Engine/DataTable.h" +#include "StatusEffectRow.generated.h" + +class UTexture2D; +class UNiagaraSystem; + +UENUM(BlueprintType) +enum class EStatusEffectKind : uint8 +{ + Buff UMETA(DisplayName = "Buff"), + Debuff UMETA(DisplayName = "Debuff"), + DoT UMETA(DisplayName = "Damage Over Time"), + HoT UMETA(DisplayName = "Heal Over Time"), + Crowd UMETA(DisplayName = "Crowd Control") +}; + +USTRUCT(BlueprintType) +struct ZMMO_API FStatusEffectRow : public FTableRowBase +{ + GENERATED_BODY() + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Status") + FText DisplayName; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Status", meta = (MultiLine = true)) + FText Description; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Status") + EStatusEffectKind Kind = EStatusEffectKind::Buff; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Status") + float Duration = 5.f; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Status") + float TickInterval = 1.f; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Status") + int32 TickValue = 0; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Status") + int32 MaxStacks = 1; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Visuals") + TSoftObjectPtr Icon; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Visuals") + TSoftObjectPtr AttachedVFX; +}; diff --git a/Source/ZMMO/Data/Items/ItemRow.h b/Source/ZMMO/Data/Items/ItemRow.h new file mode 100644 index 0000000..f80fbcc --- /dev/null +++ b/Source/ZMMO/Data/Items/ItemRow.h @@ -0,0 +1,46 @@ +#pragma once + +#include "CoreMinimal.h" +#include "Engine/DataTable.h" +#include "Items/ItemTypes.h" +#include "ItemRow.generated.h" + +class AActor; +class UStaticMesh; +class UTexture2D; + +USTRUCT(BlueprintType) +struct ZMMO_API FItemRow : public FTableRowBase +{ + GENERATED_BODY() + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Item") + FText DisplayName; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Item", meta = (MultiLine = true)) + FText Description; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Item") + EItemType Type = EItemType::None; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Item") + EItemRarity Rarity = EItemRarity::Common; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Equipment", meta = (EditCondition = "Type == EItemType::Weapon || Type == EItemType::Armor || Type == EItemType::Accessory")) + EEquipSlot EquipSlot = EEquipSlot::None; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Item") + int32 MaxStack = 1; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Item") + int32 BasePrice = 0; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Visuals") + TSoftObjectPtr Icon; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Visuals") + TSoftObjectPtr WorldMesh; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Behavior") + TSoftClassPtr BehaviorClass; +}; diff --git a/Source/ZMMO/Data/Items/ItemTypes.h b/Source/ZMMO/Data/Items/ItemTypes.h new file mode 100644 index 0000000..aeb24a7 --- /dev/null +++ b/Source/ZMMO/Data/Items/ItemTypes.h @@ -0,0 +1,45 @@ +#pragma once + +#include "CoreMinimal.h" +#include "ItemTypes.generated.h" + +UENUM(BlueprintType) +enum class EItemType : uint8 +{ + None UMETA(DisplayName = "None"), + Weapon UMETA(DisplayName = "Weapon"), + Armor UMETA(DisplayName = "Armor"), + Accessory UMETA(DisplayName = "Accessory"), + Consumable UMETA(DisplayName = "Consumable"), + Material UMETA(DisplayName = "Material"), + Quest UMETA(DisplayName = "Quest"), + Currency UMETA(DisplayName = "Currency") +}; + +UENUM(BlueprintType) +enum class EItemRarity : uint8 +{ + Common UMETA(DisplayName = "Common"), + Uncommon UMETA(DisplayName = "Uncommon"), + Rare UMETA(DisplayName = "Rare"), + Epic UMETA(DisplayName = "Epic"), + Legendary UMETA(DisplayName = "Legendary"), + Mythic UMETA(DisplayName = "Mythic") +}; + +UENUM(BlueprintType) +enum class EEquipSlot : uint8 +{ + None UMETA(DisplayName = "None"), + Head UMETA(DisplayName = "Head"), + Chest UMETA(DisplayName = "Chest"), + Legs UMETA(DisplayName = "Legs"), + Hands UMETA(DisplayName = "Hands"), + Feet UMETA(DisplayName = "Feet"), + MainHand UMETA(DisplayName = "Main Hand"), + OffHand UMETA(DisplayName = "Off Hand"), + TwoHand UMETA(DisplayName = "Two Hand"), + Ring UMETA(DisplayName = "Ring"), + Necklace UMETA(DisplayName = "Necklace"), + Cape UMETA(DisplayName = "Cape") +}; diff --git a/Source/ZMMO/Data/Mobs/MobRow.h b/Source/ZMMO/Data/Mobs/MobRow.h new file mode 100644 index 0000000..33e4665 --- /dev/null +++ b/Source/ZMMO/Data/Mobs/MobRow.h @@ -0,0 +1,48 @@ +#pragma once + +#include "CoreMinimal.h" +#include "Engine/DataTable.h" +#include "Mobs/MobTypes.h" +#include "Players/StatBlock.h" +#include "MobRow.generated.h" + +class APawn; + +USTRUCT(BlueprintType) +struct ZMMO_API FMobRow : public FTableRowBase +{ + GENERATED_BODY() + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Mob") + FText DisplayName; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Mob") + TSoftClassPtr BlueprintRef; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Mob") + EMobFamily Family = EMobFamily::Beast; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Mob") + EMobFaction Faction = EMobFaction::Hostile; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Mob") + EMobBehavior Behavior = EMobBehavior::Aggressive; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Mob") + int32 Level = 1; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Stats") + FStatBlock Stats; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Combat") + float AggroRadius = 800.f; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Combat") + float LeashRadius = 2000.f; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Rewards") + int32 ExperienceReward = 0; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Rewards") + FName DropTableRow; +}; diff --git a/Source/ZMMO/Data/Mobs/MobTypes.h b/Source/ZMMO/Data/Mobs/MobTypes.h new file mode 100644 index 0000000..c1c9041 --- /dev/null +++ b/Source/ZMMO/Data/Mobs/MobTypes.h @@ -0,0 +1,35 @@ +#pragma once + +#include "CoreMinimal.h" +#include "MobTypes.generated.h" + +UENUM(BlueprintType) +enum class EMobFaction : uint8 +{ + Neutral UMETA(DisplayName = "Neutral"), + Hostile UMETA(DisplayName = "Hostile"), + Friendly UMETA(DisplayName = "Friendly"), + Boss UMETA(DisplayName = "Boss") +}; + +UENUM(BlueprintType) +enum class EMobBehavior : uint8 +{ + Passive UMETA(DisplayName = "Passive"), + Defensive UMETA(DisplayName = "Defensive"), + Aggressive UMETA(DisplayName = "Aggressive"), + Patrol UMETA(DisplayName = "Patrol"), + Stationary UMETA(DisplayName = "Stationary") +}; + +UENUM(BlueprintType) +enum class EMobFamily : uint8 +{ + Beast UMETA(DisplayName = "Beast"), + Undead UMETA(DisplayName = "Undead"), + Humanoid UMETA(DisplayName = "Humanoid"), + Dragon UMETA(DisplayName = "Dragon"), + Elemental UMETA(DisplayName = "Elemental"), + Demon UMETA(DisplayName = "Demon"), + Construct UMETA(DisplayName = "Construct") +}; diff --git a/Source/ZMMO/Data/NPCs/DialogRow.h b/Source/ZMMO/Data/NPCs/DialogRow.h new file mode 100644 index 0000000..40828cd --- /dev/null +++ b/Source/ZMMO/Data/NPCs/DialogRow.h @@ -0,0 +1,32 @@ +#pragma once + +#include "CoreMinimal.h" +#include "Engine/DataTable.h" +#include "DialogRow.generated.h" + +USTRUCT(BlueprintType) +struct ZMMO_API FDialogChoice +{ + GENERATED_BODY() + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Dialog") + FText Text; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Dialog") + FName NextNode; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Dialog") + FName RequiredQuestState; +}; + +USTRUCT(BlueprintType) +struct ZMMO_API FDialogRow : public FTableRowBase +{ + GENERATED_BODY() + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Dialog", meta = (MultiLine = true)) + FText SpeakerLine; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Dialog") + TArray Choices; +}; diff --git a/Source/ZMMO/Data/NPCs/NPCRow.h b/Source/ZMMO/Data/NPCs/NPCRow.h new file mode 100644 index 0000000..57c2f4f --- /dev/null +++ b/Source/ZMMO/Data/NPCs/NPCRow.h @@ -0,0 +1,40 @@ +#pragma once + +#include "CoreMinimal.h" +#include "Engine/DataTable.h" +#include "NPCRow.generated.h" + +class APawn; + +UENUM(BlueprintType) +enum class ENPCRole : uint8 +{ + Generic UMETA(DisplayName = "Generic"), + Vendor UMETA(DisplayName = "Vendor"), + Questgiver UMETA(DisplayName = "Questgiver"), + Trainer UMETA(DisplayName = "Trainer"), + Banker UMETA(DisplayName = "Banker"), + Innkeeper UMETA(DisplayName = "Innkeeper"), + Guard UMETA(DisplayName = "Guard") +}; + +USTRUCT(BlueprintType) +struct ZMMO_API FNPCRow : public FTableRowBase +{ + GENERATED_BODY() + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "NPC") + FText DisplayName; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "NPC") + TSoftClassPtr BlueprintRef; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "NPC") + ENPCRole Role = ENPCRole::Generic; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Shop", meta = (EditCondition = "Role == ENPCRole::Vendor")) + TArray ShopInventory; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Dialog") + FName DialogRoot; +}; diff --git a/Source/ZMMO/Data/Players/ClassRow.h b/Source/ZMMO/Data/Players/ClassRow.h new file mode 100644 index 0000000..95679a8 --- /dev/null +++ b/Source/ZMMO/Data/Players/ClassRow.h @@ -0,0 +1,29 @@ +#pragma once + +#include "CoreMinimal.h" +#include "Engine/DataTable.h" +#include "Players/StatBlock.h" +#include "ClassRow.generated.h" + +class APawn; + +USTRUCT(BlueprintType) +struct ZMMO_API FClassRow : public FTableRowBase +{ + GENERATED_BODY() + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Class") + FText DisplayName; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Class") + TSoftClassPtr BlueprintRef; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Stats") + FStatBlock BaseStats; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Stats") + FStatBlock LevelUpStats; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Class") + TArray StartingAbilities; +}; diff --git a/Source/ZMMO/Data/Players/StatBlock.h b/Source/ZMMO/Data/Players/StatBlock.h new file mode 100644 index 0000000..ec863ea --- /dev/null +++ b/Source/ZMMO/Data/Players/StatBlock.h @@ -0,0 +1,31 @@ +#pragma once + +#include "CoreMinimal.h" +#include "StatBlock.generated.h" + +USTRUCT(BlueprintType) +struct ZMMO_API FStatBlock +{ + GENERATED_BODY() + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Stats") + int32 Health = 100; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Stats") + int32 Mana = 50; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Stats") + int32 Stamina = 100; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Stats") + int32 Attack = 10; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Stats") + int32 Defense = 5; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Stats") + float MoveSpeed = 600.f; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Stats") + float AttackSpeed = 1.0f; +}; diff --git a/Source/ZMMO/Data/Quests/QuestRow.h b/Source/ZMMO/Data/Quests/QuestRow.h new file mode 100644 index 0000000..c34c465 --- /dev/null +++ b/Source/ZMMO/Data/Quests/QuestRow.h @@ -0,0 +1,77 @@ +#pragma once + +#include "CoreMinimal.h" +#include "Engine/DataTable.h" +#include "QuestRow.generated.h" + +UENUM(BlueprintType) +enum class EQuestKind : uint8 +{ + Main UMETA(DisplayName = "Main"), + Side UMETA(DisplayName = "Side"), + Daily UMETA(DisplayName = "Daily"), + Repeatable UMETA(DisplayName = "Repeatable"), + Event UMETA(DisplayName = "Event") +}; + +UENUM(BlueprintType) +enum class EQuestObjectiveType : uint8 +{ + Kill UMETA(DisplayName = "Kill"), + Collect UMETA(DisplayName = "Collect"), + Talk UMETA(DisplayName = "Talk"), + Reach UMETA(DisplayName = "Reach Location"), + Use UMETA(DisplayName = "Use Item"), + Escort UMETA(DisplayName = "Escort") +}; + +USTRUCT(BlueprintType) +struct ZMMO_API FQuestObjective +{ + GENERATED_BODY() + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Objective") + EQuestObjectiveType Type = EQuestObjectiveType::Kill; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Objective") + FName TargetId; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Objective") + int32 Required = 1; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Objective") + FText Description; +}; + +USTRUCT(BlueprintType) +struct ZMMO_API FQuestRow : public FTableRowBase +{ + GENERATED_BODY() + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Quest") + FText DisplayName; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Quest", meta = (MultiLine = true)) + FText Description; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Quest") + EQuestKind Kind = EQuestKind::Side; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Quest") + int32 LevelRequirement = 1; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Quest") + FName GiverNPC; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Quest") + FName TurnInNPC; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Quest") + TArray Objectives; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Quest") + FName RewardRow; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Quest") + TArray Prerequisites; +}; diff --git a/Source/ZMMO/Data/UI/ThemeCalendarRow.h b/Source/ZMMO/Data/UI/ThemeCalendarRow.h new file mode 100644 index 0000000..d2aa83a --- /dev/null +++ b/Source/ZMMO/Data/UI/ThemeCalendarRow.h @@ -0,0 +1,29 @@ +#pragma once + +#include "CoreMinimal.h" +#include "Engine/DataTable.h" +#include "ThemeCalendarRow.generated.h" + +USTRUCT(BlueprintType) +struct ZMMO_API FThemeCalendarRow : public FTableRowBase +{ + GENERATED_BODY() + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Calendar") + FName ThemeId; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Calendar", meta = (ClampMin = "1", ClampMax = "12")) + int32 StartMonth = 1; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Calendar", meta = (ClampMin = "1", ClampMax = "31")) + int32 StartDay = 1; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Calendar", meta = (ClampMin = "1", ClampMax = "12")) + int32 EndMonth = 12; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Calendar", meta = (ClampMin = "1", ClampMax = "31")) + int32 EndDay = 31; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Calendar", meta = (ToolTip = "Higher priority wins when ranges overlap.")) + int32 Priority = 0; +}; diff --git a/Source/ZMMO/Data/UI/ThemeKeys.h b/Source/ZMMO/Data/UI/ThemeKeys.h new file mode 100644 index 0000000..d51d30e --- /dev/null +++ b/Source/ZMMO/Data/UI/ThemeKeys.h @@ -0,0 +1,29 @@ +#pragma once + +#include "CoreMinimal.h" +#include "ThemeKeys.generated.h" + +UENUM(BlueprintType) +enum class EZMMOThemeKey : uint8 +{ + // HUD + HUD_Frame UMETA(DisplayName = "HUD - Frame"), + HUD_HotbarBackground UMETA(DisplayName = "HUD - Hotbar Background"), + HUD_HealthBar UMETA(DisplayName = "HUD - Health Bar"), + HUD_ManaBar UMETA(DisplayName = "HUD - Mana Bar"), + + // Login / Character Select + Login_Background UMETA(DisplayName = "Login - Background"), + Login_Logo UMETA(DisplayName = "Login - Logo"), + Login_Music UMETA(DisplayName = "Login - Music"), + Login_AmbientVFX UMETA(DisplayName = "Login - Ambient VFX"), + CharSelect_Background UMETA(DisplayName = "Character Select - Background"), + + // Inventory + Inventory_SlotEmpty UMETA(DisplayName = "Inventory - Empty Slot"), + Inventory_Background UMETA(DisplayName = "Inventory - Background"), + + // Generic + MainMenu_Music UMETA(DisplayName = "Main Menu Music"), + LoadingScreen UMETA(DisplayName = "Loading Screen") +}; diff --git a/Source/ZMMO/Data/UI/ThemeRow.h b/Source/ZMMO/Data/UI/ThemeRow.h new file mode 100644 index 0000000..1161134 --- /dev/null +++ b/Source/ZMMO/Data/UI/ThemeRow.h @@ -0,0 +1,41 @@ +#pragma once + +#include "CoreMinimal.h" +#include "Engine/DataTable.h" +#include "UObject/SoftObjectPtr.h" +#include "ThemeRow.generated.h" + +class UObject; +class UTexture2D; +class USoundBase; +class UNiagaraSystem; + +USTRUCT(BlueprintType) +struct ZMMO_API FThemeEntry +{ + GENERATED_BODY() + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Theme") + TSoftObjectPtr Texture; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Theme") + TSoftObjectPtr Sound; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Theme") + TSoftObjectPtr VFX; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Theme") + TSoftObjectPtr Generic; +}; + +USTRUCT(BlueprintType) +struct ZMMO_API FThemeRow : public FTableRowBase +{ + GENERATED_BODY() + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Theme") + FText DisplayName; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Theme") + FName ThemeId; +}; diff --git a/Source/ZMMO/Data/UI/UIStyleRow.h b/Source/ZMMO/Data/UI/UIStyleRow.h new file mode 100644 index 0000000..c52f8f9 --- /dev/null +++ b/Source/ZMMO/Data/UI/UIStyleRow.h @@ -0,0 +1,70 @@ +#pragma once + +#include "CoreMinimal.h" +#include "Engine/DataTable.h" +#include "UIStyleTypes.h" +#include "UIStyleTokens.h" +#include "UIStyleRow.generated.h" + +/** + * Struct raiz que agrega todos os tokens de estilo de um tema. + * + * Adicionar membros aqui (fase 2/3) é mudança aditiva e segura para a + * DataTable existente — mas, ao alterar este struct em produção, fazer + * backup de DT_UI_Styles (UHT invalida rows serializadas se a coluna não + * preservar valores). Ver ARQUITETURA.md / docs Epic sobre DataTable. + */ +USTRUCT(BlueprintType) +struct ZMMO_API FUIStyle +{ + GENERATED_BODY() + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style") + FUIStylePalette Palette; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style") + FUIStyleSemantic Semantic; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style") + FUIStyleText Text; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style") + FUIStyleButton Button; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style") + FUIStylePanel Panel; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style") + FUIStyleBorders Borders; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style") + FUIStyleProgressBar ProgressBar; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style") + FUIStyleTooltip Tooltip; +}; + +/** + * Linha de DT_UI_Styles. O Row Name é o ThemeId (ex.: "Default", "RPG"), + * espelhando DT_ThemeCalendar e ThemeRegistry — assim a camada de estilo + * é consumidora do ThemeId já resolvido pelo UZMMOThemeSubsystem. + */ +USTRUCT(BlueprintType) +struct ZMMO_API FUIStyleRow : public FTableRowBase +{ + GENERATED_BODY() + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style") + FText DisplayName; + + /** Validação tipada de design-time; runtime resolve por ThemeId/Row Name. */ + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style") + EUITheme Theme = EUITheme::None; + + /** Ponte para o ThemeId resolvido pelo UZMMOThemeSubsystem. */ + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style") + FName ThemeId; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style") + FUIStyle Style; +}; diff --git a/Source/ZMMO/Data/UI/UIStyleTokens.h b/Source/ZMMO/Data/UI/UIStyleTokens.h new file mode 100644 index 0000000..67e57cd --- /dev/null +++ b/Source/ZMMO/Data/UI/UIStyleTokens.h @@ -0,0 +1,364 @@ +#pragma once + +#include "CoreMinimal.h" +#include "Fonts/SlateFontInfo.h" +#include "Layout/Margin.h" +#include "UIStyleTypes.h" +#include "UIStyleTokens.generated.h" + +/** + * Tokens de estilo da UI organizados em 3 camadas (design tokens): + * + * 1. Primitive (FUIStylePalette) — paleta crua "Aurora Arcana". + * Espelha Tools/Templates/Zeus_Widget/shared/styles.css (:root). + * 2. Semantic (FUIStyleSemantic) — papéis (Accent, Surface, OnSurface...) + * que referenciam a primitive. Trocar de tema mexe sobretudo aqui. + * 3. Component (FUIStyle*) — por componente, consome a camada semantic. + * + * Defaults faithful ao tema padrão; tudo é sobrescrito por linha em + * DT_UI_Styles (FUIStyleRow). Cores em FColor(R,G,B[,A]) sRGB convertidas + * implicitamente para FLinearColor. + */ + +// ===================================================================== +// 1. Primitive — paleta Aurora Arcana +// ===================================================================== +USTRUCT(BlueprintType) +struct ZMMO_API FUIStylePalette +{ + GENERATED_BODY() + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Palette") + FLinearColor Bg0 = FLinearColor(FColor(7, 10, 18)); // --bg-0 #070A12 + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Palette") + FLinearColor Bg1 = FLinearColor(FColor(11, 16, 32)); // --bg-1 #0B1020 + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Palette") + FLinearColor Panel = FLinearColor(FColor(12, 18, 34, 235)); // --panel rgba(..,.92) + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Palette") + FLinearColor Panel2 = FLinearColor(FColor(17, 24, 42)); // --panel-2 #11182A + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Palette") + FLinearColor Panel3 = FLinearColor(FColor(14, 20, 36)); // --panel-3 #0E1424 + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Palette") + FLinearColor Border = FLinearColor(FColor(58, 75, 120)); // --border #3A4B78 + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Palette") + FLinearColor BorderSoft = FLinearColor(FColor(58, 75, 120, 140)); // --border-soft + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Palette") + FLinearColor Gold = FLinearColor(FColor(201, 167, 90)); // --gold #C9A75A + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Palette") + FLinearColor GoldHi = FLinearColor(FColor(231, 200, 115)); // --gold-hi #E7C873 + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Palette") + FLinearColor Blue = FLinearColor(FColor(78, 163, 255)); // --blue #4EA3FF + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Palette") + FLinearColor Violet = FLinearColor(FColor(123, 92, 255)); // --violet #7B5CFF + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Palette") + FLinearColor Text = FLinearColor(FColor(244, 240, 230)); // --text #F4F0E6 + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Palette") + FLinearColor Text2 = FLinearColor(FColor(174, 182, 200)); // --text-2 #AEB6C8 + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Palette") + FLinearColor TextDim = FLinearColor(FColor(105, 115, 138)); // --text-dim #69738A + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Palette") + FLinearColor Danger = FLinearColor(FColor(217, 92, 92)); // --danger #D95C5C + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Palette") + FLinearColor Online = FLinearColor(FColor(80, 216, 144)); // --online #50D890 + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Palette") + FLinearColor Warn = FLinearColor(FColor(230, 180, 80)); // --warn #E6B450 +}; + +// ===================================================================== +// 2. Semantic — papéis (referenciam a primitive) +// ===================================================================== +USTRUCT(BlueprintType) +struct ZMMO_API FUIStyleSemantic +{ + GENERATED_BODY() + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Semantic") + FLinearColor Accent = FLinearColor(FColor(201, 167, 90)); // Gold + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Semantic") + FLinearColor AccentHover = FLinearColor(FColor(231, 200, 115)); // GoldHi + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Semantic") + FLinearColor Focus = FLinearColor(FColor(78, 163, 255)); // Blue + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Semantic") + FLinearColor Glow = FLinearColor(FColor(123, 92, 255)); // Violet + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Semantic") + FLinearColor SurfaceBase = FLinearColor(FColor(7, 10, 18)); // Bg0 + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Semantic") + FLinearColor Surface = FLinearColor(FColor(12, 18, 34, 235)); // Panel + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Semantic") + FLinearColor SurfaceRaised = FLinearColor(FColor(17, 24, 42)); // Panel2 + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Semantic") + FLinearColor SurfaceSunken = FLinearColor(FColor(14, 20, 36)); // Panel3 + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Semantic") + FLinearColor OutlineStrong = FLinearColor(FColor(58, 75, 120)); // Border + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Semantic") + FLinearColor OutlineSoft = FLinearColor(FColor(58, 75, 120, 140)); // BorderSoft + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Semantic") + FLinearColor OnSurface = FLinearColor(FColor(244, 240, 230)); // Text + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Semantic") + FLinearColor OnSurfaceMuted = FLinearColor(FColor(174, 182, 200)); // Text2 + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Semantic") + FLinearColor OnSurfaceDim = FLinearColor(FColor(105, 115, 138)); // TextDim + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Semantic") + FLinearColor Danger = FLinearColor(FColor(217, 92, 92)); // Danger + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Semantic") + FLinearColor Success = FLinearColor(FColor(80, 216, 144)); // Online + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Semantic") + FLinearColor Warning = FLinearColor(FColor(230, 180, 80)); // Warn +}; + +// ===================================================================== +// 3. Component +// ===================================================================== +USTRUCT(BlueprintType) +struct ZMMO_API FUIStyleText +{ + GENERATED_BODY() + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Text") + FSlateFontInfo TitleFont; // Cinzel ExtraBold (display) + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Text") + FSlateFontInfo SectionFont; // Cinzel Bold (section title) + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Text") + FSlateFontInfo BodyFont; // Rajdhani Regular + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Text") + FSlateFontInfo ButtonFont; // Rajdhani Bold + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Text") + FSlateFontInfo LabelFont; // Rajdhani Bold (label/caps) + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Text") + bool bLabelUppercase = true; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Text") + float TitleLetterSpacing = 0.f; // informativo (RichText/futuro) +}; + +/** Cores de uma variante de botão (primary/secondary/danger/ghost). */ +USTRUCT(BlueprintType) +struct ZMMO_API FUIStyleButtonVariant +{ + GENERATED_BODY() + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Button") + FLinearColor BgNormal = FLinearColor::Transparent; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Button") + FLinearColor BgHover = FLinearColor::Transparent; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Button") + FLinearColor BgPressed = FLinearColor::Transparent; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Button") + FLinearColor BgDisabled = FLinearColor(0.f, 0.f, 0.f, 0.42f); + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Button") + FLinearColor BorderNormal = FLinearColor::Transparent; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Button") + FLinearColor BorderHover = FLinearColor::Transparent; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Button") + FLinearColor TextColor = FLinearColor::White; +}; + +USTRUCT(BlueprintType) +struct ZMMO_API FUIStyleButton +{ + GENERATED_BODY() + + // .btn-primary — dourado, texto quase preto + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Button") + FUIStyleButtonVariant Primary; + + // .btn-secondary — painel sólido + borda + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Button") + FUIStyleButtonVariant Secondary; + + // .btn-danger + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Button") + FUIStyleButtonVariant Danger; + + // .btn-ghost — transparente + borda suave + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Button") + FUIStyleButtonVariant Ghost; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Button") + FMargin Padding = FMargin(22.f, 12.f); + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Button") + float MinHeight = 48.f; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Button") + float CornerRadius = 8.f; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Button") + float BorderWidth = 1.f; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Button") + float HoverScale = 1.02f; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Button") + float PressedScale = 0.98f; + + /** Tamanho por silhueta (Square/Rectangle/Topbar/Header). */ + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Button") + TMap ShapeSizes; +}; + +USTRUCT(BlueprintType) +struct ZMMO_API FUIStylePanel +{ + GENERATED_BODY() + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Panel") + FLinearColor Bg = FLinearColor(FColor(12, 18, 34, 235)); // Panel + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Panel") + FLinearColor BgRaised = FLinearColor(FColor(17, 24, 42)); // Panel2 + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Panel") + FLinearColor BgSunken = FLinearColor(FColor(14, 20, 36)); // Panel3 + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Panel") + FLinearColor BorderColor = FLinearColor(FColor(58, 75, 120)); + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Panel") + FLinearColor BorderSoftColor = FLinearColor(FColor(58, 75, 120, 140)); + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Panel") + float CornerRadius = 12.f; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Panel") + float CornerRadiusSmall = 10.f; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Panel") + float BorderWidth = 1.f; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Panel") + FMargin Padding = FMargin(30.f); + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Panel") + FMargin PaddingSmall = FMargin(20.f); + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Panel") + FLinearColor CardSelectedBorder = FLinearColor(FColor(201, 167, 90)); // Accent + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Panel") + FLinearColor CardSelectedBg = FLinearColor(FColor(24, 32, 58)); +}; + +USTRUCT(BlueprintType) +struct ZMMO_API FUIStyleBorders +{ + GENERATED_BODY() + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Borders") + FLinearColor Color = FLinearColor(FColor(58, 75, 120)); + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Borders") + FLinearColor SoftColor = FLinearColor(FColor(58, 75, 120, 140)); + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Borders") + float Width = 1.f; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Borders") + float Radius = 12.f; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Borders") + float RadiusSmall = 8.f; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Borders") + FLinearColor RuleColor = FLinearColor(FColor(201, 167, 90, 166)); // Gold ~.65 + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Borders") + float RuleThickness = 2.f; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Borders") + float RuleSoftThickness = 1.f; +}; + +USTRUCT(BlueprintType) +struct ZMMO_API FUIStyleProgressBar +{ + GENERATED_BODY() + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|ProgressBar") + FLinearColor TrackColor = FLinearColor(FColor(14, 20, 36)); // Panel3 + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|ProgressBar") + FLinearColor BorderColor = FLinearColor(FColor(58, 75, 120, 140)); + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|ProgressBar") + float Height = 10.f; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|ProgressBar") + float CornerRadius = 6.f; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|ProgressBar") + float BorderWidth = 1.f; + + /** Cor de preenchimento por tipo (Health/Mana/XP...). */ + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|ProgressBar") + TMap FillByType; +}; + +USTRUCT(BlueprintType) +struct ZMMO_API FUIStyleTooltip +{ + GENERATED_BODY() + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Tooltip") + FLinearColor Bg = FLinearColor(FColor(17, 24, 42)); // Panel2 + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Tooltip") + FLinearColor BorderColor = FLinearColor(FColor(58, 75, 120)); + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Tooltip") + float CornerRadius = 10.f; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Tooltip") + float BorderWidth = 1.f; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Tooltip") + FMargin Padding = FMargin(18.f, 14.f); + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Tooltip") + FSlateFontInfo Font; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Tooltip") + FLinearColor TextColor = FLinearColor(FColor(244, 240, 230)); // Text +}; diff --git a/Source/ZMMO/Data/UI/UIStyleTypes.h b/Source/ZMMO/Data/UI/UIStyleTypes.h new file mode 100644 index 0000000..4446300 --- /dev/null +++ b/Source/ZMMO/Data/UI/UIStyleTypes.h @@ -0,0 +1,74 @@ +#pragma once + +#include "CoreMinimal.h" +#include "UIStyleTypes.generated.h" + +/** + * Enums do sistema de UI Style (tokens de tema visual). + * + * Espelha ThemeKeys.h: enums fortes, BlueprintType, primeiro valor None. + * O conceito de "tema ativo" continua sendo do UZMMOThemeSubsystem + * (resolvido por FName ThemeId). EUITheme é apenas validação tipada de + * design-time ao preencher DT_UI_Styles — não é a chave de runtime. + */ + +UENUM(BlueprintType) +enum class EUITheme : uint8 +{ + None UMETA(DisplayName = "None"), + MMORPG UMETA(DisplayName = "MMORPG"), + Survival UMETA(DisplayName = "Survival"), + RPG UMETA(DisplayName = "RPG") +}; + +/** Forma/silhueta de um botão — usada pelo widget para escolher dimensões. */ +UENUM(BlueprintType) +enum class EUIButtonShape : uint8 +{ + None UMETA(DisplayName = "None"), + Square UMETA(DisplayName = "Square"), + Rectangle UMETA(DisplayName = "Rectangle"), + Topbar UMETA(DisplayName = "Topbar"), + HeaderButton UMETA(DisplayName = "Header Button") +}; + +UENUM(BlueprintType) +enum class EUIPanelType : uint8 +{ + None UMETA(DisplayName = "None"), + Primary UMETA(DisplayName = "Primary"), + Secondary UMETA(DisplayName = "Secondary"), + Tertiary UMETA(DisplayName = "Tertiary"), + Card UMETA(DisplayName = "Card") +}; + +UENUM(BlueprintType) +enum class EUIProgressBarType : uint8 +{ + None UMETA(DisplayName = "None"), + Health UMETA(DisplayName = "Health"), + Mana UMETA(DisplayName = "Mana"), + Experience UMETA(DisplayName = "Experience"), + Cast UMETA(DisplayName = "Cast"), + Generic UMETA(DisplayName = "Generic") +}; + +UENUM(BlueprintType) +enum class EUIHeaderType : uint8 +{ + None UMETA(DisplayName = "None"), + Section UMETA(DisplayName = "Section"), + Panel UMETA(DisplayName = "Panel"), + SubPanel UMETA(DisplayName = "Sub Panel") +}; + +UENUM(BlueprintType) +enum class EUIIconType : uint8 +{ + None UMETA(DisplayName = "None"), + Inventory UMETA(DisplayName = "Inventory"), + Equipment UMETA(DisplayName = "Equipment"), + Skill UMETA(DisplayName = "Skill"), + Status UMETA(DisplayName = "Status"), + Currency UMETA(DisplayName = "Currency") +}; diff --git a/Source/ZMMO/Data/World/ZoneRow.h b/Source/ZMMO/Data/World/ZoneRow.h new file mode 100644 index 0000000..9ee81b9 --- /dev/null +++ b/Source/ZMMO/Data/World/ZoneRow.h @@ -0,0 +1,45 @@ +#pragma once + +#include "CoreMinimal.h" +#include "Engine/DataTable.h" +#include "Engine/World.h" +#include "ZoneRow.generated.h" + +class USoundBase; + +UENUM(BlueprintType) +enum class EZoneRules : uint8 +{ + Safe UMETA(DisplayName = "Safe"), + PvE UMETA(DisplayName = "PvE"), + PvP UMETA(DisplayName = "PvP"), + Dungeon UMETA(DisplayName = "Dungeon"), + Instance UMETA(DisplayName = "Instance") +}; + +USTRUCT(BlueprintType) +struct ZMMO_API FZoneRow : public FTableRowBase +{ + GENERATED_BODY() + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Zone") + FText DisplayName; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Zone") + TSoftObjectPtr Map; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Zone") + EZoneRules Rules = EZoneRules::PvE; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Zone") + int32 RecommendedLevelMin = 1; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Zone") + int32 RecommendedLevelMax = 10; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Zone") + TSoftObjectPtr AmbientMusic; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Zone") + TSoftObjectPtr AmbientSound; +}; diff --git a/Source/ZMMO/Game/UI/ZMMOThemeDataAsset.cpp b/Source/ZMMO/Game/UI/ZMMOThemeDataAsset.cpp new file mode 100644 index 0000000..581a1e8 --- /dev/null +++ b/Source/ZMMO/Game/UI/ZMMOThemeDataAsset.cpp @@ -0,0 +1,11 @@ +#include "ZMMOThemeDataAsset.h" + +bool UZMMOThemeDataAsset::HasKey(EZMMOThemeKey Key) const +{ + return Entries.Contains(Key); +} + +const FThemeEntry* UZMMOThemeDataAsset::FindEntry(EZMMOThemeKey Key) const +{ + return Entries.Find(Key); +} diff --git a/Source/ZMMO/Game/UI/ZMMOThemeDataAsset.h b/Source/ZMMO/Game/UI/ZMMOThemeDataAsset.h new file mode 100644 index 0000000..7e678aa --- /dev/null +++ b/Source/ZMMO/Game/UI/ZMMOThemeDataAsset.h @@ -0,0 +1,26 @@ +#pragma once + +#include "CoreMinimal.h" +#include "Engine/DataAsset.h" +#include "UI/ThemeKeys.h" +#include "UI/ThemeRow.h" +#include "ZMMOThemeDataAsset.generated.h" + +UCLASS(BlueprintType) +class ZMMO_API UZMMOThemeDataAsset : public UPrimaryDataAsset +{ + GENERATED_BODY() + +public: + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Theme") + FName ThemeId; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Theme") + FText DisplayName; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Theme", meta = (ToolTip = "Only fill the keys this theme overrides. Missing keys fall back to the Default theme.")) + TMap Entries; + + bool HasKey(EZMMOThemeKey Key) const; + const FThemeEntry* FindEntry(EZMMOThemeKey Key) const; +}; diff --git a/Source/ZMMO/Game/UI/ZMMOThemeSubsystem.cpp b/Source/ZMMO/Game/UI/ZMMOThemeSubsystem.cpp new file mode 100644 index 0000000..6803d72 --- /dev/null +++ b/Source/ZMMO/Game/UI/ZMMOThemeSubsystem.cpp @@ -0,0 +1,216 @@ +#include "ZMMOThemeSubsystem.h" + +#include "ZMMOThemeDataAsset.h" +#include "Engine/DataTable.h" +#include "Engine/Texture2D.h" +#include "Sound/SoundBase.h" +#include "NiagaraSystem.h" +#include "Misc/DateTime.h" +#include "UI/ThemeCalendarRow.h" +#include "UI/UIStyleRow.h" + +namespace +{ + /** Row Name da linha de estilo de fallback em DT_UI_Styles. */ + const FName GUIStyleDefaultRow(TEXT("Default")); +} + +void UZMMOThemeSubsystem::Initialize(FSubsystemCollectionBase& Collection) +{ + Super::Initialize(Collection); + + DefaultTheme = DefaultThemeAsset.LoadSynchronous(); + if (!DefaultTheme) + { + UE_LOG(LogTemp, Warning, + TEXT("[ZMMOThemeSubsystem] DefaultThemeAsset is not set. UI will have no theme.")); + } + + ResolveActiveTheme(); +} + +void UZMMOThemeSubsystem::Deinitialize() +{ + ActiveTheme = nullptr; + DefaultTheme = nullptr; + Super::Deinitialize(); +} + +void UZMMOThemeSubsystem::ApplyServerTheme(FName ThemeId) +{ + ServerThemeId = ThemeId; + ResolveActiveTheme(); +} + +void UZMMOThemeSubsystem::ForceTheme(FName ThemeId) +{ + ForcedThemeId = ThemeId; + ResolveActiveTheme(); +} + +void UZMMOThemeSubsystem::ClearForcedTheme() +{ + ForcedThemeId = NAME_None; + ResolveActiveTheme(); +} + +void UZMMOThemeSubsystem::ResolveActiveTheme() +{ + FName Resolved = NAME_None; + + if (!ForcedThemeId.IsNone()) + { + Resolved = ForcedThemeId; + } +#if !UE_BUILD_SHIPPING + else if (!DevThemeOverride.IsNone()) + { + Resolved = DevThemeOverride; + } +#endif + else if (!ServerThemeId.IsNone()) + { + Resolved = ServerThemeId; + } + else + { + Resolved = ResolveByCalendar(); + } + + UZMMOThemeDataAsset* NewActive = !Resolved.IsNone() ? LoadThemeById(Resolved) : nullptr; + if (!NewActive) + { + NewActive = DefaultTheme; + Resolved = DefaultTheme ? DefaultTheme->ThemeId : NAME_None; + } + + if (NewActive != ActiveTheme || Resolved != ActiveThemeId) + { + ActiveTheme = NewActive; + ActiveThemeId = Resolved; + ResolveActiveUIStyle(ActiveThemeId); + OnThemeChanged.Broadcast(ActiveThemeId); + } +} + +void UZMMOThemeSubsystem::ResolveActiveUIStyle(FName ThemeId) +{ + // Reset para os defaults do struct antes de aplicar a linha resolvida — + // assim um tema sem linha cai num estado coerente (paleta Aurora Arcana). + ActiveUIStyle = FUIStyle(); + + UDataTable* Table = UIStyleTable.LoadSynchronous(); + if (!Table) + { + return; + } + + const FUIStyleRow* Row = nullptr; + if (!ThemeId.IsNone()) + { + Row = Table->FindRow(ThemeId, TEXT("UIStyle")); + } + if (!Row) + { + // Fallback: linha "Default" (mesma política dos assets, §5). + Row = Table->FindRow(GUIStyleDefaultRow, TEXT("UIStyle")); + } + if (Row) + { + ActiveUIStyle = Row->Style; + } +} + +FName UZMMOThemeSubsystem::ResolveByCalendar() const +{ + UDataTable* Table = CalendarTable.LoadSynchronous(); + if (!Table) + { + return NAME_None; + } + + const FDateTime Now = FDateTime::Now(); + const int32 NowMonth = Now.GetMonth(); + const int32 NowDay = Now.GetDay(); + const int32 NowMD = NowMonth * 100 + NowDay; + + FName Best = NAME_None; + int32 BestPriority = MIN_int32; + + TArray RowNames = Table->GetRowNames(); + for (const FName& RowName : RowNames) + { + const FThemeCalendarRow* Row = Table->FindRow(RowName, TEXT("ThemeCalendar")); + if (!Row || Row->ThemeId.IsNone()) + { + continue; + } + + const int32 StartMD = Row->StartMonth * 100 + Row->StartDay; + const int32 EndMD = Row->EndMonth * 100 + Row->EndDay; + + const bool bInRange = (StartMD <= EndMD) + ? (NowMD >= StartMD && NowMD <= EndMD) + : (NowMD >= StartMD || NowMD <= EndMD); // wraps across year (e.g. 12-15 -> 01-05) + + if (bInRange && Row->Priority > BestPriority) + { + Best = Row->ThemeId; + BestPriority = Row->Priority; + } + } + + return Best; +} + +UZMMOThemeDataAsset* UZMMOThemeSubsystem::LoadThemeById(FName ThemeId) const +{ + if (const TSoftObjectPtr* Soft = ThemeRegistry.Find(ThemeId)) + { + return Soft->LoadSynchronous(); + } + return nullptr; +} + +const FThemeEntry* UZMMOThemeSubsystem::FindEntryWithFallback(EZMMOThemeKey Key) const +{ + if (ActiveTheme) + { + if (const FThemeEntry* Entry = ActiveTheme->FindEntry(Key)) + { + return Entry; + } + } + if (DefaultTheme && DefaultTheme != ActiveTheme) + { + if (const FThemeEntry* Entry = DefaultTheme->FindEntry(Key)) + { + return Entry; + } + } + return nullptr; +} + +UTexture2D* UZMMOThemeSubsystem::GetTexture(EZMMOThemeKey Key) const +{ + const FThemeEntry* Entry = FindEntryWithFallback(Key); + return Entry ? Entry->Texture.LoadSynchronous() : nullptr; +} + +USoundBase* UZMMOThemeSubsystem::GetSound(EZMMOThemeKey Key) const +{ + const FThemeEntry* Entry = FindEntryWithFallback(Key); + return Entry ? Entry->Sound.LoadSynchronous() : nullptr; +} + +UNiagaraSystem* UZMMOThemeSubsystem::GetVFX(EZMMOThemeKey Key) const +{ + const FThemeEntry* Entry = FindEntryWithFallback(Key); + return Entry ? Entry->VFX.LoadSynchronous() : nullptr; +} + +UObject* UZMMOThemeSubsystem::GetGeneric(EZMMOThemeKey Key) const +{ + const FThemeEntry* Entry = FindEntryWithFallback(Key); + return Entry ? Entry->Generic.LoadSynchronous() : nullptr; +} diff --git a/Source/ZMMO/Game/UI/ZMMOThemeSubsystem.h b/Source/ZMMO/Game/UI/ZMMOThemeSubsystem.h new file mode 100644 index 0000000..27344ee --- /dev/null +++ b/Source/ZMMO/Game/UI/ZMMOThemeSubsystem.h @@ -0,0 +1,124 @@ +#pragma once + +#include "CoreMinimal.h" +#include "Subsystems/GameInstanceSubsystem.h" +#include "UI/ThemeKeys.h" +#include "UI/ThemeRow.h" +#include "UI/UIStyleRow.h" +#include "ZMMOThemeSubsystem.generated.h" + +class UZMMOThemeDataAsset; +class UDataTable; +class UTexture2D; +class USoundBase; +class UNiagaraSystem; + +DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnZMMOThemeChanged, FName, NewThemeId); + +/** + * Resolves which UI theme is active and answers asset lookups by EZMMOThemeKey. + * + * Resolution precedence (see ARQUITETURA.md §1.10): + * 1. Dev override (.ini DevThemeOverride) — ignored in Shipping builds. + * 2. Authoritative server theme (set via ApplyServerTheme). + * 3. Local calendar (DT_ThemeCalendar). + * 4. DA_Theme_Default. + * + * Widgets must never hold hard refs to theme textures/sounds. They consume the + * active theme through Get* methods on this subsystem. + */ +UCLASS(Config = Game) +class ZMMO_API UZMMOThemeSubsystem : public UGameInstanceSubsystem +{ + GENERATED_BODY() + +public: + // USubsystem + virtual void Initialize(FSubsystemCollectionBase& Collection) override; + virtual void Deinitialize() override; + + /** Server-authoritative theme. Call from the ZeusNetwork ServerHello handler. */ + UFUNCTION(BlueprintCallable, Category = "Theme") + void ApplyServerTheme(FName ThemeId); + + /** Forces a specific theme regardless of precedence. Use only for debug UI. */ + UFUNCTION(BlueprintCallable, Category = "Theme|Debug") + void ForceTheme(FName ThemeId); + + /** Resets to the precedence-resolved theme. */ + UFUNCTION(BlueprintCallable, Category = "Theme|Debug") + void ClearForcedTheme(); + + UFUNCTION(BlueprintPure, Category = "Theme") + FName GetActiveThemeId() const { return ActiveThemeId; } + + UFUNCTION(BlueprintCallable, Category = "Theme") + UTexture2D* GetTexture(EZMMOThemeKey Key) const; + + UFUNCTION(BlueprintCallable, Category = "Theme") + USoundBase* GetSound(EZMMOThemeKey Key) const; + + UFUNCTION(BlueprintCallable, Category = "Theme") + UNiagaraSystem* GetVFX(EZMMOThemeKey Key) const; + + UFUNCTION(BlueprintCallable, Category = "Theme") + UObject* GetGeneric(EZMMOThemeKey Key) const; + + /** + * Tokens de estilo (cores/fontes/dimensões) do tema ativo, resolvidos de + * DT_UI_Styles pelo ThemeId. Faz fallback para a linha "Default" quando o + * tema ativo não tem linha própria — mesma política dos assets (§5). + */ + UFUNCTION(BlueprintPure, Category = "Theme|Style") + const FUIStyle& GetActiveUIStyle() const { return ActiveUIStyle; } + + /** Fired whenever the active theme actually changes. */ + UPROPERTY(BlueprintAssignable, Category = "Theme") + FOnZMMOThemeChanged OnThemeChanged; + +protected: + /** Default theme. Must be filled with every key — it is the final fallback. */ + UPROPERTY(Config, EditDefaultsOnly, Category = "Theme") + TSoftObjectPtr DefaultThemeAsset; + + /** Registry of seasonal/event themes keyed by ThemeId. */ + UPROPERTY(Config, EditDefaultsOnly, Category = "Theme") + TMap> ThemeRegistry; + + /** Local calendar table (FThemeCalendarRow). Optional. */ + UPROPERTY(Config, EditDefaultsOnly, Category = "Theme") + TSoftObjectPtr CalendarTable; + + /** Tabela de tokens de estilo (FUIStyleRow), keyed por ThemeId. */ + UPROPERTY(Config, EditDefaultsOnly, Category = "Theme") + TSoftObjectPtr UIStyleTable; + + /** Dev-only override read from DefaultGame.ini. Empty in Shipping. */ + UPROPERTY(Config, EditDefaultsOnly, Category = "Theme|Debug") + FName DevThemeOverride; + +private: + void ResolveActiveTheme(); + FName ResolveByCalendar() const; + UZMMOThemeDataAsset* LoadThemeById(FName ThemeId) const; + const FThemeEntry* FindEntryWithFallback(EZMMOThemeKey Key) const; + void ResolveActiveUIStyle(FName ThemeId); + + UPROPERTY(Transient) + TObjectPtr ActiveTheme; + + UPROPERTY(Transient) + TObjectPtr DefaultTheme; + + UPROPERTY(Transient) + FName ActiveThemeId; + + UPROPERTY(Transient) + FName ServerThemeId; + + UPROPERTY(Transient) + FName ForcedThemeId; + + UPROPERTY(Transient) + FUIStyle ActiveUIStyle; +}; diff --git a/Source/ZMMO/ZMMO.Build.cs b/Source/ZMMO/ZMMO.Build.cs index a547dc8..c1f30f3 100644 --- a/Source/ZMMO/ZMMO.Build.cs +++ b/Source/ZMMO/ZMMO.Build.cs @@ -14,6 +14,7 @@ public class ZMMO : ModuleRules "EnhancedInput", "UMG", "Slate", + "Niagara", "ZeusNetwork" }); @@ -27,7 +28,17 @@ public class ZMMO : ModuleRules "ZMMO/Game/Entity", "ZMMO/Game/Controller", "ZMMO/Game/Modes", - "ZMMO/Game/Network" + "ZMMO/Game/Network", + "ZMMO/Game/UI", + "ZMMO/Data", + "ZMMO/Data/Items", + "ZMMO/Data/Mobs", + "ZMMO/Data/Players", + "ZMMO/Data/NPCs", + "ZMMO/Data/Abilities", + "ZMMO/Data/Quests", + "ZMMO/Data/UI", + "ZMMO/Data/World" }); } } diff --git a/ZMMO.uproject b/ZMMO.uproject index d21784d..c53cef7 100644 --- a/ZMMO.uproject +++ b/ZMMO.uproject @@ -41,6 +41,13 @@ "Editor" ] }, + { + "Name": "ZeusUMGForge", + "Enabled": true, + "TargetAllowList": [ + "Editor" + ] + }, { "Name": "meshy", "Enabled": false, @@ -48,6 +55,10 @@ "Win64", "Mac" ] + }, + { + "Name": "CommonUI", + "Enabled": true } ], "AdditionalPluginDirectories": [