diff --git a/Content/DynamicPawn.uasset b/Content/DynamicPawn.uasset index 377dc4b48..96278893e 100644 Binary files a/Content/DynamicPawn.uasset and b/Content/DynamicPawn.uasset differ diff --git a/Source/CesiumRuntime/Private/CesiumGeoreference.cpp b/Source/CesiumRuntime/Private/CesiumGeoreference.cpp index d134d962d..6b22575cb 100644 --- a/Source/CesiumRuntime/Private/CesiumGeoreference.cpp +++ b/Source/CesiumRuntime/Private/CesiumGeoreference.cpp @@ -4,7 +4,9 @@ #include "Camera/PlayerCameraManager.h" #include "CesiumActors.h" #include "CesiumCommon.h" +#include "CesiumCustomVersion.h" #include "CesiumGeospatial/Cartographic.h" +#include "CesiumOriginShiftComponent.h" #include "CesiumRuntime.h" #include "CesiumSubLevelComponent.h" #include "CesiumSubLevelSwitcherComponent.h" @@ -410,6 +412,8 @@ void ACesiumGeoreference::Tick(float DeltaTime) { void ACesiumGeoreference::Serialize(FArchive& Ar) { Super::Serialize(Ar); + Ar.UsingCustomVersion(FCesiumCustomVersion::GUID); + // Recompute derived values on load. if (Ar.IsLoading()) { this->_updateCoordinateSystem(); @@ -430,22 +434,6 @@ void ACesiumGeoreference::BeginPlay() { return; } - if (!this->SubLevelCamera) { - // Find the first player's camera manager - APlayerController* pPlayerController = pWorld->GetFirstPlayerController(); - if (pPlayerController) { - this->SubLevelCamera = pPlayerController->PlayerCameraManager; - } - - if (!this->SubLevelCamera) { - UE_LOG( - LogCesium, - Warning, - TEXT( - "CesiumGeoreference could not find a FirstPlayerController or a corresponding PlayerCameraManager.")); - } - } - UpdateGeoreference(); } @@ -472,6 +460,94 @@ void ACesiumGeoreference::PostLoad() { !this->GetWorld()->IsGameWorld()) { this->_createSubLevelsFromWorldComposition(); } + + const int32 CesiumVersion = + this->GetLinkerCustomVersion(FCesiumCustomVersion::GUID); + + if (CesiumVersion < FCesiumCustomVersion::OriginShiftComponent && + !this->SubLevelSwitcher->GetRegisteredSubLevelsWeak().IsEmpty()) { + // In previous versions, the CesiumGeoreference managed origin shifting + // based on a SubLevelCamera, which defaulted to the PlayerCameraManager of + // the World's `GetFirstPlayerController()`. + + // Backward compatibility for this is tricky, but we can make a decent + // attempt that will work in a lot of cases. And this is just an unfortunate + // v2.0 breakage for any remaining cases. + + AActor* SubLevelActor = nullptr; + + if (this->SubLevelCamera) { + // An explicit SubLevelCamera is specified. If it has a target Actor, + // attach a CesiumOriginShiftComponent to that Actor. + SubLevelActor = this->SubLevelCamera->ViewTarget.Target.Get(); + + if (!SubLevelActor) { + UE_LOG( + LogCesium, + Warning, + TEXT("An explicit SubLevelCamera was specified on this " + "CesiumGeoreference, but its ViewTarget is not a valid " + "Actor, so a CesiumOriginShiftComponent could not be added " + "automatically. You must manually add a " + "CesiumOriginShiftComponent to the Actor whose position " + "should be used to control sub-level switching.")); + } + } else { + // No explicit SubLevelCamera, so try to find a Pawn set to auto-possess + // player 0. + for (TActorIterator it( + GetWorld(), + APawn::StaticClass(), + EActorIteratorFlags::SkipPendingKill); + it; + ++it) { + if (it->AutoPossessPlayer == EAutoReceiveInput::Player0) { + SubLevelActor = *it; + break; + } + } + + if (!SubLevelActor) { + UE_LOG( + LogCesium, + Warning, + TEXT( + "Could not find a Pawn in the level set to auto-possess player " + "0, so a CesiumOriginShiftComponent could not be added " + "automatically. You must manually add a " + "CesiumOriginShiftComponent to the Actor whose position " + "should be used to control sub-level switching.")); + } + } + + if (SubLevelActor) { + // If this is a Blueprint object, like DynamicPawn, its construction + // scripts may not have been run yet at this point. Doing so might cause + // an origin shift component to be added. So we force it to happen here so + // that we don't end up adding a duplicate CesiumOriginShiftComponent. + SubLevelActor->RerunConstructionScripts(); + if (SubLevelActor->FindComponentByClass() == + nullptr) { + + UCesiumOriginShiftComponent* OriginShift = + Cast( + SubLevelActor->AddComponentByClass( + UCesiumOriginShiftComponent::StaticClass(), + false, + FTransform::Identity, + false)); + OriginShift->SetFlags(RF_Transactional); + SubLevelActor->AddInstanceComponent(OriginShift); + + UE_LOG( + LogCesium, + Warning, + TEXT("Added CesiumOriginShiftComponent to %s in order to preserve " + "backward compatibility for sub-level switching."), + *SubLevelActor->GetName()); + } + } + } #endif // WITH_EDITOR } @@ -582,8 +658,8 @@ void ACesiumGeoreference::_createSubLevelsFromWorldComposition() { pLevelComponent->SetEnabled(pFound->Enabled); pLevelComponent->SetLoadRadius(pFound->LoadRadius); - // But if the georeference origin is close to this sub-level's origin, make - // this the active sub-level. + // But if the georeference origin is close to this sub-level's origin, + // make this the active sub-level. if (FMath::IsNearlyEqual( this->OriginLongitude, pFound->LevelLongitude, diff --git a/Source/CesiumRuntime/Private/CesiumOriginShiftComponent.cpp b/Source/CesiumRuntime/Private/CesiumOriginShiftComponent.cpp index 2fcc51033..e4db773a1 100644 --- a/Source/CesiumRuntime/Private/CesiumOriginShiftComponent.cpp +++ b/Source/CesiumRuntime/Private/CesiumOriginShiftComponent.cpp @@ -15,6 +15,7 @@ UCesiumOriginShiftComponent::UCesiumOriginShiftComponent() : Super() { this->PrimaryComponentTick.bCanEverTick = true; this->PrimaryComponentTick.TickGroup = ETickingGroup::TG_PrePhysics; + this->bAutoActivate = true; } void UCesiumOriginShiftComponent::OnRegister() { @@ -33,6 +34,9 @@ void UCesiumOriginShiftComponent::TickComponent( FActorComponentTickFunction* ThisTickFunction) { Super::TickComponent(DeltaTime, TickType, ThisTickFunction); + if (!this->IsActive()) + return; + if (!this->GlobeAnchor) return; diff --git a/Source/CesiumRuntime/Public/CesiumCustomVersion.h b/Source/CesiumRuntime/Public/CesiumCustomVersion.h index bf5c6e38f..98bcc0640 100644 --- a/Source/CesiumRuntime/Public/CesiumCustomVersion.h +++ b/Source/CesiumRuntime/Public/CesiumCustomVersion.h @@ -25,6 +25,10 @@ struct CESIUMRUNTIME_API FCesiumCustomVersion { // an array of doubles to being an FMatrix. GlobeAnchorTransformationAsFMatrix = 4, + // The origin shifting behavior became an independent component rather than + // built into the CesiumGeoreference. + OriginShiftComponent = 5, + VersionPlusOne, LatestVersion = VersionPlusOne - 1 }; diff --git a/Source/CesiumRuntime/Public/CesiumOriginShiftComponent.h b/Source/CesiumRuntime/Public/CesiumOriginShiftComponent.h index 08139a154..254ace8da 100644 --- a/Source/CesiumRuntime/Public/CesiumOriginShiftComponent.h +++ b/Source/CesiumRuntime/Public/CesiumOriginShiftComponent.h @@ -20,7 +20,7 @@ class CESIUMRUNTIME_API UCesiumOriginShiftComponent : public UActorComponent { virtual void BeginPlay() override; virtual void TickComponent( float DeltaTime, - enum ELevelTick TickType, + ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override; private: