refactor: prefixo ZMMO -> Zeus em classes/módulos C++ do cliente
- Renomeia ~50 classes UCLASS/USTRUCT/UENUM/UINTERFACE pra Zeus* (AZeusGameMode, AZeusCharacter, UZeusGameInstance, IZeusEntityInterface, UZeusWorldSubsystem, FZeusEntitySnapshot, etc.) - Encurta AZMMOPlayerCharacter -> AZeusCharacter - Renomeia módulos satélite ZMMOAttributes -> ZeusAttributes e ZMMOJobs -> ZeusJobs (pasta + .Build.cs + .uproject) - Mantém módulo principal ZMMO (renomeia depois quando jogo ganhar nome) - DefaultEngine.ini: ActiveClassRedirects ZMMOX -> ZeusX (preserva BPs/assets) - DefaultGame.ini: sections atualizadas pra ZeusThemeSubsystem/ZeusPlayerState - Category="ZMMO|..." -> "Zeus|..." em UPROPERTYs - Preserva LogZMMO, ZMMO_API, /Script/ZMMO., /Game/ZMMO/, classes Target Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
218
Source/ZeusAttributes/Private/ZeusAttributeNetworkHandler.cpp
Normal file
218
Source/ZeusAttributes/Private/ZeusAttributeNetworkHandler.cpp
Normal file
@@ -0,0 +1,218 @@
|
||||
#include "ZeusAttributeNetworkHandler.h"
|
||||
|
||||
#include "Engine/GameInstance.h"
|
||||
#include "Engine/World.h"
|
||||
#include "GameFramework/GameStateBase.h"
|
||||
#include "GameFramework/PlayerController.h"
|
||||
#include "GameFramework/PlayerState.h"
|
||||
#include "ZeusAttributeComponent.h"
|
||||
#include "ZeusAttributeTypes.h"
|
||||
#include "ZeusNetworkSubsystem.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
// Helper privado — converte o payload binario do plugin pra USTRUCT
|
||||
// Blueprint que o componente exibe.
|
||||
FZeusAttributesSnapshot ToSnapshot(const FZeusAttributesPayload& P)
|
||||
{
|
||||
FZeusAttributesSnapshot S;
|
||||
S.EntityId = P.EntityId;
|
||||
S.ClassId = P.ClassId;
|
||||
S.BaseLevel = P.BaseLevel;
|
||||
S.BaseExp = P.BaseExp;
|
||||
S.BaseExpToNext = P.BaseExpToNext;
|
||||
S.JobLevel = P.JobLevel;
|
||||
S.JobExp = P.JobExp;
|
||||
S.JobExpToNext = P.JobExpToNext;
|
||||
S.Str = P.Str;
|
||||
S.Agi = P.Agi;
|
||||
S.Vit = P.Vit;
|
||||
S.Int = P.Int;
|
||||
S.Dex = P.Dex;
|
||||
S.Luk = P.Luk;
|
||||
S.StatusPoint = P.StatusPoint;
|
||||
S.SkillPoint = P.SkillPoint;
|
||||
S.Hp = P.Hp;
|
||||
S.MaxHp = P.MaxHp;
|
||||
S.Sp = P.Sp;
|
||||
S.MaxSp = P.MaxSp;
|
||||
S.Money = P.Money;
|
||||
S.AtkBase = P.AtkBase;
|
||||
S.AtkEquipBonus = P.AtkEquipBonus;
|
||||
S.MatkBaseMin = P.MatkBaseMin;
|
||||
S.MatkBaseMax = P.MatkBaseMax;
|
||||
S.MatkEquipBonus = P.MatkEquipBonus;
|
||||
S.DefBase = P.DefBase;
|
||||
S.DefEquipBonus = P.DefEquipBonus;
|
||||
S.MdefBase = P.MdefBase;
|
||||
S.MdefEquipBonus = P.MdefEquipBonus;
|
||||
S.HitBase = P.HitBase;
|
||||
S.HitEquipBonus = P.HitEquipBonus;
|
||||
S.FleeBase = P.FleeBase;
|
||||
S.FleeEquipBonus = P.FleeEquipBonus;
|
||||
S.CritBaseX10 = P.CritBaseX10;
|
||||
S.CritEquipBonusX10 = P.CritEquipBonusX10;
|
||||
S.Aspd = P.Aspd;
|
||||
return S;
|
||||
}
|
||||
|
||||
// Resolve `EntityId -> UZeusAttributeComponent` via PlayerArray do GameState.
|
||||
// AttributeComponent agora vive no PlayerState (vide AZeusPlayerState +
|
||||
// Component Registry em DefaultGame.ini). Itera apenas players (1 por
|
||||
// conexao), nao 1000+ atores — O(N_players).
|
||||
//
|
||||
// Cada UZeusAttributeComponent carrega seu proprio EntityId (seed em
|
||||
// AZeusCharacter::HandleLocalSpawnReady ou no primeiro snapshot).
|
||||
UZeusAttributeComponent* FindComponentForEntity(UWorld* World, int64 EntityId) // PR-HANDOFF-007 int64
|
||||
{
|
||||
if (!World || EntityId == 0) { return nullptr; }
|
||||
const AGameStateBase* GS = World->GetGameState();
|
||||
if (!GS) { return nullptr; }
|
||||
for (APlayerState* PS : GS->PlayerArray)
|
||||
{
|
||||
if (!PS) { continue; }
|
||||
UZeusAttributeComponent* Comp = PS->FindComponentByClass<UZeusAttributeComponent>();
|
||||
if (!Comp) { continue; }
|
||||
if (Comp->GetSnapshot().EntityId == EntityId)
|
||||
{
|
||||
return Comp;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool UZeusAttributeNetworkHandler::ShouldCreateSubsystem(UObject* Outer) const
|
||||
{
|
||||
// Cria apenas para mundos de gameplay (PIE/Game), nao para editor preview.
|
||||
UWorld* World = Cast<UWorld>(Outer);
|
||||
if (!World) { return false; }
|
||||
return World->WorldType == EWorldType::Game || World->WorldType == EWorldType::PIE;
|
||||
}
|
||||
|
||||
void UZeusAttributeNetworkHandler::Initialize(FSubsystemCollectionBase& Collection)
|
||||
{
|
||||
Super::Initialize(Collection);
|
||||
|
||||
if (UZeusNetworkSubsystem* Net = GetZeusNetSubsystem())
|
||||
{
|
||||
SnapshotFullHandle = Net->OnAttributeSnapshotFull.AddUObject(
|
||||
this, &UZeusAttributeNetworkHandler::HandleAttributeSnapshotFull);
|
||||
HpSpUpdateHandle = Net->OnHpSpUpdate.AddUObject(
|
||||
this, &UZeusAttributeNetworkHandler::HandleHpSpUpdate);
|
||||
LevelUpHandle = Net->OnLevelUp.AddUObject(
|
||||
this, &UZeusAttributeNetworkHandler::HandleLevelUp);
|
||||
StatAllocReplyHandle = Net->OnStatAllocReply.AddUObject(
|
||||
this, &UZeusAttributeNetworkHandler::HandleStatAllocReply);
|
||||
}
|
||||
}
|
||||
|
||||
void UZeusAttributeNetworkHandler::Deinitialize()
|
||||
{
|
||||
if (UZeusNetworkSubsystem* Net = GetZeusNetSubsystem())
|
||||
{
|
||||
if (SnapshotFullHandle.IsValid())
|
||||
{
|
||||
Net->OnAttributeSnapshotFull.Remove(SnapshotFullHandle);
|
||||
SnapshotFullHandle.Reset();
|
||||
}
|
||||
if (HpSpUpdateHandle.IsValid())
|
||||
{
|
||||
Net->OnHpSpUpdate.Remove(HpSpUpdateHandle);
|
||||
HpSpUpdateHandle.Reset();
|
||||
}
|
||||
if (LevelUpHandle.IsValid())
|
||||
{
|
||||
Net->OnLevelUp.Remove(LevelUpHandle);
|
||||
LevelUpHandle.Reset();
|
||||
}
|
||||
if (StatAllocReplyHandle.IsValid())
|
||||
{
|
||||
Net->OnStatAllocReply.Remove(StatAllocReplyHandle);
|
||||
StatAllocReplyHandle.Reset();
|
||||
}
|
||||
}
|
||||
Super::Deinitialize();
|
||||
}
|
||||
|
||||
UZeusNetworkSubsystem* UZeusAttributeNetworkHandler::GetZeusNetSubsystem() const
|
||||
{
|
||||
const UWorld* World = GetWorld();
|
||||
if (!World) { return nullptr; }
|
||||
UGameInstance* GI = World->GetGameInstance();
|
||||
if (!GI) { return nullptr; }
|
||||
return GI->GetSubsystem<UZeusNetworkSubsystem>();
|
||||
}
|
||||
|
||||
void UZeusAttributeNetworkHandler::HandleAttributeSnapshotFull(const FZeusAttributesPayload& Payload)
|
||||
{
|
||||
UWorld* World = GetWorld();
|
||||
if (!World) { return; }
|
||||
UZeusAttributeComponent* Comp = FindComponentForEntity(World, Payload.EntityId);
|
||||
if (!Comp)
|
||||
{
|
||||
// Fallback chicken-and-egg: primeiro snapshot chega antes do EntityId
|
||||
// estar seeded no componente. Aplica ao primeiro componente do
|
||||
// PlayerArray que ainda tem EntityId=0. Apos o primeiro apply, o
|
||||
// caminho normal por lookup funciona.
|
||||
const AGameStateBase* GS = World->GetGameState();
|
||||
if (GS)
|
||||
{
|
||||
for (APlayerState* PS : GS->PlayerArray)
|
||||
{
|
||||
if (!PS) { continue; }
|
||||
UZeusAttributeComponent* Candidate = PS->FindComponentByClass<UZeusAttributeComponent>();
|
||||
if (Candidate && Candidate->GetSnapshot().EntityId == 0)
|
||||
{
|
||||
Comp = Candidate;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (Comp)
|
||||
{
|
||||
Comp->ApplySnapshot(ToSnapshot(Payload));
|
||||
}
|
||||
}
|
||||
|
||||
void UZeusAttributeNetworkHandler::HandleHpSpUpdate(int64 EntityId, int32 Hp, int32 Sp)
|
||||
{
|
||||
UWorld* World = GetWorld();
|
||||
if (!World) { return; }
|
||||
UZeusAttributeComponent* Comp = FindComponentForEntity(World, EntityId);
|
||||
if (Comp)
|
||||
{
|
||||
Comp->ApplyHpSpUpdate(Hp, Sp);
|
||||
}
|
||||
}
|
||||
|
||||
void UZeusAttributeNetworkHandler::HandleLevelUp(int64 EntityId, int32 NewBaseLevel, int32 StatusPointDelta)
|
||||
{
|
||||
UWorld* World = GetWorld();
|
||||
if (!World) { return; }
|
||||
UZeusAttributeComponent* Comp = FindComponentForEntity(World, EntityId);
|
||||
if (Comp)
|
||||
{
|
||||
Comp->NotifyLevelUp(NewBaseLevel, StatusPointDelta);
|
||||
}
|
||||
}
|
||||
|
||||
void UZeusAttributeNetworkHandler::HandleStatAllocReply(bool bAccepted, int32 Reason)
|
||||
{
|
||||
// S_ATTRIBUTE_STAT_ALLOC_OK nao traz EntityId no payload — sempre do
|
||||
// player local que fez o request. Busca o AttributeComponent via PC.
|
||||
if (UZeusAttributeComponent* Comp = FindLocalPlayerAttributeComponent())
|
||||
{
|
||||
Comp->NotifyStatAllocReply(bAccepted, Reason);
|
||||
}
|
||||
}
|
||||
|
||||
UZeusAttributeComponent* UZeusAttributeNetworkHandler::FindLocalPlayerAttributeComponent() const
|
||||
{
|
||||
UWorld* World = GetWorld();
|
||||
if (!World) { return nullptr; }
|
||||
APlayerController* PC = World->GetFirstPlayerController();
|
||||
if (!PC || !PC->PlayerState) { return nullptr; }
|
||||
return PC->PlayerState->FindComponentByClass<UZeusAttributeComponent>();
|
||||
}
|
||||
Reference in New Issue
Block a user