void FDesktopPlatformWindows::EnumerateEngineInstallations(TMap<FString, FString> &OutInstallations) { // Enumerate the binary installations EnumerateLauncherEngineInstallations(OutInstallations); // Enumerate the per-user installations HKEY hKey; if (RegOpenKeyEx(HKEY_CURRENT_USER, InstallationsSubKey, 0, KEY_ALL_ACCESS, &hKey) == ERROR_SUCCESS) { // Get a list of all the directories TArray<FString> UniqueDirectories; OutInstallations.GenerateValueArray(UniqueDirectories); // Enumerate all the installations TArray<FString> InvalidKeys; for (::DWORD Index = 0;; Index++) { TCHAR ValueName[256]; TCHAR ValueData[MAX_PATH]; ::DWORD ValueType = 0; ::DWORD ValueNameLength = sizeof(ValueName) / sizeof(ValueName[0]); ::DWORD ValueDataSize = sizeof(ValueData); LRESULT Result = RegEnumValue(hKey, Index, ValueName, &ValueNameLength, NULL, &ValueType, (BYTE*)&ValueData[0], &ValueDataSize); if(Result == ERROR_SUCCESS) { int32 ValueDataLength = ValueDataSize / sizeof(TCHAR); if(ValueDataLength > 0 && ValueData[ValueDataLength - 1] == 0) ValueDataLength--; FString NormalizedInstalledDirectory(ValueDataLength, ValueData); FPaths::NormalizeDirectoryName(NormalizedInstalledDirectory); FPaths::CollapseRelativeDirectories(NormalizedInstalledDirectory); if(IsValidRootDirectory(NormalizedInstalledDirectory) && !UniqueDirectories.Contains(NormalizedInstalledDirectory)) { OutInstallations.Add(ValueName, NormalizedInstalledDirectory); UniqueDirectories.Add(NormalizedInstalledDirectory); } else { InvalidKeys.Add(ValueName); } } else if(Result == ERROR_NO_MORE_ITEMS) { break; } } // Remove all the keys which weren't valid for(const FString InvalidKey: InvalidKeys) { RegDeleteValue(hKey, *InvalidKey); } RegCloseKey(hKey); } }
// // Empty the loaders. // void ResetLoaders( UObject* InPkg ) { // Make sure we're not in the middle of loading something in the background. FlushAsyncLoading(); // Top level package to reset loaders for. UObject* TopLevelPackage = InPkg ? InPkg->GetOutermost() : NULL; // Find loader/ linker associated with toplevel package. We do this upfront as Detach resets LinkerRoot. if( TopLevelPackage ) { // Linker to reset/ detach. ULinkerLoad* LinkerToReset = ULinkerLoad::FindExistingLinkerForPackage(CastChecked<UPackage>(TopLevelPackage)); if ( LinkerToReset ) { for (TMap<UPackage*, ULinkerLoad*>::TIterator It(GObjLoaders); It; ++It) { ULinkerLoad* Linker = It.Value(); // Detach LinkerToReset from other linker's import table. if( Linker->LinkerRoot != TopLevelPackage ) { for( int32 j=0; j<Linker->ImportMap.Num(); j++ ) { if( Linker->ImportMap[j].SourceLinker == LinkerToReset ) { Linker->ImportMap[j].SourceLinker = NULL; Linker->ImportMap[j].SourceIndex = INDEX_NONE; } } } else { check(Linker == LinkerToReset); } } // Detach linker, also removes from array and sets LinkerRoot to NULL. LinkerToReset->Detach(true); } } else { TArray<ULinkerLoad *> LinkersToDetach; GObjLoaders.GenerateValueArray(LinkersToDetach); for (int32 Index = 0; Index < LinkersToDetach.Num(); Index++) { ULinkerLoad* Linker = LinkersToDetach[Index]; // Detach linker, also removes from array and sets LinkerRoot to NULL. Linker->Detach(true); } } }
void FBlueprintCompileReinstancer::ReplaceInstancesOfClass(UClass* OldClass, UClass* NewClass, UObject* OriginalCDO, TSet<UObject*>* ObjectsThatShouldUseOldStuff) { USelection* SelectedActors; bool bSelectionChanged = false; TArray<UObject*> ObjectsToReplace; const bool bLogConversions = false; // for debugging // Map of old objects to new objects TMap<UObject*, UObject*> OldToNewInstanceMap; TMap<UClass*, UClass*> OldToNewClassMap; OldToNewClassMap.Add(OldClass, NewClass); TMap<FStringAssetReference, UObject*> ReinstancedObjectsWeakReferenceMap; // actors being replace TArray<FActorReplacementHelper> ReplacementActors; // A list of objects (e.g. Blueprints) that potentially have editors open that we need to refresh TArray<UObject*> PotentialEditorsForRefreshing; // A list of component owners that need their construction scripts re-ran (because a component of theirs has been reinstanced) TSet<AActor*> OwnersToReconstruct; // Set global flag to let system know we are reconstructing blueprint instances TGuardValue<bool> GuardTemplateNameFlag(GIsReconstructingBlueprintInstances, true); struct FObjectRemappingHelper { void OnObjectsReplaced(const TMap<UObject*, UObject*>& InReplacedObjects) { ReplacedObjects.Append(InReplacedObjects); } TMap<UObject*, UObject*> ReplacedObjects; } ObjectRemappingHelper; FDelegateHandle OnObjectsReplacedHandle = GEditor->OnObjectsReplaced().AddRaw(&ObjectRemappingHelper,&FObjectRemappingHelper::OnObjectsReplaced); { BP_SCOPED_COMPILER_EVENT_STAT(EKismetReinstancerStats_ReplaceInstancesOfClass); const bool bIncludeDerivedClasses = false; GetObjectsOfClass(OldClass, ObjectsToReplace, bIncludeDerivedClasses); SelectedActors = GEditor->GetSelectedActors(); SelectedActors->BeginBatchSelectOperation(); SelectedActors->Modify(); // Then fix 'real' (non archetype) instances of the class for (UObject* OldObject : ObjectsToReplace) { // Skip non-archetype instances, EXCEPT for component templates const bool bIsComponent = NewClass->IsChildOf(UActorComponent::StaticClass()); if ((!bIsComponent && OldObject->IsTemplate()) || OldObject->IsPendingKill()) { continue; } UBlueprint* CorrespondingBlueprint = Cast<UBlueprint>(OldObject->GetClass()->ClassGeneratedBy); UObject* OldBlueprintDebugObject = nullptr; // If this object is being debugged, cache it off so we can preserve the 'object being debugged' association if ((CorrespondingBlueprint != nullptr) && (CorrespondingBlueprint->GetObjectBeingDebugged() == OldObject)) { OldBlueprintDebugObject = OldObject; } AActor* OldActor = Cast<AActor>(OldObject); UObject* NewUObject = nullptr; // if the object to replace is an actor... if (OldActor != nullptr) { FVector Location = FVector::ZeroVector; FRotator Rotation = FRotator::ZeroRotator; if (USceneComponent* OldRootComponent = OldActor->GetRootComponent()) { Location = OldActor->GetActorLocation(); Rotation = OldActor->GetActorRotation(); } // If this actor was spawned from an Archetype, we spawn the new actor from the new version of that archetype UObject* OldArchetype = OldActor->GetArchetype(); UWorld* World = OldActor->GetWorld(); AActor* NewArchetype = Cast<AActor>(OldToNewInstanceMap.FindRef(OldArchetype)); // Check that either this was an instance of the class directly, or we found a new archetype for it check(OldArchetype == OldClass->GetDefaultObject() || NewArchetype); // Spawn the new actor instance, in the same level as the original, but deferring running the construction script until we have transferred modified properties ULevel* ActorLevel = OldActor->GetLevel(); UClass** MappedClass = OldToNewClassMap.Find(OldActor->GetClass()); UClass* SpawnClass = MappedClass ? *MappedClass : NewClass; FActorSpawnParameters SpawnInfo; SpawnInfo.OverrideLevel = ActorLevel; SpawnInfo.Template = NewArchetype; SpawnInfo.bNoCollisionFail = true; SpawnInfo.bDeferConstruction = true; // Temporarily remove the deprecated flag so we can respawn the Blueprint in the level const bool bIsClassDeprecated = SpawnClass->HasAnyClassFlags(CLASS_Deprecated); SpawnClass->ClassFlags &= ~CLASS_Deprecated; AActor* NewActor = World->SpawnActor(SpawnClass, &Location, &Rotation, SpawnInfo); // Reassign the deprecated flag if it was previously assigned if (bIsClassDeprecated) { SpawnClass->ClassFlags |= CLASS_Deprecated; } check(NewActor != nullptr); NewUObject = NewActor; // store the new actor for the second pass (NOTE: this detaches // OldActor from all child/parent attachments) // // running the NewActor's construction-script is saved for that // second pass (because the construction-script may reference // another instance that hasn't been replaced yet). ReplacementActors.Add(FActorReplacementHelper(NewActor, OldActor)); ReinstancedObjectsWeakReferenceMap.Add(OldObject, NewUObject); OldActor->DestroyConstructedComponents(); // don't want to serialize components from the old actor // Unregister native components so we don't copy any sub-components they generate for themselves (like UCameraComponent does) OldActor->UnregisterAllComponents(); // Unregister any native components, might have cached state based on properties we are going to overwrite NewActor->UnregisterAllComponents(); UEditorEngine::CopyPropertiesForUnrelatedObjects(OldActor, NewActor); // reset properties/streams NewActor->ResetPropertiesForConstruction(); // register native components NewActor->RegisterAllComponents(); // // clean up the old actor (unselect it, remove it from the world, etc.)... if (OldActor->IsSelected()) { GEditor->SelectActor(OldActor, /*bInSelected =*/false, /*bNotify =*/false); bSelectionChanged = true; } if (GEditor->Layers.IsValid()) // ensure(NULL != GEditor->Layers) ?? While cooking the Layers is NULL. { GEditor->Layers->DisassociateActorFromLayers(OldActor); } World->EditorDestroyActor(OldActor, /*bShouldModifyLevel =*/true); OldToNewInstanceMap.Add(OldActor, NewActor); } else { FName OldName(OldObject->GetFName()); OldObject->Rename(NULL, OldObject->GetOuter(), REN_DoNotDirty | REN_DontCreateRedirectors); NewUObject = NewObject<UObject>(OldObject->GetOuter(), NewClass, OldName); check(NewUObject != nullptr); UEditorEngine::CopyPropertiesForUnrelatedObjects(OldObject, NewUObject); if (UAnimInstance* AnimTree = Cast<UAnimInstance>(NewUObject)) { // Initialising the anim instance isn't enough to correctly set up the skeletal mesh again in a // paused world, need to initialise the skeletal mesh component that contains the anim instance. if (USkeletalMeshComponent* SkelComponent = Cast<USkeletalMeshComponent>(AnimTree->GetOuter())) { SkelComponent->InitAnim(true); } } OldObject->RemoveFromRoot(); OldObject->MarkPendingKill(); OldToNewInstanceMap.Add(OldObject, NewUObject); if (bIsComponent) { UActorComponent* Component = Cast<UActorComponent>(NewUObject); AActor* OwningActor = Component->GetOwner(); if (OwningActor) { OwningActor->ResetOwnedComponents(); // Check to see if they have an editor that potentially needs to be refreshed if (OwningActor->GetClass()->ClassGeneratedBy) { PotentialEditorsForRefreshing.AddUnique(OwningActor->GetClass()->ClassGeneratedBy); } // we need to keep track of actor instances that need // their construction scripts re-ran (since we've just // replaced a component they own) OwnersToReconstruct.Add(OwningActor); } } } // If this original object came from a blueprint and it was in the selected debug set, change the debugging to the new object. if ((CorrespondingBlueprint) && (OldBlueprintDebugObject) && (NewUObject)) { CorrespondingBlueprint->SetObjectBeingDebugged(NewUObject); } if (bLogConversions) { UE_LOG(LogBlueprint, Log, TEXT("Converted instance '%s' to '%s'"), *OldObject->GetPathName(), *NewUObject->GetPathName()); } } } GEditor->OnObjectsReplaced().Remove(OnObjectsReplacedHandle); // Now replace any pointers to the old archetypes/instances with pointers to the new one TArray<UObject*> SourceObjects; TArray<UObject*> DstObjects; OldToNewInstanceMap.GenerateKeyArray(SourceObjects); OldToNewInstanceMap.GenerateValueArray(DstObjects); // Also look for references in new spawned objects. SourceObjects.Append(DstObjects); FReplaceReferenceHelper::IncludeCDO(OldClass, NewClass, OldToNewInstanceMap, SourceObjects, OriginalCDO); FReplaceReferenceHelper::FindAndReplaceReferences(SourceObjects, ObjectsThatShouldUseOldStuff, ObjectsToReplace, OldToNewInstanceMap, ReinstancedObjectsWeakReferenceMap); { BP_SCOPED_COMPILER_EVENT_STAT(EKismetReinstancerStats_ReplacementConstruction); // the process of setting up new replacement actors is split into two // steps (this here, is the second)... // // the "finalization" here runs the replacement actor's construction- // script and is left until late to account for a scenario where the // construction-script attempts to modify another instance of the // same class... if this were to happen above, in the ObjectsToReplace // loop, then accessing that other instance would cause an assert in // UProperty::ContainerPtrToValuePtrInternal() (which appropriatly // complains that the other instance's type doesn't match because it // hasn't been replaced yet... that's why we wait until after // FArchiveReplaceObjectRef to run construction-scripts). for (FActorReplacementHelper& ReplacementActor : ReplacementActors) { ReplacementActor.Finalize(ObjectRemappingHelper.ReplacedObjects); } } SelectedActors->EndBatchSelectOperation(); if (bSelectionChanged) { GEditor->NoteSelectionChange(); } if (GEditor) { // Refresh any editors for objects that we've updated components for for (auto BlueprintAsset : PotentialEditorsForRefreshing) { FBlueprintEditor* BlueprintEditor = static_cast<FBlueprintEditor*>(FAssetEditorManager::Get().FindEditorForAsset(BlueprintAsset, /*bFocusIfOpen =*/false)); if (BlueprintEditor) { BlueprintEditor->RefreshEditors(); } } } // in the case where we're replacing component instances, we need to make // sure to re-run their owner's construction scripts for (AActor* ActorInstance : OwnersToReconstruct) { ActorInstance->RerunConstructionScripts(); } }
void DisplayProfileData( const TMap< FString, TSharedPtr< struct FProfiledFileStatsFileBase > >& InProfileData ) { TArray< TSharedPtr<FProfiledFileStatsFileBase> > ProfileData; InProfileData.GenerateValueArray( ProfileData ); // Single root data is required for bar visualizer to work properly TSharedPtr< FVisualizerEvent > RootEvent( new FVisualizerEvent( 0.0, 1.0, 0.0, 0, TEXT("I/O") ) ); // Calculate Start time first double StartTimeMs = FPlatformTime::Seconds() * 1000.0; // All timings happened before now double EndTimeMs = 0.0; for( int32 Index = 0; Index < ProfileData.Num(); Index++ ) { TSharedPtr<FProfiledFileStatsFileBase> FileStat = ProfileData[ Index ]; double FileDurationMs = 0.0; for( int32 ChildIndex = 0; ChildIndex < FileStat->Children.Num(); ChildIndex++ ) { TSharedPtr<FProfiledFileStatsOp> FileOpStat = FileStat->Children[ ChildIndex ]; if( FileOpStat->Duration > 0.0 ) { StartTimeMs = FMath::Min( FileOpStat->StartTime, StartTimeMs ); EndTimeMs = FMath::Max( FileOpStat->StartTime + FileOpStat->Duration, EndTimeMs ); FileDurationMs += FileOpStat->Duration; } } // Create an event for each of the files TSharedPtr< FVisualizerEvent > FileEvent( new FVisualizerEvent( 0.0, 1.0, FileDurationMs, Index, FileStat->Name ) ); FileEvent->ParentEvent = RootEvent; RootEvent->Children.Add( FileEvent ); } const double TotalTimeMs = EndTimeMs - StartTimeMs; RootEvent->DurationMs = TotalTimeMs; for( int32 FileIndex = 0; FileIndex < ProfileData.Num(); FileIndex++ ) { TSharedPtr<FProfiledFileStatsFileBase> FileStat = ProfileData[ FileIndex ]; TSharedPtr<FVisualizerEvent> FileEvent( RootEvent->Children[ FileIndex ] ); for( int32 ChildIndex = 0; ChildIndex < FileStat->Children.Num(); ChildIndex++ ) { TSharedPtr<FProfiledFileStatsOp> FileOpStat = FileStat->Children[ ChildIndex ]; if( FileOpStat->Duration > 0.0 ) { FString EventName; switch( FileOpStat->Type ) { case FProfiledFileStatsOp::Tell: EventName = TEXT("Tell"); break; case FProfiledFileStatsOp::Seek: EventName = TEXT("Seek"); break; case FProfiledFileStatsOp::Read: EventName = FString::Printf( TEXT("Read (%lld)"), FileOpStat->Bytes ); break; case FProfiledFileStatsOp::Write: EventName = FString::Printf( TEXT("Write (%lld)"), FileOpStat->Bytes ); break; case FProfiledFileStatsOp::Size: EventName = TEXT("Size"); break; case FProfiledFileStatsOp::OpenRead: EventName = TEXT("OpenRead"); break; case FProfiledFileStatsOp::OpenWrite: EventName = TEXT("OpenWrite"); break; case FProfiledFileStatsOp::Exists: EventName = TEXT("Exists"); break; case FProfiledFileStatsOp::Delete: EventName = TEXT("Delete"); break; case FProfiledFileStatsOp::Move: EventName = TEXT("Move"); break; case FProfiledFileStatsOp::IsReadOnly: EventName = TEXT("IsReadOnly"); break; case FProfiledFileStatsOp::SetReadOnly: EventName = TEXT("SetReadOnly"); break; case FProfiledFileStatsOp::GetTimeStamp: EventName = TEXT("GetTimeStamp"); break; case FProfiledFileStatsOp::SetTimeStamp: EventName = TEXT("SetTimeStamp"); break; case FProfiledFileStatsOp::Create: EventName = TEXT("Create"); break; case FProfiledFileStatsOp::Copy: EventName = TEXT("Copy"); break; case FProfiledFileStatsOp::Iterate: EventName = TEXT("Iterate"); break; default: EventName = TEXT("Unknown"); break; } const double StartTime = ( FileOpStat->StartTime - StartTimeMs ) / TotalTimeMs; const double DurationTime = FileOpStat->Duration / TotalTimeMs; TSharedPtr<FVisualizerEvent> ChildEvent( new FVisualizerEvent( StartTime, DurationTime, FileOpStat->Duration, FileIndex, EventName ) ); ChildEvent->ParentEvent = FileEvent; FileEvent->Children.Add( ChildEvent ); } } } static FName TaskGraphModule(TEXT("TaskGraph")); if (FModuleManager::Get().IsModuleLoaded(TaskGraphModule)) { IProfileVisualizerModule& ProfileVisualizer = FModuleManager::GetModuleChecked<IProfileVisualizerModule>(TaskGraphModule); ProfileVisualizer.DisplayProfileVisualizer( RootEvent, TEXT("I/O") ); } }