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 ========================== 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
411 lines
11 KiB
C++
411 lines
11 KiB
C++
// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "ProjectsPrivatePCH.h"
|
|
|
|
#define LOCTEXT_NAMESPACE "ModuleDescriptor"
|
|
|
|
ELoadingPhase::Type ELoadingPhase::FromString( const TCHAR *String )
|
|
{
|
|
ELoadingPhase::Type TestType = (ELoadingPhase::Type)0;
|
|
for(; TestType < ELoadingPhase::Max; TestType = (ELoadingPhase::Type)(TestType + 1))
|
|
{
|
|
const TCHAR *TestString = ToString(TestType);
|
|
if(FCString::Stricmp(String, TestString) == 0)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
return TestType;
|
|
}
|
|
|
|
const TCHAR* ELoadingPhase::ToString( const ELoadingPhase::Type Value )
|
|
{
|
|
switch( Value )
|
|
{
|
|
case Default:
|
|
return TEXT( "Default" );
|
|
|
|
case PostDefault:
|
|
return TEXT( "PostDefault" );
|
|
|
|
case PreDefault:
|
|
return TEXT( "PreDefault" );
|
|
|
|
case PostConfigInit:
|
|
return TEXT( "PostConfigInit" );
|
|
|
|
case PreLoadingScreen:
|
|
return TEXT( "PreLoadingScreen" );
|
|
|
|
case PostEngineInit:
|
|
return TEXT( "PostEngineInit" );
|
|
|
|
default:
|
|
ensureMsgf( false, TEXT( "Unrecognized ELoadingPhase value: %i" ), Value );
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
EHostType::Type EHostType::FromString( const TCHAR *String )
|
|
{
|
|
EHostType::Type TestType = (EHostType::Type)0;
|
|
for(; TestType < EHostType::Max; TestType = (EHostType::Type)(TestType + 1))
|
|
{
|
|
const TCHAR *TestString = ToString(TestType);
|
|
if(FCString::Stricmp(String, TestString) == 0)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
return TestType;
|
|
}
|
|
|
|
const TCHAR* EHostType::ToString( const EHostType::Type Value )
|
|
{
|
|
switch( Value )
|
|
{
|
|
case Runtime:
|
|
return TEXT( "Runtime" );
|
|
|
|
case RuntimeNoCommandlet:
|
|
return TEXT( "RuntimeNoCommandlet" );
|
|
|
|
case Developer:
|
|
return TEXT( "Developer" );
|
|
|
|
case Editor:
|
|
return TEXT( "Editor" );
|
|
|
|
case EditorNoCommandlet:
|
|
return TEXT( "EditorNoCommandlet" );
|
|
|
|
case Program:
|
|
return TEXT("Program");
|
|
|
|
case ServerOnly:
|
|
return TEXT("ServerOnly");
|
|
|
|
default:
|
|
ensureMsgf( false, TEXT( "Unrecognized EModuleType value: %i" ), Value );
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
FModuleDescriptor::FModuleDescriptor(const FName InName, EHostType::Type InType, ELoadingPhase::Type InLoadingPhase)
|
|
: Name(InName)
|
|
, Type(InType)
|
|
, LoadingPhase(InLoadingPhase)
|
|
{
|
|
}
|
|
|
|
bool FModuleDescriptor::Read(const FJsonObject& Object, FText& OutFailReason)
|
|
{
|
|
// Read the module name
|
|
TSharedPtr<FJsonValue> NameValue = Object.TryGetField(TEXT("Name"));
|
|
if(!NameValue.IsValid() || NameValue->Type != EJson::String)
|
|
{
|
|
OutFailReason = LOCTEXT("ModuleWithoutAName", "Found a 'Module' entry with a missing 'Name' field");
|
|
return false;
|
|
}
|
|
Name = FName(*NameValue->AsString());
|
|
|
|
// Read the module type
|
|
TSharedPtr<FJsonValue> TypeValue = Object.TryGetField(TEXT("Type"));
|
|
if(!TypeValue.IsValid() || TypeValue->Type != EJson::String)
|
|
{
|
|
OutFailReason = FText::Format( LOCTEXT( "ModuleWithoutAType", "Found Module entry '{0}' with a missing 'Type' field" ), FText::FromName(Name) );
|
|
return false;
|
|
}
|
|
Type = EHostType::FromString(*TypeValue->AsString());
|
|
if(Type == EHostType::Max)
|
|
{
|
|
OutFailReason = FText::Format( LOCTEXT( "ModuleWithInvalidType", "Module entry '{0}' specified an unrecognized module Type '{1}'" ), FText::FromName(Name), FText::FromString(TypeValue->AsString()) );
|
|
return false;
|
|
}
|
|
|
|
// Read the loading phase
|
|
TSharedPtr<FJsonValue> LoadingPhaseValue = Object.TryGetField(TEXT("LoadingPhase"));
|
|
if(LoadingPhaseValue.IsValid() && LoadingPhaseValue->Type == EJson::String)
|
|
{
|
|
LoadingPhase = ELoadingPhase::FromString(*LoadingPhaseValue->AsString());
|
|
if(LoadingPhase == ELoadingPhase::Max)
|
|
{
|
|
OutFailReason = FText::Format( LOCTEXT( "ModuleWithInvalidLoadingPhase", "Module entry '{0}' specified an unrecognized module LoadingPhase '{1}'" ), FText::FromName(Name), FText::FromString(LoadingPhaseValue->AsString()) );
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Read the whitelisted platforms
|
|
TSharedPtr<FJsonValue> WhitelistPlatformsValue = Object.TryGetField(TEXT("WhitelistPlatforms"));
|
|
if(WhitelistPlatformsValue.IsValid() && WhitelistPlatformsValue->Type == EJson::Array)
|
|
{
|
|
const TArray< TSharedPtr< FJsonValue > >& PlatformsArray = WhitelistPlatformsValue->AsArray();
|
|
for(int Idx = 0; Idx < PlatformsArray.Num(); Idx++)
|
|
{
|
|
WhitelistPlatforms.Add(PlatformsArray[Idx]->AsString());
|
|
}
|
|
}
|
|
|
|
// Read the blacklisted platforms
|
|
TSharedPtr<FJsonValue> BlacklistPlatformsValue = Object.TryGetField(TEXT("BlacklistPlatforms"));
|
|
if(BlacklistPlatformsValue.IsValid() && BlacklistPlatformsValue->Type == EJson::Array)
|
|
{
|
|
const TArray< TSharedPtr< FJsonValue > >& PlatformsArray = BlacklistPlatformsValue->AsArray();
|
|
for(int Idx = 0; Idx < PlatformsArray.Num(); Idx++)
|
|
{
|
|
BlacklistPlatforms.Add(PlatformsArray[Idx]->AsString());
|
|
}
|
|
}
|
|
|
|
// Read the additional dependencies
|
|
TSharedPtr<FJsonValue> AdditionalDependenciesValue = Object.TryGetField(TEXT("AdditionalDependencies"));
|
|
if (AdditionalDependenciesValue.IsValid() && AdditionalDependenciesValue->Type == EJson::Array)
|
|
{
|
|
const TArray< TSharedPtr< FJsonValue > >& DepArray = AdditionalDependenciesValue->AsArray();
|
|
for (int Idx = 0; Idx < DepArray.Num(); Idx++)
|
|
{
|
|
AdditionalDependencies.Add(DepArray[Idx]->AsString());
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool FModuleDescriptor::ReadArray(const FJsonObject& Object, const TCHAR* Name, TArray<FModuleDescriptor>& OutModules, FText& OutFailReason)
|
|
{
|
|
bool bResult = true;
|
|
|
|
TSharedPtr<FJsonValue> ModulesArrayValue = Object.TryGetField(Name);
|
|
if(ModulesArrayValue.IsValid() && ModulesArrayValue->Type == EJson::Array)
|
|
{
|
|
const TArray< TSharedPtr< FJsonValue > >& ModulesArray = ModulesArrayValue->AsArray();
|
|
for(int Idx = 0; Idx < ModulesArray.Num(); Idx++)
|
|
{
|
|
const TSharedPtr<FJsonValue>& ModuleValue = ModulesArray[Idx];
|
|
if(ModuleValue.IsValid() && ModuleValue->Type == EJson::Object)
|
|
{
|
|
FModuleDescriptor Descriptor;
|
|
if(Descriptor.Read(*ModuleValue->AsObject().Get(), OutFailReason))
|
|
{
|
|
OutModules.Add(Descriptor);
|
|
}
|
|
else
|
|
{
|
|
bResult = false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
OutFailReason = LOCTEXT( "ModuleWithInvalidModulesArray", "The 'Modules' array has invalid contents and was not able to be loaded." );
|
|
bResult = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
return bResult;
|
|
}
|
|
|
|
void FModuleDescriptor::Write(TJsonWriter<>& Writer) const
|
|
{
|
|
Writer.WriteObjectStart();
|
|
Writer.WriteValue(TEXT("Name"), Name.ToString());
|
|
Writer.WriteValue(TEXT("Type"), FString(EHostType::ToString(Type)));
|
|
Writer.WriteValue(TEXT("LoadingPhase"), FString(ELoadingPhase::ToString(LoadingPhase)));
|
|
if (WhitelistPlatforms.Num() > 0)
|
|
{
|
|
Writer.WriteArrayStart(TEXT("WhitelistPlatforms"));
|
|
for(int Idx = 0; Idx < WhitelistPlatforms.Num(); Idx++)
|
|
{
|
|
Writer.WriteValue(WhitelistPlatforms[Idx]);
|
|
}
|
|
Writer.WriteArrayEnd();
|
|
}
|
|
if (BlacklistPlatforms.Num() > 0)
|
|
{
|
|
Writer.WriteArrayStart(TEXT("BlacklistPlatforms"));
|
|
for(int Idx = 0; Idx < BlacklistPlatforms.Num(); Idx++)
|
|
{
|
|
Writer.WriteValue(BlacklistPlatforms[Idx]);
|
|
}
|
|
Writer.WriteArrayEnd();
|
|
}
|
|
if (AdditionalDependencies.Num() > 0)
|
|
{
|
|
Writer.WriteArrayStart(TEXT("AdditionalDependencies"));
|
|
for (int Idx = 0; Idx < AdditionalDependencies.Num(); Idx++)
|
|
{
|
|
Writer.WriteValue(AdditionalDependencies[Idx]);
|
|
}
|
|
Writer.WriteArrayEnd();
|
|
}
|
|
Writer.WriteObjectEnd();
|
|
}
|
|
|
|
void FModuleDescriptor::WriteArray(TJsonWriter<>& Writer, const TCHAR* Name, const TArray<FModuleDescriptor>& Modules)
|
|
{
|
|
if(Modules.Num() > 0)
|
|
{
|
|
Writer.WriteArrayStart(Name);
|
|
for(int Idx = 0; Idx < Modules.Num(); Idx++)
|
|
{
|
|
Modules[Idx].Write(Writer);
|
|
}
|
|
Writer.WriteArrayEnd();
|
|
}
|
|
}
|
|
|
|
bool FModuleDescriptor::IsCompiledInCurrentConfiguration() const
|
|
{
|
|
// Cache the string for the current platform
|
|
static FString UBTPlatform(FPlatformMisc::GetUBTPlatform());
|
|
|
|
// Check the platform is whitelisted
|
|
if(WhitelistPlatforms.Num() > 0 && !WhitelistPlatforms.Contains(UBTPlatform))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// Check the platform is not blacklisted
|
|
if(BlacklistPlatforms.Num() > 0 && BlacklistPlatforms.Contains(UBTPlatform))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// Check the module is compatible with this target. This should match UEBuildTarget.ShouldIncludePluginModule in UBT
|
|
switch (Type)
|
|
{
|
|
case EHostType::Runtime:
|
|
case EHostType::RuntimeNoCommandlet:
|
|
return true;
|
|
|
|
case EHostType::Developer:
|
|
#if WITH_UNREAL_DEVELOPER_TOOLS
|
|
return true;
|
|
#endif
|
|
break;
|
|
|
|
case EHostType::Editor:
|
|
case EHostType::EditorNoCommandlet:
|
|
#if WITH_EDITOR
|
|
return true;
|
|
#endif
|
|
break;
|
|
|
|
case EHostType::Program:
|
|
#if IS_PROGRAM
|
|
return true;
|
|
#endif
|
|
break;
|
|
|
|
case EHostType::ServerOnly:
|
|
return !FPlatformProperties::IsClientOnly();
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool FModuleDescriptor::IsLoadedInCurrentConfiguration() const
|
|
{
|
|
// Check that the module is built for this configuration
|
|
if(!IsCompiledInCurrentConfiguration())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// Check that the runtime environment allows it to be loaded
|
|
switch (Type)
|
|
{
|
|
case EHostType::Runtime:
|
|
#if WITH_ENGINE || WITH_PLUGIN_SUPPORT
|
|
return true;
|
|
#endif
|
|
break;
|
|
|
|
case EHostType::RuntimeNoCommandlet:
|
|
#if WITH_ENGINE || WITH_PLUGIN_SUPPORT
|
|
if(!IsRunningCommandlet()) return true;
|
|
#endif
|
|
break;
|
|
|
|
case EHostType::Developer:
|
|
#if WITH_UNREAL_DEVELOPER_TOOLS
|
|
return true;
|
|
#endif
|
|
break;
|
|
|
|
case EHostType::Editor:
|
|
#if WITH_EDITOR
|
|
if(GIsEditor) return true;
|
|
#endif
|
|
break;
|
|
|
|
case EHostType::EditorNoCommandlet:
|
|
#if WITH_EDITOR
|
|
if(GIsEditor && !IsRunningCommandlet()) return true;
|
|
#endif
|
|
break;
|
|
|
|
case EHostType::Program:
|
|
#if WITH_PLUGIN_SUPPORT && IS_PROGRAM
|
|
return true;
|
|
#endif
|
|
break;
|
|
|
|
case EHostType::ServerOnly:
|
|
return !FPlatformProperties::IsClientOnly();
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void FModuleDescriptor::LoadModulesForPhase(ELoadingPhase::Type LoadingPhase, const TArray<FModuleDescriptor>& Modules, TMap<FName, EModuleLoadResult>& ModuleLoadErrors)
|
|
{
|
|
FScopedSlowTask SlowTask(Modules.Num());
|
|
for(int Idx = 0; Idx < Modules.Num(); Idx++)
|
|
{
|
|
SlowTask.EnterProgressFrame(1);
|
|
const FModuleDescriptor& Descriptor = Modules[Idx];
|
|
|
|
// Don't need to do anything if this module is already loaded
|
|
if( !FModuleManager::Get().IsModuleLoaded( Descriptor.Name ) )
|
|
{
|
|
if( LoadingPhase == Descriptor.LoadingPhase && Descriptor.IsLoadedInCurrentConfiguration() )
|
|
{
|
|
// @todo plugin: DLL search problems. Plugins that statically depend on other modules within this plugin may not be found? Need to test this.
|
|
|
|
// NOTE: Loading this module may cause other modules to become loaded, both in the engine or game, or other modules
|
|
// that are part of this project or plugin. That's totally fine.
|
|
EModuleLoadResult FailureReason;
|
|
const TSharedPtr<IModuleInterface>& ModuleInterface = FModuleManager::Get().LoadModuleWithFailureReason( Descriptor.Name, FailureReason );
|
|
if( ModuleInterface.IsValid() )
|
|
{
|
|
// Module loaded OK (or was already loaded.)
|
|
}
|
|
else
|
|
{
|
|
// The module failed to load. Note this in the ModuleLoadErrors list.
|
|
ModuleLoadErrors.Add(Descriptor.Name, FailureReason);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
bool FModuleDescriptor::CheckModuleCompatibility(const TArray<FModuleDescriptor>& Modules, bool bGameModules, TArray<FString>& OutIncompatibleFiles)
|
|
{
|
|
bool bResult = true;
|
|
for(int Idx = 0; Idx < Modules.Num(); Idx++)
|
|
{
|
|
const FModuleDescriptor &Module = Modules[Idx];
|
|
if (Module.IsCompiledInCurrentConfiguration() && !FModuleManager::Get().IsModuleUpToDate(Module.Name))
|
|
{
|
|
OutIncompatibleFiles.Add(FModuleManager::GetCleanModuleFilename(Module.Name, bGameModules));
|
|
bResult = false;
|
|
}
|
|
}
|
|
return bResult;
|
|
}
|
|
|
|
#undef LOCTEXT_NAMESPACE
|
|
|