void FContentDirectoryMonitor::ExtractAssetsToDelete(TArray<FAssetData>& OutAssetsToDelete)
{
	for (auto& Deletion : DeletedFiles)
	{
		for (const auto& AssetData : Utils::FindAssetsPertainingToFile(*Registry, Cache.GetDirectory() + Deletion.Filename.Get()))
		{
			OutAssetsToDelete.Add(AssetData);
		}

		// Let the cache know that we've dealt with this change (it will be imported in due course)
		Cache.CompleteTransaction(MoveTemp(Deletion));
	}

	DeletedFiles.Empty();
}
		virtual FArchive& operator<<(FStringAssetReference& Value) override
		{
			FArchive& Ar = *this;

			FString Path = Value.ToString();

			Ar << Path;

			if (IsLoading())
			{
				Value.SetPath(MoveTemp(Path));
			}

			return Ar;
		}
	/** Given a potential string, we produce a final FTextToken for it using the correct comparison mode (as inferred from the given string) */
	FTextToken CreateTextTokenFromUnquotedString(FString InString)
	{
		ETextFilterTextComparisonMode TextComparisonMode = ETextFilterTextComparisonMode::Partial;

		// The final string may embed the TextCmpExact (+) operator, or the TextCmpAnchor operators (...) - test for those now so we can use the correct comparison mode
		if (InString.Len() > 0 && InString[0] == '+')
		{
			// Matched TextCmpExact - update the comparison mode and remove the + token from the start of the string
			TextComparisonMode = ETextFilterTextComparisonMode::Exact;
			InString.RemoveAt(0, 1, false);
		}
		else if (InString.Len() > 2 && InString.StartsWith(TEXT("..."), ESearchCase::CaseSensitive))
		{
			// Matched TextCmpAnchor (pre-unary) - update the comparison mode and remove the ... token from the start of the string
			TextComparisonMode = ETextFilterTextComparisonMode::EndsWith;
			InString.RemoveAt(0, 3, false);
		}
		else if (InString.Len() > 2 && InString.EndsWith(TEXT("..."), ESearchCase::CaseSensitive))
		{
			// Matched TextCmpAnchor (post-unary) - update the comparison mode and remove the ... token from the end of the string
			TextComparisonMode = ETextFilterTextComparisonMode::StartsWith;
			InString.RemoveAt(InString.Len() - 3, 3, false);
		}

		// To preserve behavior with the old text filter, the final string may also contain a TextCmpInvert (-) operator (after stripping the TextCmpExact or TextCmpAnchor tokens from the start)
		FTextToken::EInvertResult InvertResult = FTextToken::EInvertResult::No;
		if (InString.Len() > 0 && InString[0] == '-')
		{
			// Matched TextCmpInvert - remove the - token from the start of the string
			InvertResult = FTextToken::EInvertResult::Yes;
			InString.RemoveAt(0, 1, false);
		}

		// Finally, if our string starts and ends with a quote, we need to strip those off now
		if (InString.Len() > 1 && (InString[0] == '"' || InString[0] == '\''))
		{
			const TCHAR QuoteChar = InString[0];
			if (InString[InString.Len() - 1] == QuoteChar)
			{
				// Remove the quotes
				InString.RemoveAt(0, 1, false);
				InString.RemoveAt(InString.Len() - 1, 1, false);
			}
		}

		return FTextToken(MoveTemp(InString), TextComparisonMode, InvertResult);
	}
TSharedRef<IToolTip> FWidgetTemplateBlueprintClass::GetToolTip() const
{
	FText Description;

	FString DescriptionStr = WidgetAssetData.GetTagValueRef<FString>( GET_MEMBER_NAME_CHECKED( UBlueprint, BlueprintDescription ) );
	if ( !DescriptionStr.IsEmpty() )
	{
		DescriptionStr.ReplaceInline( TEXT( "\\n" ), TEXT( "\n" ) );
		Description = FText::FromString( MoveTemp(DescriptionStr) );
	}
	else
	{
		Description = Name;
	}

	return IDocumentation::Get()->CreateToolTip( Description, nullptr, FString( TEXT( "Shared/Types/" ) ) + Name.ToString(), TEXT( "Class" ) );
}
void UCreatureAnimationAsset::PostLoad()
{
	Super::PostLoad();

	if (!creature_filename.IsEmpty() && AssetImportData && AssetImportData->GetSourceData().SourceFiles.Num() == 0)
	{
		// convert old source file path to proper UE4 Asset data system
		FAssetImportInfo Info;
		Info.Insert(FAssetImportInfo::FSourceFile(creature_filename));
		AssetImportData->SourceData = MoveTemp(Info);
	}

	if (CreatureZipBinary.Num() != 0 || CreatureFileJSonData.IsEmpty() == false)
	{
		// load the animation data caches from the json data
		GatherAnimationData();
	}
}
bool FOnlineUserCloudOculus::ReadUserFile(const FUniqueNetId& UserId, const FString& FileName)
{
	auto LoggedInPlayerId = OculusSubsystem.GetIdentityInterface()->GetUniquePlayerId(0);
	if (!LoggedInPlayerId.IsValid() || UserId != *LoggedInPlayerId)
	{
		UE_LOG_ONLINE(Warning, TEXT("Can only read data for logged in player"));
		return false;
	}

	FString BucketName;
	FString Key;
	if (!(FileName.Split(SEPARATOR, &BucketName, &Key)))
	{
		BucketName = DefaultBucket;
		Key = FileName;
	}

	OculusSubsystem.AddRequestDelegate(
		ovr_CloudStorage_Load(TCHAR_TO_UTF8(*BucketName), TCHAR_TO_UTF8(*Key)),
		FOculusMessageOnCompleteDelegate::CreateLambda([this, BucketName, Key, LoggedInPlayerId, FileName](ovrMessageHandle Message, bool bIsError)
	{
		ovrCloudStorageDataHandle response = ovr_Message_GetCloudStorageData(Message);
		check(BucketName == UTF8_TO_TCHAR(ovr_CloudStorageData_GetBucket(response)));
		check(Key == UTF8_TO_TCHAR(ovr_CloudStorageData_GetKey(response)));

		if (bIsError)
		{
			UE_LOG_ONLINE(Warning, TEXT("Failed to Load: %s%s%s"), *BucketName, *SEPARATOR, *Key);
		}
		else
		{
			int64 BlobSize = ovr_CloudStorageData_GetDataSize(response);
			const void* RawBlob = ovr_CloudStorageData_GetData(response);

			TArray<uint8> Blob;
			Blob.Insert(static_cast<const uint8 *>(RawBlob), BlobSize, 0);

			ReadCache.Add(FileName, MoveTemp(Blob));
		}
		TriggerOnReadUserFileCompleteDelegates(!bIsError, *LoggedInPlayerId, FileName);
	}));

	return true;
}
void FVideoCaptureProtocol::ProcessFrame(FCapturedFrameData Frame)
{
	FVideoFrameData* Payload = Frame.GetPayload<FVideoFrameData>();

	const int32 WriterIndex = Payload->WriterIndex;

	AVIWriters[WriterIndex]->DropFrames(Payload->Metrics.NumDroppedFrames);
	AVIWriters[WriterIndex]->Update(Payload->Metrics.TotalElapsedTime, MoveTemp(Frame.ColorBuffer));

	// Finalize previous writers if necessary
	for (int32 Index = 0; Index < Payload->WriterIndex; ++Index)
	{
		TUniquePtr<FAVIWriter>& Writer = AVIWriters[Index];
		if (Writer->IsCapturing())
		{
			Writer->Finalize();
		}
	}
}
void FVideoCaptureProtocol::ConditionallyCreateWriter(const ICaptureProtocolHost& Host)
{
#if PLATFORM_MAC
	static const TCHAR* Extension = TEXT(".mov");
#else
	static const TCHAR* Extension = TEXT(".avi");
#endif

	FString VideoFilename = Host.GenerateFilename(FFrameMetrics(), Extension);

	if (AVIWriters.Num() && VideoFilename == AVIWriters.Last()->Options.OutputFilename)
	{
		return;
	}

	Host.EnsureFileWritable(VideoFilename);

	UVideoCaptureSettings* CaptureSettings = CastChecked<UVideoCaptureSettings>(InitSettings->ProtocolSettings);

	FAVIWriterOptions Options;
	Options.OutputFilename = MoveTemp(VideoFilename);
	Options.CaptureFPS = Host.GetCaptureFrequency();
	Options.CodecName = CaptureSettings->VideoCodec;
	Options.bSynchronizeFrames = Host.GetCaptureStrategy().ShouldSynchronizeFrames();
	Options.Width = InitSettings->DesiredSize.X;
	Options.Height = InitSettings->DesiredSize.Y;

	if (CaptureSettings->bUseCompression)
	{
		Options.CompressionQuality = CaptureSettings->CompressionQuality / 100.f;
		
		float QualityOverride = 100.f;
		if (FParse::Value( FCommandLine::Get(), TEXT( "-MovieQuality=" ), QualityOverride ))
		{
			Options.CompressionQuality = FMath::Clamp(QualityOverride, 1.f, 100.f) / 100.f;
		}

		Options.CompressionQuality = FMath::Clamp<float>(Options.CompressionQuality.GetValue(), 0.f, 1.f);
	}

	AVIWriters.Emplace(FAVIWriter::CreateInstance(Options));
	AVIWriters.Last()->Initialize();
}
bool FStringAssetReference::SerializeFromMismatchedTag(struct FPropertyTag const& Tag, FArchive& Ar)
{
	struct UObjectTypePolicy
	{
		typedef UObject Type;
		static const FName FORCEINLINE GetTypeName() { return NAME_ObjectProperty; }
	};

	FString Path = ToString();

	bool bReturn = SerializeFromMismatchedTagTemplate<UObjectTypePolicy>(Path, Tag, Ar);

	if (Ar.IsLoading())
	{
		SetPath(MoveTemp(Path));
	}

	return bReturn;
}
/** 
 * Helper function for FCheckInWorker::Execute.
 * Makes sure directories are committed with files that are also marked for add.
 * If we don't do this, the commit will fail.
 */
static void AddDirectoriesToCommit(const FSubversionSourceControlCommand& InCommand, TArray<FString>& InOutFiles)
{
	// because of the use of "--parents" when we mark for add, we can just traverse up 
	// the directory tree until we meet a directory that isn't already marked for add

	TArray<FString> Directories;

	FString WorkingCopyRoot = InCommand.WorkingCopyRoot;
	FPaths::NormalizeDirectoryName(WorkingCopyRoot);

	for(const auto& Filename : InOutFiles)
	{
		FString Directory = FPaths::GetPath(Filename);
		FPaths::NormalizeDirectoryName(Directory);

		// Stop once we leave our working copy, or find a directory that isn't marked for add
		while(Directory.StartsWith(WorkingCopyRoot))
		{
			// Stop if we've already processed this directory, or if this directory isn't marked for add
			if(Directories.Contains(Directory) || !IsDirectoryAdded(InCommand, Directory))
			{
				break;
			}

			Directories.Add(Directory);

			// Chop off the end of this directory to move up to our parent directory
			// This is safe to do since we called NormalizeDirectoryName on it, and we're testing to make sure we stay within the working copy
			int32 ChopPoint = INDEX_NONE;
			if(Directory.FindLastChar('/', ChopPoint))
			{
				Directory = Directory.Left(ChopPoint);
			}
			else
			{
				// No more path to process
				break;
			}
		}
	}

	InOutFiles.Append(MoveTemp(Directories));
}
	virtual void SetupView(FSceneViewFamily& InViewFamily, FSceneView& InView)
	{
		if (!bNeedsCapture)
		{
			return;
		}

		InView.FinalPostProcessSettings.bBufferVisualizationDumpRequired = true;
		InView.FinalPostProcessSettings.BufferVisualizationOverviewMaterials.Empty();
		InView.FinalPostProcessSettings.BufferVisualizationDumpBaseFilename = MoveTemp(OutputFilename);

		struct FIterator
		{
			FFinalPostProcessSettings& FinalPostProcessSettings;
			const TArray<FString>& RenderPasses;

			FIterator(FFinalPostProcessSettings& InFinalPostProcessSettings, const TArray<FString>& InRenderPasses)
				: FinalPostProcessSettings(InFinalPostProcessSettings), RenderPasses(InRenderPasses)
			{}

			void ProcessValue(const FString& InName, UMaterial* Material, const FText& InText)
			{
				if (!RenderPasses.Num() || RenderPasses.Contains(InName) || RenderPasses.Contains(InText.ToString()))
				{
					FinalPostProcessSettings.BufferVisualizationOverviewMaterials.Add(Material);
				}
			}
		} Iterator(InView.FinalPostProcessSettings, RenderPasses);
		GetBufferVisualizationData().IterateOverAvailableMaterials(Iterator);

		if (PostProcessingMaterial)
		{
			FWeightedBlendable Blendable(1.f, PostProcessingMaterial);
			PostProcessingMaterial->OverrideBlendableSettings(InView, 1.f);
		}


		// Ensure we're rendering at full size
		InView.ViewRect = InView.UnscaledViewRect;

		bNeedsCapture = false;
	}
bool FStringAssetReference::ImportTextItem(const TCHAR*& Buffer, int32 PortFlags, UObject* Parent, FOutputDevice* ErrorText)
{
	FString ImportedPath = TEXT("");
	const TCHAR* NewBuffer = UPropertyHelpers::ReadToken(Buffer, ImportedPath, 1);
	if (!NewBuffer)
	{
		return false;
	}
	Buffer = NewBuffer;
	if (ImportedPath == TEXT("None"))
	{
		ImportedPath = TEXT("");
	}
	else
	{
		if (*Buffer == TCHAR('\''))
		{
			NewBuffer = UPropertyHelpers::ReadToken(Buffer, ImportedPath, 1);
			if (!NewBuffer)
			{
				return false;
			}
			Buffer = NewBuffer;
			if (*Buffer++ != TCHAR('\''))
			{
				return false;
			}
		}
	}

	SetPath(MoveTemp(ImportedPath));

#if WITH_EDITOR
	// Consider this a load, so Config string asset references get cooked
	if (FCoreUObjectDelegates::StringAssetReferenceLoaded.IsBound())
	{
		FCoreUObjectDelegates::StringAssetReferenceLoaded.Execute(ToString());
	}
#endif // WITH_EDITOR

	return true;
}
Exemplo n.º 13
0
	void Finalize()
	{
		TArray<uint8> FinalData;
		FMemoryWriter NameTableWriter(FinalData);

		int32 NumNames = FNameIndexLookup.Num();
		check(NumNames <= MANIFEST_MAX_NAMES);
		NameTableWriter << NumNames;
		for (auto& MapEntry : FNameIndexLookup)
		{
			FName& Name = MapEntry.Key;
			int32& Index = MapEntry.Value;
			NameTableWriter << Name;
			NameTableWriter << Index;
		}

		FinalData.Append(Bytes);

		Bytes = MoveTemp(FinalData);
	}
bool FOnlineUserCloudOculus::WriteUserFile(const FUniqueNetId& UserId, const FString& FileName, TArray<uint8>& FileContents)
{
	auto LoggedInPlayerId = OculusSubsystem.GetIdentityInterface()->GetUniquePlayerId(0);
	if (!LoggedInPlayerId.IsValid() || UserId != *LoggedInPlayerId)
	{
		UE_LOG_ONLINE(Warning, TEXT("Can only save data for logged in player"));
		return false;
	}

	FString BucketName;
	FString Key;
	if (!(FileName.Split(SEPARATOR, &BucketName, &Key)))
	{
		BucketName = DefaultBucket;
		Key = FileName;
	}

	// store the save data in a temporary buffer until the Oculus Platform threadpool can process the request
	TArray<uint8> *TmpBuffer = new TArray<uint8>(MoveTemp(FileContents));

	auto DelegateLambda = FOculusMessageOnCompleteDelegate::CreateLambda([this, BucketName, Key, LoggedInPlayerId, FileName, TmpBuffer](ovrMessageHandle Message, bool bIsError)
	{
		check(BucketName == UTF8_TO_TCHAR(ovr_CloudStorageUpdateResponse_GetBucket(ovr_Message_GetCloudStorageUpdateResponse(Message))));
		check(Key == UTF8_TO_TCHAR(ovr_CloudStorageUpdateResponse_GetKey(ovr_Message_GetCloudStorageUpdateResponse(Message))));

		if (bIsError)
		{
			UE_LOG_ONLINE(Warning, TEXT("Failed to Save: %s%s%s"), *BucketName, *SEPARATOR, *Key);
		}

		delete TmpBuffer;
		TriggerOnWriteUserFileCompleteDelegates(!bIsError, *LoggedInPlayerId, FileName);
	});

	OculusSubsystem.AddRequestDelegate(
		ovr_CloudStorage_Save(TCHAR_TO_UTF8(*BucketName), TCHAR_TO_UTF8(*Key), TmpBuffer->GetData(), TmpBuffer->Num(), 0, nullptr),
		std::move(DelegateLambda));

	return true;
}
void FContentDirectoryMonitor::Tick()
{
	Cache.Tick();

	// Immediately resolve any changes that we should not consider
	const FDateTime Threshold = FDateTime::UtcNow() - FTimespan(0, 0, GetDefault<UEditorLoadingSavingSettings>()->AutoReimportThreshold);

	TArray<DirectoryWatcher::FUpdateCacheTransaction> InsignificantTransactions = Cache.FilterOutstandingChanges([=](const DirectoryWatcher::FUpdateCacheTransaction& Transaction, const FDateTime& TimeOfChange){
		return TimeOfChange <= Threshold && !ShouldConsiderChange(Transaction);
	});

	for (DirectoryWatcher::FUpdateCacheTransaction& Transaction : InsignificantTransactions)
	{
		Cache.CompleteTransaction(MoveTemp(Transaction));
	}

	const double Now = FPlatformTime::Seconds();
	if (Now - LastSaveTime > ResaveIntervalS)
	{
		LastSaveTime = Now;
		Cache.WriteCache();
	}
}
Exemplo n.º 16
0
void UAssetImportData::Serialize(FArchive& Ar)
{
	if (Ar.UE4Ver() >= VER_UE4_ASSET_IMPORT_DATA_AS_JSON)
	{
		FString Json;
		if (Ar.IsLoading())
		{
			Ar << Json;
			TOptional<FAssetImportInfo> Copy = FromJson(MoveTemp(Json));
			if (Copy.IsSet())
			{
				CopyFrom(Copy.GetValue());
			}
		}
		else if (Ar.IsSaving())
		{
			Json = ToJson();
			Ar << Json;
		}
	}

	Super::Serialize(Ar);
}
Exemplo n.º 17
0
FArchive& FArchiveUObject::operator<<(struct FStringAssetReference& Value)
{
	FString Path = Value.ToString();

	*this << Path;

	if (IsLoading())
	{
		if (UE4Ver() < VER_UE4_KEEP_ONLY_PACKAGE_NAMES_IN_STRING_ASSET_REFERENCES_MAP)
		{
			FString NormalizedPath = FPackageName::GetNormalizedObjectPath(Path);
			if (Value.ToString() != NormalizedPath)
			{
				Value.SetPath(NormalizedPath);
			}
		}
		else
		{
			Value.SetPath(MoveTemp(Path));
		}
	}

	return *this;
}
	bool TestWithType(FAutomationTestBase* Test)
	{
		int32 NumLeaks = 0;
		
		// Test that move-assigning the expression node correctly assigns the data, and calls the destructors successfully
		{
			TGuardValue<int32*> LeakCounter(T::LeakCount, &NumLeaks);
			
			FExpressionNode Original(T(1));
			FExpressionNode New = MoveTemp(Original);
			
			int32 ResultingId = New.Cast<T>()->Id;
			if (ResultingId != 1)
			{
				Test->AddError(FString::Printf(TEXT("Expression node move operator did not operate correctly. Expected moved-to state to be 1, it's actually %d."), ResultingId));
				return false;
			}

			// Try assigning it over the top again
			Original = FExpressionNode(T(1));
			New = MoveTemp(Original);

			ResultingId = New.Cast<T>()->Id;
			if (ResultingId != 1)
			{
				Test->AddError(FString::Printf(TEXT("Expression node move operator did not operate correctly. Expected moved-to state to be 1, it's actually %d."), ResultingId));
				return false;
			}

			// Now try running it all through a parser
			FTokenDefinitions TokenDefs;
			FExpressionGrammar Grammar;
			FOperatorJumpTable JumpTable;

			// Only valid tokens are a, b, and +
			TokenDefs.DefineToken([](FExpressionTokenConsumer& Consumer){
				auto Token = Consumer.GetStream().GenerateToken(1);
				if (Token.IsSet())
				{
					switch(Consumer.GetStream().PeekChar())
					{
					case 'a': Consumer.Add(Token.GetValue(), T(1)); break;
					case '+': Consumer.Add(Token.GetValue(), FOperator()); break;
					}
				}
				return TOptional<FExpressionError>();
			});

			Grammar.DefinePreUnaryOperator<FOperator>();
			Grammar.DefineBinaryOperator<FOperator>(1);

			JumpTable.MapPreUnary<FOperator>([](const T& A)					{ return T(A.Id); });
			JumpTable.MapBinary<FOperator>([](const T& A, const T& B)		{ return T(A.Id); });

			ExpressionParser::Evaluate(TEXT("+a"), TokenDefs, Grammar, JumpTable);
			ExpressionParser::Evaluate(TEXT("a+a"), TokenDefs, Grammar, JumpTable);
			ExpressionParser::Evaluate(TEXT("+a++a"), TokenDefs, Grammar, JumpTable);
		}

		if (NumLeaks != 0)
		{
			Test->AddError(FString::Printf(TEXT("Expression node did not call wrapped type's destructors correctly. Potentially resulted in %d leaks."), NumLeaks));
			return false;
		}

		return true;
	}
Exemplo n.º 19
0
bool FPackageReader::ReadAssetRegistryData (TArray<FBackgroundAssetData*>& AssetDataList)
{
	check(Loader);

	// Does the package contain asset registry tags
	if( PackageFileSummary.AssetRegistryDataOffset == 0 )
	{
		// No Tag Table!
		return false;
	}

	// Seek the the part of the file where the asset registry tags live
	Seek( PackageFileSummary.AssetRegistryDataOffset );

	// Determine the package name and path
	FString PackageName = FPackageName::FilenameToLongPackageName(PackageFilename);
	FString PackagePath = FPackageName::GetLongPackagePath(PackageName);

	const bool bIsMapPackage = (PackageFileSummary.PackageFlags & PKG_ContainsMap) != 0;

	// Assets do not show up in map packages unless we launch with -WorldAssets
	static const bool bUsingWorldAssets = FAssetRegistry::IsUsingWorldAssets();
	if ( bIsMapPackage && !bUsingWorldAssets )
	{
		return true;
	}

	// Load the object count
	int32 ObjectCount = 0;
	*this << ObjectCount;

	// Worlds that were saved before they were marked public do not have asset data so we will synthesize it here to make sure we see all legacy umaps
	// We will also do this for maps saved after they were marked public but no asset data was saved for some reason. A bug caused this to happen for some maps.
	if (bUsingWorldAssets && bIsMapPackage)
	{
		const bool bLegacyPackage = PackageFileSummary.GetFileVersionUE4() < VER_UE4_PUBLIC_WORLDS;
		const bool bNoMapAsset = (ObjectCount == 0);
		if (bLegacyPackage || bNoMapAsset)
		{
			FString AssetName = FPackageName::GetLongPackageAssetName(PackageName);
			AssetDataList.Add(new FBackgroundAssetData(PackageName, PackagePath, FString(), MoveTemp(AssetName), TEXT("World"), TMap<FString, FString>(), PackageFileSummary.ChunkIDs, PackageFileSummary.PackageFlags));
		}
	}

	// UAsset files only have one object, but legacy or map packages may have more.
	for(int32 ObjectIdx = 0; ObjectIdx < ObjectCount; ++ObjectIdx)
	{
		FString ObjectPath;
		FString ObjectClassName;
		int32 TagCount = 0;
		*this << ObjectPath;
		*this << ObjectClassName;
		*this << TagCount;

		TMap<FString, FString> TagsAndValues;

		for(int32 TagIdx = 0; TagIdx < TagCount; ++TagIdx)
		{
			FString Key;
			FString Value;
			*this << Key;
			*this << Value;

			TagsAndValues.Add(Key, Value);
		}

		FString GroupNames;
		FString AssetName;

		if ( ObjectPath.Contains(TEXT("."), ESearchCase::CaseSensitive))
		{
			ObjectPath.Split(TEXT("."), &GroupNames, &AssetName, ESearchCase::CaseSensitive, ESearchDir::FromEnd);
		}
		else
		{
			AssetName = ObjectPath;
		}

		// Before world were RF_Public, other non-public assets were added to the asset data table in map packages.
		// Here we simply skip over them
		if ( bIsMapPackage && PackageFileSummary.GetFileVersionUE4() < VER_UE4_PUBLIC_WORLDS )
		{
			if ( AssetName != FPackageName::GetLongPackageAssetName(PackageName) )
			{
				continue;
			}
		}

		// Create a new FBackgroundAssetData for this asset and update it with the gathered data
		AssetDataList.Add(new FBackgroundAssetData(PackageName, PackagePath, MoveTemp(GroupNames), MoveTemp(AssetName), MoveTemp(ObjectClassName), MoveTemp(TagsAndValues), PackageFileSummary.ChunkIDs, PackageFileSummary.PackageFlags));
	}

	return true;
}
	/** Consume the text from the specified consumer's stream */
	TOptional<FExpressionError> ConsumeTextImpl(FExpressionTokenConsumer& Consumer, const TFunctionRef<bool(TCHAR)> IsBreakingCharacter)
	{
		auto& Stream = Consumer.GetStream();

		FString FinalString;
		FString CurrentQuotedString;

		TCHAR QuoteChar = 0;
		int32 NumConsecutiveSlashes = 0;
		TOptional<FStringToken> TextToken = Stream.ParseToken([&](TCHAR InC)
		{
			if (QuoteChar == 0) // Parsing a non-quoted string...
			{
				// Are we starting a quoted sub-string?
				if (InC == '"' || InC == '\'')
				{
					CurrentQuotedString.AppendChar(InC);
					QuoteChar = InC;
					NumConsecutiveSlashes = 0;
				}
				else
				{
					// Consume until we hit a breaking character
					if (IsBreakingCharacter(InC))
					{
						return EParseState::StopBefore;
					}

					FinalString.AppendChar(InC);
				}
			}
			else // Parsing a quoted sub-string...
			{
				CurrentQuotedString.AppendChar(InC);

				// Are we ending a quoted sub-string?
				if (InC == QuoteChar && NumConsecutiveSlashes%2 == 0)
				{
					UnescapeQuotedString(CurrentQuotedString, QuoteChar);
					FinalString.Append(CurrentQuotedString);

					CurrentQuotedString.Reset();
					QuoteChar = 0;
				}

				if (InC == '\\')
				{
					NumConsecutiveSlashes++;
				}
				else
				{
					NumConsecutiveSlashes = 0;
				}
			}

			return EParseState::Continue;
		});

		if (TextToken.IsSet())
		{
			Consumer.Add(TextToken.GetValue(), CreateTextTokenFromUnquotedString(MoveTemp(FinalString)));
		}

		return TOptional<FExpressionError>();
	}
	FExpressionResult Evaluate(const TArray<FCompiledToken>& CompiledTokens, const IOperatorEvaluationEnvironment& InEnvironment)
	{
		// Evaluation strategy: the supplied compiled tokens are const. To avoid copying the whole array, we store a separate array of
		// any tokens that are generated at runtime by the evaluator. The operand stack will consist of indices into either the CompiledTokens
		// array, or the RuntimeGeneratedTokens (where Index >= CompiledTokens.Num())
		TArray<FExpressionToken> RuntimeGeneratedTokens;
		TArray<int32> OperandStack;

		/** Get the token pertaining to the specified operand index */
		auto GetToken = [&](int32 Index) -> const FExpressionToken& {
			if (Index < CompiledTokens.Num())
			{
				return CompiledTokens[Index];
			}

			return RuntimeGeneratedTokens[Index - CompiledTokens.Num()];
		};

		/** Add a new token to the runtime generated array */
		auto AddToken = [&](FExpressionToken&& In) -> int32 {
			auto Index = CompiledTokens.Num() + RuntimeGeneratedTokens.Num();
			RuntimeGeneratedTokens.Emplace(MoveTemp(In));
			return Index;
		};


		for (int32 Index = 0; Index < CompiledTokens.Num(); ++Index)
		{
			const auto& Token = CompiledTokens[Index];

			switch(Token.Type)
			{
			case FCompiledToken::Benign:
				continue;

			case FCompiledToken::Operand:
				OperandStack.Push(Index);
				continue;

			case FCompiledToken::BinaryOperator:
				if (OperandStack.Num() >= 2)
				{
					// Binary
					const auto& R = GetToken(OperandStack.Pop());
					const auto& L = GetToken(OperandStack.Pop());

					auto OpResult = InEnvironment.ExecBinary(Token, L, R);
					if (OpResult.IsValid())
					{
						// Inherit the LHS context
						OperandStack.Push(AddToken(FExpressionToken(L.Context, MoveTemp(OpResult.GetValue()))));
					}
					else
					{
						return MakeError(OpResult.GetError());
					}
				}
				else
				{
					FFormatOrderedArguments Args;
					Args.Add(FText::FromString(Token.Context.GetString()));
					return MakeError(FText::Format(LOCTEXT("SyntaxError_NotEnoughOperandsBinary", "Not enough operands for binary operator {0}"), Args));
				}
				break;
			
			case FCompiledToken::PostUnaryOperator:
			case FCompiledToken::PreUnaryOperator:

				if (OperandStack.Num() >= 1)
				{
					const auto& Operand = GetToken(OperandStack.Pop());

					FExpressionResult OpResult = (Token.Type == FCompiledToken::PreUnaryOperator) ?
						InEnvironment.ExecPreUnary(Token, Operand) :
						InEnvironment.ExecPostUnary(Token, Operand);

					if (OpResult.IsValid())
					{
						// Inherit the LHS context
						OperandStack.Push(AddToken(FExpressionToken(Operand.Context, MoveTemp(OpResult.GetValue()))));
					}
					else
					{
						return MakeError(OpResult.GetError());
					}			
				}
				else
				{
					FFormatOrderedArguments Args;
					Args.Add(FText::FromString(Token.Context.GetString()));
					return MakeError(FText::Format(LOCTEXT("SyntaxError_NoUnaryOperand", "No operand for unary operator {0}"), Args));
				}
				break;
			}
		}

		if (OperandStack.Num() == 1)
		{
			return MakeValue(GetToken(OperandStack[0]).Node.Copy());
		}

		return MakeError(LOCTEXT("SyntaxError_InvalidExpression", "Could not evaluate expression"));
	}
Exemplo n.º 22
0
/**
* Run a Git show command to dump the binary content of a revision into a file.
*/
bool RunDumpToFile(const FString& InPathToGitBinary, const FString& InRepositoryRoot, const FString& InParameter, const FString& InDumpFileName)
{
	bool bResult = false;
	FString FullCommand;

	if(!InRepositoryRoot.IsEmpty())
	{
		// Specify the working copy (the root) of the git repository (before the command itself)
		FullCommand = TEXT("--work-tree=\"");
		FullCommand += InRepositoryRoot;
		// and the ".git" subdirectory in it (before the command itself)
		FullCommand += TEXT("\" --git-dir=\"");
		FullCommand += InRepositoryRoot;
		FullCommand += TEXT(".git\" ");
	}
	// then the git command itself
	FullCommand += TEXT("show ");

	// Append to the command the parameter
	FullCommand += InParameter;

	const bool bLaunchDetached = false;
	const bool bLaunchHidden = true;
	const bool bLaunchReallyHidden = bLaunchHidden;

	// Setup output redirection pipes, so that we can harvest compiler output and display it ourselves
#if PLATFORM_LINUX
	int pipefd[2];
	pipe(pipefd);
	void* PipeRead = &pipefd[0];
	void* PipeWrite = &pipefd[1];
#else
	void* PipeRead = NULL;
	void* PipeWrite = NULL;
#endif

	verify(FPlatformProcess::CreatePipe(PipeRead, PipeWrite));

	// @todo temp debug log
	//UE_LOG(LogSourceControl, Log, TEXT("RunDumpToFile: 'git %s'"), *FullCommand);
	FProcHandle ProcessHandle = FPlatformProcess::CreateProc(*InPathToGitBinary, *FullCommand, bLaunchDetached, bLaunchHidden, bLaunchReallyHidden, NULL, 0, NULL, PipeWrite);
	//UE_LOG(LogSourceControl, Log, TEXT("RunDumpToFile: ProcessHandle=%x"), ProcessHandle.Get());
	if(ProcessHandle.IsValid())
	{
		FPlatformProcess::Sleep(0.01);

		TArray<uint8> BinaryFileContent;
		while(FPlatformProcess::IsProcRunning(ProcessHandle))
		{
			TArray<uint8> BinaryData;
			FPlatformProcess::ReadPipeToArray(PipeRead, BinaryData);
			if(BinaryData.Num() > 0)
			{
				BinaryFileContent.Append(MoveTemp(BinaryData));
			}
		}
		TArray<uint8> BinaryData;
		FPlatformProcess::ReadPipeToArray(PipeRead, BinaryData);
		if(BinaryData.Num() > 0)
		{
			BinaryFileContent.Append(MoveTemp(BinaryData));
		}
		// Save buffer into temp file
		if(FFileHelper::SaveArrayToFile(BinaryFileContent, *InDumpFileName))
		{
			UE_LOG(LogSourceControl, Log, TEXT("Writed '%s' (%do)"), *InDumpFileName, BinaryFileContent.Num());
			bResult = true;
		}
		else
		{
			UE_LOG(LogSourceControl, Error, TEXT("Could not write %s"), *InDumpFileName);
		}
	}
	else
	{
		UE_LOG(LogSourceControl, Error, TEXT("Failed to launch 'git show'"));
	}

#if PLATFORM_LINUX
	close(*(int*)PipeRead);
	close(*(int*)PipeWrite);
#else
	FPlatformProcess::ClosePipe(PipeRead, PipeWrite);
#endif

	return bResult;
}
FCPPRichTextSyntaxHighlighterTextLayoutMarshaller::FCPPRichTextSyntaxHighlighterTextLayoutMarshaller(TSharedPtr< FSyntaxTokenizer > InTokenizer, const FSyntaxTextStyle& InSyntaxTextStyle)
	: FSyntaxHighlighterTextLayoutMarshaller(MoveTemp(InTokenizer))
	, SyntaxTextStyle(InSyntaxTextStyle)
{
}
Exemplo n.º 24
0
	static FText Format(const FText& Pattern, FGetArgumentValue GetArgumentValue)
	{
		checkf(FInternationalization::Get().IsInitialized() == true, TEXT("FInternationalization is not initialized. An FText formatting method was likely used in static object initialization - this is not supported."));
		//SCOPE_CYCLE_COUNTER( STAT_TextFormat );

		const FString& PatternString = Pattern.ToString();

		FString ResultString;

		EEscapeState::Type EscapeState = EEscapeState::None;
		EBlockState::Type BlockState = EBlockState::None;

		FString ArgumentName;

		for(int32 i = 0; i < PatternString.Len(); ++i)
		{
			switch( EscapeState )
			{
			case EEscapeState::None:
				{
					switch( PatternString[i] )
					{
					case '`':	{ EscapeState = EEscapeState::BeginEscaping; } break;
					}
				}
				break;
			case EEscapeState::BeginEscaping:
				{
					switch( PatternString[i] )
					{
						// Only begin EEscapeState::Escaping if there's a syntax character.
					case '{':
					case '}':
						{
							EscapeState = EEscapeState::Escaping;
							ResultString += PatternString[i]; // Characters are escaped, copy over.
						}
						break;
						// Cancel beginning EEscapeState::Escaping if the escape is itself escaped.
					case '`':
						{
							EscapeState = EEscapeState::None;
						}
						break;
						// Cancel beginning EEscapeState::Escaping if not a syntax character.
					default:
						{
							EscapeState = EEscapeState::None;
							ResultString += '`'; // Insert previously ignored escape marker.
						}
						break;
					}
				}
				break;
			case EEscapeState::Escaping:
				{
					switch( PatternString[i] )
					{
					case '`':	{ EscapeState = EEscapeState::EndEscaping; } break;
					default:	{ ResultString += PatternString[i]; } break; // Characters are escaped, copy over.
					}
				}
				break;
			case EEscapeState::EndEscaping:
				{
					switch( PatternString[i] )
					{
					case '`':	{ EscapeState = EEscapeState::Escaping; ResultString += PatternString[i]; } break; // Cancel ending EEscapeState::Escaping if the escape is itself escaped, copy over escaped character.
					default:	{ EscapeState = EEscapeState::None; } break;
					}
				}
				break;
			}

			if(EscapeState == EEscapeState::None)
			{
				switch( BlockState )
				{
				case EBlockState::None:
					{
						switch( PatternString[i] )
						{
						case '{':
							{
								BlockState = EBlockState::InBlock;
							}
							break;
						default:
							{
								ResultString += PatternString[i]; // Copy over characters.
							}
							break;
						}
					}
					break;
				case EBlockState::InBlock:
					{
						switch( PatternString[i] )
						{
						case '}':
							{
							
								const FFormatArgumentValue* const PossibleArgumentValue = GetArgumentValue.Execute(ArgumentName);
								if( PossibleArgumentValue )
								{
									FString ArgumentValueAsString;
									const FFormatArgumentValue& ArgumentValue = *PossibleArgumentValue;
									switch(ArgumentValue.Type)
									{
									case EFormatArgumentType::Text:
										{
											ArgumentValueAsString = ArgumentValue.TextValue->ToString();
										}
										break;
									case EFormatArgumentType::Int:
										{
											ArgumentValueAsString = FText::AsNumber(ArgumentValue.IntValue).ToString();
										}
										break;
									case EFormatArgumentType::UInt:
										{
											ArgumentValueAsString = FText::AsNumber(ArgumentValue.UIntValue).ToString();
										}
										break;
									case EFormatArgumentType::Float:
										{
											ArgumentValueAsString = FText::AsNumber(ArgumentValue.FloatValue).ToString();
										}
										break;
									case EFormatArgumentType::Double:
										{
											ArgumentValueAsString = FText::AsNumber(ArgumentValue.DoubleValue).ToString();
										}
										break;
									}
									ResultString += ArgumentValueAsString;
								}
								else
								{
									ResultString += FString("{") + ArgumentName + FString("}");
								}
								ArgumentName.Empty();
								BlockState = EBlockState::None;
							}
							break;
						default:
							{
								ArgumentName += PatternString[i];
							}
							break;
						}
					}
					break;
				}
			}
		}

		FText Result = FText(MoveTemp(ResultString));
		if (!GIsEditor)
		{
			Result.Flags = Result.Flags | ETextFlag::Transient;
		}
		return Result;
	}
FText UKismetTextLibrary::Format(FText InPattern, TArray<FFormatArgumentData> InArgs)
{
	return FText::Format(MoveTemp(InPattern), MoveTemp(InArgs));
}
		FHugeType(FHugeType&& In) : FMoveableType(MoveTemp(In)) {}
Exemplo n.º 27
0
void ULandscapeEditorObject::RefreshImportLayersList()
{
	UTexture2D* ThumbnailWeightmap = LoadObject<UTexture2D>(NULL, TEXT("/Engine/EditorLandscapeResources/LandscapeThumbnailWeightmap.LandscapeThumbnailWeightmap"), NULL, LOAD_None, NULL);
	UTexture2D* ThumbnailHeightmap = LoadObject<UTexture2D>(NULL, TEXT("/Engine/EditorLandscapeResources/LandscapeThumbnailHeightmap.LandscapeThumbnailHeightmap"), NULL, LOAD_None, NULL);

	UMaterialInterface* Material = NewLandscape_Material.Get();
	TArray<FName> LayerNames = ALandscapeProxy::GetLayersFromMaterial(Material);

	const TArray<FLandscapeImportLayer> OldLayersList = MoveTemp(ImportLandscape_Layers);
	ImportLandscape_Layers.Reset(LayerNames.Num());

	for (int32 i = 0; i < LayerNames.Num(); i++)
	{
		const FName& LayerName = LayerNames[i];

		bool bFound = false;
		FLandscapeImportLayer NewImportLayer;
		for (int32 j = 0; j < OldLayersList.Num(); j++)
		{
			if (OldLayersList[j].LayerName == LayerName)
			{
				NewImportLayer = OldLayersList[j];
				bFound = true;
				break;
			}
		}

		if (bFound)
		{
			UMaterialInstanceConstant* CombinationMaterialInstance = CastChecked<UMaterialInstanceConstant>(NewImportLayer.ThumbnailMIC->Parent);
			if (CombinationMaterialInstance->Parent != Material)
			{
				CombinationMaterialInstance->SetParentEditorOnly(Material);
				//NewImportLayer.ThumbnailMIC = ALandscapeProxy::GetLayerThumbnailMIC(Material, LayerName, ThumbnailWeightmap, ThumbnailHeightmap, NULL);
			}

			NewImportLayer.ImportError = ELandscapeImportLayerError::None;
			if (!NewImportLayer.SourceFilePath.IsEmpty())
			{
				if (NewImportLayer.LayerInfo == NULL)
				{
					NewImportLayer.ImportError = ELandscapeImportLayerError::MissingLayerInfo;
				}
				else
				{
					if (NewImportLayer.SourceFilePath.EndsWith(".png"))
					{
						TArray<uint8> ImportData;
						if (!FFileHelper::LoadFileToArray(ImportData, *NewImportLayer.SourceFilePath, FILEREAD_Silent))
						{
							NewImportLayer.ImportError = ELandscapeImportLayerError::FileNotFound;
						}
						else
						{
							IImageWrapperModule& ImageWrapperModule = FModuleManager::LoadModuleChecked<IImageWrapperModule>("ImageWrapper");
							IImageWrapperPtr ImageWrapper = ImageWrapperModule.CreateImageWrapper(EImageFormat::PNG);

							if (!ImageWrapper->SetCompressed(ImportData.GetData(), ImportData.Num()))
							{
								NewImportLayer.ImportError = ELandscapeImportLayerError::CorruptFile;
							}
							else if (ImageWrapper->GetWidth() != ImportLandscape_Width || ImageWrapper->GetHeight() != ImportLandscape_Height)
							{
								NewImportLayer.ImportError = ELandscapeImportLayerError::FileSizeMismatch;
							}
							else if (ImageWrapper->GetFormat() != ERGBFormat::Gray)
							{
								NewImportLayer.ImportError = ELandscapeImportLayerError::ColorPng;
							}
						}
					}
					else
					{
						int64 ImportFileSize = IFileManager::Get().FileSize(*NewImportLayer.SourceFilePath);

						if (ImportFileSize < 0)
						{
							NewImportLayer.ImportError = ELandscapeImportLayerError::FileNotFound;
						}
						else if (ImportFileSize != ImportLandscape_Width * ImportLandscape_Height)
						{
							NewImportLayer.ImportError = ELandscapeImportLayerError::FileSizeMismatch;
						}
					}
				}
			}
		}
		else
		{
			NewImportLayer.LayerName = LayerName;
			NewImportLayer.ThumbnailMIC = ALandscapeProxy::GetLayerThumbnailMIC(Material, LayerName, ThumbnailWeightmap, ThumbnailHeightmap, NULL);
		}

		ImportLandscape_Layers.Add(MoveTemp(NewImportLayer));
	}
}
		FHugeType& operator=(FHugeType&& In)
		{
			MoveTemp(In);
			return *this;
		}
void FNativeClassHierarchyNode::AddChild(TSharedRef<FNativeClassHierarchyNode> ChildEntry)
{
	check(Type == ENativeClassHierarchyNodeType::Folder);
	Children.Add(FNativeClassHierarchyNodeKey(ChildEntry->EntryName, ChildEntry->Type), MoveTemp(ChildEntry));
}
bool FPluginManager::ConfigureEnabledPlugins()
{
	if(!bHaveConfiguredEnabledPlugins)
	{
		// Don't need to run this again
		bHaveConfiguredEnabledPlugins = true;

		// If a current project is set, check that we know about any plugin that's explicitly enabled
		const FProjectDescriptor *Project = IProjectManager::Get().GetCurrentProject();
		const bool bHasProjectFile = Project != nullptr;

		// Get all the enabled plugin names
		TArray< FString > EnabledPluginNames;
#if IS_PROGRAM
		// Programs can also define the list of enabled plugins in ini
		GConfig->GetArray(TEXT("Plugins"), TEXT("ProgramEnabledPlugins"), EnabledPluginNames, GEngineIni);
#endif
#if !IS_PROGRAM || HACK_HEADER_GENERATOR
		if (!FParse::Param(FCommandLine::Get(), TEXT("NoEnginePlugins")))
		{
			FProjectManager::Get().GetEnabledPlugins(EnabledPluginNames);
		}
#endif

		// Build a set from the array
		TSet< FString > AllEnabledPlugins;
		AllEnabledPlugins.Append(MoveTemp(EnabledPluginNames));

		// Enable all the plugins by name
		for (const TSharedRef< FPlugin > Plugin : AllPlugins)
		{
			if (AllEnabledPlugins.Contains(Plugin->Name))
			{
				Plugin->bEnabled = (!IS_PROGRAM || !bHasProjectFile) || IsPluginSupportedByCurrentTarget(Plugin);
				if (!Plugin->bEnabled)
				{
					AllEnabledPlugins.Remove(Plugin->Name);
				}
			}
		}

		if (bHasProjectFile)
		{
			// Take a copy of the Project's plugins as we may remove some
			TArray<FPluginReferenceDescriptor> PluginsCopy = Project->Plugins;
			for(const FPluginReferenceDescriptor& Plugin: PluginsCopy)
			{
				if ((Plugin.bEnabled && !FindPluginInstance(Plugin.Name).IsValid()) &&
					 (!IS_PROGRAM || AllEnabledPlugins.Contains(Plugin.Name))) // skip if this is a program and the plugin is not enabled
				{
					FText Caption(LOCTEXT("PluginMissingCaption", "Plugin missing"));
					if(Plugin.MarketplaceURL.Len() > 0)
					{
						if(FMessageDialog::Open(EAppMsgType::YesNo, FText::Format(LOCTEXT("PluginMissingError", "This project requires the {0} plugin.\n\nWould you like to download it from the the Marketplace?"), FText::FromString(Plugin.Name)), &Caption) == EAppReturnType::Yes)
						{
							FString Error;
							FPlatformProcess::LaunchURL(*Plugin.MarketplaceURL, nullptr, &Error);
							if(Error.Len() > 0) FMessageDialog::Open(EAppMsgType::Ok, FText::FromString(Error));
							return false;
						}
					}
					else
					{
						FString Description = (Plugin.Description.Len() > 0) ? FString::Printf(TEXT("\n\n%s"), *Plugin.Description) : FString();
						FMessageDialog::Open(EAppMsgType::Ok, FText::Format(LOCTEXT("PluginRequiredError", "This project requires the {0} plugin. {1}"), FText::FromString(Plugin.Name), FText::FromString(Description)), &Caption);
						
						if (FMessageDialog::Open(EAppMsgType::YesNo, FText::Format(LOCTEXT("PluginMissingDisable", "Would you like to disable {0}? You will no longer be able to open any assets created using it."), FText::FromString(Plugin.Name)), &Caption) == EAppReturnType::No)
						{
							return false;
						}

						FText FailReason;
						if (!IProjectManager::Get().SetPluginEnabled(*Plugin.Name, false, FailReason))
						{
							FMessageDialog::Open(EAppMsgType::Ok, FailReason);
						}
					}
				}
			}
		}

		// If we made it here, we have all the required plugins
		bHaveAllRequiredPlugins = true;

		for(const TSharedRef<FPlugin>& Plugin: AllPlugins)
		{
			if (Plugin->bEnabled)
			{
				// Add the plugin binaries directory
				const FString PluginBinariesPath = FPaths::Combine(*FPaths::GetPath(Plugin->FileName), TEXT("Binaries"), FPlatformProcess::GetBinariesSubdirectory());
				FModuleManager::Get().AddBinariesDirectory(*PluginBinariesPath, Plugin->LoadedFrom == EPluginLoadedFrom::GameProject);

#if !IS_MONOLITHIC
				// Only check this when in a non-monolithic build where modules could be in separate binaries
				if (Project != NULL && Project->Modules.Num() == 0)
				{
					// Content only project - check whether any plugins are incompatible and offer to disable instead of trying to build them later
					TArray<FString> IncompatibleFiles;
					if (!FModuleDescriptor::CheckModuleCompatibility(Plugin->Descriptor.Modules, Plugin->LoadedFrom == EPluginLoadedFrom::GameProject, IncompatibleFiles))
					{
						// Ask whether to disable plugin if incompatible
						FText Caption(LOCTEXT("IncompatiblePluginCaption", "Plugin missing or incompatible"));
						if (FMessageDialog::Open(EAppMsgType::YesNo, FText::Format(LOCTEXT("IncompatiblePluginText", "Missing or incompatible modules in {0} plugin - would you like to disable it? You will no longer be able to open any assets created using it."), FText::FromString(Plugin->Name)), &Caption) == EAppReturnType::No)
						{
							return false;
						}

						FText FailReason;
						if (!IProjectManager::Get().SetPluginEnabled(*Plugin->Name, false, FailReason))
						{
							FMessageDialog::Open(EAppMsgType::Ok, FailReason);
						}
					}
				}
#endif //!IS_MONOLITHIC

			// Build the list of content folders
				if (Plugin->Descriptor.bCanContainContent)
				{
					if (auto EngineConfigFile = GConfig->Find(GEngineIni, false))
					{
						if (auto CoreSystemSection = EngineConfigFile->Find(TEXT("Core.System")))
						{
							CoreSystemSection->AddUnique("Paths", Plugin->GetContentDir());
						}
					}
				}

				// Load Default<PluginName>.ini config file if it exists
				FString PluginConfigDir = FPaths::GetPath(Plugin->FileName) / TEXT("Config/");
				FConfigFile PluginConfig;
				FConfigCacheIni::LoadExternalIniFile(PluginConfig, *Plugin->Name, *FPaths::EngineConfigDir(), *PluginConfigDir, true);
				if (PluginConfig.Num() > 0)
				{
					FString PlaformName = FPlatformProperties::PlatformName();
					FString PluginConfigFilename = FString::Printf(TEXT("%s%s/%s.ini"), *FPaths::GeneratedConfigDir(), *PlaformName, *Plugin->Name);
					FConfigFile& NewConfigFile = GConfig->Add(PluginConfigFilename, FConfigFile());
					NewConfigFile.AddMissingProperties(PluginConfig);
					NewConfigFile.Write(PluginConfigFilename);
				}
			}
		}
		
		// Mount all the plugin content folders and pak files
		TArray<FString>	FoundPaks;
		FPakFileSearchVisitor PakVisitor(FoundPaks);
		IPlatformFile& PlatformFile = FPlatformFileManager::Get().GetPlatformFile();
		for(TSharedRef<IPlugin> Plugin: GetEnabledPlugins())
		{
			if (Plugin->CanContainContent() && ensure(RegisterMountPointDelegate.IsBound()))
			{
				FString ContentDir = Plugin->GetContentDir();
				RegisterMountPointDelegate.Execute(Plugin->GetMountedAssetPath(), ContentDir);

				// Pak files are loaded from <PluginName>/Content/Paks/<PlatformName>
				if (FPlatformProperties::RequiresCookedData())
				{
					FoundPaks.Reset();
					PlatformFile.IterateDirectoryRecursively(*(ContentDir / TEXT("Paks") / FPlatformProperties::PlatformName()), PakVisitor);
					for (const auto& PakPath : FoundPaks)
					{
						if (FCoreDelegates::OnMountPak.IsBound())
						{
							FCoreDelegates::OnMountPak.Execute(PakPath, 0);
						}
					}
				}
			}
		}
	}
	return bHaveAllRequiredPlugins;
}