fix(frontend): HandleServerTravelRequested idempotente quando ja no mapa certo
Cliente fazia OpenLevel 2x: 1. CharSelect resolve mapId via DT_Maps -> TravelToMapById -> OpenLevel 2. Server confirma com S_TRAVEL_TO_MAP -> HandleServerTravelRequested -> OpenLevel **de novo** O segundo OpenLevel destruia o World, PlayerState, AttributeComponent e HUD que ja tinham sido criados/bindados. AttributeComponent novo iniciava com snapshot vazio (entity=0, level=1, hp=0/0) — HUD ficava nesse default. S_ATTRIBUTE_SNAPSHOT_FULL com dados reais chegava DEPOIS do reload, mas HUD nao tinha sido recriado/reativado no novo mundo, entao HandleAttributesChanged nunca rodava. A deduplicacao em ZeusNetworkSubsystem (`S_TRAVEL_TO_MAP duplicate ignored`) so pegava do 3o TRAVEL em diante — o 2o ja fazia o estrago. Fix: compara nome curto do World atual (strip prefixo UEDPIE_N_ do PIE) com o target. Se ja' estao no mesmo mapa, skipa OpenLevel e so seta state pra InWorld — preservando HUD/PlayerState/AttributeComponent.
This commit is contained in:
@@ -19,7 +19,9 @@
|
||||
#include "UObject/UObjectGlobals.h"
|
||||
#include "Engine/AssetManager.h"
|
||||
#include "Engine/StreamableManager.h"
|
||||
#include "Engine/World.h"
|
||||
#include "Kismet/GameplayStatics.h"
|
||||
#include "Misc/PackageName.h"
|
||||
|
||||
void UUIFrontEndFlowSubsystem::Initialize(FSubsystemCollectionBase& Collection)
|
||||
{
|
||||
@@ -406,6 +408,46 @@ void UUIFrontEndFlowSubsystem::ClearSelectedRealm()
|
||||
void UUIFrontEndFlowSubsystem::HandleServerTravelRequested(const FString& MapName, const FString& MapPath)
|
||||
{
|
||||
UE_LOG(LogZMMO, Log, TEXT("FrontEndFlow: travel pedido pelo servidor → %s (%s)."), *MapName, *MapPath);
|
||||
|
||||
// Idempotencia: se o cliente JA carregou esse mapa via TravelToMapById
|
||||
// (ex: Lobby após CharSelect resolveu DT_Maps), e o S_TRAVEL_TO_MAP do
|
||||
// servidor chega DEPOIS confirmando, NAO recarrega. Recarregar destruiria
|
||||
// HUD, PlayerState e AttributeComponent — perdendo o snapshot ja aplicado.
|
||||
if (!MapPath.IsEmpty())
|
||||
{
|
||||
if (const UWorld* CurrentWorld = GetWorld())
|
||||
{
|
||||
// CurrentWorld->GetOutermost()->GetName() devolve algo como
|
||||
// "/Game/ZMMO/Maps/World/UEDPIE_0_L_TestWorld" no PIE. Comparamos
|
||||
// pelo nome curto pra ignorar prefixo UEDPIE_N_.
|
||||
const FString CurrentShort = FPackageName::GetShortName(CurrentWorld->GetOutermost()->GetName());
|
||||
const FString TargetShort = FPackageName::GetShortName(MapPath);
|
||||
// PIE prefixa "UEDPIE_<N>_<MapName>" — strip se presente.
|
||||
FString CurrentClean = CurrentShort;
|
||||
int32 UndIdx = INDEX_NONE;
|
||||
if (CurrentClean.StartsWith(TEXT("UEDPIE_")) && CurrentClean.FindChar('_', UndIdx))
|
||||
{
|
||||
const int32 SecondUnd = CurrentClean.Find(TEXT("_"), ESearchCase::CaseSensitive, ESearchDir::FromStart, UndIdx + 1);
|
||||
if (SecondUnd != INDEX_NONE)
|
||||
{
|
||||
CurrentClean = CurrentClean.Mid(SecondUnd + 1);
|
||||
}
|
||||
}
|
||||
if (CurrentClean.Equals(TargetShort, ESearchCase::IgnoreCase))
|
||||
{
|
||||
UE_LOG(LogZMMO, Log,
|
||||
TEXT("FrontEndFlow: ja estamos em %s — ignorando OpenLevel do S_TRAVEL_TO_MAP (mantem HUD/PlayerState)"),
|
||||
*TargetShort);
|
||||
bTravelingToWorld = false;
|
||||
if (CurrentState != EZMMOFrontEndState::InWorld)
|
||||
{
|
||||
SetState(EZMMOFrontEndState::InWorld);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bTravelingToWorld = true;
|
||||
SetState(EZMMOFrontEndState::EnteringWorld);
|
||||
|
||||
@@ -415,9 +457,6 @@ void UUIFrontEndFlowSubsystem::HandleServerTravelRequested(const FString& MapNam
|
||||
// World Settings do .umap podem ter override herdado de L_FrontEnd
|
||||
// (GameModeOverride=ZMMOFrontEndGameMode) — sobrescrevemos via URL
|
||||
// option pra nao depender de cada artista configurar.
|
||||
// Evolucao natural: quando o WorldServer enviar GameMode no
|
||||
// S_TRAVEL_TO_MAP (wire estendido), trocar este literal por
|
||||
// `?game=` + valor recebido do server.
|
||||
const FString Options = TEXT("game=/Script/ZMMO.ZMMOGameMode");
|
||||
UGameplayStatics::OpenLevel(GetGameInstance(), FName(*MapPath), /*bAbsolute=*/true, Options);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user