bool FDesktopPlatformBase::EnumerateProjectsKnownByEngine(const FString &Identifier, bool bIncludeNativeProjects, TArray<FString> &OutProjectFileNames) { // Get the engine root directory FString RootDir; if (!GetEngineRootDirFromIdentifier(Identifier, RootDir)) { return false; } FString GameAgnosticConfigDir = GetEngineSavedConfigDirectory(Identifier); if (GameAgnosticConfigDir.Len() == 0) { return false; } // Find all the created project directories. Start with the default project creation path. TArray<FString> SearchDirectories; SearchDirectories.AddUnique(GetDefaultProjectCreationPath()); // Load the config file FConfigFile GameAgnosticConfig; FConfigCacheIni::LoadExternalIniFile(GameAgnosticConfig, TEXT("EditorSettings"), NULL, *GameAgnosticConfigDir, false); // Find the editor game-agnostic settings FConfigSection* Section = GameAgnosticConfig.Find(TEXT("/Script/UnrealEd.EditorSettings")); if (Section == NULL) { FConfigCacheIni::LoadExternalIniFile(GameAgnosticConfig, TEXT("EditorGameAgnostic"), NULL, *GameAgnosticConfigDir, false); Section = GameAgnosticConfig.Find(TEXT("/Script/UnrealEd.EditorGameAgnosticSettings")); } if(Section != NULL) { // Add in every path that the user has ever created a project file. This is to catch new projects showing up in the user's project folders TArray<FString> AdditionalDirectories; Section->MultiFind(TEXT("CreatedProjectPaths"), AdditionalDirectories); for(int Idx = 0; Idx < AdditionalDirectories.Num(); Idx++) { FPaths::NormalizeDirectoryName(AdditionalDirectories[Idx]); SearchDirectories.AddUnique(AdditionalDirectories[Idx]); } // Also add in all the recently opened projects TArray<FString> RecentlyOpenedFiles; Section->MultiFind(TEXT("RecentlyOpenedProjectFiles"), RecentlyOpenedFiles); for(int Idx = 0; Idx < RecentlyOpenedFiles.Num(); Idx++) { FPaths::NormalizeFilename(RecentlyOpenedFiles[Idx]); OutProjectFileNames.AddUnique(RecentlyOpenedFiles[Idx]); } } // Find all the other projects that are in the search directories for(int Idx = 0; Idx < SearchDirectories.Num(); Idx++) { TArray<FString> ProjectFolders; IFileManager::Get().FindFiles(ProjectFolders, *(SearchDirectories[Idx] / TEXT("*")), false, true); for(int32 FolderIdx = 0; FolderIdx < ProjectFolders.Num(); FolderIdx++) { TArray<FString> ProjectFiles; IFileManager::Get().FindFiles(ProjectFiles, *(SearchDirectories[Idx] / ProjectFolders[FolderIdx] / TEXT("*.uproject")), true, false); for(int32 FileIdx = 0; FileIdx < ProjectFiles.Num(); FileIdx++) { OutProjectFileNames.AddUnique(SearchDirectories[Idx] / ProjectFolders[FolderIdx] / ProjectFiles[FileIdx]); } } } // Find all the native projects, and either add or remove them from the list depending on whether we want native projects const FUProjectDictionary &Dictionary = GetCachedProjectDictionary(RootDir); if(bIncludeNativeProjects) { TArray<FString> NativeProjectPaths = Dictionary.GetProjectPaths(); for(int Idx = 0; Idx < NativeProjectPaths.Num(); Idx++) { if(!NativeProjectPaths[Idx].Contains(TEXT("/Templates/"))) { OutProjectFileNames.AddUnique(NativeProjectPaths[Idx]); } } } else { TArray<FString> NativeProjectPaths = Dictionary.GetProjectPaths(); for(int Idx = 0; Idx < NativeProjectPaths.Num(); Idx++) { OutProjectFileNames.Remove(NativeProjectPaths[Idx]); } } return true; }
void USpeedTreeImportData::LoadOptions() { int32 PortFlags = 0; for (UProperty* Property = GetClass()->PropertyLink; Property; Property = Property->PropertyLinkNext) { if (!Property->HasAnyPropertyFlags(CPF_Config)) { continue; } FString Section = TEXT("SpeedTree_Import_UI_Option_") + GetClass()->GetName(); FString Key = Property->GetName(); const bool bIsPropertyInherited = Property->GetOwnerClass() != GetClass(); UObject* SuperClassDefaultObject = GetClass()->GetSuperClass()->GetDefaultObject(); const FString& PropFileName = GEditorPerProjectIni; UArrayProperty* Array = dynamic_cast<UArrayProperty*>(Property); if (Array) { FConfigSection* Sec = GConfig->GetSectionPrivate(*Section, 0, 1, *GEditorPerProjectIni); if (Sec != nullptr) { TArray<FConfigValue> List; const FName KeyName(*Key, FNAME_Find); Sec->MultiFind(KeyName, List); FScriptArrayHelper_InContainer ArrayHelper(Array, this); // Only override default properties if there is something to override them with. if (List.Num() > 0) { ArrayHelper.EmptyAndAddValues(List.Num()); for (int32 i = List.Num() - 1, c = 0; i >= 0; i--, c++) { Array->Inner->ImportText(*List[i].GetValue(), ArrayHelper.GetRawPtr(c), PortFlags, this); } } else { int32 Index = 0; const FConfigValue* ElementValue = nullptr; do { // Add array index number to end of key FString IndexedKey = FString::Printf(TEXT("%s[%i]"), *Key, Index); // Try to find value of key const FName IndexedName(*IndexedKey, FNAME_Find); if (IndexedName == NAME_None) { break; } ElementValue = Sec->Find(IndexedName); // If found, import the element if (ElementValue != nullptr) { // expand the array if necessary so that Index is a valid element ArrayHelper.ExpandForIndex(Index); Array->Inner->ImportText(*ElementValue->GetValue(), ArrayHelper.GetRawPtr(Index), PortFlags, this); } Index++; } while (ElementValue || Index < ArrayHelper.Num()); } } } else { for (int32 i = 0; i < Property->ArrayDim; i++) { if (Property->ArrayDim != 1) { Key = FString::Printf(TEXT("%s[%i]"), *Property->GetName(), i); } FString Value; bool bFoundValue = GConfig->GetString(*Section, *Key, Value, *GEditorPerProjectIni); if (bFoundValue) { if (Property->ImportText(*Value, Property->ContainerPtrToValuePtr<uint8>(this, i), PortFlags, this) == NULL) { // this should be an error as the properties from the .ini / .int file are not correctly being read in and probably are affecting things in subtle ways UE_LOG(LogSpeedTreeImportData, Error, TEXT("SpeedTree Options LoadOptions (%s): failed for %s in: %s"), *GetPathName(), *Property->GetName(), *Value); } } } } } }