diff --git a/Source/ZMMO/Game/Network/ZeusAOIComponent.cpp b/Source/ZMMO/Game/Network/ZeusAOIComponent.cpp index c52275c..4ef4005 100644 --- a/Source/ZMMO/Game/Network/ZeusAOIComponent.cpp +++ b/Source/ZMMO/Game/Network/ZeusAOIComponent.cpp @@ -2,14 +2,18 @@ #include "ZeusAOIComponent.h" +#include "ZeusNetworkSubsystem.h" // plugin ZeusNetwork: OnDebugAoiInfo + SendDebugAoiRequest + #include "DrawDebugHelpers.h" +#include "Engine/GameInstance.h" +#include "Engine/World.h" #include "GameFramework/Actor.h" // Console vars — espelham as flags do painel (overlay liga se flag OU CVar). static TAutoConsoleVariable CVarShowAOI( - TEXT("zeus.debug.aoi"), 0, TEXT("Desenha a esfera de AOI do player local."), ECVF_Default); -static TAutoConsoleVariable CVarShowSpawn( - TEXT("zeus.debug.spawn"), 0, TEXT("Desenha a zona de spawn (placeholder)."), ECVF_Default); + TEXT("zeus.debug.aoi"), 0, TEXT("Desenha a Zona de Interesse (esfera do raio AOI)."), ECVF_Default); +static TAutoConsoleVariable CVarShowDespawn( + TEXT("zeus.debug.despawn"), 0, TEXT("Desenha a Zona de Despawn (esfera externa do AOI)."), ECVF_Default); static TAutoConsoleVariable CVarShowCell( TEXT("zeus.debug.cell"), 0, TEXT("Desenha os bounds da celula (placeholder)."), ECVF_Default); static TAutoConsoleVariable CVarShowProxy( @@ -21,8 +25,8 @@ static TAutoConsoleVariable CVarShowDrift( namespace { - const FColor kColorAOI(93, 213, 255); - const FColor kColorSpawn(122, 219, 138); + const FColor kColorInterest(93, 213, 255); // cyan — Zona de Interesse + const FColor kColorDespawn(255, 140, 90); // laranja — Zona de Despawn (externa) const FColor kColorCell(232, 192, 96); const FColor kColorHandoff(255, 155, 190); } @@ -34,6 +38,46 @@ UZeusAOIComponent::UZeusAOIComponent() SetIsReplicatedByDefault(false); // debug/cliente; gameplay AOI real entra depois } +void UZeusAOIComponent::BeginPlay() +{ + Super::BeginPlay(); + + // Bind do feed de config de AOI (servidor -> cliente). Multicast plain C++. + if (UWorld* World = GetWorld()) + { + if (UGameInstance* GI = World->GetGameInstance()) + { + if (UZeusNetworkSubsystem* Net = GI->GetSubsystem()) + { + AoiConfigHandle_ = Net->OnDebugAoiInfo.AddUObject(this, &UZeusAOIComponent::HandleAoiConfig); + } + } + } + + // Best-effort: ja' pede a config (no-op se ainda nao conectado — o request + // e' re-disparado ao ligar um overlay em SetOverlayEnabled). + RequestAoiConfig(); +} + +void UZeusAOIComponent::EndPlay(const EEndPlayReason::Type EndPlayReason) +{ + if (AoiConfigHandle_.IsValid()) + { + if (UWorld* World = GetWorld()) + { + if (UGameInstance* GI = World->GetGameInstance()) + { + if (UZeusNetworkSubsystem* Net = GI->GetSubsystem()) + { + Net->OnDebugAoiInfo.Remove(AoiConfigHandle_); + } + } + } + AoiConfigHandle_.Reset(); + } + Super::EndPlay(EndPlayReason); +} + void UZeusAOIComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) { @@ -45,16 +89,36 @@ void UZeusAOIComponent::TickComponent(float DeltaTime, ELevelTick TickType, } } +void UZeusAOIComponent::RequestAoiConfig() +{ + if (UWorld* World = GetWorld()) + { + if (UGameInstance* GI = World->GetGameInstance()) + { + if (UZeusNetworkSubsystem* Net = GI->GetSubsystem()) + { + Net->SendDebugAoiRequest(); // no-op se nao conectado + } + } + } +} + +void UZeusAOIComponent::HandleAoiConfig(float InterestCm, float DespawnCm) +{ + InterestRadiusCm = InterestCm; + DespawnRadiusCm = DespawnCm; +} + bool UZeusAOIComponent::ResolveOverlay(EZeusAOIOverlay Overlay) const { switch (Overlay) { - case EZeusAOIOverlay::AOIRadius: return bShowAOIRadius || CVarShowAOI.GetValueOnGameThread() > 0; - case EZeusAOIOverlay::SpawnZone: return bShowSpawnZone || CVarShowSpawn.GetValueOnGameThread() > 0; - case EZeusAOIOverlay::CellBounds: return bShowCellBounds || CVarShowCell.GetValueOnGameThread() > 0; - case EZeusAOIOverlay::ProxyLabels: return bShowProxyLabels || CVarShowProxy.GetValueOnGameThread() > 0; - case EZeusAOIOverlay::HandoffLine: return bShowHandoffLine || CVarShowHandoff.GetValueOnGameThread() > 0; - case EZeusAOIOverlay::AuthDrift: return bShowAuthDrift || CVarShowDrift.GetValueOnGameThread() > 0; + case EZeusAOIOverlay::AOIRadius: return bShowAOIRadius || CVarShowAOI.GetValueOnGameThread() > 0; + case EZeusAOIOverlay::DespawnZone: return bShowDespawnZone || CVarShowDespawn.GetValueOnGameThread() > 0; + case EZeusAOIOverlay::CellBounds: return bShowCellBounds || CVarShowCell.GetValueOnGameThread() > 0; + case EZeusAOIOverlay::ProxyLabels: return bShowProxyLabels || CVarShowProxy.GetValueOnGameThread() > 0; + case EZeusAOIOverlay::HandoffLine: return bShowHandoffLine || CVarShowHandoff.GetValueOnGameThread() > 0; + case EZeusAOIOverlay::AuthDrift: return bShowAuthDrift || CVarShowDrift.GetValueOnGameThread() > 0; default: return false; } } @@ -62,7 +126,7 @@ bool UZeusAOIComponent::ResolveOverlay(EZeusAOIOverlay Overlay) const bool UZeusAOIComponent::AnyOverlayActive() const { return ResolveOverlay(EZeusAOIOverlay::AOIRadius) - || ResolveOverlay(EZeusAOIOverlay::SpawnZone) + || ResolveOverlay(EZeusAOIOverlay::DespawnZone) || ResolveOverlay(EZeusAOIOverlay::CellBounds) || ResolveOverlay(EZeusAOIOverlay::ProxyLabels) || ResolveOverlay(EZeusAOIOverlay::HandoffLine) @@ -77,14 +141,16 @@ void UZeusAOIComponent::DrawOverlays() const FVector Loc = Owner->GetActorLocation(); - if (ResolveOverlay(EZeusAOIOverlay::AOIRadius)) + // Zona de Interesse (interna) — raio real do servidor. Sem o raio (==0), + // ainda nao chegou a config: nao desenha (loading). + if (ResolveOverlay(EZeusAOIOverlay::AOIRadius) && InterestRadiusCm > 0.0f) { - DrawDebugSphere(World, Loc, AOIRadiusCm, 32, kColorAOI, false, -1.0f, 0, LineThickness); + DrawDebugSphere(World, Loc, InterestRadiusCm, 32, kColorInterest, false, -1.0f, 0, LineThickness); } - if (ResolveOverlay(EZeusAOIOverlay::SpawnZone)) + // Zona de Despawn (externa, > interesse = histerese) — raio real do servidor. + if (ResolveOverlay(EZeusAOIOverlay::DespawnZone) && DespawnRadiusCm > 0.0f) { - // PLACEHOLDER: box em volta do player. TODO spawn zones reais do servidor. - DrawDebugBox(World, Loc, FVector(SpawnZoneExtentCm), kColorSpawn, false, -1.0f, 0, LineThickness); + DrawDebugSphere(World, Loc, DespawnRadiusCm, 32, kColorDespawn, false, -1.0f, 0, LineThickness); } if (ResolveOverlay(EZeusAOIOverlay::CellBounds)) { @@ -95,7 +161,8 @@ void UZeusAOIComponent::DrawOverlays() if (ResolveOverlay(EZeusAOIOverlay::HandoffLine)) { // PLACEHOLDER: vetor pra frente. TODO apontar pro centro da cell vizinha. - const FVector End = Loc + Owner->GetActorForwardVector() * AOIRadiusCm; + const float Len = InterestRadiusCm > 0.0f ? InterestRadiusCm : 3000.0f; + const FVector End = Loc + Owner->GetActorForwardVector() * Len; DrawDebugDirectionalArrow(World, Loc, End, 200.0f, kColorHandoff, false, -1.0f, 0, LineThickness); } // ProxyLabels / AuthDrift: TODO (precisam do registry de proxies/snapshots). @@ -106,19 +173,31 @@ void UZeusAOIComponent::SetOverlayEnabled_Implementation(EZeusAOIOverlay Overlay switch (Overlay) { case EZeusAOIOverlay::AOIRadius: bShowAOIRadius = bEnabled; break; - case EZeusAOIOverlay::SpawnZone: bShowSpawnZone = bEnabled; break; + case EZeusAOIOverlay::DespawnZone: bShowDespawnZone = bEnabled; break; case EZeusAOIOverlay::CellBounds: bShowCellBounds = bEnabled; break; case EZeusAOIOverlay::ProxyLabels: bShowProxyLabels = bEnabled; break; case EZeusAOIOverlay::HandoffLine: bShowHandoffLine = bEnabled; break; case EZeusAOIOverlay::AuthDrift: bShowAuthDrift = bEnabled; break; default: break; } + + // Ao ligar uma zona de AOI sem ter os raios ainda, pede a config (loading). + const bool bAoiZone = (Overlay == EZeusAOIOverlay::AOIRadius || Overlay == EZeusAOIOverlay::DespawnZone); + if (bEnabled && bAoiZone && InterestRadiusCm <= 0.0f) + { + RequestAoiConfig(); + } } void UZeusAOIComponent::SetAllOverlays_Implementation(bool bEnabled) { - bShowAOIRadius = bShowSpawnZone = bShowCellBounds = bEnabled; + bShowAOIRadius = bShowDespawnZone = bShowCellBounds = bEnabled; bShowProxyLabels = bShowHandoffLine = bShowAuthDrift = bEnabled; + + if (bEnabled && InterestRadiusCm <= 0.0f) + { + RequestAoiConfig(); + } } bool UZeusAOIComponent::IsOverlayEnabled_Implementation(EZeusAOIOverlay Overlay) const @@ -127,8 +206,18 @@ bool UZeusAOIComponent::IsOverlayEnabled_Implementation(EZeusAOIOverlay Overlay) return ResolveOverlay(Overlay); } +float UZeusAOIComponent::GetInterestRadiusCm_Implementation() const +{ + return InterestRadiusCm; // 0 = config do servidor ainda nao chegou (loading) +} + +float UZeusAOIComponent::GetDespawnRadiusCm_Implementation() const +{ + return DespawnRadiusCm; +} + int32 UZeusAOIComponent::GetEnabledOverlayCount() const { - return (bShowAOIRadius ? 1 : 0) + (bShowSpawnZone ? 1 : 0) + (bShowCellBounds ? 1 : 0) + return (bShowAOIRadius ? 1 : 0) + (bShowDespawnZone ? 1 : 0) + (bShowCellBounds ? 1 : 0) + (bShowProxyLabels ? 1 : 0) + (bShowHandoffLine ? 1 : 0) + (bShowAuthDrift ? 1 : 0); } diff --git a/Source/ZMMO/Game/Network/ZeusAOIComponent.h b/Source/ZMMO/Game/Network/ZeusAOIComponent.h index f901606..e91bab6 100644 --- a/Source/ZMMO/Game/Network/ZeusAOIComponent.h +++ b/Source/ZMMO/Game/Network/ZeusAOIComponent.h @@ -16,6 +16,12 @@ * DEBUG: overlays via DrawDebug* dirigidos pelo painel admin (plugin) atraves * de IZeusAOIDebugTarget, e/ou por console vars (zeus.debug.aoi etc.). * + * As DUAS zonas do AOI (Interesse interna + Despawn externa = histerese) vem do + * SERVIDOR: ao ligar um overlay (ou no BeginPlay) o componente pede a config via + * C_DEBUG_AOI_REQUEST e recebe S_DEBUG_AOI_INFO (delegate OnDebugAoiInfo do + * UZeusNetworkSubsystem) com interestRadiusCm + despawnRadiusCm. Enquanto nao + * chega (raio == 0), nao desenha (loading). + * * Vive na src do ZMMO (nao no plugin): e' um componente do JOGO. O plugin * ZeusAdminTools apenas COMUNICA com ele via a interface — direcao da * dependencia: ZMMO -> plugin (implementa a interface). @@ -28,6 +34,8 @@ class ZMMO_API UZeusAOIComponent : public UActorComponent, public IZeusAOIDebugT public: UZeusAOIComponent(); + virtual void BeginPlay() override; + virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override; virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override; @@ -35,18 +43,21 @@ public: virtual void SetOverlayEnabled_Implementation(EZeusAOIOverlay Overlay, bool bEnabled) override; virtual void SetAllOverlays_Implementation(bool bEnabled) override; virtual bool IsOverlayEnabled_Implementation(EZeusAOIOverlay Overlay) const override; + virtual float GetInterestRadiusCm_Implementation() const override; + virtual float GetDespawnRadiusCm_Implementation() const override; // === Flags de debug por overlay === - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Zeus|AOI Debug|Overlays") bool bShowAOIRadius = false; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Zeus|AOI Debug|Overlays") bool bShowSpawnZone = false; + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Zeus|AOI Debug|Overlays") bool bShowAOIRadius = false; // Zona de Interesse + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Zeus|AOI Debug|Overlays") bool bShowDespawnZone = false; // Zona de Despawn UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Zeus|AOI Debug|Overlays") bool bShowCellBounds = false; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Zeus|AOI Debug|Overlays") bool bShowProxyLabels = false; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Zeus|AOI Debug|Overlays") bool bShowHandoffLine = false; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Zeus|AOI Debug|Overlays") bool bShowAuthDrift = false; // === Parametros === - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Zeus|AOI Debug|Params") float AOIRadiusCm = 3000.0f; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Zeus|AOI Debug|Params") float SpawnZoneExtentCm = 800.0f; + // Raios reais vem do servidor (S_DEBUG_AOI_INFO). 0 = ainda nao recebido (loading). + UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Zeus|AOI Debug|Params") float InterestRadiusCm = 0.0f; + UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Zeus|AOI Debug|Params") float DespawnRadiusCm = 0.0f; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Zeus|AOI Debug|Params") float CellBoundsExtentCm = 50000.0f; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Zeus|AOI Debug|Params") float LineThickness = 2.0f; @@ -57,4 +68,14 @@ private: void DrawOverlays(); bool ResolveOverlay(EZeusAOIOverlay Overlay) const; bool AnyOverlayActive() const; + + /** Pede a config de AOI ao servidor (C_DEBUG_AOI_REQUEST). No-op se ja' temos + * os raios ou se nao houver UZeusNetworkSubsystem conectado. */ + void RequestAoiConfig(); + + /** Bind de UZeusNetworkSubsystem::OnDebugAoiInfo: armazena os raios reais. */ + void HandleAoiConfig(float InterestCm, float DespawnCm); + + /** Handle do bind do OnDebugAoiInfo (pra remover no EndPlay). */ + FDelegateHandle AoiConfigHandle_; };