You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
#lockdown Nick.Penwarden
#rb none
==========================
MAJOR FEATURES + CHANGES
==========================
Change 3256692 on 2017/01/13 by Ben.Cosh
This updates the blueprint variable config option tooltip to be more accurate when describing the config to override the value in.
#Jira UE-40334 - Blueprint variables report the wrong config file in the UI when using the set from config option
#Proj Kismet
Change 3258553 on 2017/01/16 by Phillip.Kavan
[UE-40131] Revised fix that will work for "inclusive" BP nativization with data-only BPs.
- Mirrored from //UE4/Release-4.15 (CL# 3258541).
#jira UE-40131
Change 3258958 on 2017/01/16 by Mike.Beach
Adopted fix from UDN - resolves problems with Blueprints which inherit from UDataAsset. Compiling/Reinstancing them was leaving the data asset packages empty.
Change 3259363 on 2017/01/16 by Mike.Beach
Revising fix in UBlueprint::BeginCacheForCookedPlatformData(), saving off nativization data if the -nativizeAssets param is present (not just if it was enabled in packaging settings).
#jira UE-40620
Change 3260722 on 2017/01/17 by Maciej.Mroz
Exclude client-only BPGC from Server.
#jira UE-39728
Change 3261420 on 2017/01/17 by Dan.Oconnor
Final prototype of the GMinimalCompileOnLoad pass
Change 3262208 on 2017/01/18 by Dan.Oconnor
SA fix
Change 3263168 on 2017/01/18 by Dan.Oconnor
Tweak to minimal compile on load pass, doing node refreshing early because node refresh can trigger CDO generation (which cannot happen while reinstancing, unless the new class is ready)
Change 3263844 on 2017/01/19 by Maciej.Mroz
Error when CDO is created for an incomplete dynamic class
Change 3264647 on 2017/01/19 by Mike.Beach
PR #3146: Only ensure if ptr != nullptr (Contributed by projectgheist )
#jira UE-40846
Change 3264818 on 2017/01/19 by Dan.Oconnor
Undo overzealous use of GMinimalCompileOnLoad
Change 3265075 on 2017/01/19 by Dan.Oconnor
Make sure we use the authoritative class for the component template, fixes reinst issue in GMinimalCompileOnLoad pass
Change 3265085 on 2017/01/19 by Mike.Beach
Mirroring CL 3260397
Making it so CreateEvent nodes are searchable using the function name they are bound to (as requested by Jeff Farris). To find this data across your content library, in unopened Blueprints, you'll have to resave those Blueprints (so the new data is available in the asset registry).
Change 3272401 on 2017/01/25 by Mike.Beach
Fixed a bug where modifying certain timeline settings would not dirty the Blueprint.
PR #3137: UE-40674: Mark TimeLine BP as modified (Contributed by projectgheist)
#jira UE-40680, UE-40674
Change 3273050 on 2017/01/26 by Maciej.Mroz
#jira ODIN-4913, UE-40974
merged cl3268193 from Odin branch
Nativization:
- added ConstructTInlineValue function
- TInlineValue structures will be initialized using UScriptStruct::InitializeStruct, instead of callind default constructor ( default constructor is unrealible)
Change 3273052 on 2017/01/26 by Maciej.Mroz
#jira UE-40917
merged cl#3270456 from Odin branch
Nativization:
Actor template from ChildActorComponent is a subobject of nativized class.
Change 3275646 on 2017/01/27 by Dan.Oconnor
Fix obscure issue when reinstancing interface types
Change 3275811 on 2017/01/27 by Dan.Oconnor
ImplementsGetWorld now properly inherited for blueprint types that derive from a blueprint type that derives from a native type that "ImplementsGetWorld"
Change 3275922 on 2017/01/27 by Dan.Oconnor
Preserve trashed properties' names, don't force regen nodes when using the new compile manager (it has already regen'd nodes)
Change 3276037 on 2017/01/27 by Dan.Oconnor
Uses Authoritative class for this type check, added const version of GetAuthoritativeClass
Change 3276109 on 2017/01/27 by Phillip.Kavan
[UE-40894] Fix data loss issues with non-native Blueprint classes that override inherited component default values from a nativized parent Blueprint class hierarchy.
change summary:
- modified FBlueprintEditorUtils::BuildComponentInstancingData() to accept an additional parameter indicating whether or not to use the CDO or the template's Archetype as the basis for building the delta property list.
- revised UBlueprint::BeginCacheForCookedPlatformData() to first generate "override" data for ICH records that override SCS nodes from parent classes that are targeted for nativization. this also makes the optimized component instancing feature compatible with nativization as well (should that ever become useful).
- revised UBlueprintGeneratedClass::CheckAndApplyComponentTemplateOverrides() to utilize the additional delta property list data that's now generated at cook time along with a delta serialization pass against the ICH template that's serializes changed properties to a cached data block at load time. this cached "override" data is then applied to instanced subobjects inherited from nativized parent Blueprint classes using a minimal binary serialization pass.
#jira UE-40894
Change 3277671 on 2017/01/30 by Mike.Beach
Mirroring CL 3276602.
Refactoring FBlueprintCompilerCppBackend::SortNodesInUberGraphExecutionGroup() a bit. Catching cases that weren't acounted for - detecting cyclical logic now when we've pulled a node/statement out of order, and other nodes need to fall through to that logic (not relying on a goto).
#jira UE-41188, UE-41189, UE-41186, UE-41037
Change 3278454 on 2017/01/30 by Mike.Beach
Mirroring CL 3278054
Upgrading USimpleConstructionScript::FixupSceneNodeHierarchy() so that the SCS detects orphaned components, and adds them to the hierarchy (notifying users of the issue with a warning).
#jira UE-41247
Change 3278814 on 2017/01/31 by Maciej.Mroz
fixed CIS warning
fixed FBlueprintNativeCodeGenModule::FindReplacedNameAndOuter
Change 3279398 on 2017/01/31 by Mike.Beach
Back out changelist 3278454 - causing unforseen issues, restructuring the component hierarchy.
Change 3282200 on 2017/02/01 by Dan.Oconnor
Moved ForceLoad helpers into UBlueprint so that new compile on load path can prod the linker into loading stuff before flushing the compilation queue
Change 3282269 on 2017/02/01 by Mike.Beach
ClassGeneratedBy not dependable in cooked builds, must rely on class flags to determine if this is a Blueprint class.
Change 3284455 on 2017/02/02 by Dan.Oconnor
Reinstancer optimizations and skipping loader reset when using the new compile manager
Change 3284463 on 2017/02/02 by Dan.Oconnor
Handling missing GeneratedClass
Change 3284476 on 2017/02/02 by Dan.Oconnor
Flush compilation manager when we would normally do a bytecode pass, this guarantees clients of LoadObject that we won't reinstance a pointer on load (giving them back a stale object)
Change 3284523 on 2017/02/02 by Dan.Oconnor
Optimize FBlueprintUnloader::ReplaceStaleRefs, add option to skip reinstancing when recompiling bytecode, refactored bytecode recompilation options into a flag parameter
Change 3285731 on 2017/02/03 by Dan.Oconnor
Merging //UE4/Dev-Main to Dev-Blueprints (//UE4/Dev-Blueprints)
Auto resolved, with merging:
K2Node_CreateDelegate.h/cpp, KismetCompiler.cpp, WidgetBlueprintCompiler.cpp, Kismet2.cpp, KismetReinstanceUtilities.cpp/h, KismetEditorUtils.h, BlueprintSupport.cpp, Class.cpp, LinkerLoad.cpp, Obj.cpp, Class.h, Object.h, BlueprintGeneratedClass.cpp, DefaultEngine.ini,
Manually resolved:
BlueprintEditorUtils.cpp, TestRunner.Automation.Tests.cs, OrionAutobuyCardStatEntry.cpp/h, OrionStateWidget_DraftLobby.cpp
All else resolved safely (no merging)
Change 3286019 on 2017/02/03 by Dan.Oconnor
Add assertion that was added in main
Change 3286031 on 2017/02/03 by Dan.Oconnor
Build fix, missing include
Change 3286056 on 2017/02/03 by Mike.Beach
Corrected fix (from CL 3278454, which had to be backed out) - USimpleConstructionScript::FixupSceneNodeHierarchy() so that the SCS detects orphaned components, and adds them to the hierarchy (notifying users of the issue with a warning).
#jira UE-41247
Change 3286302 on 2017/02/03 by Dan.Oconnor
Allow reinstancing to run very early or in other situation where GEditor is not yet set up
Change 3286386 on 2017/02/03 by Dan.Oconnor
GMinimalCompileOnLoad checks no longer needed with my local changes to BlueprintCompilationManager
Change 3286391 on 2017/02/03 by Dan.Oconnor
Missed old comment
Change 3286614 on 2017/02/03 by Dan.Oconnor
GMinimalCompileOnLoad logic no longer needed
Change 3286655 on 2017/02/03 by Dan.Oconnor
Refactor FKismetEditorUtilities::CompileBlueprint flags into EBlueprintCompileOptions
Change 3286662 on 2017/02/03 by Dan.Oconnor
Build fix, missed file
Change 3288770 on 2017/02/06 by Mike.Beach
Attempt to fix up CIS warnings from CL 3286056.
Change 3289236 on 2017/02/06 by Mike.Beach
Missed fix for CIS warning.
Change 3289276 on 2017/02/06 by Dan.Oconnor
Duplication of CDO is unnecessary
#fyi Maciej.Mroz
Change 3289334 on 2017/02/06 by Dan.Oconnor
Add option to skip all reinstancing logic when running CompileBlueprint - used locally by the blueprint compilation manager. Fixed Typo.
Change 3289443 on 2017/02/06 by Dan.Oconnor
Further cleanup of GMinimalCompileOnLoad abuse. added flag to skip reinstancing and "stub on failure" compile pass
Change 3290509 on 2017/02/07 by Dan.Oconnor
Addressed this with a change to the blueprint compiler manager - no modification needed
Change 3290534 on 2017/02/07 by Dan.Oconnor
Remove old forward declare and outdated comment
Change 3291446 on 2017/02/07 by Dan.Oconnor
This CPFUO call is unused with my latest iteration on the compiler manager
Change 3291516 on 2017/02/07 by Dan.Oconnor
Running compile manager earlier means we don't need to worry about this weird (and costly) call
Change 3291534 on 2017/02/07 by Dan.Oconnor
This compile children call is no longer running with latest improvents to the compile manager
Change 3292587 on 2017/02/08 by Maciej.Mroz
#jira UE-41694
Mirroring cl#3292273 from Odin branch
Change 3293344 on 2017/02/08 by Dan.Oconnor
Iteration on blueprint compile manager - fortnite loads without issue. For now I do the three compile passes that are done by the existing load paths. Timing is actually quite reasonable. Centralizing reinstancing has sped things up.
#fyi Maciej.Mroz
Change 3293565 on 2017/02/08 by Dan.Oconnor
Back out changelist 3293344 - wrong CL
Change 3293567 on 2017/02/08 by Dan.Oconnor
Iteration on blueprint compile manager - fortnite loads without issue. For now I do the three compile passes that are done by the existing load paths. Timing is actually quite reasonable. Centralizing reinstancing has sped things up.
#fyi Maciej.Mroz
Change 3294334 on 2017/02/09 by Phillip.Kavan
[UE-41246] Fix misaligned memory access of noexport struct properties leading to incorrectly initialized values.
- Mirrored from //Odin/Main/... (CL# 3284308).
#jira UE-41246
Change 3294343 on 2017/02/09 by Phillip.Kavan
[UE-41246] Add a whitelist mechanism to handle native noexport types that can support direct field access in nativized Blueprint code.
- Mirrored from //Odin/Main/... (CL# 3285789).
#jira UE-41246
Change 3295913 on 2017/02/09 by Dan.Oconnor
Back out reinstancer optimization, failing to find a reference and it's causing a crash when a component is renamed
#jira UE-41843
Change 3297279 on 2017/02/10 by Dan.Oconnor
SA fix
Change 3297587 on 2017/02/10 by Mike.Beach
Temporarily disabling a spurious warning that gets triggered in Fortnite, when correctly excluding client-only Blueprints.
#jira UE-41880
Change 3298078 on 2017/02/10 by Dan.Oconnor
Try to suppress confused SA warning
[CL 3298251 by Mike Beach in Main branch]
941 lines
31 KiB
C++
941 lines
31 KiB
C++
// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "BlueprintNativeCodeGenModule.h"
|
|
#include "Engine/Blueprint.h"
|
|
#include "HAL/FileManager.h"
|
|
#include "Misc/FileHelper.h"
|
|
#include "Misc/Paths.h"
|
|
#include "Misc/ConfigCacheIni.h"
|
|
#include "UObject/UObjectHash.h"
|
|
#include "UObject/Package.h"
|
|
#include "Templates/Greater.h"
|
|
#include "Components/ActorComponent.h"
|
|
#include "Engine/BlueprintGeneratedClass.h"
|
|
#include "AssetData.h"
|
|
#include "Engine/UserDefinedEnum.h"
|
|
#include "Engine/UserDefinedStruct.h"
|
|
#include "Settings/ProjectPackagingSettings.h"
|
|
|
|
#include "AssetRegistryModule.h"
|
|
#include "BlueprintNativeCodeGenManifest.h"
|
|
#include "Blueprint/BlueprintSupport.h"
|
|
#include "BlueprintCompilerCppBackendInterface.h"
|
|
#include "IBlueprintCompilerCppBackendModule.h"
|
|
#include "BlueprintNativeCodeGenUtils.h"
|
|
#include "Engine/SCS_Node.h"
|
|
#include "Kismet2/BlueprintEditorUtils.h"
|
|
#include "Engine/InheritableComponentHandler.h"
|
|
#include "Animation/AnimBlueprint.h"
|
|
|
|
/*******************************************************************************
|
|
* NativizationCookControllerImpl
|
|
******************************************************************************/
|
|
|
|
namespace NativizationCookControllerImpl
|
|
{
|
|
// If you change this plugin name you must update logic in CookCommand.Automation.cs
|
|
static const TCHAR* DefaultPluginName = TEXT("NativizedAssets");
|
|
}
|
|
|
|
/*******************************************************************************
|
|
* FBlueprintNativeCodeGenModule
|
|
******************************************************************************/
|
|
|
|
class FBlueprintNativeCodeGenModule : public IBlueprintNativeCodeGenModule
|
|
, public IBlueprintNativeCodeGenCore
|
|
{
|
|
public:
|
|
FBlueprintNativeCodeGenModule()
|
|
{
|
|
}
|
|
|
|
//~ Begin IBlueprintNativeCodeGenModule interface
|
|
virtual void Convert(UPackage* Package, ESavePackageResult ReplacementType, const TCHAR* PlatformName) override;
|
|
virtual void SaveManifest(int32 Id = -1) override;
|
|
virtual void MergeManifest(int32 ManifestIdentifier) override;
|
|
virtual void FinalizeManifest() override;
|
|
virtual void GenerateStubs() override;
|
|
virtual void GenerateFullyConvertedClasses() override;
|
|
virtual void MarkUnconvertedBlueprintAsNecessary(TAssetPtr<UBlueprint> BPPtr) override;
|
|
virtual const TMultiMap<FName, TAssetSubclassOf<UObject>>& GetFunctionsBoundToADelegate() override;
|
|
|
|
FFileHelper::EEncodingOptions::Type ForcedEncoding() const
|
|
{
|
|
return FFileHelper::EEncodingOptions::ForceUTF8;
|
|
}
|
|
protected:
|
|
virtual void Initialize(const FNativeCodeGenInitData& InitData) override;
|
|
virtual void InitializeForRerunDebugOnly(const TArray<FPlatformNativizationDetails>& CodegenTargets) override;
|
|
//~ End IBlueprintNativeCodeGenModule interface
|
|
|
|
//~ Begin FScriptCookReplacmentCoordinator interface
|
|
virtual EReplacementResult IsTargetedForReplacement(const UPackage* Package) const override;
|
|
virtual EReplacementResult IsTargetedForReplacement(const UObject* Object) const override;
|
|
virtual UClass* FindReplacedClassForObject(const UObject* Object) const override;
|
|
virtual UObject* FindReplacedNameAndOuter(UObject* Object, FName& OutName) const override;
|
|
//~ End FScriptCookReplacmentCoordinator interface
|
|
private:
|
|
void ReadConfig();
|
|
void FillTargetedForReplacementQuery();
|
|
void FillIsFunctionUsedInADelegate();
|
|
FBlueprintNativeCodeGenManifest& GetManifest(const TCHAR* PlatformName);
|
|
void GenerateSingleStub(UBlueprint* BP, const TCHAR* PlatformName);
|
|
void CollectBoundFunctions(UBlueprint* BP);
|
|
void GenerateSingleAsset(UField* ForConversion, const TCHAR* PlatformName, TSharedPtr<FNativizationSummary> NativizationSummary = TSharedPtr<FNativizationSummary>());
|
|
|
|
TMap< FString, TUniquePtr<FBlueprintNativeCodeGenManifest> > Manifests;
|
|
|
|
// Children of these classes won't be nativized
|
|
TArray<FString> ExcludedAssetTypes;
|
|
// Eg: +ExcludedBlueprintTypes=/Script/Engine.AnimBlueprint
|
|
TArray<TAssetSubclassOf<UBlueprint>> ExcludedBlueprintTypes;
|
|
// Individually excluded assets
|
|
TSet<FStringAssetReference> ExcludedAssets;
|
|
// Excluded folders. It excludes only BPGCs, enums and structures are still converted.
|
|
TArray<FString> ExcludedFolderPaths;
|
|
|
|
TArray<FString> TargetPlatformNames;
|
|
|
|
// A stub-wrapper must be generated only if the BP is really accessed/required by some other generated code.
|
|
TSet<TAssetPtr<UBlueprint>> StubsRequiredByGeneratedCode;
|
|
TSet<TAssetPtr<UBlueprint>> AllPotentialStubs;
|
|
|
|
TSet<TAssetPtr<UBlueprint>> ToGenerate;
|
|
TMultiMap<FName, TAssetSubclassOf<UObject>> FunctionsBoundToADelegate; // is a function could be bound to a delegate, then it must have UFUNCTION macro. So we cannot optimize it.
|
|
|
|
// Cached values from IsTargetedForReplacement
|
|
mutable TMap<FStringAssetReference, EReplacementResult> CachedIsTargetedForReplacement;
|
|
};
|
|
|
|
void FBlueprintNativeCodeGenModule::ReadConfig()
|
|
{
|
|
GConfig->GetArray(TEXT("BlueprintNativizationSettings"), TEXT("ExcludedAssetTypes"), ExcludedAssetTypes, GEditorIni);
|
|
|
|
{
|
|
TArray<FString> ExcludedBlueprintTypesPath;
|
|
GConfig->GetArray(TEXT("BlueprintNativizationSettings"), TEXT("ExcludedBlueprintTypes"), ExcludedBlueprintTypesPath, GEditorIni);
|
|
for (FString& Path : ExcludedBlueprintTypesPath)
|
|
{
|
|
TAssetSubclassOf<UBlueprint> ClassPtr;
|
|
ClassPtr = FStringAssetReference(Path);
|
|
ClassPtr.LoadSynchronous();
|
|
ExcludedBlueprintTypes.Add(ClassPtr);
|
|
}
|
|
}
|
|
|
|
TArray<FString> ExcludedAssetPaths;
|
|
GConfig->GetArray(TEXT("BlueprintNativizationSettings"), TEXT("ExcludedAssets"), ExcludedAssetPaths, GEditorIni);
|
|
for (FString& Path : ExcludedAssetPaths)
|
|
{
|
|
ExcludedAssets.Add(FStringAssetReference(Path));
|
|
}
|
|
|
|
GConfig->GetArray(TEXT("BlueprintNativizationSettings"), TEXT("ExcludedFolderPaths"), ExcludedFolderPaths, GEditorIni);
|
|
}
|
|
|
|
void FBlueprintNativeCodeGenModule::MarkUnconvertedBlueprintAsNecessary(TAssetPtr<UBlueprint> BPPtr)
|
|
{
|
|
StubsRequiredByGeneratedCode.Add(BPPtr);
|
|
}
|
|
|
|
void FBlueprintNativeCodeGenModule::FillTargetedForReplacementQuery()
|
|
{
|
|
IBlueprintCompilerCppBackendModule& BackEndModule = (IBlueprintCompilerCppBackendModule&)IBlueprintCompilerCppBackendModule::Get();
|
|
auto& ConversionQueryDelegate = BackEndModule.OnIsTargetedForConversionQuery();
|
|
auto ShouldConvert = [](const UObject* AssetObj)
|
|
{
|
|
if (ensure(IBlueprintNativeCodeGenCore::Get()))
|
|
{
|
|
EReplacementResult ReplacmentResult = IBlueprintNativeCodeGenCore::Get()->IsTargetedForReplacement(AssetObj);
|
|
return ReplacmentResult == EReplacementResult::ReplaceCompletely;
|
|
}
|
|
return false;
|
|
};
|
|
ConversionQueryDelegate.BindStatic(ShouldConvert);
|
|
|
|
auto LocalMarkUnconvertedBlueprintAsNecessary = [](TAssetPtr<UBlueprint> BPPtr)
|
|
{
|
|
IBlueprintNativeCodeGenModule::Get().MarkUnconvertedBlueprintAsNecessary(BPPtr);
|
|
};
|
|
BackEndModule.OnIncludingUnconvertedBP().BindStatic(LocalMarkUnconvertedBlueprintAsNecessary);
|
|
}
|
|
|
|
namespace
|
|
{
|
|
void GetFieldFormPackage(const UPackage* Package, UStruct*& OutStruct, UEnum*& OutEnum, EObjectFlags ExcludedFlags = RF_Transient)
|
|
{
|
|
TArray<UObject*> Objects;
|
|
GetObjectsWithOuter(Package, Objects, false);
|
|
for (UObject* Entry : Objects)
|
|
{
|
|
if (Entry->HasAnyFlags(ExcludedFlags))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (FBlueprintSupport::IsDeferredDependencyPlaceholder(Entry))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// Not a skeleton class
|
|
if (UClass* AsClass = Cast<UClass>(Entry))
|
|
{
|
|
if (UBlueprint* GeneratingBP = Cast<UBlueprint>(AsClass->ClassGeneratedBy))
|
|
{
|
|
if (AsClass != GeneratingBP->GeneratedClass)
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
OutStruct = Cast<UStruct>(Entry);
|
|
if (OutStruct)
|
|
{
|
|
break;
|
|
}
|
|
|
|
OutEnum = Cast<UEnum>(Entry);
|
|
if (OutEnum)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void FBlueprintNativeCodeGenModule::CollectBoundFunctions(UBlueprint* BP)
|
|
{
|
|
TArray<UFunction*> Functions = IBlueprintCompilerCppBackendModule::CollectBoundFunctions(BP);
|
|
for (UFunction* Func : Functions)
|
|
{
|
|
if (Func)
|
|
{
|
|
FunctionsBoundToADelegate.AddUnique(Func->GetFName(), Func->GetOwnerClass());
|
|
}
|
|
}
|
|
}
|
|
|
|
const TMultiMap<FName, TAssetSubclassOf<UObject>>& FBlueprintNativeCodeGenModule::GetFunctionsBoundToADelegate()
|
|
{
|
|
return FunctionsBoundToADelegate;
|
|
}
|
|
|
|
void FBlueprintNativeCodeGenModule::FillIsFunctionUsedInADelegate()
|
|
{
|
|
IBlueprintCompilerCppBackendModule& BackEndModule = (IBlueprintCompilerCppBackendModule&)IBlueprintCompilerCppBackendModule::Get();
|
|
|
|
auto IsFunctionUsed = [](const UFunction* InFunction) -> bool
|
|
{
|
|
auto& TargetFunctionsBoundToADelegate = IBlueprintNativeCodeGenModule::Get().GetFunctionsBoundToADelegate();
|
|
return InFunction && (nullptr != TargetFunctionsBoundToADelegate.FindPair(InFunction->GetFName(), InFunction->GetOwnerClass()));
|
|
};
|
|
|
|
BackEndModule.GetIsFunctionUsedInADelegateCallback().BindStatic(IsFunctionUsed);
|
|
}
|
|
|
|
void FBlueprintNativeCodeGenModule::Initialize(const FNativeCodeGenInitData& InitData)
|
|
{
|
|
CachedIsTargetedForReplacement.Reset();
|
|
ReadConfig();
|
|
|
|
IBlueprintNativeCodeGenCore::Register(this);
|
|
|
|
// Each platform will need a manifest, because each platform could cook different assets:
|
|
for (const FPlatformNativizationDetails& Platform : InitData.CodegenTargets)
|
|
{
|
|
FString OutputPath = FPaths::Combine(*Platform.PlatformTargetDirectory, NativizationCookControllerImpl::DefaultPluginName);
|
|
|
|
Manifests.Add(*Platform.PlatformName, TUniquePtr<FBlueprintNativeCodeGenManifest>(new FBlueprintNativeCodeGenManifest(NativizationCookControllerImpl::DefaultPluginName, OutputPath, Platform.CompilerNativizationOptions)));
|
|
|
|
TargetPlatformNames.Add(Platform.PlatformName);
|
|
|
|
// Clear source code folder
|
|
const FString SourceCodeDir = GetManifest(*Platform.PlatformName).GetTargetPaths().PluginSourceDir();
|
|
UE_LOG(LogBlueprintCodeGen, Log, TEXT("Clear nativized source code directory: %s"), *SourceCodeDir);
|
|
IFileManager::Get().DeleteDirectory(*SourceCodeDir, false, true);
|
|
}
|
|
|
|
FillTargetedForReplacementQuery();
|
|
|
|
FillIsFunctionUsedInADelegate();
|
|
}
|
|
|
|
void FBlueprintNativeCodeGenModule::InitializeForRerunDebugOnly(const TArray<FPlatformNativizationDetails>& CodegenTargets)
|
|
{
|
|
CachedIsTargetedForReplacement.Reset();
|
|
ReadConfig();
|
|
IBlueprintNativeCodeGenCore::Register(this);
|
|
FillTargetedForReplacementQuery();
|
|
FillIsFunctionUsedInADelegate();
|
|
|
|
for (const FPlatformNativizationDetails& Platform : CodegenTargets)
|
|
{
|
|
// load the old manifest:
|
|
FString OutputPath = FPaths::Combine(*Platform.PlatformTargetDirectory, NativizationCookControllerImpl::DefaultPluginName, *FBlueprintNativeCodeGenPaths::GetDefaultManifestPath());
|
|
Manifests.Add(Platform.PlatformName, TUniquePtr<FBlueprintNativeCodeGenManifest>(new FBlueprintNativeCodeGenManifest(FPaths::ConvertRelativePathToFull(OutputPath))));
|
|
//FBlueprintNativeCodeGenManifest OldManifest(FPaths::ConvertRelativePathToFull(OutputPath));
|
|
// reconvert every assets listed in the manifest:
|
|
for (const auto& ConversionTarget : GetManifest(*Platform.PlatformName).GetConversionRecord())
|
|
{
|
|
// load the package:
|
|
UPackage* Package = LoadPackage(nullptr, *ConversionTarget.Value.TargetObjPath, LOAD_None);
|
|
|
|
if (!Package)
|
|
{
|
|
UE_LOG(LogBlueprintCodeGen, Error, TEXT("Unable to load the package: %s"), *ConversionTarget.Value.TargetObjPath);
|
|
continue;
|
|
}
|
|
|
|
// reconvert it
|
|
Convert(Package, ESavePackageResult::ReplaceCompletely, *Platform.PlatformName);
|
|
}
|
|
|
|
// reconvert every unconverted dependency listed in the manifest:
|
|
for (const auto& ConversionTarget : GetManifest(*Platform.PlatformName).GetUnconvertedDependencies())
|
|
{
|
|
// load the package:
|
|
UPackage* Package = LoadPackage(nullptr, *ConversionTarget.Key.GetPlainNameString(), LOAD_None);
|
|
|
|
UStruct* Struct = nullptr;
|
|
UEnum* Enum = nullptr;
|
|
GetFieldFormPackage(Package, Struct, Enum);
|
|
UBlueprint* BP = Cast<UBlueprint>(CastChecked<UClass>(Struct)->ClassGeneratedBy);
|
|
if (ensure(BP))
|
|
{
|
|
CollectBoundFunctions(BP);
|
|
GenerateSingleStub(BP, *Platform.PlatformName);
|
|
}
|
|
}
|
|
|
|
for (TAssetPtr<UBlueprint>& BPPtr : ToGenerate)
|
|
{
|
|
UBlueprint* BP = BPPtr.LoadSynchronous();
|
|
if (ensure(BP))
|
|
{
|
|
GenerateSingleAsset(BP->GeneratedClass, *Platform.PlatformName);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void FBlueprintNativeCodeGenModule::GenerateFullyConvertedClasses()
|
|
{
|
|
TSharedPtr<FNativizationSummary> NativizationSummary(new FNativizationSummary());
|
|
{
|
|
IBlueprintCompilerCppBackendModule& CodeGenBackend = (IBlueprintCompilerCppBackendModule&)IBlueprintCompilerCppBackendModule::Get();
|
|
CodeGenBackend.NativizationSummary() = NativizationSummary;
|
|
}
|
|
|
|
for (TAssetPtr<UBlueprint>& BPPtr : ToGenerate)
|
|
{
|
|
UBlueprint* BP = BPPtr.LoadSynchronous();
|
|
if (ensure(BP))
|
|
{
|
|
for (const FString& PlatformName : TargetPlatformNames)
|
|
{
|
|
GenerateSingleAsset(BP->GeneratedClass, *PlatformName, NativizationSummary);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (NativizationSummary->InaccessiblePropertyStat.Num())
|
|
{
|
|
UE_LOG(LogBlueprintCodeGen, Display, TEXT("Nativization Summary - Inaccessible Properties:"));
|
|
NativizationSummary->InaccessiblePropertyStat.ValueSort(TGreater<int32>());
|
|
for (auto& Iter : NativizationSummary->InaccessiblePropertyStat)
|
|
{
|
|
UE_LOG(LogBlueprintCodeGen, Display, TEXT("\t %s \t - %d"), *Iter.Key.ToString(), Iter.Value);
|
|
}
|
|
}
|
|
{
|
|
UE_LOG(LogBlueprintCodeGen, Display, TEXT("Nativization Summary - AnimBP:"));
|
|
UE_LOG(LogBlueprintCodeGen, Display, TEXT("Name, Children, Non-empty Functions (Empty Functions), Variables, FunctionUsage, VariableUsage"));
|
|
for (auto& Iter : NativizationSummary->AnimBlueprintStat)
|
|
{
|
|
UE_LOG(LogBlueprintCodeGen, Display
|
|
, TEXT("%s, %d, %d (%d), %d, %d, %d")
|
|
, *Iter.Key.ToString()
|
|
, Iter.Value.Children
|
|
, Iter.Value.Functions - Iter.Value.ReducibleFunctions
|
|
, Iter.Value.ReducibleFunctions
|
|
, Iter.Value.Variables
|
|
, Iter.Value.FunctionUsage
|
|
, Iter.Value.VariableUsage);
|
|
}
|
|
}
|
|
UE_LOG(LogBlueprintCodeGen, Display, TEXT("Nativization Summary - Shared Variables From Graph: %d"), NativizationSummary->MemberVariablesFromGraph);
|
|
}
|
|
|
|
FBlueprintNativeCodeGenManifest& FBlueprintNativeCodeGenModule::GetManifest(const TCHAR* PlatformName)
|
|
{
|
|
FString PlatformNameStr(PlatformName);
|
|
TUniquePtr<FBlueprintNativeCodeGenManifest>* Result = Manifests.Find(PlatformNameStr);
|
|
check(Result->IsValid());
|
|
return **Result;
|
|
}
|
|
|
|
void FBlueprintNativeCodeGenModule::GenerateSingleStub(UBlueprint* BP, const TCHAR* PlatformName)
|
|
{
|
|
if (!ensure(BP))
|
|
{
|
|
return;
|
|
}
|
|
|
|
UClass* Class = BP->GeneratedClass;
|
|
if (!ensure(Class))
|
|
{
|
|
return;
|
|
}
|
|
|
|
// no PCHFilename should be necessary
|
|
const IAssetRegistry& Registry = FModuleManager::LoadModuleChecked<FAssetRegistryModule>("AssetRegistry").Get();
|
|
FAssetData AssetInfo = Registry.GetAssetByObjectPath(*Class->GetPathName());
|
|
FString FileContents;
|
|
TUniquePtr<IBlueprintCompilerCppBackend> Backend_CPP(IBlueprintCompilerCppBackendModuleInterface::Get().Create());
|
|
// Apparently we can only generate wrappers for classes, so any logic that results in non classes requesting
|
|
// wrappers will fail here:
|
|
|
|
FileContents = Backend_CPP->GenerateWrapperForClass(Class);
|
|
|
|
if (!FileContents.IsEmpty())
|
|
{
|
|
FFileHelper::SaveStringToFile(FileContents
|
|
, *(GetManifest(PlatformName).CreateUnconvertedDependencyRecord(AssetInfo.PackageName, AssetInfo).GeneratedWrapperPath)
|
|
, ForcedEncoding());
|
|
}
|
|
// The stub we generate still may have dependencies on other modules, so make sure the module dependencies are
|
|
// still recorded so that the .build.cs is generated correctly. Without this you'll get include related errors
|
|
// (or possibly linker errors) in stub headers:
|
|
GetManifest(PlatformName).GatherModuleDependencies(BP->GetOutermost());
|
|
}
|
|
|
|
void FBlueprintNativeCodeGenModule::GenerateSingleAsset(UField* ForConversion, const TCHAR* PlatformName, TSharedPtr<FNativizationSummary> NativizationSummary)
|
|
{
|
|
IBlueprintCompilerCppBackendModule& BackEndModule = (IBlueprintCompilerCppBackendModule&)IBlueprintCompilerCppBackendModule::Get();
|
|
auto& BackendPCHQuery = BackEndModule.OnPCHFilenameQuery();
|
|
const IAssetRegistry& Registry = FModuleManager::LoadModuleChecked<FAssetRegistryModule>("AssetRegistry").Get();
|
|
FAssetData AssetInfo = Registry.GetAssetByObjectPath(*ForConversion->GetPathName());
|
|
|
|
FBlueprintNativeCodeGenPaths TargetPaths = GetManifest(PlatformName).GetTargetPaths();
|
|
BackendPCHQuery.BindLambda([TargetPaths]()->FString
|
|
{
|
|
return TargetPaths.RuntimePCHFilename();
|
|
});
|
|
|
|
FConvertedAssetRecord& ConversionRecord = GetManifest(PlatformName).CreateConversionRecord(*ForConversion->GetPathName(), AssetInfo);
|
|
TSharedPtr<FString> HeaderSource(new FString());
|
|
TSharedPtr<FString> CppSource(new FString());
|
|
|
|
FBlueprintNativeCodeGenUtils::GenerateCppCode(ForConversion, HeaderSource, CppSource, NativizationSummary, GetManifest(PlatformName).GetCompilerNativizationOptions());
|
|
bool bSuccess = !HeaderSource->IsEmpty() || !CppSource->IsEmpty();
|
|
// Run the cpp first, because we cue off of the presence of a header for a valid conversion record (see
|
|
// FConvertedAssetRecord::IsValid)
|
|
if (!CppSource->IsEmpty())
|
|
{
|
|
if (!FFileHelper::SaveStringToFile(*CppSource, *ConversionRecord.GeneratedCppPath, ForcedEncoding()))
|
|
{
|
|
bSuccess &= false;
|
|
ConversionRecord.GeneratedCppPath.Empty();
|
|
}
|
|
CppSource->Empty(CppSource->Len());
|
|
}
|
|
else
|
|
{
|
|
ConversionRecord.GeneratedCppPath.Empty();
|
|
}
|
|
|
|
if (bSuccess && !HeaderSource->IsEmpty())
|
|
{
|
|
if (!FFileHelper::SaveStringToFile(*HeaderSource, *ConversionRecord.GeneratedHeaderPath, ForcedEncoding()))
|
|
{
|
|
bSuccess &= false;
|
|
ConversionRecord.GeneratedHeaderPath.Empty();
|
|
}
|
|
HeaderSource->Empty(HeaderSource->Len());
|
|
}
|
|
else
|
|
{
|
|
ConversionRecord.GeneratedHeaderPath.Empty();
|
|
}
|
|
|
|
if (bSuccess)
|
|
{
|
|
GetManifest(PlatformName).GatherModuleDependencies(ForConversion->GetOutermost());
|
|
}
|
|
else
|
|
{
|
|
UE_LOG(LogBlueprintCodeGen, Error, TEXT("FBlueprintNativeCodeGenModule::GenerateSingleAsset error: %s"), *GetPathNameSafe(ForConversion));
|
|
}
|
|
|
|
BackendPCHQuery.Unbind();
|
|
}
|
|
|
|
void FBlueprintNativeCodeGenModule::GenerateStubs()
|
|
{
|
|
TSet<TAssetPtr<UBlueprint>> AlreadyGenerated;
|
|
while (AlreadyGenerated.Num() < StubsRequiredByGeneratedCode.Num())
|
|
{
|
|
const int32 OldGeneratedNum = AlreadyGenerated.Num();
|
|
for (TAssetPtr<UBlueprint>& BPPtr : StubsRequiredByGeneratedCode)
|
|
{
|
|
bool bAlreadyGenerated = false;
|
|
AlreadyGenerated.Add(BPPtr, &bAlreadyGenerated);
|
|
if (bAlreadyGenerated)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
ensureMsgf(AllPotentialStubs.Contains(BPPtr), TEXT("A required blueprint doesn't generate stub: %s"), *BPPtr.ToString());
|
|
for (auto& PlatformName : TargetPlatformNames)
|
|
{
|
|
GenerateSingleStub(BPPtr.LoadSynchronous(), *PlatformName);
|
|
}
|
|
}
|
|
|
|
if (!ensure(OldGeneratedNum != AlreadyGenerated.Num()))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
UE_LOG(LogBlueprintCodeGen, Log, TEXT("GenerateStubs - all unconverted bp: %d, generated wrapers: %d"), AllPotentialStubs.Num(), StubsRequiredByGeneratedCode.Num());
|
|
}
|
|
|
|
void FBlueprintNativeCodeGenModule::Convert(UPackage* Package, ESavePackageResult CookResult, const TCHAR* PlatformName)
|
|
{
|
|
// Find the struct/enum to convert:
|
|
UStruct* Struct = nullptr;
|
|
UEnum* Enum = nullptr;
|
|
GetFieldFormPackage(Package, Struct, Enum);
|
|
|
|
// First we gather information about bound functions.
|
|
UClass* AsClass = Cast<UClass>(Struct);
|
|
UBlueprint* BP = AsClass ? Cast<UBlueprint>(AsClass->ClassGeneratedBy) : nullptr;
|
|
if (BP)
|
|
{
|
|
CollectBoundFunctions(BP);
|
|
}
|
|
|
|
if (CookResult != ESavePackageResult::ReplaceCompletely && CookResult != ESavePackageResult::GenerateStub)
|
|
{
|
|
// nothing to convert
|
|
return;
|
|
}
|
|
|
|
if (Struct == nullptr && Enum == nullptr)
|
|
{
|
|
ensure(false);
|
|
return;
|
|
}
|
|
|
|
if (CookResult == ESavePackageResult::GenerateStub)
|
|
{
|
|
if (ensure(BP))
|
|
{
|
|
ensure(!ToGenerate.Contains(BP));
|
|
AllPotentialStubs.Add(BP);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
check(CookResult == ESavePackageResult::ReplaceCompletely);
|
|
if (AsClass)
|
|
{
|
|
if (ensure(BP))
|
|
{
|
|
ensure(!AllPotentialStubs.Contains(BP));
|
|
ToGenerate.Add(BP);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
UField* ForConversion = Struct ? (UField*)Struct : (UField*)Enum;
|
|
GenerateSingleAsset(ForConversion, PlatformName);
|
|
}
|
|
}
|
|
}
|
|
|
|
void FBlueprintNativeCodeGenModule::SaveManifest(int32 Id )
|
|
{
|
|
for (auto& PlatformName : TargetPlatformNames)
|
|
{
|
|
GetManifest(*PlatformName).Save(Id);
|
|
}
|
|
}
|
|
|
|
void FBlueprintNativeCodeGenModule::MergeManifest(int32 ManifestIdentifier)
|
|
{
|
|
for (auto& PlatformName : TargetPlatformNames)
|
|
{
|
|
FBlueprintNativeCodeGenManifest& CurrentManifest = GetManifest(*PlatformName);
|
|
FBlueprintNativeCodeGenManifest OtherManifest = FBlueprintNativeCodeGenManifest(CurrentManifest.GetTargetPaths().ManifestFilePath() + FString::FromInt(ManifestIdentifier));
|
|
CurrentManifest.Merge(OtherManifest);
|
|
}
|
|
}
|
|
|
|
void FBlueprintNativeCodeGenModule::FinalizeManifest()
|
|
{
|
|
for(auto& PlatformName : TargetPlatformNames)
|
|
{
|
|
GetManifest(*PlatformName).Save(-1);
|
|
check(FBlueprintNativeCodeGenUtils::FinalizePlugin(GetManifest(*PlatformName)));
|
|
}
|
|
}
|
|
|
|
UClass* FBlueprintNativeCodeGenModule::FindReplacedClassForObject(const UObject* Object) const
|
|
{
|
|
// we're only looking to replace class types:
|
|
if (Object && Object->IsA<UField>()
|
|
&& (EReplacementResult::ReplaceCompletely == IsTargetedForReplacement(Object)))
|
|
{
|
|
for (const UClass* Class = Object->GetClass(); Class; Class = Class->GetSuperClass())
|
|
{
|
|
if (Class == UUserDefinedEnum::StaticClass())
|
|
{
|
|
return UEnum::StaticClass();
|
|
}
|
|
if (Class == UUserDefinedStruct::StaticClass())
|
|
{
|
|
return UScriptStruct::StaticClass();
|
|
}
|
|
if (Class == UBlueprintGeneratedClass::StaticClass())
|
|
{
|
|
return UDynamicClass::StaticClass();
|
|
}
|
|
}
|
|
}
|
|
ensure(!Object || !(Object->IsA<UUserDefinedStruct>() || Object->IsA<UUserDefinedEnum>()));
|
|
return nullptr;
|
|
}
|
|
|
|
UObject* FBlueprintNativeCodeGenModule::FindReplacedNameAndOuter(UObject* Object, FName& OutName) const
|
|
{
|
|
OutName = NAME_None;
|
|
|
|
auto GetOuterBPGC = [](UObject* FirstOuter) -> UBlueprintGeneratedClass*
|
|
{
|
|
UBlueprintGeneratedClass* BPGC = nullptr;
|
|
for (UObject* OuterObject = FirstOuter; OuterObject && !BPGC; OuterObject = OuterObject->GetOuter())
|
|
{
|
|
if (OuterObject->HasAnyFlags(RF_ClassDefaultObject))
|
|
{
|
|
return nullptr;
|
|
}
|
|
BPGC = Cast<UBlueprintGeneratedClass>(OuterObject);
|
|
}
|
|
return BPGC;
|
|
};
|
|
|
|
UActorComponent* ActorComponent = Cast<UActorComponent>(Object);
|
|
if (ActorComponent)
|
|
{
|
|
//if is child of a BPGC and not child of a CDO
|
|
UBlueprintGeneratedClass* BPGC = GetOuterBPGC(ActorComponent->GetOuter());
|
|
FName NewName = NAME_None;
|
|
UObject* OuterCDO = nullptr;
|
|
for (UBlueprintGeneratedClass* SuperBPGC = BPGC; SuperBPGC && (NewName == NAME_None); SuperBPGC = Cast<UBlueprintGeneratedClass>(SuperBPGC->GetSuperClass()))
|
|
{
|
|
if (SuperBPGC->InheritableComponentHandler)
|
|
{
|
|
FComponentKey FoundKey = SuperBPGC->InheritableComponentHandler->FindKey(ActorComponent);
|
|
if (FoundKey.IsValid())
|
|
{
|
|
NewName = FoundKey.IsSCSKey() ? FoundKey.GetSCSVariableName() : ActorComponent->GetFName();
|
|
OuterCDO = BPGC->GetDefaultObject(false);
|
|
break;
|
|
}
|
|
}
|
|
if (SuperBPGC->SimpleConstructionScript)
|
|
{
|
|
for (auto Node : SuperBPGC->SimpleConstructionScript->GetAllNodes())
|
|
{
|
|
if (Node->ComponentTemplate == ActorComponent)
|
|
{
|
|
NewName = Node->GetVariableName();
|
|
if (NewName != NAME_None)
|
|
{
|
|
OuterCDO = BPGC->GetDefaultObject(false);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (OuterCDO && (EReplacementResult::ReplaceCompletely == IsTargetedForReplacement(OuterCDO->GetClass())))
|
|
{
|
|
OutName = NewName;
|
|
UE_LOG(LogBlueprintCodeGen, Log, TEXT("Object '%s' has replaced name '%s' and outer: '%s'"), *GetPathNameSafe(Object), *OutName.ToString(), *GetPathNameSafe(OuterCDO));
|
|
return OuterCDO;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
UChildActorComponent* OuterCAC = Cast<UChildActorComponent>(Object->GetOuter());
|
|
if (OuterCAC && OuterCAC->GetChildActorTemplate() == Object)
|
|
{
|
|
UBlueprintGeneratedClass* BPGC = GetOuterBPGC(OuterCAC->GetOuter());
|
|
if (BPGC && (EReplacementResult::ReplaceCompletely == IsTargetedForReplacement(BPGC)))
|
|
{
|
|
return BPGC;
|
|
}
|
|
}
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
EReplacementResult FBlueprintNativeCodeGenModule::IsTargetedForReplacement(const UPackage* Package) const
|
|
{
|
|
// non-native packages with enums and structs should be converted, unless they are blacklisted:
|
|
UStruct* Struct = nullptr;
|
|
UEnum* Enum = nullptr;
|
|
GetFieldFormPackage(Package, Struct, Enum, RF_NoFlags);
|
|
|
|
UObject* Target = Struct;
|
|
if (Target == nullptr)
|
|
{
|
|
Target = Enum;
|
|
}
|
|
return IsTargetedForReplacement(Target);
|
|
}
|
|
|
|
EReplacementResult FBlueprintNativeCodeGenModule::IsTargetedForReplacement(const UObject* Object) const
|
|
{
|
|
if (Object == nullptr)
|
|
{
|
|
return EReplacementResult::DontReplace;
|
|
}
|
|
|
|
const UUserDefinedStruct* const UDStruct = Cast<const UUserDefinedStruct>(Object);
|
|
const UUserDefinedEnum* const UDEnum = Cast<const UUserDefinedEnum>(Object);
|
|
const UBlueprintGeneratedClass* const BlueprintClass = Cast<const UBlueprintGeneratedClass>(Object);
|
|
if (UDStruct == nullptr && UDEnum == nullptr && BlueprintClass == nullptr)
|
|
{
|
|
return EReplacementResult::DontReplace;
|
|
}
|
|
|
|
const FStringAssetReference ObjectKey(Object);
|
|
{
|
|
const EReplacementResult* const CachedValue = CachedIsTargetedForReplacement.Find(ObjectKey); //THe referenced returned by FindOrAdd could be invalid later, when filled.
|
|
if (CachedValue)
|
|
{
|
|
return *CachedValue;
|
|
}
|
|
}
|
|
|
|
const UBlueprint* const Blueprint = BlueprintClass ? Cast<UBlueprint>(BlueprintClass->ClassGeneratedBy) : nullptr;
|
|
|
|
|
|
const UProjectPackagingSettings* const PackagingSettings = GetDefault<UProjectPackagingSettings>();
|
|
const bool bNativizeOnlySelectedBPs = PackagingSettings && PackagingSettings->BlueprintNativizationMethod == EProjectPackagingBlueprintNativizationMethod::Exclusive;
|
|
|
|
|
|
auto ObjectIsNotReplacedAtAll = [&]() -> bool
|
|
{
|
|
// EDITOR ON DEVELOPMENT OBJECT
|
|
{
|
|
auto IsDeveloperObject = [](const UObject* Obj) -> bool
|
|
{
|
|
auto IsObjectFromDeveloperPackage = [](const UObject* InObj) -> bool
|
|
{
|
|
return InObj && InObj->GetOutermost()->HasAllPackagesFlags(PKG_Developer);
|
|
};
|
|
|
|
if (Obj)
|
|
{
|
|
if (IsObjectFromDeveloperPackage(Obj))
|
|
{
|
|
return true;
|
|
}
|
|
const UStruct* StructToTest = Obj->IsA<UStruct>() ? CastChecked<const UStruct>(Obj) : Obj->GetClass();
|
|
for (; StructToTest; StructToTest = StructToTest->GetSuperStruct())
|
|
{
|
|
if (IsObjectFromDeveloperPackage(StructToTest))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
};
|
|
if (Object && (IsEditorOnlyObject(Object) || IsDeveloperObject(Object)))
|
|
{
|
|
UE_LOG(LogBlueprintCodeGen, Warning, TEXT("Object %s depends on Editor or Development stuff. It shouldn't be cooked."), *GetPathNameSafe(Object));
|
|
return true;
|
|
}
|
|
}
|
|
// DATA ONLY BP
|
|
{
|
|
static const FBoolConfigValueHelper DontNativizeDataOnlyBP(TEXT("BlueprintNativizationSettings"), TEXT("bDontNativizeDataOnlyBP"));
|
|
if (DontNativizeDataOnlyBP && !bNativizeOnlySelectedBPs && Blueprint && FBlueprintEditorUtils::IsDataOnlyBlueprint(Blueprint))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
// Don't convert objects like Default__WidgetBlueprintGeneratedClass
|
|
if (Object && (Object->HasAnyFlags(RF_ClassDefaultObject)))
|
|
{
|
|
return true;
|
|
}
|
|
return false;
|
|
};
|
|
if (ObjectIsNotReplacedAtAll())
|
|
{
|
|
CachedIsTargetedForReplacement.Add(ObjectKey, EReplacementResult::DontReplace);
|
|
return EReplacementResult::DontReplace;
|
|
}
|
|
|
|
auto ObjectGenratesOnlyStub = [&]() -> bool
|
|
{
|
|
// ExcludedFolderPaths
|
|
if (BlueprintClass)
|
|
{
|
|
const FString ObjPathName = Object->GetPathName();
|
|
for (const FString& ExcludedPath : ExcludedFolderPaths)
|
|
{
|
|
if (ObjPathName.StartsWith(ExcludedPath))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
// ExcludedAssetTypes
|
|
{
|
|
// we can't use FindObject, because we may be converting a type while saving
|
|
if (UDEnum && ExcludedAssetTypes.Find(UDEnum->GetPathName()) != INDEX_NONE)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
const UStruct* LocStruct = Cast<const UStruct>(Object);
|
|
while (LocStruct)
|
|
{
|
|
if (ExcludedAssetTypes.Find(LocStruct->GetPathName()) != INDEX_NONE)
|
|
{
|
|
return true;
|
|
}
|
|
LocStruct = LocStruct->GetSuperStruct();
|
|
}
|
|
}
|
|
|
|
// ExcludedAssets
|
|
{
|
|
if (ExcludedAssets.Contains(Object->GetOutermost()))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
|
|
if (Blueprint && BlueprintClass)
|
|
{
|
|
// Reducible AnimBP
|
|
{
|
|
static const FBoolConfigValueHelper NativizeAnimBPOnlyWhenNonReducibleFuncitons(TEXT("BlueprintNativizationSettings"), TEXT("bNativizeAnimBPOnlyWhenNonReducibleFuncitons"));
|
|
if (NativizeAnimBPOnlyWhenNonReducibleFuncitons)
|
|
{
|
|
if (const UAnimBlueprint* AnimBlueprint = Cast<UAnimBlueprint>(Blueprint))
|
|
{
|
|
ensure(AnimBlueprint->bHasBeenRegenerated);
|
|
if (AnimBlueprint->bHasAnyNonReducibleFunction == UBlueprint::EIsBPNonReducible::No)
|
|
{
|
|
UE_LOG(LogBlueprintCodeGen, Log, TEXT("AnimBP %s without non-reducible functions is excluded from nativization"), *GetPathNameSafe(Blueprint));
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Unconvertable Blueprint
|
|
{
|
|
const EBlueprintType UnconvertableBlueprintTypes[] = {
|
|
//BPTYPE_Const, // What is a "const" Blueprint?
|
|
BPTYPE_MacroLibrary,
|
|
BPTYPE_LevelScript,
|
|
};
|
|
const EBlueprintType BlueprintType = Blueprint->BlueprintType;
|
|
for (int32 TypeIndex = 0; TypeIndex < ARRAY_COUNT(UnconvertableBlueprintTypes); ++TypeIndex)
|
|
{
|
|
if (BlueprintType == UnconvertableBlueprintTypes[TypeIndex])
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
// ExcludedBlueprintTypes
|
|
for (TAssetSubclassOf<UBlueprint> ExcludedBlueprintTypeAsset : ExcludedBlueprintTypes)
|
|
{
|
|
UClass* ExcludedBPClass = ExcludedBlueprintTypeAsset.Get();
|
|
if (!ExcludedBPClass)
|
|
{
|
|
ExcludedBPClass = ExcludedBlueprintTypeAsset.LoadSynchronous();
|
|
}
|
|
if (ExcludedBPClass && Blueprint->IsA(ExcludedBPClass))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
const bool bFlaggedForNativization = (Blueprint->NativizationFlag == EBlueprintNativizationFlag::Dependency) ?
|
|
PackagingSettings->IsBlueprintAssetInNativizationList(Blueprint) :
|
|
(Blueprint->NativizationFlag == EBlueprintNativizationFlag::ExplicitlyEnabled);
|
|
// Blueprint is not selected
|
|
if (bNativizeOnlySelectedBPs && !bFlaggedForNativization)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
// Parent Class in not converted
|
|
for (const UBlueprintGeneratedClass* ParentClassIt = Cast<UBlueprintGeneratedClass>(BlueprintClass->GetSuperClass())
|
|
; ParentClassIt; ParentClassIt = Cast<UBlueprintGeneratedClass>(ParentClassIt->GetSuperClass()))
|
|
{
|
|
const EReplacementResult ParentResult = IsTargetedForReplacement(ParentClassIt);
|
|
if (ParentResult != EReplacementResult::ReplaceCompletely)
|
|
{
|
|
if (bNativizeOnlySelectedBPs)
|
|
{
|
|
UE_LOG(LogBlueprintCodeGen, Error, TEXT("BP %s is selected for nativization, but its parent class %s is not nativized."), *GetPathNameSafe(Blueprint), *GetPathNameSafe(ParentClassIt));
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// Interface class not converted
|
|
TArray<UClass*> InterfaceClasses;
|
|
FBlueprintEditorUtils::FindImplementedInterfaces(Blueprint, false, InterfaceClasses);
|
|
for (const UClass* InterfaceClassIt : InterfaceClasses)
|
|
{
|
|
const UBlueprintGeneratedClass* InterfaceBPGC = Cast<const UBlueprintGeneratedClass>(InterfaceClassIt);
|
|
if (InterfaceBPGC)
|
|
{
|
|
const EReplacementResult InterfaceResult = IsTargetedForReplacement(InterfaceBPGC);
|
|
if (InterfaceResult != EReplacementResult::ReplaceCompletely)
|
|
{
|
|
if (bNativizeOnlySelectedBPs)
|
|
{
|
|
UE_LOG(LogBlueprintCodeGen, Error, TEXT("BP %s is selected for nativization, but BP interface class %s is not nativized."), *GetPathNameSafe(Blueprint), *GetPathNameSafe(InterfaceClassIt));
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
};
|
|
if (ObjectGenratesOnlyStub())
|
|
{
|
|
CachedIsTargetedForReplacement.Add(ObjectKey, EReplacementResult::GenerateStub);
|
|
return EReplacementResult::GenerateStub;
|
|
}
|
|
|
|
CachedIsTargetedForReplacement.Add(ObjectKey, EReplacementResult::ReplaceCompletely);
|
|
return EReplacementResult::ReplaceCompletely;
|
|
}
|
|
|
|
IMPLEMENT_MODULE(FBlueprintNativeCodeGenModule, BlueprintNativeCodeGen);
|