text: // Copyright 1998-2016 Epic Games, Inc. All Rights Reserved.
  
  #include "BlueprintNativeCodeGenPCH.h"
  
  #include "App.h"								// for GetGameName()
  #include "BlueprintNativeCodeGenManifest.h"
  #include "BlueprintNativeCodeGenModule.h"
  #include "IBlueprintCompilerCppBackendModule.h" // for ConstructBaseFilename()
  #include "Engine/Blueprint.h"					// for GeneratedClass
  #include "JsonObjectConverter.h"
  #include "NativeCodeGenCommandlineParams.h"
  #include "Serialization/JsonReader.h"
  #include "Serialization/JsonSerializer.h"
  #include "Serialization/JsonWriter.h"
  
  DEFINE_LOG_CATEGORY_STATIC(LogNativeCodeGenManifest, Log, All);
  
  /*******************************************************************************
   * BlueprintNativeCodeGenManifestImpl
   ******************************************************************************/
  
  namespace BlueprintNativeCodeGenManifestImpl
  {
  	static const int64   CPF_NoFlags          = 0x00;
  	static const FString ManifestFileExt      = TEXT(".BpCodeGenManifest.json");
  	static const FString CppFileExt	          = TEXT(".cpp");
  	static const FString HeaderFileExt        = TEXT(".h");
  	static const FString HeaderSubDir         = TEXT("Public");
  	static const FString CppSubDir            = TEXT("Private");
  	static const FString ModuleBuildFileExt   = TEXT(".Build.cs");
  	static const FString FallbackPluginName   = TEXT("NativizedScript");
  	static const FString PreviewFilePostfix   = TEXT("-Preview");
  	static const FString PluginFileExt        = TEXT(".uplugin");
  	static const FString SourceSubDir         = TEXT("Source");
  	static const FString EditorModulePostfix  = TEXT("Editor");
  
  	/**
  	 * Populates the provided manifest object with data from the specified file.
  	 * 
  	 * @param  FilePath    A json file path, denoting the file you want loaded and serialized in.
  	 * @param  Manifest    The target object that you want filled out with data from the file.
  	 * @return True if the manifest was successfully loaded, otherwise false.
  	 */
  	static bool LoadManifest(const FString& FilePath, FBlueprintNativeCodeGenManifest* Manifest);
  
  	/**
  	 * Helper function that homogenizes file/directory paths so that they can be 
  	 * compared for equivalence against others.
  	 * 
  	 * @param  DirectoryPath    The path that you want sanitized.
  	 * @return A equivalent file/directory path, standardized for comparisons.
  	 */
  	static FString GetComparibleDirPath(const FString& DirectoryPath);
  
  	/**
  	 * Retrieves the sub-directory for either header or cpp source files 
  	 * (depending on which was requested).
  	 * 
  	 * @param  SourceType    Defines the type of source file to return for (header or cpp).
  	 * @return A directory name for the specified source file type.
  	 */
  	static const FString& GetSourceSubDir(const FBlueprintNativeCodeGenPaths::ESourceFileType SourceType);
  
  	/**
  	 * Retrieves the extension for either header or cpp source files (depending
  	 * on which was requested).
  	 * 
  	 * @param  SourceType    Defines the type of source file to return for (header or cpp).
  	 * @return A file extension (including the leading dot), for the specified source file type.
  	 */
  	static const FString& GetSourceFileExt(const FBlueprintNativeCodeGenPaths::ESourceFileType SourceType);
  
  	/**
  	 * Constructs a source file path for the specified asset.
  	 * 
  	 * @param  TargetPaths	Specified the destination directory for the file.
  	 * @param  Asset		The asset you want a header file for.
  	 * @param  SourceType	Defines the type of source file to generate for (header or cpp).
  	 * @return A target file path for the specified asset to save a header to.
  	 */
  	static FString GenerateSourceFileSavePath(const FBlueprintNativeCodeGenPaths& TargetPaths, const FAssetData& Asset, const FBlueprintNativeCodeGenPaths::ESourceFileType SourceType);
  
  	/**
  	 * 
  	 * 
  	 * @param  TargetPaths    
  	 * @param  Asset    
  	 * @return 
  	 */
  	static FString GenerateUnconvertedWrapperPath(const FBlueprintNativeCodeGenPaths& TargetPaths, const FAssetData& Asset);
  
  	/**
  	 * Coordinates with the code-gen backend, to produce a base filename (one 
  	 * without a file extension).
  	 * 
  	 * @param  Asset    The asset you want a filename for.
  	 * @return A filename (without extension) that matches the #include statements generated by the backend.
  	 */
  	static FString GetBaseFilename(const FAssetData& Asset);
  
  	/**
  	 * Collects native packages (which reflect distinct modules) that the 
  	 * specified object relies upon.
  	 * 
  	 * @param  AssetObj			The object you want dependencies for.
  	 * @param  DependenciesOut	An output array, which will be filled out with module packages that the target object relies upon.
  	 * @return False if the function failed to collect dependencies for the specified object.
  	 */
  	static bool GatherModuleDependencies(const UObject* AssetObj, TArray<UPackage*>& DependenciesOut);
  
  	/**
  	 * Obtains the reflected name for the native field (class/enum/struct) that 
  	 * we'll generate to replace the specified asset.
  	 *
  	 * @param  Asset	The asset you want a name from.
  	 * @return The name of the asset field (class/enum/struct).
  	 */
  	static FString GetFieldName(const FAssetData& Asset);
  
  	/**
  	 * The object returned by FAssetData::GetAsset() doesn't always give us the 
  	 * target object that will be replaced (for Blueprint's, it would be the 
  	 * class instead). So this helper function will suss out the right object 
  	 * for you.
  	 * 
  	 * @param  Asset    The asset you want an object for.
  	 * @return A pointer to the targeted object from the asset's package.
  	 */
  	static UField* GetTargetAssetObject(const FAssetData& Asset);
  
  	/**
  	 * Returns the object path for the field from the specified asset's package
  	 * that is being replaced (Asset.ObjectPath will not suffice, as that 
  	 * does not always reflect the object that is being replaced).
  	 * 
  	 * @param  Asset    The asset you want an object-path for.
  	 * @return An object-path for the target field-object within the asset's package.
  	 */
  	static FString GetTargetObjectPath(const FAssetData& Asset);
  }
  
  //------------------------------------------------------------------------------
  static bool BlueprintNativeCodeGenManifestImpl::LoadManifest(const FString& FilePath, FBlueprintNativeCodeGenManifest* Manifest)
  {
  	FString ManifestStr;
  	if (FFileHelper::LoadFileToString(ManifestStr, *FilePath))
  	{
  		TSharedRef< TJsonReader<> > JsonReader = TJsonReaderFactory<>::Create(ManifestStr);
  
  		TSharedPtr<FJsonObject> JsonObject;
  		if (FJsonSerializer::Deserialize(JsonReader, JsonObject))
  		{
  			return FJsonObjectConverter::JsonObjectToUStruct<FBlueprintNativeCodeGenManifest>(JsonObject.ToSharedRef(), Manifest,
  				/*CheckFlags =*/CPF_NoFlags, /*SkipFlags =*/CPF_NoFlags);
  		}
  	}
  	return false;
  }
  
  //------------------------------------------------------------------------------
  static const FString& BlueprintNativeCodeGenManifestImpl::GetSourceSubDir(const FBlueprintNativeCodeGenPaths::ESourceFileType SourceType)
  {
  	return (SourceType == FBlueprintNativeCodeGenPaths::HFile) ? HeaderSubDir : CppSubDir;
  }
  
  //------------------------------------------------------------------------------
  static const FString& BlueprintNativeCodeGenManifestImpl::GetSourceFileExt(const FBlueprintNativeCodeGenPaths::ESourceFileType SourceType)
  {
  	return (SourceType == FBlueprintNativeCodeGenPaths::HFile) ? HeaderFileExt : CppFileExt;
  }
  
  //------------------------------------------------------------------------------
  static FString BlueprintNativeCodeGenManifestImpl::GenerateSourceFileSavePath(const FBlueprintNativeCodeGenPaths& TargetPaths, const FAssetData& Asset, const FBlueprintNativeCodeGenPaths::ESourceFileType SourceType)
  {
  	return FPaths::Combine(*TargetPaths.RuntimeSourceDir(SourceType), *GetBaseFilename(Asset)) + GetSourceFileExt(SourceType);
  }
  
  //------------------------------------------------------------------------------
  static FString BlueprintNativeCodeGenManifestImpl::GenerateUnconvertedWrapperPath(const FBlueprintNativeCodeGenPaths& TargetPaths, const FAssetData& Asset)
  {
  	const FBlueprintNativeCodeGenPaths::ESourceFileType WrapperFileType = FBlueprintNativeCodeGenPaths::HFile;
  	return FPaths::Combine(*TargetPaths.RuntimeSourceDir(WrapperFileType), *GetBaseFilename(Asset)) + GetSourceFileExt(WrapperFileType);
  }
  
  //------------------------------------------------------------------------------
  static FString BlueprintNativeCodeGenManifestImpl::GetBaseFilename(const FAssetData& Asset)
  {
  	IBlueprintCompilerCppBackendModule& CodeGenBackend = (IBlueprintCompilerCppBackendModule&)IBlueprintCompilerCppBackendModule::Get();
  	return CodeGenBackend.ConstructBaseFilename(Asset.GetAsset());
  }
  
  //------------------------------------------------------------------------------
  static FString BlueprintNativeCodeGenManifestImpl::GetComparibleDirPath(const FString& DirectoryPath)
  {
  	FString NormalizedPath = DirectoryPath;
  
  	const FString PathDelim = TEXT("/");
  	if (!NormalizedPath.EndsWith(PathDelim))
  	{
  		// to account for the case where the relative path would resolve to X: 
  		// (when we want "X:/")... ConvertRelativePathToFull() leaves the 
  		// trailing slash, and NormalizeDirectoryName() will remove it (if it is
  		// not a drive letter)
  		NormalizedPath += PathDelim;
  	}
  
  	if (FPaths::IsRelative(NormalizedPath))
  	{
  		NormalizedPath = FPaths::ConvertRelativePathToFull(NormalizedPath);
  	}
  	FPaths::NormalizeDirectoryName(NormalizedPath);
  	return NormalizedPath;
  }
  
  //------------------------------------------------------------------------------
  static bool BlueprintNativeCodeGenManifestImpl::GatherModuleDependencies(const UObject* AssetObj, TArray<UPackage*>& DependenciesOut)
  {
  	UPackage* AssetPackage = AssetObj->GetOutermost();
  
  	const FLinkerLoad* PkgLinker = FLinkerLoad::FindExistingLinkerForPackage(AssetPackage);
  	const bool bFoundLinker = (PkgLinker != nullptr);
  
  	if (ensure(bFoundLinker))
  	{
  		for (const FObjectImport& PkgImport : PkgLinker->ImportMap)
  		{
  			if (PkgImport.ClassName != NAME_Package)
  			{
  				continue;
  			}
  
  			UPackage* DependentPackage = FindObject<UPackage>(/*Outer =*/nullptr, *PkgImport.ObjectName.ToString(), /*ExactClass =*/true);
  			if (DependentPackage == nullptr)
  			{
  				continue;
  			}
  
  			// we want only native packages, ones that are not editor-only
  			if ((DependentPackage->GetPackageFlags() & (PKG_CompiledIn | PKG_EditorOnly | PKG_Developer)) == PKG_CompiledIn)
  			{
  				DependenciesOut.AddUnique(DependentPackage);// PkgImport.ObjectName.ToString());
  			}
  		}
  	}
  
  	return bFoundLinker;
  }
  
  //------------------------------------------------------------------------------
  static FString BlueprintNativeCodeGenManifestImpl::GetFieldName(const FAssetData& Asset)
  {
  	UField* AssetField = GetTargetAssetObject(Asset);
  	return (AssetField != nullptr) ? AssetField->GetName() : TEXT("");
  }
  
  //------------------------------------------------------------------------------
  static UField* BlueprintNativeCodeGenManifestImpl::GetTargetAssetObject(const FAssetData& Asset)
  {
  	UObject* AssetObj = Asset.GetAsset();
  
  	UField* AssetField = nullptr;
  	if (UBlueprint* BlueprintAsset = Cast<UBlueprint>(AssetObj))
  	{
  		AssetField = BlueprintAsset->GeneratedClass;
  		if (!AssetField)
  		{
  			UE_LOG(LogNativeCodeGenManifest, Warning, TEXT("null BPGC in %s"), *BlueprintAsset->GetPathName());
  		}
  	}
  	else
  	{
  		// only other asset types that we should be converting are enums and 
  		// structs (both UFields)
  		AssetField = CastChecked<UField>(AssetObj);
  	}
  
  	return AssetField;
  }
  
  //------------------------------------------------------------------------------
  static FString BlueprintNativeCodeGenManifestImpl::GetTargetObjectPath(const FAssetData& Asset)
  {
  	UField* AssetField = GetTargetAssetObject(Asset);
  	return (AssetField != nullptr) ? AssetField->GetPathName() : TEXT("");
  }
  
  /*******************************************************************************
   * FConvertedAssetRecord
   ******************************************************************************/
   
  //------------------------------------------------------------------------------
  FConvertedAssetRecord::FConvertedAssetRecord(const FAssetData& AssetInfo, const FBlueprintNativeCodeGenPaths& TargetPaths)
  	: AssetType(AssetInfo.GetClass())
  	, TargetObjPath(BlueprintNativeCodeGenManifestImpl::GetTargetObjectPath(AssetInfo))
  {
  	GeneratedCppPath    = BlueprintNativeCodeGenManifestImpl::GenerateSourceFileSavePath(TargetPaths, AssetInfo, FBlueprintNativeCodeGenPaths::CppFile);
  	GeneratedHeaderPath = BlueprintNativeCodeGenManifestImpl::GenerateSourceFileSavePath(TargetPaths, AssetInfo, FBlueprintNativeCodeGenPaths::HFile);
  }
  
  //------------------------------------------------------------------------------
  bool FConvertedAssetRecord::IsValid()
  {
  	// every conversion will have a header file (interfaces don't have implementation files)
  	return ToAssetRef().IsValid() && (AssetType != nullptr) && !GeneratedHeaderPath.IsEmpty();
  }
  
  //------------------------------------------------------------------------------
  FStringAssetReference FConvertedAssetRecord::ToAssetRef() const
  {
  	return FStringAssetReference(TargetObjPath);
  }
  
  /*******************************************************************************
   * FUnconvertedDependencyRecord
   ******************************************************************************/
   
  //------------------------------------------------------------------------------
  FUnconvertedDependencyRecord::FUnconvertedDependencyRecord(const FAssetData& AssetInfo, const FBlueprintNativeCodeGenPaths& TargetPaths)
  	: GeneratedWrapperPath(BlueprintNativeCodeGenManifestImpl::GenerateUnconvertedWrapperPath(TargetPaths, AssetInfo))
  {
  }
  
  //------------------------------------------------------------------------------
  bool FUnconvertedDependencyRecord::IsValid()
  {
  	return !GeneratedWrapperPath.IsEmpty();
  }
  
  /*******************************************************************************
   * FBlueprintNativeCodeGenPaths
   ******************************************************************************/
  
  //------------------------------------------------------------------------------
  FString FBlueprintNativeCodeGenPaths::GetDefaultManifestPath()
  {
  	return FApp::GetGameName() + BlueprintNativeCodeGenManifestImpl::ManifestFileExt;
  }
  
  //------------------------------------------------------------------------------
  FBlueprintNativeCodeGenPaths::FBlueprintNativeCodeGenPaths(const FString& PluginNameIn, const FString& TargetDirIn, const FString& ManifestPathIn)
  	: TargetDir(TargetDirIn)
  	, PluginName(PluginNameIn)
  	, ManifestPath(ManifestPathIn)
  {
  }
  
  //------------------------------------------------------------------------------
  FString FBlueprintNativeCodeGenPaths::ManifestFilePath() const
  {
  	return ManifestPath;
  }
  
  //------------------------------------------------------------------------------
  FString FBlueprintNativeCodeGenPaths::PluginRootDir() const
  {
  	return TargetDir;
  }
  
  //------------------------------------------------------------------------------
  FString FBlueprintNativeCodeGenPaths::PluginFilePath() const
  {
  	return FPaths::Combine(*PluginRootDir(), *PluginName) + BlueprintNativeCodeGenManifestImpl::PluginFileExt;;
  }
  
  //------------------------------------------------------------------------------
  FString FBlueprintNativeCodeGenPaths::PluginSourceDir() const
  {
  	return FPaths::Combine(*PluginRootDir(), *BlueprintNativeCodeGenManifestImpl::SourceSubDir);
  }
  
  //------------------------------------------------------------------------------
  FString FBlueprintNativeCodeGenPaths::RuntimeModuleDir() const
  {
  	return FPaths::Combine(*PluginSourceDir(), *RuntimeModuleName());
  }
  
  //------------------------------------------------------------------------------
  FString FBlueprintNativeCodeGenPaths::RuntimeModuleName() const
  {
  	return PluginName;
  }
  
  //------------------------------------------------------------------------------
  FString FBlueprintNativeCodeGenPaths::RuntimeBuildFile() const
  {
  	return FPaths::Combine(*RuntimeModuleDir(), *RuntimeModuleName()) + BlueprintNativeCodeGenManifestImpl::ModuleBuildFileExt;
  }
  
  //------------------------------------------------------------------------------
  FString FBlueprintNativeCodeGenPaths::RuntimeSourceDir(ESourceFileType SourceType) const
  {
  	return FPaths::Combine(*RuntimeModuleDir(), *BlueprintNativeCodeGenManifestImpl::GetSourceSubDir(SourceType));
  }
  
  //------------------------------------------------------------------------------
  FString FBlueprintNativeCodeGenPaths::RuntimeModuleFile(ESourceFileType SourceType) const
  {
  	return FPaths::Combine(*RuntimeSourceDir(SourceType), *RuntimeModuleName()) + BlueprintNativeCodeGenManifestImpl::GetSourceFileExt(SourceType);
  }
  
  //------------------------------------------------------------------------------
  FString FBlueprintNativeCodeGenPaths::RuntimePCHFilename() const
  {
  	return FPaths::GetCleanFilename(RuntimeModuleFile(HFile));
  }
  
  /*******************************************************************************
   * FBlueprintNativeCodeGenManifest
   ******************************************************************************/
  
  //------------------------------------------------------------------------------
  FBlueprintNativeCodeGenManifest::FBlueprintNativeCodeGenManifest()
  	: OutputDir(FPaths::ConvertRelativePathToFull( FPaths::Combine(*FPaths::Combine(*FPaths::GameIntermediateDir(), TEXT("Plugins")), *BlueprintNativeCodeGenManifestImpl::FallbackPluginName) ))
  {
  	PluginName = FPaths::GetBaseFilename(OutputDir);
  	ManifestFilePath = FPaths::Combine(*GetTargetDir(), *FBlueprintNativeCodeGenPaths::GetDefaultManifestPath());
  }
  
  //------------------------------------------------------------------------------
  FBlueprintNativeCodeGenManifest::FBlueprintNativeCodeGenManifest(const FNativeCodeGenCommandlineParams& CommandlineParams)
  {
  	using namespace BlueprintNativeCodeGenManifestImpl;
  	bool const bLoadExistingManifest = !CommandlineParams.bWipeRequested || CommandlineParams.OutputDir.IsEmpty();
  	
  	PluginName = CommandlineParams.PluginName;
  	OutputDir  = CommandlineParams.OutputDir;
  	if (FPaths::IsRelative(OutputDir))
  	{
  		FPaths::MakePathRelativeTo(OutputDir, *FPaths::GameDir());
  	}
  
  	if (!CommandlineParams.ManifestFilePath.IsEmpty())
  	{
  		ManifestFilePath = CommandlineParams.ManifestFilePath;
  	}
  	else
  	{
  		if (!ensure(!PluginName.IsEmpty()))
  		{
  			PluginName = FallbackPluginName;
  		}
  		if (!ensure(!OutputDir.IsEmpty()))
  		{
  			OutputDir = FPaths::Combine(*FPaths::GameIntermediateDir(), *PluginName);
  		}
  
  		FString ManifestFilename = FBlueprintNativeCodeGenPaths::GetDefaultManifestPath();
  		if (CommandlineParams.bPreviewRequested)
  		{
  			ManifestFilename.InsertAt(ManifestFilename.Find(ManifestFileExt, ESearchCase::CaseSensitive, ESearchDir::FromEnd), PreviewFilePostfix);
  		}
  		ManifestFilePath = FPaths::Combine(*GetTargetDir(), *ManifestFilename);
  	}
  	
  	// incorporate an existing manifest (in case we're only re-converting a 
  	// handful of assets and adding them into an existing module)
  	if (bLoadExistingManifest && LoadManifest(ManifestFilePath, this))
  	{
  		// if they specified a separate plugin path, lets make sure we use that
  		// over what was found in the existing manifest
  		if (!CommandlineParams.OutputDir.IsEmpty())
  		{
  			if (CommandlineParams.bWipeRequested)
  			{
  				OutputDir = CommandlineParams.OutputDir;
  			}
  			else
  			{
  				const FString ExpectedPath = GetComparibleDirPath(CommandlineParams.OutputDir);
  
  				FString TargetPath = GetTargetDir();
  				TargetPath = GetComparibleDirPath(TargetPath);
  
  				if ( !FPaths::IsSamePath(ExpectedPath, TargetPath) )
  				{
  					UE_LOG(LogNativeCodeGenManifest, Error, 
  						TEXT("The existing manifest's plugin path does not match what was specified via the commandline."));
  				}
  			}
  		}
  
  		const bool bNewPluginNameRequested = !CommandlineParams.PluginName.IsEmpty() && (CommandlineParams.PluginName != PluginName);
  		if (bNewPluginNameRequested && !CommandlineParams.bPreviewRequested)
  		{
  			// delete the old plugin file (if one exists)
  			IFileManager::Get().Delete(*GetTargetPaths().PluginFilePath());
  		}
  
  		// if we were only interested in obtaining the plugin path
  		if (CommandlineParams.bWipeRequested)
  		{
  			PluginName = CommandlineParams.PluginName;
  			Clear();
  		}
  		else
  		{
  			if (bNewPluginNameRequested)
  			{
  				UE_LOG(LogNativeCodeGenManifest, Warning, TEXT("The specified plugin name (%s) doesn't match the existing one (%s). Overridding with the new name."),
  					*CommandlineParams.PluginName, *PluginName);
  				PluginName = CommandlineParams.PluginName;
  			}
  		}
  	}
  }
  
  //------------------------------------------------------------------------------
  FBlueprintNativeCodeGenManifest::FBlueprintNativeCodeGenManifest(const FString& ManifestFilePathIn)
  	: ManifestFilePath(ManifestFilePathIn)
  {
  	BlueprintNativeCodeGenManifestImpl::LoadManifest(ManifestFilePathIn, this);
  }
  
  //------------------------------------------------------------------------------
  FBlueprintNativeCodeGenPaths FBlueprintNativeCodeGenManifest::GetTargetPaths() const
  {
  	return FBlueprintNativeCodeGenPaths(PluginName, GetTargetDir(), ManifestFilePath);
  }
  
  //------------------------------------------------------------------------------
  FConvertedAssetRecord& FBlueprintNativeCodeGenManifest::CreateConversionRecord(const FAssetId Key, const FAssetData& AssetInfo)
  {
  	const FBlueprintNativeCodeGenPaths TargetPaths = GetTargetPaths();
  
  	UClass* AssetType = AssetInfo.GetClass();
  	// load the asset (if it isn't already)
  	const UObject* AssetObj = AssetInfo.GetAsset();
  
  	FConvertedAssetRecord* ConversionRecordPtr = ConvertedAssets.Find(Key);
  	if (ConversionRecordPtr == nullptr)
  	{
  		UnconvertedDependencies.Remove(Key);
  		ConversionRecordPtr = &ConvertedAssets.Add(Key, FConvertedAssetRecord(AssetInfo, TargetPaths));
  	}
  	else if (!ensure(AssetType == ConversionRecordPtr->AssetType))
  	{
  		UE_LOG(LogNativeCodeGenManifest, Warning, TEXT("Existing manifest entry for '%s' has a different type, overriding with: '%s'"),
  			*AssetInfo.ObjectPath.ToString(), *AssetType->GetName());
  
  		ConversionRecordPtr->AssetType = AssetType;
  		ConversionRecordPtr->TargetObjPath = BlueprintNativeCodeGenManifestImpl::GetTargetObjectPath(AssetInfo);
  	}
  	
  	FConvertedAssetRecord& ConversionRecord = *ConversionRecordPtr;
  	if (!ConversionRecord.IsValid())
  	{
  		if (ConversionRecord.GeneratedHeaderPath.IsEmpty())
  		{
  			ConversionRecord.GeneratedCppPath    = BlueprintNativeCodeGenManifestImpl::GenerateSourceFileSavePath(TargetPaths, AssetInfo, FBlueprintNativeCodeGenPaths::CppFile);
  			ConversionRecord.GeneratedHeaderPath = BlueprintNativeCodeGenManifestImpl::GenerateSourceFileSavePath(TargetPaths, AssetInfo, FBlueprintNativeCodeGenPaths::HFile);
  		}
  		ensure(ConversionRecord.IsValid());
  	}
  
  	return ConversionRecord;
  }
  
  //------------------------------------------------------------------------------
  FUnconvertedDependencyRecord& FBlueprintNativeCodeGenManifest::CreateUnconvertedDependencyRecord(const FAssetId UnconvertedAssetKey, const FAssetData& AssetInfo, const FAssetId ReferencingAsset)
  {
  	FUnconvertedDependencyRecord* RecordPtr = UnconvertedDependencies.Find(UnconvertedAssetKey);
  	if (RecordPtr == nullptr)
  	{
  		const FBlueprintNativeCodeGenPaths TargetPaths = GetTargetPaths();
  		RecordPtr = &UnconvertedDependencies.Add(UnconvertedAssetKey, FUnconvertedDependencyRecord(AssetInfo, TargetPaths));
  	}
  	check(RecordPtr != nullptr);
  
  	FUnconvertedDependencyRecord& DependencyRecord = *RecordPtr;
  	if (!DependencyRecord.IsValid())
  	{
  		const FBlueprintNativeCodeGenPaths TargetPaths = GetTargetPaths();
  		DependencyRecord.GeneratedWrapperPath = BlueprintNativeCodeGenManifestImpl::GenerateUnconvertedWrapperPath(TargetPaths, AssetInfo);
  
  		ensure(DependencyRecord.IsValid());
  	}
  
  	DependencyRecord.ReferencedBy.AddUnique(ReferencingAsset);
  	return DependencyRecord;
  }
  
  //------------------------------------------------------------------------------
  const FConvertedAssetRecord* FBlueprintNativeCodeGenManifest::FindConversionRecord(const FAssetId AssetId) const
  {
  	return ConvertedAssets.Find(AssetId);
  }
  
  //------------------------------------------------------------------------------
  void FBlueprintNativeCodeGenManifest::GatherModuleDependencies(UPackage* Package)
  {
  	BlueprintNativeCodeGenManifestImpl::GatherModuleDependencies(Package, ModuleDependencies);
  }
  
  //------------------------------------------------------------------------------
  bool FBlueprintNativeCodeGenManifest::Save() const
  {
  	return SaveAs(*ManifestFilePath);
  }
  
  //------------------------------------------------------------------------------
  bool FBlueprintNativeCodeGenManifest::SaveAs(const TCHAR* Filename) const
  {
  	TSharedRef<FJsonObject> JsonObject = MakeShareable(new FJsonObject());
  
  	if (FJsonObjectConverter::UStructToJsonObject(FBlueprintNativeCodeGenManifest::StaticStruct(), this, JsonObject,
  		/*CheckFlags =*/BlueprintNativeCodeGenManifestImpl::CPF_NoFlags, /*SkipFlags =*/BlueprintNativeCodeGenManifestImpl::CPF_NoFlags))
  	{
  		FString FileContents;
  		TSharedRef< TJsonWriter<> > JsonWriter = TJsonWriterFactory<>::Create(&FileContents);
  
  		if (FJsonSerializer::Serialize(JsonObject, JsonWriter))
  		{
  			JsonWriter->Close();
  			return FFileHelper::SaveStringToFile(FileContents, Filename);
  		}
  	}
  	return false;
  }
  
  void FBlueprintNativeCodeGenManifest::Merge(const TCHAR* Filename)
  {
  	FBlueprintNativeCodeGenManifest OtherManifest = FBlueprintNativeCodeGenManifest(FString(Filename));
  	for (auto& Entry : OtherManifest.ModuleDependencies)
  	{
  		ModuleDependencies.AddUnique(Entry);
  	}
  
  	for (auto& Entry : OtherManifest.ConvertedAssets)
  	{
  		ConvertedAssets.Add(Entry.Key, Entry.Value);
  	}
  
  	for (auto& Entry : UnconvertedDependencies)
  	{
  		OtherManifest.UnconvertedDependencies.Add(Entry.Key, Entry.Value);
  	}
  }
  
  //------------------------------------------------------------------------------
  FString FBlueprintNativeCodeGenManifest::GetTargetDir() const
  {
  	FString TargetPath = OutputDir;
  	if (FPaths::IsRelative(TargetPath))
  	{
  		TargetPath = FPaths::ConvertRelativePathToFull(FPaths::GameDir(), TargetPath);
  		TargetPath = FPaths::ConvertRelativePathToFull(TargetPath);
  	}
  	return TargetPath;
  }
  
  //------------------------------------------------------------------------------
  void FBlueprintNativeCodeGenManifest::Clear()
  {
  	ConvertedAssets.Empty();
  }
  