diff --git a/Source/ZMMO/Game/UI/FrontEnd/UIFrontEndFlowSubsystem.cpp b/Source/ZMMO/Game/UI/FrontEnd/UIFrontEndFlowSubsystem.cpp index 2165ad4..a4c18b2 100644 --- a/Source/ZMMO/Game/UI/FrontEnd/UIFrontEndFlowSubsystem.cpp +++ b/Source/ZMMO/Game/UI/FrontEnd/UIFrontEndFlowSubsystem.cpp @@ -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__" — 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); }