- PlayerState ganha CharName (Replicated) + SetCharInfo(CharName, GuildName) - ZMMOPlayerCharacter assina FZeusOnCharInfoReceived; TryApplyCachedCharInfo resolve race se S_CHAR_INFO chega antes do pawn possuir - UIPlayerStatus_Window header le PlayerState->CharName (fallback p/ GetPlayerName) em vez do "Mateuus-61E9B19A4FB2" generico Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
125 lines
4.7 KiB
C++
125 lines
4.7 KiB
C++
#pragma once
|
|
|
|
#include "CoreMinimal.h"
|
|
#include "GameFramework/PlayerState.h"
|
|
#include "Templates/SubclassOf.h"
|
|
#include "ZMMOPlayerState.generated.h"
|
|
|
|
class FLifetimeProperty;
|
|
class UActorComponent;
|
|
|
|
/**
|
|
* PlayerState do MMO. Pattern UE5 idiomatico: o GameMode atribui
|
|
* `PlayerStateClass`, engine cria 1 instancia por PlayerController.
|
|
*
|
|
* Responsabilidade — estado **publico** do jogador (visivel pra outros):
|
|
* - Identidade: charId, entityId, name, guild
|
|
* - Progressao publica: baseLevel, classId
|
|
* - Estado: alive/dead, in-combat (futuro)
|
|
*
|
|
* Dados PRIVADOS (HP/SP atuais, stats brutos, inventory, hotbar) vivem
|
|
* em componentes anexados via Component Registry (vide abaixo).
|
|
*
|
|
* Por que componentes no PlayerState e nao no Pawn:
|
|
* - **Sobrevive ao despawn** (morte/respawn — Pawn destrui, PlayerState
|
|
* mantem). Padrao MMO classico (rathena, TrinityCore).
|
|
* - **Spectator-friendly**: dados acessiveis sem ter pawn.
|
|
* - **1:1 com player** (Pawn pode trocar — vehicle, mount, possession).
|
|
*
|
|
* ## Component Registry (Open-Closed)
|
|
*
|
|
* Cada modulo (ZMMOAttributes, ZMMOInventory, ZMMOSkills futuros) declara
|
|
* sua component class em DefaultGame.ini:
|
|
*
|
|
* [/Script/ZMMO.ZMMOPlayerState]
|
|
* +ComponentClasses=/Script/ZMMOAttributes.ZMMOAttributeComponent
|
|
* +ComponentClasses=/Script/ZMMOInventory.ZMMOInventoryComponent
|
|
* +ComponentClasses=/Script/ZMMOSkills.ZMMOSkillComponent
|
|
*
|
|
* O construtor de AZMMOPlayerState le essa lista (Config) e instancia
|
|
* cada classe como subobject. PlayerState fica fechado pra modificacao,
|
|
* modulos abertos pra extensao — adicionar Inventory NAO requer
|
|
* recompilar/editar AZMMOPlayerState.
|
|
*
|
|
* Acesso: `PlayerState->FindComponentByClass<UZMMOAttributeComponent>()`
|
|
* ou o helper `GetZMMOComponent<T>()`.
|
|
*/
|
|
UCLASS(Config = Game, BlueprintType)
|
|
class ZMMO_API AZMMOPlayerState : public APlayerState
|
|
{
|
|
GENERATED_BODY()
|
|
|
|
public:
|
|
AZMMOPlayerState();
|
|
|
|
// === Identidade publica ===
|
|
//
|
|
// Todos os campos publicos sao Replicated — hoje o cliente UE5 roda em
|
|
// Standalone (servidor C++ standalone, sem replicacao UE5 ativa), entao
|
|
// a marca nao tem efeito em runtime; deixa a classe pronta caso o projeto
|
|
// passe a usar dedicated UE5 no futuro.
|
|
|
|
/** EntityId autoritativo do server. 0 ate o spawn local confirmar. */
|
|
UPROPERTY(Replicated, VisibleInstanceOnly, BlueprintReadOnly, Category = "ZMMO|Identity")
|
|
int64 ZMMOEntityId = 0;
|
|
|
|
/** CharId (BIGINT no DB; FString pra preservar 64 bits em Blueprint). */
|
|
UPROPERTY(Replicated, VisibleInstanceOnly, BlueprintReadOnly, Category = "ZMMO|Identity")
|
|
FString CharId;
|
|
|
|
/** Nome do char vindo do DB (`characters.name`). Setado por
|
|
* AZMMOPlayerCharacter::HandleLocalSpawnReady com o payload do
|
|
* S_SPAWN_PLAYER. UI prefere isto a APlayerState::GetPlayerName(). */
|
|
UPROPERTY(Replicated, VisibleInstanceOnly, BlueprintReadOnly, Category = "ZMMO|Identity")
|
|
FString CharName;
|
|
|
|
// === Progressao publica ===
|
|
|
|
UPROPERTY(Replicated, VisibleInstanceOnly, BlueprintReadOnly, Category = "ZMMO|Progress")
|
|
int32 BaseLevel = 1;
|
|
|
|
UPROPERTY(Replicated, VisibleInstanceOnly, BlueprintReadOnly, Category = "ZMMO|Progress")
|
|
int32 ClassId = 0;
|
|
|
|
// === Guild (futuro) ===
|
|
|
|
UPROPERTY(Replicated, VisibleInstanceOnly, BlueprintReadOnly, Category = "ZMMO|Guild")
|
|
FString GuildName;
|
|
|
|
virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;
|
|
|
|
// === Helpers ===
|
|
|
|
/// Setado por AZMMOPlayerCharacter::HandleLocalSpawnReady (pose/EntityId)
|
|
/// e atualizado por handlers de snapshot/level up para refletir dados
|
|
/// publicos do char no PlayerState.
|
|
UFUNCTION(BlueprintCallable, Category = "ZMMO|Identity")
|
|
void SetPublicIdentity(int64 InEntityId, const FString& InCharId,
|
|
int32 InBaseLevel, int32 InClassId);
|
|
|
|
/// Setado pelo handler do S_CHAR_INFO (chega antes de S_SPAWN_PLAYER) —
|
|
/// metadados publicos do char vindos do servidor.
|
|
UFUNCTION(BlueprintCallable, Category = "ZMMO|Identity")
|
|
void SetCharInfo(const FString& InCharName, const FString& InGuildName);
|
|
|
|
/// Template helper: PS->GetZMMOComponent<UZMMOAttributeComponent>()
|
|
template <typename T>
|
|
T* GetZMMOComponent() const
|
|
{
|
|
return Cast<T>(FindComponentByClass(T::StaticClass()));
|
|
}
|
|
|
|
protected:
|
|
/**
|
|
* Component Registry — config-driven. Modulos registram suas classes
|
|
* via DefaultGame.ini com prefix `+`. Construtor instancia cada uma
|
|
* como CreateDefaultSubobject.
|
|
*
|
|
* TSubclassOf (nao TSoftClassPtr): config UE resolve classes nativas
|
|
* diretamente. Modulos C++ precisam estar carregados antes do CDO ser
|
|
* instanciado — garantido por LoadingPhase=PreDefault no .uproject.
|
|
*/
|
|
UPROPERTY(Config, EditDefaultsOnly, Category = "ZMMO|Components")
|
|
TArray<TSubclassOf<UActorComponent>> ComponentClasses;
|
|
};
|