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 3209340 on 2016/11/23 by Ben.Marsh Convert UE4 codebase to an "include what you use" model - where every header just includes the dependencies it needs, rather than every source file including large monolithic headers like Engine.h and UnrealEd.h. Measured full rebuild times around 2x faster using XGE on Windows, and improvements of 25% or more for incremental builds and full rebuilds on most other platforms. * Every header now includes everything it needs to compile. * There's a CoreMinimal.h header that gets you a set of ubiquitous types from Core (eg. FString, FName, TArray, FVector, etc...). Most headers now include this first. * There's a CoreTypes.h header that sets up primitive UE4 types and build macros (int32, PLATFORM_WIN64, etc...). All headers in Core include this first, as does CoreMinimal.h. * Every .cpp file includes its matching .h file first. * This helps validate that each header is including everything it needs to compile. * No engine code includes a monolithic header such as Engine.h or UnrealEd.h any more. * You will get a warning if you try to include one of these from the engine. They still exist for compatibility with game projects and do not produce warnings when included there. * There have only been minor changes to our internal games down to accommodate these changes. The intent is for this to be as seamless as possible. * No engine code explicitly includes a precompiled header any more. * We still use PCHs, but they're force-included on the compiler command line by UnrealBuildTool instead. This lets us tune what they contain without breaking any existing include dependencies. * PCHs are generated by a tool to get a statistical amount of coverage for the source files using it, and I've seeded the new shared PCHs to contain any header included by > 15% of source files. Tool used to generate this transform is at Engine\Source\Programs\IncludeTool. [CL 3209342 by Ben Marsh in Main branch]
444 lines
12 KiB
C++
444 lines
12 KiB
C++
// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "ModuleDescriptor.h"
|
|
#include "Misc/ScopedSlowTask.h"
|
|
#include "Dom/JsonObject.h"
|
|
#include "Modules/ModuleManager.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" );
|
|
|
|
case None:
|
|
return TEXT( "None" );
|
|
|
|
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 RuntimeAndProgram:
|
|
return TEXT("RuntimeAndProgram");
|
|
|
|
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");
|
|
|
|
case ClientOnly:
|
|
return TEXT("ClientOnly");
|
|
|
|
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:
|
|
#if IS_PROGRAM
|
|
return false;
|
|
#else
|
|
return true;
|
|
#endif
|
|
|
|
case EHostType::RuntimeAndProgram:
|
|
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();
|
|
|
|
case EHostType::ClientOnly:
|
|
return !FPlatformProperties::IsServerOnly();
|
|
|
|
}
|
|
|
|
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::RuntimeAndProgram:
|
|
#if (WITH_ENGINE || WITH_PLUGIN_SUPPORT)
|
|
return true;
|
|
#endif
|
|
break;
|
|
|
|
case EHostType::Runtime:
|
|
#if (WITH_ENGINE || WITH_PLUGIN_SUPPORT) && !IS_PROGRAM
|
|
return true;
|
|
#endif
|
|
break;
|
|
|
|
case EHostType::RuntimeNoCommandlet:
|
|
#if (WITH_ENGINE || WITH_PLUGIN_SUPPORT) && !IS_PROGRAM
|
|
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();
|
|
|
|
case EHostType::ClientOnly:
|
|
return !IsRunningDedicatedServer();
|
|
|
|
}
|
|
|
|
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
|
|
|