Consolidar GameplayAbilitySystem na main (baseline cliente tudo funcionando 2026-06-16) #6
@@ -42,6 +42,7 @@ void UZeusWorldSubsystem::OnWorldBeginPlay(UWorld& InWorld)
|
|||||||
Net->OnEntityDespawned.AddDynamic(this, &UZeusWorldSubsystem::OnNetEntityDespawned);
|
Net->OnEntityDespawned.AddDynamic(this, &UZeusWorldSubsystem::OnNetEntityDespawned);
|
||||||
Net->OnEntityDeltaApplied.AddDynamic(this, &UZeusWorldSubsystem::OnNetEntityDelta);
|
Net->OnEntityDeltaApplied.AddDynamic(this, &UZeusWorldSubsystem::OnNetEntityDelta);
|
||||||
Net->OnSelfEntityAssigned.AddDynamic(this, &UZeusWorldSubsystem::OnNetSelfEntityAssigned);
|
Net->OnSelfEntityAssigned.AddDynamic(this, &UZeusWorldSubsystem::OnNetSelfEntityAssigned);
|
||||||
|
Net->OnCharInfo.AddDynamic(this, &UZeusWorldSubsystem::OnNetCharInfo);
|
||||||
UE_LOG(LogZMMO, Log, TEXT("ZeusWorldSubsystem bound to network client subsystem delegates."));
|
UE_LOG(LogZMMO, Log, TEXT("ZeusWorldSubsystem bound to network client subsystem delegates."));
|
||||||
|
|
||||||
// O subsystem de rede e' per-GameInstance e sobrevive ao OpenLevel, entao
|
// O subsystem de rede e' per-GameInstance e sobrevive ao OpenLevel, entao
|
||||||
@@ -77,9 +78,11 @@ void UZeusWorldSubsystem::Deinitialize()
|
|||||||
Net->OnEntityDespawned.RemoveDynamic(this, &UZeusWorldSubsystem::OnNetEntityDespawned);
|
Net->OnEntityDespawned.RemoveDynamic(this, &UZeusWorldSubsystem::OnNetEntityDespawned);
|
||||||
Net->OnEntityDeltaApplied.RemoveDynamic(this, &UZeusWorldSubsystem::OnNetEntityDelta);
|
Net->OnEntityDeltaApplied.RemoveDynamic(this, &UZeusWorldSubsystem::OnNetEntityDelta);
|
||||||
Net->OnSelfEntityAssigned.RemoveDynamic(this, &UZeusWorldSubsystem::OnNetSelfEntityAssigned);
|
Net->OnSelfEntityAssigned.RemoveDynamic(this, &UZeusWorldSubsystem::OnNetSelfEntityAssigned);
|
||||||
|
Net->OnCharInfo.RemoveDynamic(this, &UZeusWorldSubsystem::OnNetCharInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
RemoteEntities.Reset();
|
RemoteEntities.Reset();
|
||||||
|
PendingCharInfo.Reset();
|
||||||
LocalEntityId = 0;
|
LocalEntityId = 0;
|
||||||
Super::Deinitialize();
|
Super::Deinitialize();
|
||||||
}
|
}
|
||||||
@@ -112,6 +115,9 @@ void UZeusWorldSubsystem::RegisterLocalEntity(const int64 EntityId, AActor* Loca
|
|||||||
}
|
}
|
||||||
|
|
||||||
RemoteEntities.Add(EntityId, TWeakObjectPtr<AActor>(LocalActor));
|
RemoteEntities.Add(EntityId, TWeakObjectPtr<AActor>(LocalActor));
|
||||||
|
// V1-CHARINFO: o nome do proprio char pode ter chegado antes do pawn local
|
||||||
|
// existir (CHAR_INFO vem logo apos ENT_SELF); aplica agora.
|
||||||
|
FlushPendingCharInfo(EntityId);
|
||||||
UE_LOG(LogZMMO, Log, TEXT("ZeusWorldSubsystem: local entity registered EntityId=%lld actor=%s"),
|
UE_LOG(LogZMMO, Log, TEXT("ZeusWorldSubsystem: local entity registered EntityId=%lld actor=%s"),
|
||||||
EntityId, *GetNameSafe(LocalActor));
|
EntityId, *GetNameSafe(LocalActor));
|
||||||
}
|
}
|
||||||
@@ -255,10 +261,63 @@ void UZeusWorldSubsystem::HandlePlayerSpawned(const int64 EntityId, const bool b
|
|||||||
}
|
}
|
||||||
|
|
||||||
RemoteEntities.Add(EntityId, TWeakObjectPtr<AActor>(SpawnedActor));
|
RemoteEntities.Add(EntityId, TWeakObjectPtr<AActor>(SpawnedActor));
|
||||||
|
// V1-CHARINFO: o nome chega ANTES do ator (server emite ENT_CHAR_INFO antes
|
||||||
|
// do ENT_SPAWN); aplica agora que o proxy + PlayerState ja existem.
|
||||||
|
FlushPendingCharInfo(EntityId);
|
||||||
UE_LOG(LogZMMO, Log, TEXT("ZeusWorldSubsystem: spawned remote EntityId=%d at (%s) yaw=%.1f t=%lld"),
|
UE_LOG(LogZMMO, Log, TEXT("ZeusWorldSubsystem: spawned remote EntityId=%d at (%s) yaw=%.1f t=%lld"),
|
||||||
EntityId, *PosCm.ToString(), YawDeg, ServerTimeMs);
|
EntityId, *PosCm.ToString(), YawDeg, ServerTimeMs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void UZeusWorldSubsystem::OnNetCharInfo(const int64 EntityId, const FString& CharName, const FString& GuildName)
|
||||||
|
{
|
||||||
|
if (EntityId == 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Aplica direto se o ator/PlayerState ja existe; senao guarda pra aplicar no spawn.
|
||||||
|
if (!ApplyCharInfoToEntity(EntityId, CharName, GuildName))
|
||||||
|
{
|
||||||
|
PendingCharInfo.Add(EntityId, FZeusPendingCharInfo{ CharName, GuildName });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UZeusWorldSubsystem::ApplyCharInfoToEntity(const int64 EntityId, const FString& CharName, const FString& GuildName)
|
||||||
|
{
|
||||||
|
const TWeakObjectPtr<AActor>* Found = RemoteEntities.Find(EntityId);
|
||||||
|
if (!Found || !Found->IsValid())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
APawn* Pawn = Cast<APawn>(Found->Get());
|
||||||
|
if (!Pawn)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
AZeusPlayerState* PS = Pawn->GetPlayerState<AZeusPlayerState>();
|
||||||
|
if (!PS)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
PS->SetCharInfo(CharName, GuildName);
|
||||||
|
UE_LOG(LogZMMO, Log,
|
||||||
|
TEXT("ZeusWorldSubsystem: CHAR_INFO aplicado EntityId=%lld name='%s' guild='%s'"),
|
||||||
|
EntityId, *CharName, *GuildName);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UZeusWorldSubsystem::FlushPendingCharInfo(const int64 EntityId)
|
||||||
|
{
|
||||||
|
const FZeusPendingCharInfo* Pending = PendingCharInfo.Find(EntityId);
|
||||||
|
if (!Pending)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (ApplyCharInfoToEntity(EntityId, Pending->CharName, Pending->GuildName))
|
||||||
|
{
|
||||||
|
PendingCharInfo.Remove(EntityId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void UZeusWorldSubsystem::HandlePlayerDespawned(const int64 EntityId)
|
void UZeusWorldSubsystem::HandlePlayerDespawned(const int64 EntityId)
|
||||||
{
|
{
|
||||||
const TWeakObjectPtr<AActor>* Entry = RemoteEntities.Find(EntityId);
|
const TWeakObjectPtr<AActor>* Entry = RemoteEntities.Find(EntityId);
|
||||||
|
|||||||
@@ -96,10 +96,24 @@ private:
|
|||||||
UFUNCTION()
|
UFUNCTION()
|
||||||
void OnNetSelfEntityAssigned(int64 EntityId);
|
void OnNetSelfEntityAssigned(int64 EntityId);
|
||||||
|
|
||||||
|
// V1-CHARINFO: nome/guild do char (opcode ENT_CHAR_INFO 6045). Chega ANTES
|
||||||
|
// do ENT_SPAWN do proxy / do RegisterLocalEntity do self, entao se o ator
|
||||||
|
// ainda nao existe o dado fica em PendingCharInfo e e' aplicado no spawn.
|
||||||
|
UFUNCTION()
|
||||||
|
void OnNetCharInfo(int64 EntityId, const FString& CharName, const FString& GuildName);
|
||||||
|
|
||||||
UClass* ResolveActorClass(EZeusEntityType EntityType) const;
|
UClass* ResolveActorClass(EZeusEntityType EntityType) const;
|
||||||
UZeusNetworkSubsystem* ResolveZeusNetworkSubsystem() const;
|
UZeusNetworkSubsystem* ResolveZeusNetworkSubsystem() const;
|
||||||
UZeusNetworkingClientSubsystem* ResolveNetClientSubsystem() const;
|
UZeusNetworkingClientSubsystem* ResolveNetClientSubsystem() const;
|
||||||
|
|
||||||
|
// Aplica nome/guild no AZeusPlayerState do EntityId (self ou proxy). Retorna
|
||||||
|
// false se o ator/PlayerState ainda nao existe (caller deve cachear).
|
||||||
|
bool ApplyCharInfoToEntity(int64 EntityId, const FString& CharName, const FString& GuildName);
|
||||||
|
|
||||||
|
// Aplica (e consome) o char info pendente de EntityId, se houver. Chamado
|
||||||
|
// quando o ator passa a existir (spawn de proxy / RegisterLocalEntity).
|
||||||
|
void FlushPendingCharInfo(int64 EntityId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Registry de proxies remotos. Chave = `EntityId` autoritativo do servidor.
|
* Registry de proxies remotos. Chave = `EntityId` autoritativo do servidor.
|
||||||
* Usamos `TWeakObjectPtr` para nao impedir GC se algo der errado e o ator
|
* Usamos `TWeakObjectPtr` para nao impedir GC se algo der errado e o ator
|
||||||
@@ -110,4 +124,12 @@ private:
|
|||||||
|
|
||||||
/** Cached id do jogador local, para ignorar snapshots dele (cliente solto). */
|
/** Cached id do jogador local, para ignorar snapshots dele (cliente solto). */
|
||||||
int64 LocalEntityId = 0;
|
int64 LocalEntityId = 0;
|
||||||
|
|
||||||
|
/** V1-CHARINFO: nome/guild recebido antes do ator existir. Chave = EntityId. */
|
||||||
|
struct FZeusPendingCharInfo
|
||||||
|
{
|
||||||
|
FString CharName;
|
||||||
|
FString GuildName;
|
||||||
|
};
|
||||||
|
TMap<int64, FZeusPendingCharInfo> PendingCharInfo;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
#include "ZeusGameInstance.h"
|
#include "ZeusGameInstance.h"
|
||||||
#include "ZeusThemeSubsystem.h"
|
#include "ZeusThemeSubsystem.h"
|
||||||
#include "ZeusNetworkSubsystem.h"
|
#include "ZeusNetworkSubsystem.h"
|
||||||
|
#include "ZeusNetworkingClientSubsystem.h" // V1 canonico (sinal de spawn local)
|
||||||
#include "ZeusCharServerSubsystem.h"
|
#include "ZeusCharServerSubsystem.h"
|
||||||
#include "CommonActivatableWidget.h"
|
#include "CommonActivatableWidget.h"
|
||||||
#include "Engine/DataTable.h"
|
#include "Engine/DataTable.h"
|
||||||
@@ -265,6 +266,12 @@ UZeusNetworkSubsystem* UUIFrontEndFlowSubsystem::GetZeusNetwork() const
|
|||||||
return GI ? GI->GetSubsystem<UZeusNetworkSubsystem>() : nullptr;
|
return GI ? GI->GetSubsystem<UZeusNetworkSubsystem>() : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UZeusNetworkingClientSubsystem* UUIFrontEndFlowSubsystem::GetNetClient() const
|
||||||
|
{
|
||||||
|
const UGameInstance* GI = GetGameInstance();
|
||||||
|
return GI ? GI->GetSubsystem<UZeusNetworkingClientSubsystem>() : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
UZeusCharServerSubsystem* UUIFrontEndFlowSubsystem::GetCharServer() const
|
UZeusCharServerSubsystem* UUIFrontEndFlowSubsystem::GetCharServer() const
|
||||||
{
|
{
|
||||||
const UGameInstance* GI = GetGameInstance();
|
const UGameInstance* GI = GetGameInstance();
|
||||||
@@ -314,11 +321,20 @@ void UUIFrontEndFlowSubsystem::BindNetwork()
|
|||||||
Char->OnConnectionFailed.AddDynamic(this, &UUIFrontEndFlowSubsystem::HandleConnectionFailed);
|
Char->OnConnectionFailed.AddDynamic(this, &UUIFrontEndFlowSubsystem::HandleConnectionFailed);
|
||||||
Char->OnDisconnected.AddDynamic(this, &UUIFrontEndFlowSubsystem::HandleCharDisconnected);
|
Char->OnDisconnected.AddDynamic(this, &UUIFrontEndFlowSubsystem::HandleCharDisconnected);
|
||||||
}
|
}
|
||||||
// UDP (world server) só interessa para o handoff de travel.
|
// UDP (world server): o travel (TRAVEL_TO_MAP) ainda passa pelo objeto legacy
|
||||||
|
// como PONTE (HandleTravelToMap V1 reusa OnServerTravelRequested) -- isso some
|
||||||
|
// na Fase D quando o travel ganhar delegate proprio no V1.
|
||||||
if (UZeusNetworkSubsystem* Zeus = GetZeusNetwork())
|
if (UZeusNetworkSubsystem* Zeus = GetZeusNetwork())
|
||||||
{
|
{
|
||||||
Zeus->OnServerTravelRequested.AddDynamic(this, &UUIFrontEndFlowSubsystem::HandleServerTravelRequested);
|
Zeus->OnServerTravelRequested.AddDynamic(this, &UUIFrontEndFlowSubsystem::HandleServerTravelRequested);
|
||||||
Zeus->OnPlayerSpawned.AddDynamic(this, &UUIFrontEndFlowSubsystem::HandlePlayerSpawned);
|
}
|
||||||
|
// V1 CANONICO: o spawn do player local chega via ENT_SELF (o cliente aprende
|
||||||
|
// o proprio entityId) -> OnSelfEntityAssigned. O legacy OnPlayerSpawned NAO
|
||||||
|
// dispara mais com V1, entao a etapa "Spawn" do loading ficava eterna
|
||||||
|
// (loading travado). Liga a etapa ao sinal V1.
|
||||||
|
if (UZeusNetworkingClientSubsystem* Net = GetNetClient())
|
||||||
|
{
|
||||||
|
Net->OnSelfEntityAssigned.AddDynamic(this, &UUIFrontEndFlowSubsystem::HandleV1LocalSpawned);
|
||||||
}
|
}
|
||||||
bNetBound = true;
|
bNetBound = true;
|
||||||
}
|
}
|
||||||
@@ -338,7 +354,10 @@ void UUIFrontEndFlowSubsystem::UnbindNetwork()
|
|||||||
if (UZeusNetworkSubsystem* Zeus = GetZeusNetwork())
|
if (UZeusNetworkSubsystem* Zeus = GetZeusNetwork())
|
||||||
{
|
{
|
||||||
Zeus->OnServerTravelRequested.RemoveDynamic(this, &UUIFrontEndFlowSubsystem::HandleServerTravelRequested);
|
Zeus->OnServerTravelRequested.RemoveDynamic(this, &UUIFrontEndFlowSubsystem::HandleServerTravelRequested);
|
||||||
Zeus->OnPlayerSpawned.RemoveDynamic(this, &UUIFrontEndFlowSubsystem::HandlePlayerSpawned);
|
}
|
||||||
|
if (UZeusNetworkingClientSubsystem* Net = GetNetClient())
|
||||||
|
{
|
||||||
|
Net->OnSelfEntityAssigned.RemoveDynamic(this, &UUIFrontEndFlowSubsystem::HandleV1LocalSpawned);
|
||||||
}
|
}
|
||||||
bNetBound = false;
|
bNetBound = false;
|
||||||
}
|
}
|
||||||
@@ -505,6 +524,13 @@ void UUIFrontEndFlowSubsystem::HandlePlayerSpawned(int64 /*EntityId*/, bool bIsL
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void UUIFrontEndFlowSubsystem::HandleV1LocalSpawned(int64 EntityId)
|
||||||
|
{
|
||||||
|
// ENT_SELF e' SEMPRE o proprio char (o cliente aprendendo seu entityId), entao
|
||||||
|
// bIsLocal=true. Reusa a logica de marcar a etapa "Spawn" + memoizacao anti-race.
|
||||||
|
HandlePlayerSpawned(EntityId, /*bIsLocal=*/true, FVector::ZeroVector, 0.0f, 0);
|
||||||
|
}
|
||||||
|
|
||||||
void UUIFrontEndFlowSubsystem::HandleLoadingComplete()
|
void UUIFrontEndFlowSubsystem::HandleLoadingComplete()
|
||||||
{
|
{
|
||||||
if (UUILoadingScreen_Base* Loading = ActiveLoadingScreen.Get())
|
if (UUILoadingScreen_Base* Loading = ActiveLoadingScreen.Get())
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ class UUIManagerSubsystem;
|
|||||||
class UUILoadingScreen_Base;
|
class UUILoadingScreen_Base;
|
||||||
class UZeusLoadingProfilesDataAsset;
|
class UZeusLoadingProfilesDataAsset;
|
||||||
class UZeusNetworkSubsystem;
|
class UZeusNetworkSubsystem;
|
||||||
|
class UZeusNetworkingClientSubsystem;
|
||||||
class UZeusCharServerSubsystem;
|
class UZeusCharServerSubsystem;
|
||||||
struct FZeusMapDef;
|
struct FZeusMapDef;
|
||||||
|
|
||||||
@@ -171,6 +172,7 @@ private:
|
|||||||
void BindNetwork();
|
void BindNetwork();
|
||||||
void UnbindNetwork();
|
void UnbindNetwork();
|
||||||
UZeusNetworkSubsystem* GetZeusNetwork() const;
|
UZeusNetworkSubsystem* GetZeusNetwork() const;
|
||||||
|
UZeusNetworkingClientSubsystem* GetNetClient() const; // V1 canonico
|
||||||
UZeusCharServerSubsystem* GetCharServer() const;
|
UZeusCharServerSubsystem* GetCharServer() const;
|
||||||
UUIManagerSubsystem* GetUIManager() const;
|
UUIManagerSubsystem* GetUIManager() const;
|
||||||
UUIFrontEndScreenSet* GetScreenSet();
|
UUIFrontEndScreenSet* GetScreenSet();
|
||||||
@@ -198,6 +200,15 @@ private:
|
|||||||
void HandlePlayerSpawned(int64 EntityId, bool bIsLocal, FVector PosCm,
|
void HandlePlayerSpawned(int64 EntityId, bool bIsLocal, FVector PosCm,
|
||||||
float YawDeg, int64 ServerTimeMs);
|
float YawDeg, int64 ServerTimeMs);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* V1 canonico: o spawn do player local chega via ENT_SELF (o cliente
|
||||||
|
* aprende o proprio entityId) -> OnSelfEntityAssigned. Marca a etapa
|
||||||
|
* "Spawn" do loading no fluxo V1 (o legacy OnPlayerSpawned nao dispara
|
||||||
|
* mais). Adapta a assinatura OneParam pra logica de HandlePlayerSpawned.
|
||||||
|
*/
|
||||||
|
UFUNCTION()
|
||||||
|
void HandleV1LocalSpawned(int64 EntityId);
|
||||||
|
|
||||||
/** Disparado pela tela de loading quando todas as etapas viram Done. */
|
/** Disparado pela tela de loading quando todas as etapas viram Done. */
|
||||||
UFUNCTION()
|
UFUNCTION()
|
||||||
void HandleLoadingComplete();
|
void HandleLoadingComplete();
|
||||||
|
|||||||
Reference in New Issue
Block a user