feat(attributes/ui): Status Window com alocação STR/AGI/VIT/INT/DEX/LUK + derivados
- ZMMOStatusWindowWidget (UCommonActivatableWidget, modo Menu): grid 2 colunas estilo RO. Esquerda: stats primários com botões + por stat (RequestStatAlloc). Direita: derivados ATK/MATK/DEF/MDEF/HIT/FLEE/CRIT/ASPD vindos do snapshot do server — cliente NUNCA recalcula (anti-cheat foundation). - Botão + envia C_STAT_ALLOC → server valida cost RO (floor((stat-1)/10)+2), aplica + recalcula derivados + SaveCharFull async, manda S_ATTRIBUTE_SNAPSHOT_FULL + reply. UI atualiza em tempo real via OnAttributesChanged. - ZMMOAttributeComponent ganha RequestStatAlloc + NotifyStatAllocReply + delegate OnStatAllocReply para feedback de rejeição. - ZMMOAttributeNetworkHandler: HandleStatAllocReply roteia pro componente do player local (reply não traz EntityId — sempre quem fez o request). - PlayerController: hotkey Alt+A (FInputChord legacy + BindKey, sem precisar de IA asset). ToggleStatusWindow via UUIInGameFlowSubsystem. - WBP_StatusWindow: layout 2 colunas via MCP set_widget_tree (43 widgets) + BgBorder escuro semi-transparente + centralizado no overlay. - DA_InGameScreenSet: StatusWindow → WBP_StatusWindow.
This commit is contained in:
106
Source/ZMMO/Game/UI/InGame/ZMMOStatusWindowWidget.h
Normal file
106
Source/ZMMO/Game/UI/InGame/ZMMOStatusWindowWidget.h
Normal file
@@ -0,0 +1,106 @@
|
||||
#pragma once
|
||||
|
||||
#include "CommonActivatableWidget.h"
|
||||
#include "CoreMinimal.h"
|
||||
#include "ZMMOAttributeTypes.h"
|
||||
#include "ZMMOStatusWindowWidget.generated.h"
|
||||
|
||||
class UButton;
|
||||
class UTextBlock;
|
||||
class UCommonButtonBase;
|
||||
class UZMMOAttributeComponent;
|
||||
|
||||
/**
|
||||
* Tela "Status" — atributos do jogador + alocacao via botões `+`.
|
||||
*
|
||||
* Modo Menu: cursor visível, movimento bloqueado, Esc fecha. Push em
|
||||
* UI.Layer.GameMenu pelo `UUIInGameFlowSubsystem::ToggleScreen(StatusWindow)`.
|
||||
* HUD continua visível em UI.Layer.Game por baixo.
|
||||
*
|
||||
* Composicao do WBP_StatusWindow (BindWidgetOptional pra permitir variantes):
|
||||
* - Labels de stats primarios: StrText / AgiText / VitText / IntText / DexText / LukText
|
||||
* - Botões +: PlusBtn_Str / PlusBtn_Agi / PlusBtn_Vit / PlusBtn_Int / PlusBtn_Dex / PlusBtn_Luk
|
||||
* - Derivados (server-authoritative): AtkText / MatkText / DefText / MdefText /
|
||||
* HitText / FleeText / CritText / AspdText
|
||||
* - StatusPointText (pontos disponíveis pra alocar)
|
||||
* - CloseBtn (fecha — fallback do Esc/back handler)
|
||||
*
|
||||
* Workflow:
|
||||
* 1. NativeOnActivated: busca AttributeComponent (PlayerState do player local)
|
||||
* 2. Subscreve OnAttributesChanged + OnStatAllocReply
|
||||
* 3. Refresh inicial via snapshot atual
|
||||
* 4. Clique no `+X` chama `Comp->RequestStatAlloc(X, 1)` → server valida
|
||||
* 5. Server responde com S_ATTRIBUTE_STAT_ALLOC_OK + (se ok) snapshot novo
|
||||
* 6. UI atualiza via delegate
|
||||
*/
|
||||
UCLASS(Abstract, Blueprintable, BlueprintType)
|
||||
class ZMMO_API UZMMOStatusWindowWidget : public UCommonActivatableWidget
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
UZMMOStatusWindowWidget(const FObjectInitializer& ObjectInitializer);
|
||||
|
||||
protected:
|
||||
virtual void NativeOnActivated() override;
|
||||
virtual void NativeOnDeactivated() override;
|
||||
|
||||
/// Modo Menu: cursor visível + bloqueia input de gameplay (movimento).
|
||||
virtual TOptional<FUIInputConfig> GetDesiredInputConfig() const override;
|
||||
|
||||
/// Texto dos stats (label + valor). BindWidgetOptional pra permitir
|
||||
/// WBPs custom (ex.: sem display de SP em variantes).
|
||||
UPROPERTY(BlueprintReadOnly, meta = (BindWidgetOptional), Category = "Zeus|Status") UTextBlock* StrText = nullptr;
|
||||
UPROPERTY(BlueprintReadOnly, meta = (BindWidgetOptional), Category = "Zeus|Status") UTextBlock* AgiText = nullptr;
|
||||
UPROPERTY(BlueprintReadOnly, meta = (BindWidgetOptional), Category = "Zeus|Status") UTextBlock* VitText = nullptr;
|
||||
UPROPERTY(BlueprintReadOnly, meta = (BindWidgetOptional), Category = "Zeus|Status") UTextBlock* IntText = nullptr;
|
||||
UPROPERTY(BlueprintReadOnly, meta = (BindWidgetOptional), Category = "Zeus|Status") UTextBlock* DexText = nullptr;
|
||||
UPROPERTY(BlueprintReadOnly, meta = (BindWidgetOptional), Category = "Zeus|Status") UTextBlock* LukText = nullptr;
|
||||
|
||||
/// Pontos restantes pra alocar + label "Status Points: N".
|
||||
UPROPERTY(BlueprintReadOnly, meta = (BindWidgetOptional), Category = "Zeus|Status") UTextBlock* StatusPointText = nullptr;
|
||||
|
||||
/// Derivados (sempre calculados pelo servidor — cliente NUNCA recalcula).
|
||||
/// Mostra `base + bonus` quando aplicavel (camadas equip/buff vem do server
|
||||
/// pre-somadas no snapshot). BindWidgetOptional pra suportar HUDs minimalistas.
|
||||
UPROPERTY(BlueprintReadOnly, meta = (BindWidgetOptional), Category = "Zeus|Status|Derived") UTextBlock* AtkText = nullptr;
|
||||
UPROPERTY(BlueprintReadOnly, meta = (BindWidgetOptional), Category = "Zeus|Status|Derived") UTextBlock* MatkText = nullptr;
|
||||
UPROPERTY(BlueprintReadOnly, meta = (BindWidgetOptional), Category = "Zeus|Status|Derived") UTextBlock* DefText = nullptr;
|
||||
UPROPERTY(BlueprintReadOnly, meta = (BindWidgetOptional), Category = "Zeus|Status|Derived") UTextBlock* MdefText = nullptr;
|
||||
UPROPERTY(BlueprintReadOnly, meta = (BindWidgetOptional), Category = "Zeus|Status|Derived") UTextBlock* HitText = nullptr;
|
||||
UPROPERTY(BlueprintReadOnly, meta = (BindWidgetOptional), Category = "Zeus|Status|Derived") UTextBlock* FleeText = nullptr;
|
||||
UPROPERTY(BlueprintReadOnly, meta = (BindWidgetOptional), Category = "Zeus|Status|Derived") UTextBlock* CritText = nullptr;
|
||||
UPROPERTY(BlueprintReadOnly, meta = (BindWidgetOptional), Category = "Zeus|Status|Derived") UTextBlock* AspdText = nullptr;
|
||||
|
||||
/// Botoes + por stat.
|
||||
UPROPERTY(BlueprintReadOnly, meta = (BindWidgetOptional), Category = "Zeus|Status") UButton* PlusBtn_Str = nullptr;
|
||||
UPROPERTY(BlueprintReadOnly, meta = (BindWidgetOptional), Category = "Zeus|Status") UButton* PlusBtn_Agi = nullptr;
|
||||
UPROPERTY(BlueprintReadOnly, meta = (BindWidgetOptional), Category = "Zeus|Status") UButton* PlusBtn_Vit = nullptr;
|
||||
UPROPERTY(BlueprintReadOnly, meta = (BindWidgetOptional), Category = "Zeus|Status") UButton* PlusBtn_Int = nullptr;
|
||||
UPROPERTY(BlueprintReadOnly, meta = (BindWidgetOptional), Category = "Zeus|Status") UButton* PlusBtn_Dex = nullptr;
|
||||
UPROPERTY(BlueprintReadOnly, meta = (BindWidgetOptional), Category = "Zeus|Status") UButton* PlusBtn_Luk = nullptr;
|
||||
|
||||
/// Botao Close (fallback do Esc/back).
|
||||
UPROPERTY(BlueprintReadOnly, meta = (BindWidgetOptional), Category = "Zeus|Status") UButton* CloseBtn = nullptr;
|
||||
|
||||
private:
|
||||
void BindToLocalPlayer();
|
||||
void UnbindFromComponent();
|
||||
void RefreshFromSnapshot(const FZMMOAttributesSnapshot& Snap);
|
||||
|
||||
UFUNCTION() void HandleAttributesChanged(const FZMMOAttributesSnapshot& Snapshot);
|
||||
UFUNCTION() void HandleStatAllocReply(bool bAccepted, int32 Reason);
|
||||
|
||||
UFUNCTION() void OnPlusStr();
|
||||
UFUNCTION() void OnPlusAgi();
|
||||
UFUNCTION() void OnPlusVit();
|
||||
UFUNCTION() void OnPlusInt();
|
||||
UFUNCTION() void OnPlusDex();
|
||||
UFUNCTION() void OnPlusLuk();
|
||||
UFUNCTION() void OnCloseClicked();
|
||||
|
||||
void RequestAlloc(int32 StatId);
|
||||
|
||||
UPROPERTY(Transient)
|
||||
TWeakObjectPtr<UZMMOAttributeComponent> BoundComponent;
|
||||
};
|
||||
Reference in New Issue
Block a user