feat(player): CharName do DB no PlayerState + header do Status Window
- 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>
This commit is contained in:
Binary file not shown.
@@ -18,6 +18,7 @@
|
|||||||
#include "UObject/ConstructorHelpers.h"
|
#include "UObject/ConstructorHelpers.h"
|
||||||
#include "ZMMO.h"
|
#include "ZMMO.h"
|
||||||
#include "ZMMOAttributeComponent.h"
|
#include "ZMMOAttributeComponent.h"
|
||||||
|
#include "ZMMOPlayerState.h"
|
||||||
#include "ZMMOWorldSubsystem.h"
|
#include "ZMMOWorldSubsystem.h"
|
||||||
#include "ZeusNetworkSubsystem.h"
|
#include "ZeusNetworkSubsystem.h"
|
||||||
#include "UI/FrontEnd/UIFrontEndFlowSubsystem.h"
|
#include "UI/FrontEnd/UIFrontEndFlowSubsystem.h"
|
||||||
@@ -278,6 +279,7 @@ void AZMMOPlayerCharacter::BindZeusSpawnDelegate()
|
|||||||
}
|
}
|
||||||
|
|
||||||
ZeusNetwork->OnPlayerSpawned.AddDynamic(this, &AZMMOPlayerCharacter::HandleZeusPlayerSpawned);
|
ZeusNetwork->OnPlayerSpawned.AddDynamic(this, &AZMMOPlayerCharacter::HandleZeusPlayerSpawned);
|
||||||
|
ZeusNetwork->OnCharInfoReceived.AddDynamic(this, &AZMMOPlayerCharacter::HandleZeusCharInfo);
|
||||||
bSpawnDelegateBound = true;
|
bSpawnDelegateBound = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -289,6 +291,7 @@ void AZMMOPlayerCharacter::UnbindZeusSpawnDelegate()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ZeusNetwork->OnPlayerSpawned.RemoveDynamic(this, &AZMMOPlayerCharacter::HandleZeusPlayerSpawned);
|
ZeusNetwork->OnPlayerSpawned.RemoveDynamic(this, &AZMMOPlayerCharacter::HandleZeusPlayerSpawned);
|
||||||
|
ZeusNetwork->OnCharInfoReceived.RemoveDynamic(this, &AZMMOPlayerCharacter::HandleZeusCharInfo);
|
||||||
bSpawnDelegateBound = false;
|
bSpawnDelegateBound = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -307,6 +310,10 @@ void AZMMOPlayerCharacter::TryRegisterLocalEntityFromCachedSpawn()
|
|||||||
{
|
{
|
||||||
HandleLocalSpawnReady(CachedEntityId, CachedPosCm, CachedYawDeg, CachedServerTimeMs);
|
HandleLocalSpawnReady(CachedEntityId, CachedPosCm, CachedYawDeg, CachedServerTimeMs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Race fix: o S_CHAR_INFO chega ANTES de S_SPAWN_PLAYER mas o pawn pode
|
||||||
|
// nao existir ainda (OpenLevel em andamento). Aplica o ultimo cacheado.
|
||||||
|
TryApplyCachedCharInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AZMMOPlayerCharacter::HandleZeusPlayerSpawned(const int32 InEntityId, const bool bIsLocal,
|
void AZMMOPlayerCharacter::HandleZeusPlayerSpawned(const int32 InEntityId, const bool bIsLocal,
|
||||||
@@ -349,25 +356,74 @@ void AZMMOPlayerCharacter::HandleLocalSpawnReady(const int32 InEntityId, const F
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Seed do EntityId no AttributeComponent do PlayerState. O componente
|
// Identidade publica (EntityId) + seed no AttributeComponent. CharName/Guild
|
||||||
// vive no AZMMOPlayerState via Component Registry — busca via PlayerState
|
// vem separado via S_CHAR_INFO -> HandleZeusCharInfo. AttributeComponent vive
|
||||||
// (sobrevive ao despawn do Pawn). S_ATTRIBUTE_SNAPSHOT_FULL chega via
|
// como subobject e recebe seed pra que o ZMMOAttributeNetworkHandler consiga
|
||||||
// UDP e e' rouado pelo ZMMOAttributeNetworkHandler via lookup por
|
// rotear o snapshot por EntityId desde o primeiro pacote.
|
||||||
// EntityId no PlayerArray do GameState.
|
|
||||||
if (APlayerState* PS = GetPlayerState())
|
if (APlayerState* PS = GetPlayerState())
|
||||||
{
|
{
|
||||||
|
if (AZMMOPlayerState* ZMMOPs = Cast<AZMMOPlayerState>(PS))
|
||||||
|
{
|
||||||
|
ZMMOPs->SetPublicIdentity(EntityIdAsInt64, /*CharId*/ FString(),
|
||||||
|
/*BaseLevel*/ 1, /*ClassId*/ 0);
|
||||||
|
}
|
||||||
if (UZMMOAttributeComponent* AttrComp = PS->FindComponentByClass<UZMMOAttributeComponent>())
|
if (UZMMOAttributeComponent* AttrComp = PS->FindComponentByClass<UZMMOAttributeComponent>())
|
||||||
{
|
{
|
||||||
AttrComp->SeedEntityId(InEntityId);
|
AttrComp->SeedEntityId(InEntityId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Aplica char info cacheada (caso S_CHAR_INFO tenha chegado antes do PS existir).
|
||||||
|
TryApplyCachedCharInfo();
|
||||||
|
|
||||||
// UI in-game e' responsabilidade do AZMMOHUD (GameMode.HUDClass), nao do
|
// UI in-game e' responsabilidade do AZMMOHUD (GameMode.HUDClass), nao do
|
||||||
// Pawn. AHUD::BeginPlay chama UUIInGameFlowSubsystem::StartInGame, que
|
// Pawn. AHUD::BeginPlay chama UUIInGameFlowSubsystem::StartInGame, que
|
||||||
// pushea WBP_HUD em UI.Layer.Game. UZMMOHudWidget::NativeOnActivated auto-binda
|
// pushea WBP_HUD em UI.Layer.Game. UZMMOHudWidget::NativeOnActivated auto-binda
|
||||||
// no UZMMOAttributeComponent via PlayerState.
|
// no UZMMOAttributeComponent via PlayerState.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AZMMOPlayerCharacter::HandleZeusCharInfo(const int32 InEntityId, const FString& CharName, const FString& GuildName)
|
||||||
|
{
|
||||||
|
UE_LOG(LogZMMOPlayer, Log,
|
||||||
|
TEXT("AZMMOPlayerCharacter: S_CHAR_INFO recebido EntityId=%d name=%s guild=%s"),
|
||||||
|
InEntityId, *CharName, *GuildName);
|
||||||
|
|
||||||
|
APlayerState* PS = GetPlayerState();
|
||||||
|
if (!PS)
|
||||||
|
{
|
||||||
|
// Race fix: pawn pode nao ter PlayerState ainda. Subsystem ja cacheou
|
||||||
|
// (LastLocalCharInfoCache); TryApplyCachedCharInfo aplica em
|
||||||
|
// HandleLocalSpawnReady ou em outra oportunidade.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (AZMMOPlayerState* ZMMOPs = Cast<AZMMOPlayerState>(PS))
|
||||||
|
{
|
||||||
|
ZMMOPs->SetCharInfo(CharName, GuildName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AZMMOPlayerCharacter::TryApplyCachedCharInfo()
|
||||||
|
{
|
||||||
|
if (!ZeusNetwork)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int32 CachedEntityId = 0;
|
||||||
|
FString CachedCharName;
|
||||||
|
FString CachedGuildName;
|
||||||
|
if (!ZeusNetwork->TryGetLastLocalCharInfo(CachedEntityId, CachedCharName, CachedGuildName))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (APlayerState* PS = GetPlayerState())
|
||||||
|
{
|
||||||
|
if (AZMMOPlayerState* ZMMOPs = Cast<AZMMOPlayerState>(PS))
|
||||||
|
{
|
||||||
|
ZMMOPs->SetCharInfo(CachedCharName, CachedGuildName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void AZMMOPlayerCharacter::FlushInputAxisToServer(const float DeltaSeconds)
|
void AZMMOPlayerCharacter::FlushInputAxisToServer(const float DeltaSeconds)
|
||||||
{
|
{
|
||||||
ResolveZeusNetworkSubsystem();
|
ResolveZeusNetworkSubsystem();
|
||||||
|
|||||||
@@ -133,12 +133,19 @@ private:
|
|||||||
/**
|
/**
|
||||||
* Memoriza `EntityId` autoritativo e regista o pawn no `UZMMOWorldSubsystem`
|
* Memoriza `EntityId` autoritativo e regista o pawn no `UZMMOWorldSubsystem`
|
||||||
* para o registry partilhado por proxies remotos (filtra snapshots locais).
|
* para o registry partilhado por proxies remotos (filtra snapshots locais).
|
||||||
|
* Metadados publicos do char (Name/Guild) chegam via S_CHAR_INFO em
|
||||||
|
* HandleZeusCharInfo (servidor envia ANTES de S_SPAWN_PLAYER).
|
||||||
*/
|
*/
|
||||||
void HandleLocalSpawnReady(int32 InEntityId, FVector PosCm, float YawDeg, int64 ServerTimeMs);
|
void HandleLocalSpawnReady(int32 InEntityId, FVector PosCm, float YawDeg, int64 ServerTimeMs);
|
||||||
|
|
||||||
UFUNCTION()
|
UFUNCTION()
|
||||||
void HandleZeusPlayerSpawned(int32 InEntityId, bool bIsLocal, FVector PosCm, float YawDeg, int64 ServerTimeMs);
|
void HandleZeusPlayerSpawned(int32 InEntityId, bool bIsLocal, FVector PosCm, float YawDeg, int64 ServerTimeMs);
|
||||||
|
|
||||||
|
UFUNCTION()
|
||||||
|
void HandleZeusCharInfo(int32 InEntityId, const FString& CharName, const FString& GuildName);
|
||||||
|
|
||||||
|
void TryApplyCachedCharInfo();
|
||||||
|
|
||||||
UPROPERTY()
|
UPROPERTY()
|
||||||
TObjectPtr<UZeusNetworkSubsystem> ZeusNetwork;
|
TObjectPtr<UZeusNetworkSubsystem> ZeusNetwork;
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include "Components/ActorComponent.h"
|
#include "Components/ActorComponent.h"
|
||||||
#include "Misc/ConfigCacheIni.h"
|
#include "Misc/ConfigCacheIni.h"
|
||||||
|
#include "Net/UnrealNetwork.h"
|
||||||
#include "ZMMO.h"
|
#include "ZMMO.h"
|
||||||
|
|
||||||
AZMMOPlayerState::AZMMOPlayerState()
|
AZMMOPlayerState::AZMMOPlayerState()
|
||||||
@@ -72,6 +73,17 @@ AZMMOPlayerState::AZMMOPlayerState()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AZMMOPlayerState::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
|
||||||
|
{
|
||||||
|
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
|
||||||
|
DOREPLIFETIME(AZMMOPlayerState, ZMMOEntityId);
|
||||||
|
DOREPLIFETIME(AZMMOPlayerState, CharId);
|
||||||
|
DOREPLIFETIME(AZMMOPlayerState, CharName);
|
||||||
|
DOREPLIFETIME(AZMMOPlayerState, BaseLevel);
|
||||||
|
DOREPLIFETIME(AZMMOPlayerState, ClassId);
|
||||||
|
DOREPLIFETIME(AZMMOPlayerState, GuildName);
|
||||||
|
}
|
||||||
|
|
||||||
void AZMMOPlayerState::SetPublicIdentity(int64 InEntityId, const FString& InCharId,
|
void AZMMOPlayerState::SetPublicIdentity(int64 InEntityId, const FString& InCharId,
|
||||||
int32 InBaseLevel, int32 InClassId)
|
int32 InBaseLevel, int32 InClassId)
|
||||||
{
|
{
|
||||||
@@ -80,3 +92,9 @@ void AZMMOPlayerState::SetPublicIdentity(int64 InEntityId, const FString& InChar
|
|||||||
BaseLevel = InBaseLevel;
|
BaseLevel = InBaseLevel;
|
||||||
ClassId = InClassId;
|
ClassId = InClassId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AZMMOPlayerState::SetCharInfo(const FString& InCharName, const FString& InGuildName)
|
||||||
|
{
|
||||||
|
CharName = InCharName;
|
||||||
|
GuildName = InGuildName;
|
||||||
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#include "Templates/SubclassOf.h"
|
#include "Templates/SubclassOf.h"
|
||||||
#include "ZMMOPlayerState.generated.h"
|
#include "ZMMOPlayerState.generated.h"
|
||||||
|
|
||||||
|
class FLifetimeProperty;
|
||||||
class UActorComponent;
|
class UActorComponent;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -52,36 +53,55 @@ public:
|
|||||||
AZMMOPlayerState();
|
AZMMOPlayerState();
|
||||||
|
|
||||||
// === Identidade publica ===
|
// === 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. */
|
/** EntityId autoritativo do server. 0 ate o spawn local confirmar. */
|
||||||
UPROPERTY(VisibleInstanceOnly, BlueprintReadOnly, Category = "ZMMO|Identity")
|
UPROPERTY(Replicated, VisibleInstanceOnly, BlueprintReadOnly, Category = "ZMMO|Identity")
|
||||||
int64 ZMMOEntityId = 0;
|
int64 ZMMOEntityId = 0;
|
||||||
|
|
||||||
/** CharId (BIGINT no DB; FString pra preservar 64 bits em Blueprint). */
|
/** CharId (BIGINT no DB; FString pra preservar 64 bits em Blueprint). */
|
||||||
UPROPERTY(VisibleInstanceOnly, BlueprintReadOnly, Category = "ZMMO|Identity")
|
UPROPERTY(Replicated, VisibleInstanceOnly, BlueprintReadOnly, Category = "ZMMO|Identity")
|
||||||
FString CharId;
|
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 ===
|
// === Progressao publica ===
|
||||||
|
|
||||||
UPROPERTY(VisibleInstanceOnly, BlueprintReadOnly, Category = "ZMMO|Progress")
|
UPROPERTY(Replicated, VisibleInstanceOnly, BlueprintReadOnly, Category = "ZMMO|Progress")
|
||||||
int32 BaseLevel = 1;
|
int32 BaseLevel = 1;
|
||||||
|
|
||||||
UPROPERTY(VisibleInstanceOnly, BlueprintReadOnly, Category = "ZMMO|Progress")
|
UPROPERTY(Replicated, VisibleInstanceOnly, BlueprintReadOnly, Category = "ZMMO|Progress")
|
||||||
int32 ClassId = 0;
|
int32 ClassId = 0;
|
||||||
|
|
||||||
// === Guild (futuro) ===
|
// === Guild (futuro) ===
|
||||||
|
|
||||||
UPROPERTY(VisibleInstanceOnly, BlueprintReadOnly, Category = "ZMMO|Guild")
|
UPROPERTY(Replicated, VisibleInstanceOnly, BlueprintReadOnly, Category = "ZMMO|Guild")
|
||||||
FString GuildName;
|
FString GuildName;
|
||||||
|
|
||||||
|
virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;
|
||||||
|
|
||||||
// === Helpers ===
|
// === Helpers ===
|
||||||
|
|
||||||
/// Atualizado quando S_ATTRIBUTE_SNAPSHOT_FULL chega — UZMMOHudWidget chama
|
/// Setado por AZMMOPlayerCharacter::HandleLocalSpawnReady (pose/EntityId)
|
||||||
/// isso pra refletir os dados publicos do snapshot no PlayerState.
|
/// e atualizado por handlers de snapshot/level up para refletir dados
|
||||||
|
/// publicos do char no PlayerState.
|
||||||
UFUNCTION(BlueprintCallable, Category = "ZMMO|Identity")
|
UFUNCTION(BlueprintCallable, Category = "ZMMO|Identity")
|
||||||
void SetPublicIdentity(int64 InEntityId, const FString& InCharId,
|
void SetPublicIdentity(int64 InEntityId, const FString& InCharId,
|
||||||
int32 InBaseLevel, int32 InClassId);
|
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 helper: PS->GetZMMOComponent<UZMMOAttributeComponent>()
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T* GetZMMOComponent() const
|
T* GetZMMOComponent() const
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
#include "ZMMOAttributeComponent.h"
|
#include "ZMMOAttributeComponent.h"
|
||||||
#include "ZMMOJobDataAsset.h"
|
#include "ZMMOJobDataAsset.h"
|
||||||
#include "ZMMOJobsSubsystem.h"
|
#include "ZMMOJobsSubsystem.h"
|
||||||
|
#include "ZMMOPlayerState.h"
|
||||||
#include "UI/InGame/UIInGameFlowSubsystem.h"
|
#include "UI/InGame/UIInGameFlowSubsystem.h"
|
||||||
#include "UI/InGameTypes.h"
|
#include "UI/InGameTypes.h"
|
||||||
#include "UI/Widgets/UIPlayerStatus_BonusRow.h"
|
#include "UI/Widgets/UIPlayerStatus_BonusRow.h"
|
||||||
@@ -87,10 +88,20 @@ void UUIPlayerStatus_Window::BindToLocalPlayer()
|
|||||||
APlayerController* PC = World->GetFirstPlayerController();
|
APlayerController* PC = World->GetFirstPlayerController();
|
||||||
if (!PC || !PC->PlayerState) return;
|
if (!PC || !PC->PlayerState) return;
|
||||||
|
|
||||||
// CharName vem do PlayerState (estável por sessão) — popula uma vez.
|
// CharName vem do AZMMOPlayerState (setado pelo S_SPAWN_PLAYER no spawn
|
||||||
|
// local). Fallback pra APlayerState::GetPlayerName() se o cast falhar ou
|
||||||
|
// se CharName ainda nao chegou (race com handler que dispara o widget).
|
||||||
if (Text_CharName)
|
if (Text_CharName)
|
||||||
{
|
{
|
||||||
Text_CharName->SetText(FText::FromString(PC->PlayerState->GetPlayerName()));
|
FString DisplayName = PC->PlayerState->GetPlayerName();
|
||||||
|
if (const AZMMOPlayerState* ZMMOPs = Cast<AZMMOPlayerState>(PC->PlayerState))
|
||||||
|
{
|
||||||
|
if (!ZMMOPs->CharName.IsEmpty())
|
||||||
|
{
|
||||||
|
DisplayName = ZMMOPs->CharName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Text_CharName->SetText(FText::FromString(DisplayName));
|
||||||
}
|
}
|
||||||
|
|
||||||
UZMMOAttributeComponent* Comp = PC->PlayerState->FindComponentByClass<UZMMOAttributeComponent>();
|
UZMMOAttributeComponent* Comp = PC->PlayerState->FindComponentByClass<UZMMOAttributeComponent>();
|
||||||
|
|||||||
Reference in New Issue
Block a user