void UActorRecording::StartRecordingNewComponents(ULevelSequence* CurrentSequence, float CurrentSequenceTime)
{
	if (GetActorToRecord() != nullptr)
	{
		// find the new component(s)
		TInlineComponentArray<USceneComponent*> NewComponents;
		TArray<USceneComponent*> SceneComponents;
		GetSceneComponents(SceneComponents);
		for(USceneComponent* SceneComponent : SceneComponents)
		{
			if(ValidComponent(SceneComponent))
			{
				TWeakObjectPtr<USceneComponent> WeakSceneComponent(SceneComponent);
				int32 FoundIndex = TrackedComponents.Find(WeakSceneComponent);
				if(FoundIndex == INDEX_NONE)
				{
					// new component!
					NewComponents.Add(SceneComponent);
				}
			}
		}

		ProcessNewComponentArray(NewComponents);

		UMovieScene* MovieScene = CurrentSequence->GetMovieScene();
		check(MovieScene);

		FAnimationRecordingSettings ComponentAnimationSettings = AnimationSettings;
		ComponentAnimationSettings.bRemoveRootAnimation = false;
		ComponentAnimationSettings.bRecordInWorldSpace = false;

		const USequenceRecorderSettings* Settings = GetDefault<USequenceRecorderSettings>();
		if (!bRecordToPossessable)
		{
			FMovieSceneSpawnable* Spawnable = MovieScene->FindSpawnable(Guid);
			check(Spawnable);

			AActor* ObjectTemplate = CastChecked<AActor>(Spawnable->GetObjectTemplate());

			for (USceneComponent* SceneComponent : NewComponents)
			{
				// new component, so we need to add this to our BP if it didn't come from SCS
				FName NewName;
				if (SceneComponent->CreationMethod != EComponentCreationMethod::SimpleConstructionScript)
				{
					// Give this component a unique name within its parent
					NewName = *FString::Printf(TEXT("Dynamic%s"), *SceneComponent->GetFName().GetPlainNameString());
					NewName.SetNumber(1);
					while (FindObjectFast<UObject>(ObjectTemplate, NewName))
					{
						NewName.SetNumber(NewName.GetNumber() + 1);
					}

					USceneComponent* TemplateRoot = ObjectTemplate->GetRootComponent();
					USceneComponent* AttachToComponent = nullptr;

					// look for a similar attach parent in the current structure
					USceneComponent* AttachParent = SceneComponent->GetAttachParent();
					if(AttachParent != nullptr)
					{
						// First off, check if we're attached to a component that has already been duplicated into this object
						// If so, the name lookup will fail, so we use a direct reference
						if (TWeakObjectPtr<USceneComponent>* DuplicatedComponent = DuplicatedDynamicComponents.Find(AttachParent))
						{
							AttachToComponent = DuplicatedComponent->Get();
						}
					
						// If we don't have an attachment parent duplicated already, perform a name lookup
						if (!AttachToComponent)
						{
							FName AttachName = SceneComponent->GetAttachParent()->GetFName();

							TInlineComponentArray<USceneComponent*> AllChildren;
							ObjectTemplate->GetComponents(AllChildren);

							for (USceneComponent* Child : AllChildren)
							{
								CA_SUPPRESS(28182); // Dereferencing NULL pointer. 'Child' contains the same NULL value as 'AttachToComponent' did.
								if (Child->GetFName() == AttachName)
								{
									AttachToComponent = Child;
									break;
								}
							}
						}
					}

					if (!AttachToComponent)
					{
						AttachToComponent = ObjectTemplate->GetRootComponent();
					}

					USceneComponent* NewTemplateComponent = Cast<USceneComponent>(StaticDuplicateObject(SceneComponent, ObjectTemplate, NewName, RF_AllFlags & ~RF_Transient));
					NewTemplateComponent->AttachToComponent(AttachToComponent, FAttachmentTransformRules::KeepRelativeTransform, SceneComponent->GetAttachSocketName());

					ObjectTemplate->AddInstanceComponent(NewTemplateComponent);

					DuplicatedDynamicComponents.Add(SceneComponent, NewTemplateComponent);
				}
				else
				{
					NewName = SceneComponent->GetFName();
				}

				StartRecordingComponentProperties(NewName, SceneComponent, GetActorToRecord(), CurrentSequence, CurrentSequenceTime, ComponentAnimationSettings);

				bNewComponentAddedWhileRecording = true;
			}

			SyncTrackedComponents();
		}
		else
		{
			for (USceneComponent* SceneComponent : NewComponents)
			{
				// new component, start recording
				StartRecordingComponentProperties(SceneComponent->GetFName(), SceneComponent, GetActorToRecord(), CurrentSequence, CurrentSequenceTime, ComponentAnimationSettings);
			}

			SyncTrackedComponents();
		}
	}
}
Exemplo n.º 2
0
void FTextHistory_FormatNumber::Serialize(FArchive& Ar)
{
	Ar << SourceValue;

	bool bHasFormatOptions = FormatOptions != nullptr;
	Ar << bHasFormatOptions;

	if(bHasFormatOptions)
	{
		if(Ar.IsLoading())
		{
			FormatOptions = new FNumberFormattingOptions;
		}
		CA_SUPPRESS(6011)
		Ar << *FormatOptions;
	}

	if(Ar.IsSaving())
	{
		FString CultureName = TargetCulture.IsValid()? TargetCulture->GetName() : FString();
		Ar << CultureName;
	}
	else if(Ar.IsLoading())
	{
		FString CultureName;
		Ar << CultureName;

		if(!CultureName.IsEmpty())
		{
			TargetCulture = FInternationalization::Get().GetCulture(CultureName);
		}
	}
}
Exemplo n.º 3
0
void FRedirectCollector::ResolveStringAssetReference()
{
	while (StringAssetReferences.Num())
	{
		TMultiMap<FString, FString>::TIterator First(StringAssetReferences);
		FString ToLoad = First.Key();
		FString RefFilename = First.Value();
		First.RemoveCurrent();

		if (ToLoad.Len() > 0)
		{
			UE_LOG(LogRedirectors, Log, TEXT("String Asset Reference '%s'"), *ToLoad);
			StringAssetRefFilenameStack.Push(RefFilename);

			UObject *Loaded = LoadObject<UObject>(NULL, *ToLoad, NULL, LOAD_None, NULL);
			StringAssetRefFilenameStack.Pop();

			UObjectRedirector* Redirector = dynamic_cast<UObjectRedirector*>(Loaded);
			if (Redirector)
			{
				UE_LOG(LogRedirectors, Log, TEXT("    Found redir '%s'"), *Redirector->GetFullName());
				FRedirection Redir;
				Redir.PackageFilename = RefFilename;
				Redir.RedirectorName = Redirector->GetFullName();
				Redir.RedirectorPackageFilename = Redirector->GetLinker()->Filename;
				CA_SUPPRESS(28182)
				Redir.DestinationObjectName = Redirector->DestinationObject->GetFullName();
				Redirections.AddUnique(Redir);
				Loaded = Redirector->DestinationObject;
			}
			if (Loaded)
			{
				FString Dest = Loaded->GetPathName();
				UE_LOG(LogRedirectors, Log, TEXT("    Resolved to '%s'"), *Dest);
				if (Dest != ToLoad)
				{
					StringAssetRemap.Add(ToLoad, Dest);
				}
			}
			else
			{
				UE_LOG(LogRedirectors, Log, TEXT("    Not Found!"));
			}
		}
	}
}
void UK2Node_CallArrayFunction::PropagateArrayTypeInfo(const UEdGraphPin* SourcePin)
{
	if( SourcePin )
	{
		const UEdGraphSchema_K2* Schema = CastChecked<UEdGraphSchema_K2>(GetSchema());
		const FEdGraphPinType& SourcePinType = SourcePin->PinType;

		TArray<UEdGraphPin*> DependentPins;
		GetArrayTypeDependentPins(DependentPins);
		DependentPins.Add(GetTargetArrayPin());
	
		// Propagate pin type info (except for array info!) to pins with dependent types
		for (UEdGraphPin* CurrentPin : DependentPins)
		{
			if (CurrentPin != SourcePin)
			{
				CA_SUPPRESS(6011); // warning C6011: Dereferencing NULL pointer 'CurrentPin'.
				FEdGraphPinType& CurrentPinType = CurrentPin->PinType;

				bool const bHasTypeMismatch = (CurrentPinType.PinCategory != SourcePinType.PinCategory) ||
					(CurrentPinType.PinSubCategory != SourcePinType.PinSubCategory) ||
					(CurrentPinType.PinSubCategoryObject != SourcePinType.PinSubCategoryObject);

				if (!bHasTypeMismatch)
				{
					continue;
				}

				if (CurrentPin->SubPins.Num() > 0)
				{
					Schema->RecombinePin(CurrentPin->SubPins[0]);
				}

				CurrentPinType.PinCategory          = SourcePinType.PinCategory;
				CurrentPinType.PinSubCategory       = SourcePinType.PinSubCategory;
				CurrentPinType.PinSubCategoryObject = SourcePinType.PinSubCategoryObject;

				// Reset default values
				if (!Schema->IsPinDefaultValid(CurrentPin, CurrentPin->DefaultValue, CurrentPin->DefaultObject, CurrentPin->DefaultTextValue).IsEmpty())
				{
					CurrentPin->ResetDefaultValue();
				}
			}
		}
	}
}
Exemplo n.º 5
0
bool APawn::IsNetRelevantFor(const AActor* RealViewer, const AActor* ViewTarget, const FVector& SrcLocation) const
{
	CA_SUPPRESS(6011);
	if (bAlwaysRelevant || RealViewer == Controller || IsOwnedBy(ViewTarget) || IsOwnedBy(RealViewer) || this == ViewTarget || ViewTarget == Instigator
		|| IsBasedOnActor(ViewTarget) || (ViewTarget && ViewTarget->IsBasedOnActor(this)))
	{
		return true;
	}
	else if( (bHidden || bOnlyRelevantToOwner) && (!GetRootComponent() || !GetRootComponent()->IsCollisionEnabled()) ) 
	{
		return false;
	}
	else
	{
		UPrimitiveComponent* MovementBase = GetMovementBase();
		AActor* BaseActor = MovementBase ? MovementBase->GetOwner() : NULL;
		if ( MovementBase && BaseActor && GetMovementComponent() && ((Cast<const USkeletalMeshComponent>(MovementBase)) || (BaseActor == GetOwner())) )
		{
			return BaseActor->IsNetRelevantFor(RealViewer, ViewTarget, SrcLocation);
		}
	}

	return ((SrcLocation - GetActorLocation()).SizeSquared() < NetCullDistanceSquared);
}
Exemplo n.º 6
0
/**
 * Returns a supported screen resolution that most closely matches the input.
 * @param Width - Input: Desired resolution width in pixels. Output: A width that the platform supports.
 * @param Height - Input: Desired resolution height in pixels. Output: A height that the platform supports.
 */
void FD3D11DynamicRHI::RHIGetSupportedResolution( uint32 &Width, uint32 &Height )
{
	uint32 InitializedMode = false;
	DXGI_MODE_DESC BestMode;
	BestMode.Width = 0;
	BestMode.Height = 0;

	{
		HRESULT hr = S_OK;
		TRefCountPtr<IDXGIAdapter> Adapter;
		hr = DXGIFactory->EnumAdapters(ChosenAdapter,Adapter.GetInitReference());
		if( DXGI_ERROR_NOT_FOUND == hr )
		{
			return;
		}
		if( FAILED(hr) )
		{
			return;
		}

		// get the description of the adapter
		DXGI_ADAPTER_DESC AdapterDesc;
		VERIFYD3D11RESULT(Adapter->GetDesc(&AdapterDesc));
	  
		// Enumerate outputs for this adapter
		// TODO: Cap at 1 for default output
		for(uint32 o = 0;o < 1; o++)
		{
			TRefCountPtr<IDXGIOutput> Output;
			hr = Adapter->EnumOutputs(o,Output.GetInitReference());
			if(DXGI_ERROR_NOT_FOUND == hr)
				break;
			if(FAILED(hr))
				return;

			// TODO: GetDisplayModeList is a terribly SLOW call.  It can take up to a second per invocation.
			//  We might want to work around some DXGI badness here.
			DXGI_FORMAT Format = DXGI_FORMAT_R8G8B8A8_UNORM;
			uint32 NumModes = 0;
			hr = Output->GetDisplayModeList(Format,0,&NumModes,NULL);
			if(hr == DXGI_ERROR_NOT_FOUND)
			{
				return;
			}
			else if(hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE)
			{
				UE_LOG(LogD3D11RHI, Fatal,
					TEXT("This application cannot be run over a remote desktop configuration")
					);
				return;
			}
			DXGI_MODE_DESC* ModeList = new DXGI_MODE_DESC[ NumModes ];
			VERIFYD3D11RESULT(Output->GetDisplayModeList(Format,0,&NumModes,ModeList));

			for(uint32 m = 0;m < NumModes;m++)
			{
				// Search for the best mode
				
				// Suppress static analysis warnings about a potentially out-of-bounds read access to ModeList. This is a false positive - Index is always within range.
				CA_SUPPRESS( 6385 );
				bool IsEqualOrBetterWidth = FMath::Abs((int32)ModeList[m].Width - (int32)Width) <= FMath::Abs((int32)BestMode.Width - (int32)Width);
				bool IsEqualOrBetterHeight = FMath::Abs((int32)ModeList[m].Height - (int32)Height) <= FMath::Abs((int32)BestMode.Height - (int32)Height);
				if(!InitializedMode || (IsEqualOrBetterWidth && IsEqualOrBetterHeight))
				{
					BestMode = ModeList[m];
					InitializedMode = true;
				}
			}

			delete[] ModeList;
		}
	}

	check(InitializedMode);
	Width = BestMode.Width;
	Height = BestMode.Height;
}
void FRedirectCollector::ResolveStringAssetReference(FString FilterPackage)
{
    SCOPE_REDIRECT_TIMER(ResolveTimeTotal);


    FName FilterPackageFName = NAME_None;
    if (!FilterPackage.IsEmpty())
    {
        FilterPackageFName = FName(*FilterPackage);
    }

    TMultiMap<FName, FPackagePropertyPair> SkippedReferences;
    SkippedReferences.Empty(StringAssetReferences.Num());
    while ( StringAssetReferences.Num())
    {

        TMultiMap<FName, FPackagePropertyPair> CurrentReferences;
        Swap(StringAssetReferences, CurrentReferences);

        for (const auto& CurrentReference : CurrentReferences)
        {
            const FName& ToLoadFName = CurrentReference.Key;
            const FPackagePropertyPair& RefFilenameAndProperty = CurrentReference.Value;

            if ((FilterPackageFName != NAME_None) && // not using a filter
                    (FilterPackageFName != RefFilenameAndProperty.GetCachedPackageName()) && // this is the package we are looking for
                    (RefFilenameAndProperty.GetCachedPackageName() != NAME_None) // if we have an empty package name then process it straight away
               )
            {
                // If we have a valid filter and it doesn't match, skip this reference
                SkippedReferences.Add(ToLoadFName, RefFilenameAndProperty);
                continue;
            }

            const FString ToLoad = ToLoadFName.ToString();

            if (FCoreDelegates::LoadStringAssetReferenceInCook.IsBound())
            {
                SCOPE_REDIRECT_TIMER(ResolveTimeDelegate);
                if (FCoreDelegates::LoadStringAssetReferenceInCook.Execute(ToLoad) == false)
                {
                    // Skip this reference
                    continue;
                }
            }

            if (ToLoad.Len() > 0 )
            {
                SCOPE_REDIRECT_TIMER(ResolveTimeLoad);

                UE_LOG(LogRedirectors, Verbose, TEXT("String Asset Reference '%s'"), *ToLoad);
                UE_CLOG(RefFilenameAndProperty.GetProperty().ToString().Len(), LogRedirectors, Verbose, TEXT("    Referenced by '%s'"), *RefFilenameAndProperty.GetProperty().ToString());

                StringAssetRefFilenameStack.Push(RefFilenameAndProperty.GetPackage().ToString());

                UObject *Loaded = LoadObject<UObject>(NULL, *ToLoad, NULL, RefFilenameAndProperty.GetReferencedByEditorOnlyProperty() ? LOAD_EditorOnly : LOAD_None, NULL);
                StringAssetRefFilenameStack.Pop();

                UObjectRedirector* Redirector = dynamic_cast<UObjectRedirector*>(Loaded);
                if (Redirector)
                {
                    UE_LOG(LogRedirectors, Verbose, TEXT("    Found redir '%s'"), *Redirector->GetFullName());
                    FRedirection Redir;
                    Redir.PackageFilename = RefFilenameAndProperty.GetPackage().ToString();
                    Redir.RedirectorName = Redirector->GetFullName();
                    Redir.RedirectorPackageFilename = Redirector->GetLinker()->Filename;
                    CA_SUPPRESS(28182)
                    Redir.DestinationObjectName = Redirector->DestinationObject->GetFullName();
                    Redirections.AddUnique(Redir);
                    Loaded = Redirector->DestinationObject;
                }
                if (Loaded)
                {
                    if (FCoreUObjectDelegates::PackageLoadedFromStringAssetReference.IsBound())
                    {
                        FCoreUObjectDelegates::PackageLoadedFromStringAssetReference.Broadcast(Loaded->GetOutermost()->GetFName());
                    }
                    FString Dest = Loaded->GetPathName();
                    UE_LOG(LogRedirectors, Verbose, TEXT("    Resolved to '%s'"), *Dest);
                    if (Dest != ToLoad)
                    {
                        StringAssetRemap.Add(ToLoad, Dest);
                    }
                }
                else
                {
                    const FString Referencer = RefFilenameAndProperty.GetProperty().ToString().Len() ? RefFilenameAndProperty.GetProperty().ToString() : TEXT("Unknown");

                    int32 DotIndex = ToLoad.Find(TEXT("."));

                    FString PackageName = DotIndex != INDEX_NONE ? ToLoad.Left(DotIndex) : ToLoad;

                    if (FLinkerLoad::IsKnownMissingPackage(FName(*PackageName)) == false)
                    {
                        UE_LOG(LogRedirectors, Warning, TEXT("String Asset Reference '%s' was not found! (Referencer '%s')"), *ToLoad, *Referencer);
                    }
                }
            }

        }
    }

    check(StringAssetReferences.Num() == 0);
    // Add any skipped references back into the map for the next time this is called
    Swap(StringAssetReferences, SkippedReferences);
    // we shouldn't have any references left if we decided to resolve them all
    check((StringAssetReferences.Num() == 0) || (FilterPackageFName != NAME_None));
}
Exemplo n.º 8
0
TSharedRef<FString, ESPMode::ThreadSafe> FTextLocalizationManager::GetString(const FString& Namespace, const FString& Key, const FString* const SourceString)
{
	FScopeLock ScopeLock( &SynchronizationObject );

	// Hack fix for old assets that don't have namespace/key info
	if(Namespace.IsEmpty() && Key.IsEmpty())
	{
		return MakeShareable( new FString( SourceString ? **SourceString : TEXT("") ) );
	}

#if ENABLE_LOC_TESTING
	const bool bShouldLEETIFYAll = bIsInitialized && FInternationalization::Get().GetCurrentCulture()->GetName() == TEXT("LEET");

	// Attempt to set bShouldLEETIFYUnlocalizedString appropriately, only once, after the commandline is initialized and parsed
	static bool bShouldLEETIFYUnlocalizedString = false;
	{
		static bool bHasParsedCommandLine = false;
		if(!bHasParsedCommandLine && FCommandLine::IsInitialized())
		{
			bShouldLEETIFYUnlocalizedString = FParse::Param(FCommandLine::Get(), TEXT("LEETIFYUnlocalized"));
			bHasParsedCommandLine = true;
		}
	}
#endif

	// Find namespace's key table.
	FTextLookupTable::FKeyTable* LiveKeyTable = LiveTable.NamespaceTable.Find( Namespace );

	// Find key table's entry.
	FStringEntry* LiveEntry = LiveKeyTable ? LiveKeyTable->Find( Key ) : NULL;

	// Entry is present.
	if( LiveEntry )
	{
		// If we're in some sort of development setting, source may have changed but localization resources have not, in which case the source should be used.
		const uint32 SourceStringHash = SourceString ? FCrc::StrCrc32(**SourceString) : 0;

		// If the source string (hash) is different, the local source has changed and should override - can't be localized.
		if( SourceStringHash != 0 && SourceStringHash != LiveEntry->SourceStringHash )
		{
			LiveEntry->SourceStringHash = SourceStringHash;
			LiveEntry->String.Get() = SourceString ? **SourceString : TEXT("");

#if ENABLE_LOC_TESTING
			if( (bShouldLEETIFYAll || bShouldLEETIFYUnlocalizedString) && SourceString )
			{
				FInternationalization::Leetify(*LiveEntry->String);
				if(*LiveEntry->String == *SourceString)
				{
					UE_LOG(LogTextLocalizationManager, Warning, TEXT("Leetify failed to alter a string (%s)."), **SourceString );
				}
			}
#endif

			UE_LOG(LogTextLocalizationManager, Verbose, TEXT("An attempt was made to get a localized string (Namespace:%s, Key:%s), but the source string hash does not match - the source string (%s) will be used."), *Namespace, *Key, **LiveEntry->String);

#if ENABLE_LOC_TESTING
			LiveEntry->bIsLocalized = bShouldLEETIFYAll;
#else
			LiveEntry->bIsLocalized = false;
#endif
		}

		return LiveEntry->String;
	}
	// Entry is absent.
	else
	{
		// Don't log warnings about unlocalized strings if the system hasn't been initialized - we simply don't have localization data yet.
		if( bIsInitialized )
		{
			UE_LOG(LogTextLocalizationManager, Verbose, TEXT("An attempt was made to get a localized string (Namespace:%s, Key:%s, Source:%s), but it did not exist."), *Namespace, *Key, SourceString ? **SourceString : TEXT(""));
		}

		const TSharedRef<FString, ESPMode::ThreadSafe> UnlocalizedString = MakeShareable( new FString( SourceString ? **SourceString : TEXT("") ) );

		// If live-culture-swap is enabled or the system is uninitialized - make entries so that they can be updated when system is initialized or a culture swap occurs.
		CA_SUPPRESS(6236)
		CA_SUPPRESS(6316)
		if( !(bIsInitialized) || ENABLE_LOC_TESTING )
		{
#if ENABLE_LOC_TESTING
			if( (bShouldLEETIFYAll || bShouldLEETIFYUnlocalizedString) && SourceString )
			{
				FInternationalization::Leetify(*UnlocalizedString);
				if(*UnlocalizedString == *SourceString)
				{
					UE_LOG(LogTextLocalizationManager, Warning, TEXT("Leetify failed to alter a string (%s)."), **SourceString );
				}
			}
#endif

			if ( UnlocalizedString->IsEmpty() )
			{
				if ( !bIsInitialized )
				{
					*(UnlocalizedString) = AccessedStringBeforeLocLoadedErrorMsg;
				}
			}

			FStringEntry NewEntry(
#if ENABLE_LOC_TESTING
				bShouldLEETIFYAll						/*bIsLocalized*/
#else
				false												/*bIsLocalized*/
#endif
				, TEXT("")
				, SourceString ? FCrc::StrCrc32(**SourceString) : 0	/*SourceStringHash*/
				, UnlocalizedString									/*String*/
				);

			if( !LiveKeyTable )
			{
				LiveKeyTable = &(LiveTable.NamespaceTable.Add( Namespace, FTextLookupTable::FKeyTable() ));
			}

			LiveKeyTable->Add( Key, NewEntry );

			ReverseLiveTable.Add(NewEntry.String, FNamespaceKeyEntry( MakeShareable( new FString( Namespace ) ), MakeShareable( new FString( Key ) )));

		}

		return UnlocalizedString;
	}
}
void FLogVisualizer::UpdateCameraPosition(FName RowName, int32 ItemIndes)
{
    const FVisualLoggerDBRow& DBRow = FVisualLoggerDatabase::Get().GetRowByName(RowName);
    auto &Entries = DBRow.GetItems();
    if (DBRow.GetCurrentItemIndex() == INDEX_NONE || Entries.IsValidIndex(DBRow.GetCurrentItemIndex()) == false)
    {
        return;
    }

    UWorld* World = GetWorld();

    FVector CurrentLocation = Entries[DBRow.GetCurrentItemIndex()].Entry.Location;

    FVector Extent(150);
    bool bFoundActor = false;
    FName OwnerName = Entries[DBRow.GetCurrentItemIndex()].OwnerName;
    for (FActorIterator It(World); It; ++It)
    {
        AActor* Actor = *It;
        if (Actor->GetFName() == OwnerName)
        {
            FVector Orgin;
            Actor->GetActorBounds(false, Orgin, Extent);
            bFoundActor = true;
            break;
        }
    }


    const float DefaultCameraDistance = ULogVisualizerSettings::StaticClass()->GetDefaultObject<ULogVisualizerSettings>()->DefaultCameraDistance;
    Extent = Extent.SizeSquared() < FMath::Square(DefaultCameraDistance) ? FVector(DefaultCameraDistance) : Extent;

#if WITH_EDITOR
    UEditorEngine *EEngine = Cast<UEditorEngine>(GEngine);
    if (GIsEditor && EEngine != NULL)
    {
        for (auto ViewportClient : EEngine->AllViewportClients)
        {
            ViewportClient->FocusViewportOnBox(FBox::BuildAABB(CurrentLocation, Extent));
        }
    }
    else if (AVisualLoggerCameraController::IsEnabled(World) && AVisualLoggerCameraController::Instance.IsValid() && AVisualLoggerCameraController::Instance->GetSpectatorPawn())
    {
        ULocalPlayer* LocalPlayer = Cast<ULocalPlayer>(AVisualLoggerCameraController::Instance->Player);
        if (LocalPlayer && LocalPlayer->ViewportClient && LocalPlayer->ViewportClient->Viewport)
        {

            FViewport* Viewport = LocalPlayer->ViewportClient->Viewport;

            FBox BoundingBox = FBox::BuildAABB(CurrentLocation, Extent);
            const FVector Position = BoundingBox.GetCenter();
            float Radius = BoundingBox.GetExtent().Size();

            FViewportCameraTransform ViewTransform;
            ViewTransform.TransitionToLocation(Position, nullptr, true);

            float NewOrthoZoom;
            const float AspectRatio = 1.777777f;
            CA_SUPPRESS(6326);
            uint32 MinAxisSize = (AspectRatio > 1.0f) ? Viewport->GetSizeXY().Y : Viewport->GetSizeXY().X;
            float Zoom = Radius / (MinAxisSize / 2.0f);

            NewOrthoZoom = Zoom * (Viewport->GetSizeXY().X*15.0f);
            NewOrthoZoom = FMath::Clamp<float>(NewOrthoZoom, 250, MAX_FLT);
            ViewTransform.SetOrthoZoom(NewOrthoZoom);

            AVisualLoggerCameraController::Instance->GetSpectatorPawn()->TeleportTo(ViewTransform.GetLocation(), ViewTransform.GetRotation(), false, true);
        }
    }
#endif
}
void FRedirectCollector::ResolveStringAssetReference(FString FilterPackage)
{
	TMultiMap<FString, FPackagePropertyPair> SkippedReferences;
	while (StringAssetReferences.Num())
	{
		TMultiMap<FString, FPackagePropertyPair>::TIterator First(StringAssetReferences);
		FString ToLoad = First.Key();
		FPackagePropertyPair RefFilenameAndProperty = First.Value();
		First.RemoveCurrent();
		
		if (FCoreDelegates::LoadStringAssetReferenceInCook.IsBound())
		{
			if (FCoreDelegates::LoadStringAssetReferenceInCook.Execute(ToLoad) == false)
			{
				// Skip this reference
				continue;
			}
		}

		if (!FilterPackage.IsEmpty() && FilterPackage != RefFilenameAndProperty.Package)
		{
			// If we have a valid filter and it doesn't match, skip this reference
			SkippedReferences.Add(ToLoad, RefFilenameAndProperty);
			continue;
		}

		if (ToLoad.Len() > 0)
		{
			UE_LOG(LogRedirectors, Verbose, TEXT("String Asset Reference '%s'"), *ToLoad);
			UE_CLOG(RefFilenameAndProperty.Property.Len(), LogRedirectors, Verbose, TEXT("    Referenced by '%s'"), *RefFilenameAndProperty.Property);

			StringAssetRefFilenameStack.Push(RefFilenameAndProperty.Package);

			UObject *Loaded = LoadObject<UObject>(NULL, *ToLoad, NULL, RefFilenameAndProperty.bReferencedByEditorOnlyProperty ? LOAD_EditorOnly : LOAD_None, NULL);
			StringAssetRefFilenameStack.Pop();

			UObjectRedirector* Redirector = dynamic_cast<UObjectRedirector*>(Loaded);
			if (Redirector)
			{
				UE_LOG(LogRedirectors, Verbose, TEXT("    Found redir '%s'"), *Redirector->GetFullName());
				FRedirection Redir;
				Redir.PackageFilename = RefFilenameAndProperty.Package;
				Redir.RedirectorName = Redirector->GetFullName();
				Redir.RedirectorPackageFilename = Redirector->GetLinker()->Filename;
				CA_SUPPRESS(28182)
				Redir.DestinationObjectName = Redirector->DestinationObject->GetFullName();
				Redirections.AddUnique(Redir);
				Loaded = Redirector->DestinationObject;
			}
			if (Loaded)
			{
				FString Dest = Loaded->GetPathName();
				UE_LOG(LogRedirectors, Verbose, TEXT("    Resolved to '%s'"), *Dest);
				if (Dest != ToLoad)
				{
					StringAssetRemap.Add(ToLoad, Dest);
				}
			}
			else
			{
				const FString Referencer = RefFilenameAndProperty.Property.Len() ? RefFilenameAndProperty.Property : TEXT("Unknown");
				UE_LOG(LogRedirectors, Warning, TEXT("String Asset Reference '%s' was not found! (Referencer '%s')"), *ToLoad, *Referencer);
			}
		}
	}

	// Add any skipped references back into the map for the next time this is called
	StringAssetReferences = SkippedReferences;
}