Files
UnrealEngineUWP/Engine/Source/Developer/BlueprintNativeCodeGen/Private/NativeCodeGenCommandlineParams.cpp
Mike Beach 134cb04d27 Copying //UE4/Dev-Blueprints to Dev-Main (//UE4/Dev-Main) @ 2781164
#lockdown Nick.Penwarden

==========================
MAJOR FEATURES + CHANGES
==========================

Change 2716841 on 2015/10/05 by Mike.Beach

	(WIP) Cleaning up how we setup script assets for replacement on cook (aligning more with the Blueprint conversion tool).

	#codereview Maciej.Mroz

Change 2719089 on 2015/10/07 by Maciej.Mroz

	ToValidCPPIdentifierChars handles propertly '?' char.

	#codereview Dan.Oconnor

Change 2719361 on 2015/10/07 by Maciej.Mroz

	Generated native code for AnimBPGC - some preliminary changes.

	Refactor: UAnimBlueprintGeneratedClass is not accessed directly in runtime. It is accessed via UAnimClassInterface interface.
	Properties USkeletalMeshComponent::AnimBlueprintGeneratedClass and UInterpTrackFloatAnimBPParam::AnimBlueprintClass were changed into "TSubclassOf<UAnimInstance> AnimClass"

	The UDynamicClass also can deliver the IAnimClassInterface interface. See UAnimClassData, IAnimClassInterface::GetFromClass and UDynamicClass::AnimClassImplementation.

	#codereview Lina.Halper, Thomas.Sarkanen

Change 2719383 on 2015/10/07 by Maciej.Mroz

	Debug-only code removed

Change 2720528 on 2015/10/07 by Dan.Oconnor

	Fix for determinsitc cooking of async tasks and load asset nodes
	#codereview Mike.Beach, Maciej.Mroz

Change 2721273 on 2015/10/08 by Maciej.Mroz

	Blueprint Compiler Cpp Backend
	- Anim Blueprints can be converted
	- Various fixes/improvements

Change 2721310 on 2015/10/08 by Maciej.Mroz

	refactor (cl#2719361) - no "auto" keyword

Change 2721727 on 2015/10/08 by Mike.Beach

	(WIP) Setup the cook commandlet so it handles converted assets, replacing them with generated classes.

	    - Refactored the conversion manifest (using a map over an array)
	    - Centralized destination paths into a helper struct (for the manifest)
	    - Generating an Editor module that automatically hooks into the cook process when enabled
	    - Loading and applying native replacments for the cook

Change 2723276 on 2015/10/09 by Michael.Schoell

	Blueprints duplicated for PIE will no longer register as dependencies to other Blueprint.

	#jira UE-16695 - Editor freezes then crashes while attempting to save during PIE
	#jira UE-21614 - [CrashReport] Crash while saving during PIE - FKismetEditorUtilities::CompileBlueprint() kismet2.cpp:736

Change 2724345 on 2015/10/11 by Ben.Cosh

	Blueprint profiler at first pass, this includes the ability to instrument specific blueprints with realtime editor stat display.
	#UEBP-21 - Profiling data capture and storage
	#UEBP-13 - Performance capture landing page
	#Branch UE4
	#Proj BlueprintProfiler, BlueprintGraph, EditorStyle, Kismet, UnrealEd, CoreUObject, Engine

Change 2724613 on 2015/10/12 by Ben.Cosh

	Incremental update for blueprint profiler to fix the way some of the reported stats cascade through events and branches and additionally some missed bits of code are refactored/removed.
	#Branch UE4
	#Proj BlueprintProfiler

	#info Whilst looking into this I spotted the reason why the stats seem so erratic, There appears to be an issue with FText's use of EXPERIMENTAL_TEXT_FAST_DECIMAL_FORMAT which I have reported, but ideally disable this locally until a fix is integrated.

Change 2724723 on 2015/10/12 by Maciej.Mroz

	Constructor of a dynamic class creates CDO.

	#codereview Robert.Manuszewski

Change 2725108 on 2015/10/12 by Mike.Beach

	[UE-21891] Minor fix to the array shuffle() function; now processes the last entry like all the others.

Change 2726358 on 2015/10/13 by Maciej.Mroz

	UDataTable is properly saved even if its RowStruct is null.

	https://udn.unrealengine.com/questions/264064/crash-using-hotreload-in-custom-datatable-cdo-clas.html

Change 2727395 on 2015/10/13 by Mike.Beach

	(WIP) Second pass on the Blueprint conversion pipeline; setting it up for more optimal (speedier) performance.
	    * Using stubs for replacements (rather than loading dynamic replacement).
	    * Giving the cook commandlet more control (so a conversion could be ran directly).
	    * Now logging replacements by old object path (to account for UPackage replacement queries).
	    * Fix for [UE-21947], unshelved from CL 2724944 (by Maciej.Mroz).

	#codereview Maciej.Mroz

Change 2727484 on 2015/10/13 by Mike.Beach

	[UE-22008] Fixing up comment/tooltip typo for UActorComponent::bAutoActivate.

Change 2727527 on 2015/10/13 by Mike.Beach

	Downgrading an inactionable EdGraph warning, while adding more info so we could possibly determine what's happening.

Change 2727702 on 2015/10/13 by Dan.Oconnor

	Fix for crash in UDelegateProperty::GetCPPType when called on a function with no OwnerClass (events)

Change 2727968 on 2015/10/14 by Maciej.Mroz

	Since ConstructorHelpers::FClassFinder is usually static, the loaded class should be in root set, to prevent the pointer stored in  ConstructorHelpers::FClassFinder from being obsolete.
	FindOrLoadClass behaves now like FindOrLoadObject.

	#codereview Robert.Manuszewski, Nick.Whiting

Change 2728139 on 2015/10/14 by Phillip.Kavan
2015-11-25 18:47:20 -05:00

242 lines
10 KiB
C++

// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
#include "BlueprintNativeCodeGenPCH.h"
#include "NativeCodeGenCommandlineParams.h"
#include "BlueprintNativeCodeGenManifest.h"
DEFINE_LOG_CATEGORY_STATIC(LogNativeCodeGenCommandline, Log, All);
/** */
const FString FNativeCodeGenCommandlineParams::HelpMessage = TEXT("\n\
\n\
-------------------------------------------------------------------------------\n\
:: GenerateNativePluginFromBlueprint :: Converts Blueprint assets into C++ \n\
-------------------------------------------------------------------------------\n\
\n\
:: \n\
:: Usage \n\
:: \n\
\n\
UE4Editor.exe <project> -run=GenerateNativePluginFromBlueprint [parameters]\n\
\n\
:: \n\
:: Parameters \n\
:: \n\
\n\
-whitelist=<Assets> Identifies assets that you wish to convert. <Assets> \n\
can be a comma seperated list, specifying multiple \n\
packages (either directories, or explicit assets) in \n\
the form: /Game/MyContentDir,/Engine/EngineAssetName. \n\
\n\
-blacklist=<Assets> Explicitly specifies assets that you don't want \n\
converted (listed in the same manner as the -whitelist \n\
param). This takes priority over the whitelist (even if\n\
it results in uncompilable code). \n\
\n\
-output=<TargetDir> Specifies the path where you want converted assets \n\
saved to. If left unset, this will default to the \n\
project's intermeadiate folder (within a sub-folder of \n\
its own). If specified as a relative path, it will be \n\
interpreted as relative to the project directory. \n\
\n\
-pluginName=<Name> Defines the generated plugin's name. If the output \n\
directory doesn't match this in name, then a sub-folder\n\
will be created there to house the plugin. \n\
\n\
-noWipe By default, we'll clear out the target directory from \n\
previous conversions. However, with this, if the \n\
target directory contains source from a previous run, \n\
we'll build atop the existing module and append to its \n\
existing manifest. \n\
\n\
-dependencies=<Rule> By default, we convert all required Blueprint \n\
dependencies (that are not blacklisted), even if they \n\
weren't found in the whitelist. You can also specify: \n\
'None' or 'All' (default is 'RequiredOnly'), which will\n\
only convert whitelisted assets, or every dependency \n\
respectively. This param has no use if when a whitelist\n\
is not provided (either through the commandline, or an \n\
ini config file). \n\
\n\
-manifest=<Path> Specifies where to save the resultant manifest file. If\n\
<Path> is not an existing directory or file, then it is\n\
assumed that this is a file path. If a manifest already\n\
exists here, then it'll be used to define the target \n\
output directory (which will be read from the existing \n\
manifest file). If left unset then the manifest will \n\
default to the plugin's directory. \n\
\n\
-preview When specified, the process will NOT wipe any existing \n\
files, and the target assets will NOT be compiled and \n\
converted. Instead, just a manifest file will be \n\
generated, detailing the command's predicted output. \n\
\n\
-help, -h, -? Display this message and then exit. \n\
\n");
/*******************************************************************************
* NativeCodeGenCommandlineParamsImpl
******************************************************************************/
namespace NativeCodeGenCommandlineParamsImpl
{
static const FString DefaultPluginName(TEXT("GeneratedBpCode"));
static const FString ParamListDelim(TEXT(","));
/**
* Cleans up the passed in path from the commandline (removes quotes,
* corrects slashes, etc.), so that it is ready to be utilized by the
* conversion process.
*
* @param PathInOut The path you want standardized.
*/
static void SanitizePathParam(FString& PathInOut);
}
//------------------------------------------------------------------------------
static void NativeCodeGenCommandlineParamsImpl::SanitizePathParam(FString& PathInOut)
{
PathInOut.RemoveFromStart(TEXT("\""));
PathInOut.RemoveFromEnd(TEXT("\""));
FPaths::NormalizeDirectoryName(PathInOut);
}
/*******************************************************************************
* FNativeCodeGenCommandlineParams
******************************************************************************/
//------------------------------------------------------------------------------
FNativeCodeGenCommandlineParams::FNativeCodeGenCommandlineParams(const TArray<FString>& CommandlineSwitches)
: bHelpRequested(false)
, bWipeRequested(true)
, bPreviewRequested(false)
, DependencyConversionRule(EDependencyConversionRule::RequiredOnly)
{
using namespace NativeCodeGenCommandlineParamsImpl;
IFileManager& FileManager = IFileManager::Get();
for (const FString& Param : CommandlineSwitches)
{
FString Switch = Param, Value;
Param.Split(TEXT("="), &Switch, &Value);
if (!Switch.Compare(TEXT("h"), ESearchCase::IgnoreCase) ||
!Switch.Compare(TEXT("?"), ESearchCase::IgnoreCase) ||
!Switch.Compare(TEXT("help"), ESearchCase::IgnoreCase))
{
bHelpRequested = true;
}
else if (!Switch.Compare(TEXT("whitelist"), ESearchCase::IgnoreCase))
{
Value.ParseIntoArray(WhiteListedAssetPaths, *NativeCodeGenCommandlineParamsImpl::ParamListDelim);
}
else if (!Switch.Compare(TEXT("blacklist"), ESearchCase::IgnoreCase))
{
Value.ParseIntoArray(BlackListedAssetPaths, *NativeCodeGenCommandlineParamsImpl::ParamListDelim);
}
else if (!Switch.Compare(TEXT("output"), ESearchCase::IgnoreCase))
{
SanitizePathParam(Value);
// if it's a relative path, let's have it relative to the game
// directory (not the UE executable)
if (FPaths::IsRelative(Value))
{
Value = FPaths::Combine(*FPaths::GameDir(), *Value);
}
if (FileManager.DirectoryExists(*Value) || FileManager.MakeDirectory(*Value))
{
OutputDir = Value;
}
else
{
UE_LOG(LogNativeCodeGenCommandline, Warning, TEXT("'%s' doesn't appear to be a valid output directory, reverting to the default."), *Value);
}
}
else if (!Switch.Compare(TEXT("pluginName"), ESearchCase::IgnoreCase))
{
PluginName = Value;
}
else if (!Switch.Compare(TEXT("noWipe"), ESearchCase::IgnoreCase))
{
bWipeRequested = false;
}
else if (!Switch.Compare(TEXT("dependencies"), ESearchCase::IgnoreCase))
{
if (UEnum* const DependencyRuleEnum = FindObject<UEnum>(ANY_PACKAGE, TEXT("EDependencyConversionRule")))
{
FString EnumValueName = UEnum::GenerateFullEnumName(DependencyRuleEnum, *Value);
if (DependencyRuleEnum->IsValidEnumName(*EnumValueName))
{
DependencyConversionRule = (EDependencyConversionRule)DependencyRuleEnum->GetValueByName(*EnumValueName);
}
else
{
UE_LOG(LogNativeCodeGenCommandline, Warning, TEXT("Invalid dependency rule: '%s' (defaulting to 'RequiredOnly')."), *Value);
}
}
}
else if (!Switch.Compare(TEXT("preview"), ESearchCase::IgnoreCase))
{
bPreviewRequested = true;
}
else if (!Switch.Compare(TEXT("manifest"), ESearchCase::IgnoreCase))
{
SanitizePathParam(Value);
if (FileManager.FileExists(*Value))
{
ManifestFilePath = Value;
}
else if (FileManager.DirectoryExists(*Value))
{
ManifestFilePath = FPaths::Combine(*Value, *FBlueprintNativeCodeGenPaths::GetDefaultManifestPath());
}
else
{
UE_LOG(LogNativeCodeGenCommandline, Display, TEXT("Unsure if '%s' is supposed to denote a directory or a filename, assuming it's a file."), *Value);
FString FilePath = FPaths::GetPath(*Value);
if (FileManager.DirectoryExists(*FilePath) || FileManager.MakeDirectory(*FilePath))
{
ManifestFilePath = Value;
}
else
{
if (FPaths::IsRelative(Value))
{
Value = FPaths::ConvertRelativePathToFull(Value);
}
UE_LOG( LogNativeCodeGenCommandline, Warning, TEXT("'%s' doesn't appear to be a valid manifest file name/path, defaulting to: '%s'."),
*Value, *FBlueprintNativeCodeGenPaths::GetDefaultManifestPath() );
}
}
}
else
{
//UE_LOG(LogNativeCodeGenCommandline, Warning, TEXT("Unrecognized commandline parameter: %s"), *Switch);
}
}
bool const bUtilizeExistingManifest = !ManifestFilePath.IsEmpty() && !bWipeRequested && FileManager.FileExists(*ManifestFilePath);
// an existing manifest would specify where to put the plugin
if (!bUtilizeExistingManifest)
{
if (PluginName.IsEmpty())
{
PluginName = NativeCodeGenCommandlineParamsImpl::DefaultPluginName;
}
if (OutputDir.IsEmpty())
{
const FString DefaultOutputPath = FPaths::Combine(*FPaths::Combine(*FPaths::GameIntermediateDir(), TEXT("Plugins")), *PluginName);
OutputDir = DefaultOutputPath;
}
if ( PluginName.Compare(FPaths::GetBaseFilename(OutputDir)) )
{
OutputDir = FPaths::Combine(*OutputDir, *PluginName);
}
}
}