feat(frontend): esqueleto CommonUI de MainMenu (boot→login→lobby)
Estrutura principal de front-end estilo Lyra portada para C++ proprio do ZMMO (sem CommonGame), seguindo o padrao C++ Abstract -> WBP concreto: - EZMMOFrontEndState / EZMMOLobbyPage e GameplayTags UI.Layer.* nativos - UUIActivatableScreen_Base: base de tela (input config, hook de tema, voltar) espelhando o padrao de UUIButton_Base - UUIPrimaryGameLayout_Base: switch principal (4 stacks CommonUI/camada) - UUIManagerSubsystem (LocalPlayer): dono do root layout, idempotente - UUIFrontEndFlowSubsystem (GameInstance): maquina de estados + driver de rede (Boot->Connecting->Login->ServerSelect->Lobby->EnteringWorld ->InWorld); Lobby e o hub logado, paginas internas = EZMMOLobbyPage - UUIFrontEndScreenSet (DataAsset): mapa estado->tela, forge-ready - AZMMOFrontEndGameMode + AZMMOFrontEndPlayerController - GameInstance: bAutoConnectOnStart=false (conexao dirigida pelo fluxo) - Build.cs: +GameplayTags; ARQUITETURA.md PR-first (s2.1/2.2/3.3/4.8/5) - Assets: L_FrontEnd (GameMode via World Settings), WBP_PrimaryGameLayout, DA_FrontEndScreenSet; Config wiring WBPs de pagina (Boot/Login/...) virao do Zeus UMG Forge depois (s4.8). Smoke test PIE OK: root layout no viewport, fluxo Boot->Connecting, no-op+log para telas nao configuradas, sem crash. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -203,10 +203,16 @@ Content/
|
||||
│ │ ├── Environment/ ← Architecture/ Nature/ Props/
|
||||
│ │ └── Interactables/ ← baús, portas, warps, recursos
|
||||
│ │
|
||||
│ ├── Maps/ ← mapas que NÃO são de mundo
|
||||
│ │ └── FrontEnd/ ← L_FrontEnd (boot/menu; GameMode via
|
||||
│ │ World Settings = AZMMOFrontEndGameMode)
|
||||
│ │
|
||||
│ ├── UI/ ← HUD, Login, CharacterSelect, Inventory,
|
||||
│ │ │ Chat, Party, Guild, Trade, Quest, Map,
|
||||
│ │ │ Shared, Icons
|
||||
│ │ ├── Shared/ ← WBPs reutilizáveis (UI_Button_Master…)
|
||||
│ │ ├── FrontEnd/ ← WBP_PrimaryGameLayout, DA_FrontEndScreenSet,
|
||||
│ │ │ telas refinadas (Boot/Login/… vindas do Forge)
|
||||
│ │ ├── Fonts/ ← Font_*/FF_* (Cinzel, Rajdhani)
|
||||
│ │ ├── CommonUI/Style/ ← estilos CommonUI (espelha o Hyper)
|
||||
│ │ │ ├── Button/ ← BSB_* (UCommonButtonStyle)
|
||||
@@ -236,6 +242,9 @@ Content/
|
||||
│
|
||||
├── Developers/ ← rascunho por dev (não cooka)
|
||||
│ └── <nick-do-dev>/
|
||||
├── AutoCreated/ ← saída CRUA do Zeus UMG Forge (HTML→WBP).
|
||||
│ └── <batch>/ Quarentena: refina-se e MOVE p/ ZMMO/UI/
|
||||
│ FrontEnd/ antes de produção (não cooka cru)
|
||||
├── ExternalContent/ ← Fab / Megascans / Marketplace
|
||||
│ ├── Fab/ Megascans/ Marketplace/
|
||||
├── Collections/
|
||||
@@ -252,9 +261,20 @@ Source/ZMMO/
|
||||
│
|
||||
├── Game/ ← gameplay runtime (já existe)
|
||||
│ ├── Entity/ ← AZMMOEntity + derivados
|
||||
│ ├── Controller/ ← AZMMOPlayerController
|
||||
│ ├── Modes/ ← GameMode + GameInstance
|
||||
│ └── Network/ ← UZMMOWorldSubsystem
|
||||
│ ├── Controller/ ← AZMMOPlayerController,
|
||||
│ │ AZMMOFrontEndPlayerController
|
||||
│ ├── Modes/ ← GameMode + GameInstance,
|
||||
│ │ AZMMOFrontEndGameMode
|
||||
│ ├── Network/ ← UZMMOWorldSubsystem
|
||||
│ └── UI/ ← runtime de UI (não é contrato de dados)
|
||||
│ ├── ZMMOThemeSubsystem.* ← resolução de tema
|
||||
│ ├── Widgets/ ← UUIButton_Base, UUIPanel_Base
|
||||
│ └── FrontEnd/ ← infra de navegação CommonUI:
|
||||
│ UUIActivatableScreen_Base,
|
||||
│ UUIPrimaryGameLayout_Base,
|
||||
│ UUIManagerSubsystem (LocalPlayer),
|
||||
│ UUIFrontEndFlowSubsystem (GameInstance),
|
||||
│ UUIFrontEndScreenSet (UDataAsset)
|
||||
│
|
||||
└── Data/ ← contrato de dados (USTRUCT + UENUM)
|
||||
├── ZMMOData.h ← header agregador (opcional)
|
||||
@@ -278,7 +298,9 @@ Source/ZMMO/
|
||||
├── UI/
|
||||
│ ├── ThemeKeys.h ← EZMMOThemeKey (HUD_Frame, Login_BG…)
|
||||
│ ├── ThemeRow.h ← FThemeEntry (Key → SoftAsset)
|
||||
│ └── ThemeCalendarRow.h ← FThemeCalendarRow (data → ThemeId)
|
||||
│ ├── ThemeCalendarRow.h ← FThemeCalendarRow (data → ThemeId)
|
||||
│ ├── FrontEndTypes.h ← EZMMOFrontEndState, EZMMOLobbyPage
|
||||
│ └── UILayerTags.h/.cpp ← GameplayTags nativos UI.Layer.*
|
||||
└── World/
|
||||
└── ZoneRow.h
|
||||
```
|
||||
@@ -365,6 +387,16 @@ base de widget = `UUI<Componente>_Base`, sempre `UCLASS(Abstract)` (não
|
||||
instanciável direto; só os filhos derivam — padrão `_Abstract` do Hyper).
|
||||
Ex.: `UUIButton_Base`, `UUIPanel_Base`, `UUIProgressBar_Base`.
|
||||
|
||||
**Sub-regra — infra de navegação de front-end:** as classes que orquestram a
|
||||
navegação CommonUI seguem o mesmo prefixo `UUI` (sem `ZMMO`) por coerência com
|
||||
a família de UI, **mesmo não sendo widgets**. Assim: o layout raiz é
|
||||
`UUIPrimaryGameLayout_Base` (Abstract, widget), a base de tela é
|
||||
`UUIActivatableScreen_Base` (Abstract, widget), e os subsistemas de UI são
|
||||
`UUIManagerSubsystem` (`ULocalPlayerSubsystem`) e `UUIFrontEndFlowSubsystem`
|
||||
(`UGameInstanceSubsystem`). Atores de gameplay do front-end (GameMode,
|
||||
PlayerController) **mantêm** o prefixo `AZMMO` — não são UI, espelham
|
||||
`AZMMOGameMode`: `AZMMOFrontEndGameMode`, `AZMMOFrontEndPlayerController`.
|
||||
|
||||
**Regra do UMG (importante):** um Widget Blueprint **não pode** herdar de outro
|
||||
Widget Blueprint que tenha árvore de widgets (UMG aborta a compilação: "apenas
|
||||
um deles deve ter árvore"). Portanto a camada abstrata é **só a classe C++**
|
||||
@@ -577,6 +609,38 @@ o opcode de spawn. O cliente nunca instancia mob "por nome" — sempre via id.
|
||||
O subsystem aplica fallback internamente: pergunta ao tema activo; se a
|
||||
chave não estiver preenchida, devolve a do `Default`.
|
||||
|
||||
### 4.8. Adicionar uma tela de front-end (ex: `Login`)
|
||||
|
||||
**Pré-requisito:** já existem `UUIActivatableScreen_Base` e
|
||||
`UUIFrontEndFlowSubsystem` em `Source/ZMMO/Game/UI/FrontEnd/`, o
|
||||
`WBP_PrimaryGameLayout` e o `DA_FrontEndScreenSet` em
|
||||
`Content/ZMMO/UI/FrontEnd/`.
|
||||
|
||||
Fluxo geral: **Boot → Connecting → Login → ServerSelect → Lobby → EnteringWorld
|
||||
→ InWorld**. O **Lobby** é o hub principal logado; suas páginas internas
|
||||
(CharacterSelect, CharacterCreate, Shop, Settings…) são `EZMMOLobbyPage`,
|
||||
navegadas por um stack CommonUI **dentro** da tela do Lobby — não são estados
|
||||
de topo do fluxo.
|
||||
|
||||
1. Prototipar a tela em HTML/CSS em `Tools/Templates/MMO_Widget/` (ou usar os
|
||||
templates já existentes).
|
||||
2. Rodar o Zeus UMG Forge (HTML→UMG). Saída crua: `Content/AutoCreated/<batch>/`.
|
||||
3. Abrir o `WBP_*` gerado e **reparent** a classe pai para
|
||||
`UUIActivatableScreen_Base` (a base é `UCommonActivatableWidget`; o WBP tem
|
||||
árvore própria — respeita §3.3, nunca encadeia WBP→WBP).
|
||||
4. **Reconectar tema:** o Forge gera hard ref de textura (proibido §5).
|
||||
Substituir por consumo via `UZMMOThemeSubsystem` por `EZMMOThemeKey` no
|
||||
override de `RefreshUIStyle`; remontar botões/painéis com os widgets
|
||||
compartilhados (`UI_Button_Master`, `UI_Panel_Master`).
|
||||
5. **Mover** o asset refinado de `Content/AutoCreated/…` para
|
||||
`Content/ZMMO/UI/FrontEnd/` (o cru não cooka).
|
||||
6. Registrar no `DA_FrontEndScreenSet`: `StateScreens[EZMMOFrontEndState::Login]`
|
||||
= soft class do WBP refinado (páginas do Lobby vão no map de
|
||||
`EZMMOLobbyPage` da tela de Lobby). Sem registro, o flow faz no-op + log.
|
||||
|
||||
**Regra:** uma tela nunca segura hard ref a asset de tema (textura/som/VFX) —
|
||||
sempre via `UZMMOThemeSubsystem` por `EZMMOThemeKey` (igual §4.7 e §5).
|
||||
|
||||
---
|
||||
|
||||
## 5. O que **NÃO** fazer
|
||||
@@ -588,7 +652,9 @@ chave não estiver preenchida, devolve a do `Default`.
|
||||
- **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}/...`.
|
||||
`Content/{Developers,AutoCreated,ExternalContent}/...`. `AutoCreated/` é
|
||||
quarentena do Zeus UMG Forge: refina-se e **move** para `ZMMO/UI/FrontEnd/`
|
||||
antes de produção; o cru não cooka.
|
||||
- **Não** importar conteúdo do Fab/Megascans directo para dentro de `ZMMO/`.
|
||||
Vai sempre para `ExternalContent/` e, se quiser usar, **referencia** dali.
|
||||
- **Não** colocar dados tabulares em Blueprint (lista hardcoded de itens,
|
||||
@@ -598,7 +664,10 @@ chave não estiver preenchida, devolve a do `Default`.
|
||||
- **Não** colocar hard ref de textura/som de tema dentro de um Widget
|
||||
(`TObjectPtr<UTexture2D> ChristmasFrame` é proibido). Widgets pedem ao
|
||||
`UZMMOThemeSubsystem` via `EZMMOThemeKey`. Hard ref a asset de tema
|
||||
bloqueia a troca em runtime e quebra a política de fallback.
|
||||
bloqueia a troca em runtime e quebra a política de fallback. Vale também
|
||||
para **telas de front-end** (Boot/Login/ServerSelect/Lobby/…): a saída crua
|
||||
do Forge traz hard ref — tem de ser reconectada ao subsystem antes do merge
|
||||
(ver §4.8).
|
||||
- **Não** criar chave de tema "ad-hoc" como `FName("HUD.Frame")`. Toda chave
|
||||
é entrada do enum C++ `EZMMOThemeKey`. String literal é proibida — o
|
||||
compilador tem de quebrar quando alguém esquecer de adicionar a chave.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[/Script/EngineSettings.GameMapsSettings]
|
||||
GameDefaultMap=/Game/ThirdPerson/Lvl_ThirdPerson.Lvl_ThirdPerson
|
||||
EditorStartupMap=/Game/ThirdPerson/Lvl_ThirdPerson.Lvl_ThirdPerson
|
||||
GameDefaultMap=/Game/ZMMO/Maps/FrontEnd/L_FrontEnd.L_FrontEnd
|
||||
EditorStartupMap=/Game/ZMMO/Maps/FrontEnd/L_FrontEnd.L_FrontEnd
|
||||
; GameMode/PlayerController/PlayerCharacter agora moram em C++ (Game/Modes/Entity/Controller).
|
||||
; O motor pode spawnar AZMMOGameMode directamente; um BP filho continua opcional.
|
||||
GlobalDefaultGameMode=/Script/ZMMO.ZMMOGameMode
|
||||
|
||||
@@ -24,3 +24,8 @@ ProjectName=Third Person Game Template
|
||||
;CalendarTable=/Game/ZMMO/UI/Themes/DT_ThemeCalendar.DT_ThemeCalendar
|
||||
UIStyleTable=/Game/ZMMO/Data/UI/DT_UI_Styles.DT_UI_Styles
|
||||
;DevThemeOverride=Christmas
|
||||
|
||||
[/Script/ZMMO.UIFrontEndFlowSubsystem]
|
||||
; Mapa estado->tela. O DA já existe (RootLayoutClass = WBP_PrimaryGameLayout);
|
||||
; StateScreens fica vazio até os WBPs de página virem do Zeus UMG Forge (§4.8).
|
||||
ScreenSetAsset=/Game/ZMMO/UI/FrontEnd/DA_FrontEndScreenSet.DA_FrontEndScreenSet
|
||||
|
||||
BIN
Content/ZMMO/Maps/FrontEnd/L_FrontEnd.umap
Normal file
BIN
Content/ZMMO/Maps/FrontEnd/L_FrontEnd.umap
Normal file
Binary file not shown.
BIN
Content/ZMMO/UI/FrontEnd/DA_FrontEndScreenSet.uasset
Normal file
BIN
Content/ZMMO/UI/FrontEnd/DA_FrontEndScreenSet.uasset
Normal file
Binary file not shown.
BIN
Content/ZMMO/UI/FrontEnd/WBP_PrimaryGameLayout.uasset
Normal file
BIN
Content/ZMMO/UI/FrontEnd/WBP_PrimaryGameLayout.uasset
Normal file
Binary file not shown.
40
Source/ZMMO/Data/UI/FrontEndTypes.h
Normal file
40
Source/ZMMO/Data/UI/FrontEndTypes.h
Normal file
@@ -0,0 +1,40 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "FrontEndTypes.generated.h"
|
||||
|
||||
/**
|
||||
* Estados de topo do fluxo de front-end (MainMenu). Dirigidos pelo
|
||||
* UUIFrontEndFlowSubsystem; cada estado resolve uma tela
|
||||
* (UUIActivatableScreen_Base) via DA_FrontEndScreenSet.
|
||||
*
|
||||
* Fluxo: Boot → Connecting → Login → ServerSelect → Lobby → EnteringWorld
|
||||
* → InWorld. O Lobby é o hub principal logado; suas páginas internas são
|
||||
* EZMMOLobbyPage (não são estados de topo — ver ARQUITETURA.md §4.8).
|
||||
*/
|
||||
UENUM(BlueprintType)
|
||||
enum class EZMMOFrontEndState : uint8
|
||||
{
|
||||
None,
|
||||
Boot, // splash inicial enquanto subsistemas sobem
|
||||
Connecting, // conectando ao servidor Zeus (UDP)
|
||||
Login, // autenticação
|
||||
ServerSelect, // escolha de servidor/realm
|
||||
Lobby, // hub principal logado (host das EZMMOLobbyPage)
|
||||
EnteringWorld, // loading/handoff: OpenLevel do mapa de mundo
|
||||
InWorld // no mundo (HUD de gameplay assume)
|
||||
};
|
||||
|
||||
/**
|
||||
* Páginas internas do Lobby — navegadas por um stack CommonUI DENTRO da tela
|
||||
* de Lobby ("Switch principal"), não pelo fluxo de topo.
|
||||
*/
|
||||
UENUM(BlueprintType)
|
||||
enum class EZMMOLobbyPage : uint8
|
||||
{
|
||||
None,
|
||||
CharacterSelect,
|
||||
CharacterCreate,
|
||||
Shop,
|
||||
Settings
|
||||
};
|
||||
9
Source/ZMMO/Data/UI/UILayerTags.cpp
Normal file
9
Source/ZMMO/Data/UI/UILayerTags.cpp
Normal file
@@ -0,0 +1,9 @@
|
||||
#include "UI/UILayerTags.h"
|
||||
|
||||
namespace ZMMOUITags
|
||||
{
|
||||
UE_DEFINE_GAMEPLAY_TAG(UI_Layer_Game, "UI.Layer.Game");
|
||||
UE_DEFINE_GAMEPLAY_TAG(UI_Layer_GameMenu, "UI.Layer.GameMenu");
|
||||
UE_DEFINE_GAMEPLAY_TAG(UI_Layer_Menu, "UI.Layer.Menu");
|
||||
UE_DEFINE_GAMEPLAY_TAG(UI_Layer_Modal, "UI.Layer.Modal");
|
||||
}
|
||||
21
Source/ZMMO/Data/UI/UILayerTags.h
Normal file
21
Source/ZMMO/Data/UI/UILayerTags.h
Normal file
@@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include "NativeGameplayTags.h"
|
||||
|
||||
/**
|
||||
* GameplayTags nativos das camadas do switch principal de UI. Declaração
|
||||
* nativa (não depende de DefaultGameplayTags.ini) — registradas no startup
|
||||
* do módulo. Mapeadas para os stacks do UUIPrimaryGameLayout_Base.
|
||||
*
|
||||
* UI.Layer.Game — HUD de gameplay (camada de fundo)
|
||||
* UI.Layer.GameMenu — menus sobre o jogo (inventário, mapa…)
|
||||
* UI.Layer.Menu — front-end (Boot/Login/ServerSelect/Lobby)
|
||||
* UI.Layer.Modal — diálogos/loading por cima de tudo
|
||||
*/
|
||||
namespace ZMMOUITags
|
||||
{
|
||||
ZMMO_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(UI_Layer_Game);
|
||||
ZMMO_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(UI_Layer_GameMenu);
|
||||
ZMMO_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(UI_Layer_Menu);
|
||||
ZMMO_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(UI_Layer_Modal);
|
||||
}
|
||||
24
Source/ZMMO/Game/Controller/ZMMOFrontEndPlayerController.cpp
Normal file
24
Source/ZMMO/Game/Controller/ZMMOFrontEndPlayerController.cpp
Normal file
@@ -0,0 +1,24 @@
|
||||
#include "ZMMOFrontEndPlayerController.h"
|
||||
|
||||
#include "UIFrontEndFlowSubsystem.h"
|
||||
#include "Engine/GameInstance.h"
|
||||
|
||||
AZMMOFrontEndPlayerController::AZMMOFrontEndPlayerController()
|
||||
{
|
||||
bShowMouseCursor = true;
|
||||
}
|
||||
|
||||
void AZMMOFrontEndPlayerController::BeginPlay()
|
||||
{
|
||||
Super::BeginPlay();
|
||||
|
||||
SetInputMode(FInputModeUIOnly());
|
||||
|
||||
if (const UGameInstance* GI = GetGameInstance())
|
||||
{
|
||||
if (UUIFrontEndFlowSubsystem* Flow = GI->GetSubsystem<UUIFrontEndFlowSubsystem>())
|
||||
{
|
||||
Flow->StartFrontEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
26
Source/ZMMO/Game/Controller/ZMMOFrontEndPlayerController.h
Normal file
26
Source/ZMMO/Game/Controller/ZMMOFrontEndPlayerController.h
Normal file
@@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "GameFramework/PlayerController.h"
|
||||
#include "ZMMOFrontEndPlayerController.generated.h"
|
||||
|
||||
/**
|
||||
* AZMMOFrontEndPlayerController
|
||||
*
|
||||
* Controller do mapa de front-end. Não herda de AZMMOPlayerController (sem
|
||||
* Enhanced Input de gameplay/touch). Em BeginPlay arranca o fluxo de
|
||||
* front-end (UUIFrontEndFlowSubsystem) — feito aqui, e não no
|
||||
* GameInstance::Init, porque os subsistemas já existem neste ponto (ver
|
||||
* aviso no header do ZeusNetworkSubsystem).
|
||||
*/
|
||||
UCLASS(Blueprintable, BlueprintType)
|
||||
class ZMMO_API AZMMOFrontEndPlayerController : public APlayerController
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
AZMMOFrontEndPlayerController();
|
||||
|
||||
protected:
|
||||
virtual void BeginPlay() override;
|
||||
};
|
||||
10
Source/ZMMO/Game/Modes/ZMMOFrontEndGameMode.cpp
Normal file
10
Source/ZMMO/Game/Modes/ZMMOFrontEndGameMode.cpp
Normal file
@@ -0,0 +1,10 @@
|
||||
#include "ZMMOFrontEndGameMode.h"
|
||||
|
||||
#include "ZMMOFrontEndPlayerController.h"
|
||||
|
||||
AZMMOFrontEndGameMode::AZMMOFrontEndGameMode()
|
||||
{
|
||||
// UI pura: sem pawn. O controller cria o root layout e arranca o fluxo.
|
||||
DefaultPawnClass = nullptr;
|
||||
PlayerControllerClass = AZMMOFrontEndPlayerController::StaticClass();
|
||||
}
|
||||
22
Source/ZMMO/Game/Modes/ZMMOFrontEndGameMode.h
Normal file
22
Source/ZMMO/Game/Modes/ZMMOFrontEndGameMode.h
Normal file
@@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "GameFramework/GameModeBase.h"
|
||||
#include "ZMMOFrontEndGameMode.generated.h"
|
||||
|
||||
/**
|
||||
* AZMMOFrontEndGameMode
|
||||
*
|
||||
* GameMode do mapa de front-end (L_FrontEnd): só UI, sem pawn nem network
|
||||
* play. NÃO é o GameMode global (esse continua AZMMOGameMode para mapas de
|
||||
* mundo) — aplicado via override no World Settings de L_FrontEnd
|
||||
* (ARQUITETURA.md §3.3 / decisão de mapa dedicado).
|
||||
*/
|
||||
UCLASS(Blueprintable, BlueprintType)
|
||||
class ZMMO_API AZMMOFrontEndGameMode : public AGameModeBase
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
AZMMOFrontEndGameMode();
|
||||
};
|
||||
@@ -32,11 +32,12 @@ public:
|
||||
|
||||
/**
|
||||
* Se `true`, tenta ligar ao servidor Zeus em `Init()` usando
|
||||
* `ZeusServerHost`/`ZeusServerPort`. Default `true` em V0 (smoke test);
|
||||
* passar a `false` quando existir UI de login que controle a conexao.
|
||||
* `ZeusServerHost`/`ZeusServerPort`. Default `false`: a conexao agora e
|
||||
* dirigida pelo `UUIFrontEndFlowSubsystem` (fluxo Boot→Connecting→Login).
|
||||
* Pôr `true` apenas para smoke test legado sem front-end.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Config, Category = "ZMMO|Network")
|
||||
bool bAutoConnectOnStart = true;
|
||||
bool bAutoConnectOnStart = false;
|
||||
|
||||
/** Host (IPv4 ou hostname) do servidor Zeus. */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Config, Category = "ZMMO|Network")
|
||||
|
||||
99
Source/ZMMO/Game/UI/FrontEnd/UIActivatableScreen_Base.cpp
Normal file
99
Source/ZMMO/Game/UI/FrontEnd/UIActivatableScreen_Base.cpp
Normal file
@@ -0,0 +1,99 @@
|
||||
#include "UIActivatableScreen_Base.h"
|
||||
|
||||
#include "ZMMOThemeSubsystem.h"
|
||||
#include "UIFrontEndFlowSubsystem.h"
|
||||
#include "Engine/GameInstance.h"
|
||||
#include "Input/UIActionBindingHandle.h"
|
||||
#include "CommonInputModeTypes.h"
|
||||
|
||||
TOptional<FUIInputConfig> UUIActivatableScreen_Base::GetDesiredInputConfig() const
|
||||
{
|
||||
switch (InputConfig)
|
||||
{
|
||||
case EZMMOScreenInputMode::GameAndMenu:
|
||||
return FUIInputConfig(ECommonInputMode::All, GameMouseCaptureMode);
|
||||
case EZMMOScreenInputMode::Game:
|
||||
return FUIInputConfig(ECommonInputMode::Game, GameMouseCaptureMode);
|
||||
case EZMMOScreenInputMode::Menu:
|
||||
return FUIInputConfig(ECommonInputMode::Menu, EMouseCaptureMode::NoCapture);
|
||||
case EZMMOScreenInputMode::Default:
|
||||
default:
|
||||
return TOptional<FUIInputConfig>();
|
||||
}
|
||||
}
|
||||
|
||||
void UUIActivatableScreen_Base::RefreshUIStyle_Implementation()
|
||||
{
|
||||
// Base no-op: cada WBP/filho sobrescreve para reaplicar tokens do tema
|
||||
// ativo (via UZMMOThemeSubsystem). Mantém o contrato igual a
|
||||
// UUIButton_Base::RefreshUIStyle / UUIPanel_Base::RefreshUIStyle.
|
||||
}
|
||||
|
||||
void UUIActivatableScreen_Base::NativeConstruct()
|
||||
{
|
||||
Super::NativeConstruct();
|
||||
|
||||
if (!bThemeBound)
|
||||
{
|
||||
if (const UGameInstance* GI = GetGameInstance())
|
||||
{
|
||||
if (UZMMOThemeSubsystem* Theme = GI->GetSubsystem<UZMMOThemeSubsystem>())
|
||||
{
|
||||
Theme->OnThemeChanged.AddDynamic(this, &UUIActivatableScreen_Base::HandleThemeChanged);
|
||||
bThemeBound = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RefreshUIStyle();
|
||||
}
|
||||
|
||||
void UUIActivatableScreen_Base::NativeDestruct()
|
||||
{
|
||||
if (bThemeBound)
|
||||
{
|
||||
if (const UGameInstance* GI = GetGameInstance())
|
||||
{
|
||||
if (UZMMOThemeSubsystem* Theme = GI->GetSubsystem<UZMMOThemeSubsystem>())
|
||||
{
|
||||
Theme->OnThemeChanged.RemoveDynamic(this, &UUIActivatableScreen_Base::HandleThemeChanged);
|
||||
}
|
||||
}
|
||||
bThemeBound = false;
|
||||
}
|
||||
|
||||
Super::NativeDestruct();
|
||||
}
|
||||
|
||||
void UUIActivatableScreen_Base::NativeOnActivated()
|
||||
{
|
||||
Super::NativeOnActivated();
|
||||
RefreshUIStyle();
|
||||
BP_OnScreenActivated();
|
||||
}
|
||||
|
||||
void UUIActivatableScreen_Base::NativeOnDeactivated()
|
||||
{
|
||||
Super::NativeOnDeactivated();
|
||||
BP_OnScreenDeactivated();
|
||||
}
|
||||
|
||||
bool UUIActivatableScreen_Base::NativeOnHandleBackAction()
|
||||
{
|
||||
if (const UGameInstance* GI = GetGameInstance())
|
||||
{
|
||||
if (UUIFrontEndFlowSubsystem* Flow = GI->GetSubsystem<UUIFrontEndFlowSubsystem>())
|
||||
{
|
||||
if (Flow->RequestBack())
|
||||
{
|
||||
return true; // consumido pelo fluxo
|
||||
}
|
||||
}
|
||||
}
|
||||
return Super::NativeOnHandleBackAction();
|
||||
}
|
||||
|
||||
void UUIActivatableScreen_Base::HandleThemeChanged(FName /*NewThemeId*/)
|
||||
{
|
||||
RefreshUIStyle();
|
||||
}
|
||||
77
Source/ZMMO/Game/UI/FrontEnd/UIActivatableScreen_Base.h
Normal file
77
Source/ZMMO/Game/UI/FrontEnd/UIActivatableScreen_Base.h
Normal file
@@ -0,0 +1,77 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "CommonActivatableWidget.h"
|
||||
#include "Engine/EngineBaseTypes.h"
|
||||
#include "UIActivatableScreen_Base.generated.h"
|
||||
|
||||
/**
|
||||
* Modo de input desejado pela tela (espelha o padrão do Lyra). O
|
||||
* UUIActivatableScreen_Base converte isto num FUIInputConfig em
|
||||
* GetDesiredInputConfig.
|
||||
*/
|
||||
UENUM(BlueprintType)
|
||||
enum class EZMMOScreenInputMode : uint8
|
||||
{
|
||||
Default, // não força nada (herda do CommonUI)
|
||||
GameAndMenu, // jogo + UI (ex.: HUD com cursor)
|
||||
Game, // só jogo
|
||||
Menu // só UI (telas de front-end — default)
|
||||
};
|
||||
|
||||
/**
|
||||
* Base de TODAS as telas de front-end (Boot/Login/ServerSelect/Lobby/…).
|
||||
*
|
||||
* Fundação CommonUI (UCommonActivatableWidget) cuida de
|
||||
* ativação/foco/voltar/stack. Camada Abstract; o WBP concreto herda DIRETO
|
||||
* desta classe C++ (UMG não encadeia árvores — ARQUITETURA.md §3.3). Os WBPs
|
||||
* gerados pelo Zeus UMG Forge são reparented para cá (§4.8).
|
||||
*
|
||||
* Reage à troca de tema via UZMMOThemeSubsystem (mesmo padrão de
|
||||
* UUIButton_Base) e encaminha o "voltar" ao UUIFrontEndFlowSubsystem.
|
||||
*/
|
||||
UCLASS(Abstract, Blueprintable)
|
||||
class ZMMO_API UUIActivatableScreen_Base : public UCommonActivatableWidget
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
/** Re-resolve os tokens do tema ativo e reaplica. WBP/filho sobrescreve. */
|
||||
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "UI Style")
|
||||
void RefreshUIStyle();
|
||||
virtual void RefreshUIStyle_Implementation();
|
||||
|
||||
protected:
|
||||
// ---- Input config (desktop/gamepad) ----
|
||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Input")
|
||||
EZMMOScreenInputMode InputConfig = EZMMOScreenInputMode::Menu;
|
||||
|
||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Input")
|
||||
EMouseCaptureMode GameMouseCaptureMode = EMouseCaptureMode::CapturePermanently;
|
||||
|
||||
virtual TOptional<FUIInputConfig> GetDesiredInputConfig() const override;
|
||||
|
||||
// ---- Lifecycle (espelha o hook de tema de UUIButton_Base) ----
|
||||
virtual void NativeConstruct() override;
|
||||
virtual void NativeDestruct() override;
|
||||
virtual void NativeOnActivated() override;
|
||||
virtual void NativeOnDeactivated() override;
|
||||
|
||||
/** "Voltar" (Esc/B): encaminha ao UUIFrontEndFlowSubsystem::RequestBack. */
|
||||
virtual bool NativeOnHandleBackAction() override;
|
||||
|
||||
/** Hooks Blueprint para o WBP refinado. */
|
||||
UFUNCTION(BlueprintImplementableEvent, Category = "UI",
|
||||
meta = (DisplayName = "On Screen Activated"))
|
||||
void BP_OnScreenActivated();
|
||||
|
||||
UFUNCTION(BlueprintImplementableEvent, Category = "UI",
|
||||
meta = (DisplayName = "On Screen Deactivated"))
|
||||
void BP_OnScreenDeactivated();
|
||||
|
||||
private:
|
||||
UFUNCTION()
|
||||
void HandleThemeChanged(FName NewThemeId);
|
||||
|
||||
bool bThemeBound = false;
|
||||
};
|
||||
339
Source/ZMMO/Game/UI/FrontEnd/UIFrontEndFlowSubsystem.cpp
Normal file
339
Source/ZMMO/Game/UI/FrontEnd/UIFrontEndFlowSubsystem.cpp
Normal file
@@ -0,0 +1,339 @@
|
||||
#include "UIFrontEndFlowSubsystem.h"
|
||||
|
||||
#include "ZMMO.h"
|
||||
#include "UIFrontEndScreenSet.h"
|
||||
#include "UIManagerSubsystem.h"
|
||||
#include "UIPrimaryGameLayout_Base.h"
|
||||
#include "UI/UILayerTags.h"
|
||||
#include "ZMMOGameInstance.h"
|
||||
#include "ZMMOThemeSubsystem.h"
|
||||
#include "ZeusNetworkSubsystem.h"
|
||||
#include "CommonActivatableWidget.h"
|
||||
#include "Engine/GameInstance.h"
|
||||
#include "Engine/LocalPlayer.h"
|
||||
#include "UObject/UObjectGlobals.h"
|
||||
#include "Engine/AssetManager.h"
|
||||
#include "Engine/StreamableManager.h"
|
||||
#include "Kismet/GameplayStatics.h"
|
||||
|
||||
void UUIFrontEndFlowSubsystem::Initialize(FSubsystemCollectionBase& Collection)
|
||||
{
|
||||
Super::Initialize(Collection);
|
||||
|
||||
// Detecta chegada ao mundo após o OpenLevel disparado por travel.
|
||||
PostLoadMapHandle = FCoreUObjectDelegates::PostLoadMapWithWorld.AddUObject(
|
||||
this, &UUIFrontEndFlowSubsystem::HandlePostLoadMap);
|
||||
}
|
||||
|
||||
void UUIFrontEndFlowSubsystem::Deinitialize()
|
||||
{
|
||||
if (PostLoadMapHandle.IsValid())
|
||||
{
|
||||
FCoreUObjectDelegates::PostLoadMapWithWorld.Remove(PostLoadMapHandle);
|
||||
PostLoadMapHandle.Reset();
|
||||
}
|
||||
UnbindNetwork();
|
||||
Super::Deinitialize();
|
||||
}
|
||||
|
||||
void UUIFrontEndFlowSubsystem::StartFrontEnd()
|
||||
{
|
||||
UUIFrontEndScreenSet* SS = GetScreenSet();
|
||||
|
||||
if (UUIManagerSubsystem* Mgr = GetUIManager())
|
||||
{
|
||||
TSubclassOf<UUIPrimaryGameLayout_Base> LayoutClass;
|
||||
if (SS && !SS->RootLayoutClass.IsNull())
|
||||
{
|
||||
LayoutClass = SS->RootLayoutClass.LoadSynchronous();
|
||||
}
|
||||
Mgr->CreateAndAddRootLayout(LayoutClass);
|
||||
}
|
||||
|
||||
BindNetwork();
|
||||
|
||||
SetState(EZMMOFrontEndState::Boot);
|
||||
|
||||
// Substitui o auto-connect do GameInstance: o fluxo dirige a conexão.
|
||||
if (UZeusNetworkSubsystem* Zeus = GetZeusNetwork())
|
||||
{
|
||||
FString Host = TEXT("127.0.0.1");
|
||||
int32 Port = 27777;
|
||||
if (const UZMMOGameInstance* GI = Cast<UZMMOGameInstance>(GetGameInstance()))
|
||||
{
|
||||
Host = GI->ZeusServerHost;
|
||||
Port = GI->ZeusServerPort;
|
||||
}
|
||||
SetState(EZMMOFrontEndState::Connecting);
|
||||
Zeus->ConnectToZeusServer(Host, Port);
|
||||
}
|
||||
else
|
||||
{
|
||||
UE_LOG(LogZMMO, Warning, TEXT("FrontEndFlow: ZeusNetworkSubsystem indisponível; sem conexão."));
|
||||
}
|
||||
}
|
||||
|
||||
void UUIFrontEndFlowSubsystem::SetState(EZMMOFrontEndState NewState)
|
||||
{
|
||||
if (NewState == CurrentState)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
CurrentState = NewState;
|
||||
UE_LOG(LogZMMO, Log, TEXT("FrontEndFlow: estado → %s"),
|
||||
*UEnum::GetValueAsString(NewState));
|
||||
OnStateChanged.Broadcast(NewState);
|
||||
|
||||
const FGameplayTag MenuLayer = ZMMOUITags::UI_Layer_Menu.GetTag();
|
||||
const FGameplayTag ModalLayer = ZMMOUITags::UI_Layer_Modal.GetTag();
|
||||
|
||||
switch (NewState)
|
||||
{
|
||||
case EZMMOFrontEndState::Boot:
|
||||
case EZMMOFrontEndState::Connecting:
|
||||
case EZMMOFrontEndState::Login:
|
||||
case EZMMOFrontEndState::ServerSelect:
|
||||
case EZMMOFrontEndState::Lobby:
|
||||
// Telas do front-end vivem na camada Menu (uma por vez).
|
||||
if (UUIManagerSubsystem* Mgr = GetUIManager())
|
||||
{
|
||||
Mgr->ClearLayer(MenuLayer);
|
||||
}
|
||||
ResolveAndPushScreen(NewState);
|
||||
break;
|
||||
|
||||
case EZMMOFrontEndState::EnteringWorld:
|
||||
// Loading/handoff por cima de tudo (camada Modal).
|
||||
ResolveAndPushScreen(NewState);
|
||||
break;
|
||||
|
||||
case EZMMOFrontEndState::InWorld:
|
||||
// HUD de gameplay assume — limpa front-end e loading.
|
||||
if (UUIManagerSubsystem* Mgr = GetUIManager())
|
||||
{
|
||||
Mgr->ClearLayer(ModalLayer);
|
||||
Mgr->ClearLayer(MenuLayer);
|
||||
}
|
||||
break;
|
||||
|
||||
case EZMMOFrontEndState::None:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void UUIFrontEndFlowSubsystem::ShowLobbyPage(EZMMOLobbyPage Page)
|
||||
{
|
||||
UUIFrontEndScreenSet* SS = GetScreenSet();
|
||||
UUIManagerSubsystem* Mgr = GetUIManager();
|
||||
if (!SS || !Mgr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const TSoftClassPtr<UCommonActivatableWidget> Soft = SS->GetLobbyPage(Page);
|
||||
if (Soft.IsNull())
|
||||
{
|
||||
UE_LOG(LogZMMO, Warning, TEXT("FrontEndFlow: página de Lobby %s não configurada (DA vazio)."),
|
||||
*UEnum::GetValueAsString(Page));
|
||||
return;
|
||||
}
|
||||
|
||||
const FGameplayTag MenuLayer = ZMMOUITags::UI_Layer_Menu.GetTag();
|
||||
const FSoftObjectPath Path = Soft.ToSoftObjectPath();
|
||||
UAssetManager::GetStreamableManager().RequestAsyncLoad(
|
||||
Path,
|
||||
FStreamableDelegate::CreateWeakLambda(this, [this, Soft, MenuLayer]()
|
||||
{
|
||||
if (UUIManagerSubsystem* M = GetUIManager())
|
||||
{
|
||||
if (UClass* Cls = Soft.Get())
|
||||
{
|
||||
M->PushScreenToLayer(MenuLayer, Cls);
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
bool UUIFrontEndFlowSubsystem::RequestBack()
|
||||
{
|
||||
switch (CurrentState)
|
||||
{
|
||||
case EZMMOFrontEndState::ServerSelect:
|
||||
SetState(EZMMOFrontEndState::Login);
|
||||
return true;
|
||||
case EZMMOFrontEndState::Lobby:
|
||||
SetState(EZMMOFrontEndState::ServerSelect);
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void UUIFrontEndFlowSubsystem::ResolveAndPushScreen(EZMMOFrontEndState State)
|
||||
{
|
||||
UUIFrontEndScreenSet* SS = GetScreenSet();
|
||||
if (!SS)
|
||||
{
|
||||
UE_LOG(LogZMMO, Warning,
|
||||
TEXT("FrontEndFlow: ScreenSet não configurado; tela de %s ignorada."),
|
||||
*UEnum::GetValueAsString(State));
|
||||
return;
|
||||
}
|
||||
|
||||
const TSoftClassPtr<UCommonActivatableWidget> Soft = SS->GetScreenForState(State);
|
||||
if (Soft.IsNull())
|
||||
{
|
||||
UE_LOG(LogZMMO, Warning, TEXT("FrontEndFlow: Screen for state %s not configured."),
|
||||
*UEnum::GetValueAsString(State));
|
||||
return;
|
||||
}
|
||||
|
||||
UUIManagerSubsystem* Mgr = GetUIManager();
|
||||
if (!Mgr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const FGameplayTag Layer = (State == EZMMOFrontEndState::EnteringWorld)
|
||||
? ZMMOUITags::UI_Layer_Modal.GetTag()
|
||||
: ZMMOUITags::UI_Layer_Menu.GetTag();
|
||||
|
||||
const FSoftObjectPath Path = Soft.ToSoftObjectPath();
|
||||
UAssetManager::GetStreamableManager().RequestAsyncLoad(
|
||||
Path,
|
||||
FStreamableDelegate::CreateWeakLambda(this, [this, Soft, Layer]()
|
||||
{
|
||||
if (UUIManagerSubsystem* M = GetUIManager())
|
||||
{
|
||||
if (UClass* Cls = Soft.Get())
|
||||
{
|
||||
M->PushScreenToLayer(Layer, Cls);
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
UZeusNetworkSubsystem* UUIFrontEndFlowSubsystem::GetZeusNetwork() const
|
||||
{
|
||||
const UGameInstance* GI = GetGameInstance();
|
||||
return GI ? GI->GetSubsystem<UZeusNetworkSubsystem>() : nullptr;
|
||||
}
|
||||
|
||||
UUIManagerSubsystem* UUIFrontEndFlowSubsystem::GetUIManager() const
|
||||
{
|
||||
if (const UGameInstance* GI = GetGameInstance())
|
||||
{
|
||||
if (ULocalPlayer* LP = GI->GetFirstGamePlayer())
|
||||
{
|
||||
return LP->GetSubsystem<UUIManagerSubsystem>();
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
UUIFrontEndScreenSet* UUIFrontEndFlowSubsystem::GetScreenSet()
|
||||
{
|
||||
if (ScreenSet)
|
||||
{
|
||||
return ScreenSet;
|
||||
}
|
||||
if (!ScreenSetAsset.IsNull())
|
||||
{
|
||||
ScreenSet = ScreenSetAsset.LoadSynchronous();
|
||||
}
|
||||
else
|
||||
{
|
||||
UE_LOG(LogZMMO, Warning,
|
||||
TEXT("FrontEndFlow: ScreenSetAsset não setado em DefaultGame.ini; telas farão no-op."));
|
||||
}
|
||||
return ScreenSet;
|
||||
}
|
||||
|
||||
void UUIFrontEndFlowSubsystem::BindNetwork()
|
||||
{
|
||||
if (bNetBound)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (UZeusNetworkSubsystem* Zeus = GetZeusNetwork())
|
||||
{
|
||||
Zeus->OnConnected.AddDynamic(this, &UUIFrontEndFlowSubsystem::HandleConnected);
|
||||
Zeus->OnConnectionFailed.AddDynamic(this, &UUIFrontEndFlowSubsystem::HandleConnectionFailed);
|
||||
Zeus->OnDisconnected.AddDynamic(this, &UUIFrontEndFlowSubsystem::HandleDisconnected);
|
||||
Zeus->OnServerTravelRequested.AddDynamic(this, &UUIFrontEndFlowSubsystem::HandleServerTravelRequested);
|
||||
bNetBound = true;
|
||||
}
|
||||
}
|
||||
|
||||
void UUIFrontEndFlowSubsystem::UnbindNetwork()
|
||||
{
|
||||
if (!bNetBound)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (UZeusNetworkSubsystem* Zeus = GetZeusNetwork())
|
||||
{
|
||||
Zeus->OnConnected.RemoveDynamic(this, &UUIFrontEndFlowSubsystem::HandleConnected);
|
||||
Zeus->OnConnectionFailed.RemoveDynamic(this, &UUIFrontEndFlowSubsystem::HandleConnectionFailed);
|
||||
Zeus->OnDisconnected.RemoveDynamic(this, &UUIFrontEndFlowSubsystem::HandleDisconnected);
|
||||
Zeus->OnServerTravelRequested.RemoveDynamic(this, &UUIFrontEndFlowSubsystem::HandleServerTravelRequested);
|
||||
}
|
||||
bNetBound = false;
|
||||
}
|
||||
|
||||
void UUIFrontEndFlowSubsystem::HandleConnected()
|
||||
{
|
||||
UE_LOG(LogZMMO, Log, TEXT("FrontEndFlow: conectado → Login."));
|
||||
SetState(EZMMOFrontEndState::Login);
|
||||
}
|
||||
|
||||
void UUIFrontEndFlowSubsystem::HandleConnectionFailed(FString Reason)
|
||||
{
|
||||
UE_LOG(LogZMMO, Warning, TEXT("FrontEndFlow: conexão falhou (%s) → volta a Login."), *Reason);
|
||||
SetState(EZMMOFrontEndState::Login);
|
||||
}
|
||||
|
||||
void UUIFrontEndFlowSubsystem::HandleDisconnected()
|
||||
{
|
||||
UE_LOG(LogZMMO, Log, TEXT("FrontEndFlow: desconectado."));
|
||||
if (CurrentState != EZMMOFrontEndState::InWorld)
|
||||
{
|
||||
SetState(EZMMOFrontEndState::Login);
|
||||
}
|
||||
}
|
||||
|
||||
void UUIFrontEndFlowSubsystem::HandleServerTravelRequested(const FString& MapName, const FString& MapPath)
|
||||
{
|
||||
UE_LOG(LogZMMO, Log, TEXT("FrontEndFlow: travel pedido pelo servidor → %s (%s)."), *MapName, *MapPath);
|
||||
bTravelingToWorld = true;
|
||||
SetState(EZMMOFrontEndState::EnteringWorld);
|
||||
|
||||
if (!MapPath.IsEmpty())
|
||||
{
|
||||
UGameplayStatics::OpenLevel(GetGameInstance(), FName(*MapPath));
|
||||
}
|
||||
}
|
||||
|
||||
void UUIFrontEndFlowSubsystem::HandlePostLoadMap(UWorld* /*LoadedWorld*/)
|
||||
{
|
||||
if (bTravelingToWorld)
|
||||
{
|
||||
bTravelingToWorld = false;
|
||||
SetState(EZMMOFrontEndState::InWorld);
|
||||
}
|
||||
}
|
||||
|
||||
void UUIFrontEndFlowSubsystem::HandleServerHelloTheme(FName ThemeId)
|
||||
{
|
||||
// Dívida técnica (D5): ainda não há gancho no ZeusNetworkSubsystem para o
|
||||
// ThemeId do ServerHello. Mantido pronto para quando o plugin expuser.
|
||||
if (const UGameInstance* GI = GetGameInstance())
|
||||
{
|
||||
if (UZMMOThemeSubsystem* Theme = GI->GetSubsystem<UZMMOThemeSubsystem>())
|
||||
{
|
||||
Theme->ApplyServerTheme(ThemeId);
|
||||
}
|
||||
}
|
||||
}
|
||||
109
Source/ZMMO/Game/UI/FrontEnd/UIFrontEndFlowSubsystem.h
Normal file
109
Source/ZMMO/Game/UI/FrontEnd/UIFrontEndFlowSubsystem.h
Normal file
@@ -0,0 +1,109 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Subsystems/GameInstanceSubsystem.h"
|
||||
#include "UI/FrontEndTypes.h"
|
||||
#include "UIFrontEndFlowSubsystem.generated.h"
|
||||
|
||||
class UUIFrontEndScreenSet;
|
||||
class UUIManagerSubsystem;
|
||||
class UZeusNetworkSubsystem;
|
||||
|
||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnZMMOFrontEndStateChanged, EZMMOFrontEndState, NewState);
|
||||
|
||||
/**
|
||||
* Orquestrador do fluxo de front-end. UGameInstanceSubsystem porque o
|
||||
* GameInstance persiste o travel boot→mundo (a máquina de estados não pode
|
||||
* morrer no OpenLevel).
|
||||
*
|
||||
* Responsável por: (a) dirigir a conexão via UZeusNetworkSubsystem;
|
||||
* (b) manter EZMMOFrontEndState; (c) resolver estado→tela pelo
|
||||
* DA_FrontEndScreenSet e pedir ao UUIManagerSubsystem para empurrar na
|
||||
* camada certa; (d) detectar a chegada ao mundo.
|
||||
*
|
||||
* As telas (WBP) ainda não existem — virão do Zeus UMG Forge (§4.8).
|
||||
* Enquanto não registradas no DA, cada transição faz no-op + log.
|
||||
*/
|
||||
UCLASS(Config = Game)
|
||||
class ZMMO_API UUIFrontEndFlowSubsystem : public UGameInstanceSubsystem
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
// USubsystem
|
||||
virtual void Initialize(FSubsystemCollectionBase& Collection) override;
|
||||
virtual void Deinitialize() override;
|
||||
|
||||
/**
|
||||
* Ponto de entrada chamado pelo AZMMOFrontEndPlayerController::BeginPlay
|
||||
* (garante que os subsistemas já existem — ver aviso no header do
|
||||
* ZeusNetworkSubsystem sobre GameInstance::Init). Cria o root layout,
|
||||
* liga os delegates de rede e dispara Boot→Connecting.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "FrontEnd")
|
||||
void StartFrontEnd();
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "FrontEnd")
|
||||
void SetState(EZMMOFrontEndState NewState);
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "FrontEnd")
|
||||
EZMMOFrontEndState GetCurrentState() const { return CurrentState; }
|
||||
|
||||
/** Mostra uma página interna do Lobby ("switch principal"). */
|
||||
UFUNCTION(BlueprintCallable, Category = "FrontEnd")
|
||||
void ShowLobbyPage(EZMMOLobbyPage Page);
|
||||
|
||||
/** "Voltar". Retorna true se o fluxo consumiu (tela base encaminha aqui). */
|
||||
UFUNCTION(BlueprintCallable, Category = "FrontEnd")
|
||||
bool RequestBack();
|
||||
|
||||
UPROPERTY(BlueprintAssignable, Category = "FrontEnd")
|
||||
FOnZMMOFrontEndStateChanged OnStateChanged;
|
||||
|
||||
protected:
|
||||
/** DA com o mapa estado→tela. Config em DefaultGame.ini. */
|
||||
UPROPERTY(Config, EditDefaultsOnly, Category = "FrontEnd")
|
||||
TSoftObjectPtr<UUIFrontEndScreenSet> ScreenSetAsset;
|
||||
|
||||
private:
|
||||
void BindNetwork();
|
||||
void UnbindNetwork();
|
||||
UZeusNetworkSubsystem* GetZeusNetwork() const;
|
||||
UUIManagerSubsystem* GetUIManager() const;
|
||||
UUIFrontEndScreenSet* GetScreenSet();
|
||||
|
||||
/** Resolve a soft class do estado e empurra na camada Menu (no-op+log se vazio). */
|
||||
void ResolveAndPushScreen(EZMMOFrontEndState State);
|
||||
|
||||
UFUNCTION()
|
||||
void HandleConnected();
|
||||
|
||||
UFUNCTION()
|
||||
void HandleConnectionFailed(FString Reason);
|
||||
|
||||
UFUNCTION()
|
||||
void HandleDisconnected();
|
||||
|
||||
UFUNCTION()
|
||||
void HandleServerTravelRequested(const FString& MapName, const FString& MapPath);
|
||||
|
||||
void HandlePostLoadMap(UWorld* LoadedWorld);
|
||||
|
||||
/**
|
||||
* Dívida técnica (D5): ServerHello traz ThemeId, mas o UZeusNetworkSubsystem
|
||||
* ainda não expõe um delegate/getter dedicado. Quando expuser, ligar aqui
|
||||
* → UZMMOThemeSubsystem::ApplyServerTheme. Sem isto, o tema resolve por
|
||||
* calendário/Default (ARQUITETURA.md §1.10).
|
||||
*/
|
||||
void HandleServerHelloTheme(FName ThemeId);
|
||||
|
||||
UPROPERTY(Transient)
|
||||
EZMMOFrontEndState CurrentState = EZMMOFrontEndState::None;
|
||||
|
||||
UPROPERTY(Transient)
|
||||
TObjectPtr<UUIFrontEndScreenSet> ScreenSet;
|
||||
|
||||
bool bNetBound = false;
|
||||
bool bTravelingToWorld = false;
|
||||
FDelegateHandle PostLoadMapHandle;
|
||||
};
|
||||
19
Source/ZMMO/Game/UI/FrontEnd/UIFrontEndScreenSet.cpp
Normal file
19
Source/ZMMO/Game/UI/FrontEnd/UIFrontEndScreenSet.cpp
Normal file
@@ -0,0 +1,19 @@
|
||||
#include "UIFrontEndScreenSet.h"
|
||||
|
||||
TSoftClassPtr<UCommonActivatableWidget> UUIFrontEndScreenSet::GetScreenForState(EZMMOFrontEndState State) const
|
||||
{
|
||||
if (const TSoftClassPtr<UCommonActivatableWidget>* Found = StateScreens.Find(State))
|
||||
{
|
||||
return *Found;
|
||||
}
|
||||
return TSoftClassPtr<UCommonActivatableWidget>();
|
||||
}
|
||||
|
||||
TSoftClassPtr<UCommonActivatableWidget> UUIFrontEndScreenSet::GetLobbyPage(EZMMOLobbyPage Page) const
|
||||
{
|
||||
if (const TSoftClassPtr<UCommonActivatableWidget>* Found = LobbyPages.Find(Page))
|
||||
{
|
||||
return *Found;
|
||||
}
|
||||
return TSoftClassPtr<UCommonActivatableWidget>();
|
||||
}
|
||||
45
Source/ZMMO/Game/UI/FrontEnd/UIFrontEndScreenSet.h
Normal file
45
Source/ZMMO/Game/UI/FrontEnd/UIFrontEndScreenSet.h
Normal file
@@ -0,0 +1,45 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Engine/DataAsset.h"
|
||||
#include "Templates/SubclassOf.h"
|
||||
#include "UI/FrontEndTypes.h"
|
||||
#include "UIFrontEndScreenSet.generated.h"
|
||||
|
||||
class UCommonActivatableWidget;
|
||||
class UUIPrimaryGameLayout_Base;
|
||||
|
||||
/**
|
||||
* Mapa data-driven estado → tela. Desacopla o UUIFrontEndFlowSubsystem das
|
||||
* classes concretas: as telas (WBP) ainda não existem — serão geradas pelo
|
||||
* Zeus UMG Forge, refinadas e registradas aqui depois (ARQUITETURA.md §4.8).
|
||||
* Enquanto o registro estiver vazio, o flow faz no-op + log.
|
||||
*
|
||||
* Asset concreto: DA_FrontEndScreenSet em Content/ZMMO/UI/FrontEnd/.
|
||||
*/
|
||||
UCLASS(BlueprintType)
|
||||
class ZMMO_API UUIFrontEndScreenSet : public UDataAsset
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
/** WBP de layout raiz (herda UUIPrimaryGameLayout_Base). */
|
||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "FrontEnd")
|
||||
TSoftClassPtr<UUIPrimaryGameLayout_Base> RootLayoutClass;
|
||||
|
||||
/** Tela por estado de topo do fluxo. */
|
||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "FrontEnd")
|
||||
TMap<EZMMOFrontEndState, TSoftClassPtr<UCommonActivatableWidget>> StateScreens;
|
||||
|
||||
/** Páginas internas do Lobby (host = a tela de Lobby; "switch principal"). */
|
||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "FrontEnd")
|
||||
TMap<EZMMOLobbyPage, TSoftClassPtr<UCommonActivatableWidget>> LobbyPages;
|
||||
|
||||
/** Soft class da tela do estado (vazio se não configurado). */
|
||||
UFUNCTION(BlueprintCallable, Category = "FrontEnd")
|
||||
TSoftClassPtr<UCommonActivatableWidget> GetScreenForState(EZMMOFrontEndState State) const;
|
||||
|
||||
/** Soft class da página de Lobby (vazio se não configurado). */
|
||||
UFUNCTION(BlueprintCallable, Category = "FrontEnd")
|
||||
TSoftClassPtr<UCommonActivatableWidget> GetLobbyPage(EZMMOLobbyPage Page) const;
|
||||
};
|
||||
95
Source/ZMMO/Game/UI/FrontEnd/UIManagerSubsystem.cpp
Normal file
95
Source/ZMMO/Game/UI/FrontEnd/UIManagerSubsystem.cpp
Normal file
@@ -0,0 +1,95 @@
|
||||
#include "UIManagerSubsystem.h"
|
||||
|
||||
#include "ZMMO.h"
|
||||
#include "UIPrimaryGameLayout_Base.h"
|
||||
#include "CommonActivatableWidget.h"
|
||||
#include "Engine/LocalPlayer.h"
|
||||
#include "GameFramework/PlayerController.h"
|
||||
#include "Blueprint/UserWidget.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
constexpr int32 GRootLayoutZOrder = 1000;
|
||||
}
|
||||
|
||||
void UUIManagerSubsystem::CreateAndAddRootLayout(TSubclassOf<UUIPrimaryGameLayout_Base> LayoutClass)
|
||||
{
|
||||
// Idempotente: sobrevive ao travel boot→mundo sem recriar.
|
||||
if (RootLayout && RootLayout->IsInViewport())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!LayoutClass)
|
||||
{
|
||||
UE_LOG(LogZMMO, Warning,
|
||||
TEXT("UIManagerSubsystem: RootLayoutClass não configurado (DA_FrontEndScreenSet vazio?). Sem root layout."));
|
||||
return;
|
||||
}
|
||||
|
||||
ULocalPlayer* LP = GetLocalPlayer();
|
||||
if (!LP)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
APlayerController* PC = LP->GetPlayerController(LP->GetWorld());
|
||||
if (!PC)
|
||||
{
|
||||
UE_LOG(LogZMMO, Warning, TEXT("UIManagerSubsystem: PlayerController ausente; root layout adiado."));
|
||||
return;
|
||||
}
|
||||
|
||||
RootLayout = CreateWidget<UUIPrimaryGameLayout_Base>(PC, LayoutClass);
|
||||
if (!RootLayout)
|
||||
{
|
||||
UE_LOG(LogZMMO, Warning, TEXT("UIManagerSubsystem: falha ao criar o root layout."));
|
||||
return;
|
||||
}
|
||||
|
||||
RootLayout->AddToViewport(GRootLayoutZOrder);
|
||||
UE_LOG(LogZMMO, Log, TEXT("UIManagerSubsystem: root layout criado e adicionado ao viewport."));
|
||||
}
|
||||
|
||||
bool UUIManagerSubsystem::IsRootLayoutReady() const
|
||||
{
|
||||
return RootLayout != nullptr && RootLayout->IsInViewport();
|
||||
}
|
||||
|
||||
UCommonActivatableWidget* UUIManagerSubsystem::PushScreenToLayer(
|
||||
FGameplayTag LayerTag,
|
||||
TSubclassOf<UCommonActivatableWidget> WidgetClass)
|
||||
{
|
||||
if (!RootLayout)
|
||||
{
|
||||
UE_LOG(LogZMMO, Warning, TEXT("UIManagerSubsystem: PushScreenToLayer sem root layout."));
|
||||
return nullptr;
|
||||
}
|
||||
return RootLayout->PushWidgetToLayer(LayerTag, WidgetClass);
|
||||
}
|
||||
|
||||
void UUIManagerSubsystem::PopScreenFromLayer(FGameplayTag LayerTag, UCommonActivatableWidget* Widget)
|
||||
{
|
||||
if (RootLayout)
|
||||
{
|
||||
RootLayout->PopWidgetFromLayer(LayerTag, Widget);
|
||||
}
|
||||
}
|
||||
|
||||
void UUIManagerSubsystem::ClearLayer(FGameplayTag LayerTag)
|
||||
{
|
||||
if (RootLayout)
|
||||
{
|
||||
RootLayout->ClearLayer(LayerTag);
|
||||
}
|
||||
}
|
||||
|
||||
void UUIManagerSubsystem::Deinitialize()
|
||||
{
|
||||
if (RootLayout)
|
||||
{
|
||||
RootLayout->RemoveFromParent();
|
||||
RootLayout = nullptr;
|
||||
}
|
||||
Super::Deinitialize();
|
||||
}
|
||||
55
Source/ZMMO/Game/UI/FrontEnd/UIManagerSubsystem.h
Normal file
55
Source/ZMMO/Game/UI/FrontEnd/UIManagerSubsystem.h
Normal file
@@ -0,0 +1,55 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Subsystems/LocalPlayerSubsystem.h"
|
||||
#include "GameplayTagContainer.h"
|
||||
#include "Templates/SubclassOf.h"
|
||||
#include "UIManagerSubsystem.generated.h"
|
||||
|
||||
class UCommonActivatableWidget;
|
||||
class UUIPrimaryGameLayout_Base;
|
||||
|
||||
/**
|
||||
* Dono do layout raiz para o LocalPlayer. ULocalPlayerSubsystem porque o
|
||||
* LocalPlayer persiste entre mapas (non-seamless do mesmo GameInstance) e
|
||||
* troca de PlayerController — o root layout sobrevive ao travel
|
||||
* boot→mundo sem ser recriado (idempotente).
|
||||
*
|
||||
* É "burro": recebe classes já resolvidas. Quem resolve estado→tela e dirige
|
||||
* a navegação é o UUIFrontEndFlowSubsystem.
|
||||
*/
|
||||
UCLASS()
|
||||
class ZMMO_API UUIManagerSubsystem : public ULocalPlayerSubsystem
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
/** Cria o root layout e adiciona ao viewport. Idempotente. */
|
||||
UFUNCTION(BlueprintCallable, Category = "UI|Manager")
|
||||
void CreateAndAddRootLayout(TSubclassOf<UUIPrimaryGameLayout_Base> LayoutClass);
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "UI|Manager")
|
||||
bool IsRootLayoutReady() const;
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "UI|Manager")
|
||||
UUIPrimaryGameLayout_Base* GetRootLayout() const { return RootLayout; }
|
||||
|
||||
/** Empurra a widget no topo do stack da camada. */
|
||||
UFUNCTION(BlueprintCallable, Category = "UI|Manager")
|
||||
UCommonActivatableWidget* PushScreenToLayer(
|
||||
FGameplayTag LayerTag,
|
||||
TSubclassOf<UCommonActivatableWidget> WidgetClass);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "UI|Manager")
|
||||
void PopScreenFromLayer(FGameplayTag LayerTag, UCommonActivatableWidget* Widget);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "UI|Manager")
|
||||
void ClearLayer(FGameplayTag LayerTag);
|
||||
|
||||
// USubsystem
|
||||
virtual void Deinitialize() override;
|
||||
|
||||
private:
|
||||
UPROPERTY(Transient)
|
||||
TObjectPtr<UUIPrimaryGameLayout_Base> RootLayout;
|
||||
};
|
||||
64
Source/ZMMO/Game/UI/FrontEnd/UIPrimaryGameLayout_Base.cpp
Normal file
64
Source/ZMMO/Game/UI/FrontEnd/UIPrimaryGameLayout_Base.cpp
Normal file
@@ -0,0 +1,64 @@
|
||||
#include "UIPrimaryGameLayout_Base.h"
|
||||
|
||||
#include "CommonActivatableWidget.h"
|
||||
#include "Widgets/CommonActivatableWidgetContainer.h"
|
||||
#include "UI/UILayerTags.h"
|
||||
|
||||
void UUIPrimaryGameLayout_Base::NativeOnInitialized()
|
||||
{
|
||||
Super::NativeOnInitialized();
|
||||
|
||||
RegisterLayer(ZMMOUITags::UI_Layer_Game, Stack_Game);
|
||||
RegisterLayer(ZMMOUITags::UI_Layer_GameMenu, Stack_GameMenu);
|
||||
RegisterLayer(ZMMOUITags::UI_Layer_Menu, Stack_Menu);
|
||||
RegisterLayer(ZMMOUITags::UI_Layer_Modal, Stack_Modal);
|
||||
}
|
||||
|
||||
void UUIPrimaryGameLayout_Base::RegisterLayer(FGameplayTag LayerTag, UCommonActivatableWidgetStack* Stack)
|
||||
{
|
||||
if (Stack)
|
||||
{
|
||||
Layers.Add(LayerTag, Stack);
|
||||
}
|
||||
}
|
||||
|
||||
UCommonActivatableWidgetStack* UUIPrimaryGameLayout_Base::GetLayerStack(FGameplayTag LayerTag) const
|
||||
{
|
||||
const TObjectPtr<UCommonActivatableWidgetStack>* Found = Layers.Find(LayerTag);
|
||||
return Found ? *Found : nullptr;
|
||||
}
|
||||
|
||||
UCommonActivatableWidget* UUIPrimaryGameLayout_Base::PushWidgetToLayer(
|
||||
FGameplayTag LayerTag,
|
||||
TSubclassOf<UCommonActivatableWidget> WidgetClass)
|
||||
{
|
||||
if (!WidgetClass)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
if (UCommonActivatableWidgetStack* Stack = GetLayerStack(LayerTag))
|
||||
{
|
||||
return Stack->AddWidget(WidgetClass);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void UUIPrimaryGameLayout_Base::PopWidgetFromLayer(FGameplayTag LayerTag, UCommonActivatableWidget* Widget)
|
||||
{
|
||||
if (!Widget)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (UCommonActivatableWidgetStack* Stack = GetLayerStack(LayerTag))
|
||||
{
|
||||
Stack->RemoveWidget(*Widget);
|
||||
}
|
||||
}
|
||||
|
||||
void UUIPrimaryGameLayout_Base::ClearLayer(FGameplayTag LayerTag)
|
||||
{
|
||||
if (UCommonActivatableWidgetStack* Stack = GetLayerStack(LayerTag))
|
||||
{
|
||||
Stack->ClearWidgets();
|
||||
}
|
||||
}
|
||||
72
Source/ZMMO/Game/UI/FrontEnd/UIPrimaryGameLayout_Base.h
Normal file
72
Source/ZMMO/Game/UI/FrontEnd/UIPrimaryGameLayout_Base.h
Normal file
@@ -0,0 +1,72 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "CommonUserWidget.h"
|
||||
#include "GameplayTagContainer.h"
|
||||
#include "Templates/SubclassOf.h"
|
||||
#include "UIPrimaryGameLayout_Base.generated.h"
|
||||
|
||||
class UCommonActivatableWidget;
|
||||
class UCommonActivatableWidgetStack;
|
||||
|
||||
/**
|
||||
* Layout raiz ("switch principal") do cliente. Mantém 4 stacks CommonUI,
|
||||
* um por camada (GameplayTag UI.Layer.* — ver UI/UILayerTags.h):
|
||||
*
|
||||
* Stack_Game ← UI.Layer.Game (HUD de gameplay)
|
||||
* Stack_GameMenu ← UI.Layer.GameMenu (menus sobre o jogo)
|
||||
* Stack_Menu ← UI.Layer.Menu (front-end: Boot/Login/Lobby/…)
|
||||
* Stack_Modal ← UI.Layer.Modal (diálogos/loading por cima)
|
||||
*
|
||||
* Camada Abstract; o WBP concreto (WBP_PrimaryGameLayout) herda DIRETO desta
|
||||
* classe C++ e nomeia os 4 stacks exatamente como os BindWidget abaixo
|
||||
* (ARQUITETURA.md §3.3). O UUIManagerSubsystem instancia o WBP e o adiciona
|
||||
* ao viewport; o UUIFrontEndFlowSubsystem empurra telas por camada.
|
||||
*/
|
||||
UCLASS(Abstract, Blueprintable)
|
||||
class ZMMO_API UUIPrimaryGameLayout_Base : public UCommonUserWidget
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
/** Stack da camada (nullptr se a tag não for uma UI.Layer.* conhecida). */
|
||||
UFUNCTION(BlueprintCallable, Category = "UI|Layout")
|
||||
UCommonActivatableWidgetStack* GetLayerStack(FGameplayTag LayerTag) const;
|
||||
|
||||
/** Instancia e empurra a widget no topo do stack da camada. */
|
||||
UFUNCTION(BlueprintCallable, Category = "UI|Layout")
|
||||
UCommonActivatableWidget* PushWidgetToLayer(
|
||||
FGameplayTag LayerTag,
|
||||
TSubclassOf<UCommonActivatableWidget> WidgetClass);
|
||||
|
||||
/** Remove uma widget específica do stack da camada. */
|
||||
UFUNCTION(BlueprintCallable, Category = "UI|Layout")
|
||||
void PopWidgetFromLayer(FGameplayTag LayerTag, UCommonActivatableWidget* Widget);
|
||||
|
||||
/** Esvazia o stack da camada. */
|
||||
UFUNCTION(BlueprintCallable, Category = "UI|Layout")
|
||||
void ClearLayer(FGameplayTag LayerTag);
|
||||
|
||||
protected:
|
||||
virtual void NativeOnInitialized() override;
|
||||
|
||||
/** Registra um stack numa camada (chamado em NativeOnInitialized). */
|
||||
void RegisterLayer(FGameplayTag LayerTag, UCommonActivatableWidgetStack* Stack);
|
||||
|
||||
// ---- Stacks por camada (o WBP concreto deve nomear assim) ----
|
||||
UPROPERTY(BlueprintReadOnly, Category = "UI|Layout", meta = (BindWidget))
|
||||
TObjectPtr<UCommonActivatableWidgetStack> Stack_Game;
|
||||
|
||||
UPROPERTY(BlueprintReadOnly, Category = "UI|Layout", meta = (BindWidget))
|
||||
TObjectPtr<UCommonActivatableWidgetStack> Stack_GameMenu;
|
||||
|
||||
UPROPERTY(BlueprintReadOnly, Category = "UI|Layout", meta = (BindWidget))
|
||||
TObjectPtr<UCommonActivatableWidgetStack> Stack_Menu;
|
||||
|
||||
UPROPERTY(BlueprintReadOnly, Category = "UI|Layout", meta = (BindWidget))
|
||||
TObjectPtr<UCommonActivatableWidgetStack> Stack_Modal;
|
||||
|
||||
private:
|
||||
UPROPERTY(Transient)
|
||||
TMap<FGameplayTag, TObjectPtr<UCommonActivatableWidgetStack>> Layers;
|
||||
};
|
||||
@@ -17,6 +17,7 @@ public class ZMMO : ModuleRules
|
||||
"Niagara",
|
||||
"CommonUI",
|
||||
"CommonInput",
|
||||
"GameplayTags",
|
||||
"ZeusNetwork"
|
||||
});
|
||||
|
||||
@@ -33,6 +34,7 @@ public class ZMMO : ModuleRules
|
||||
"ZMMO/Game/Network",
|
||||
"ZMMO/Game/UI",
|
||||
"ZMMO/Game/UI/Widgets",
|
||||
"ZMMO/Game/UI/FrontEnd",
|
||||
"ZMMO/Data",
|
||||
"ZMMO/Data/Items",
|
||||
"ZMMO/Data/Mobs",
|
||||
|
||||
Reference in New Issue
Block a user