Files
UnrealEngineUWP/Engine/Source/Developer/TargetPlatform/Private/TargetPlatformManagerModule.cpp
Thomas Sarkanen 59267dc158 Copying //UE4/Dev-AnimPhys to //UE4/Dev-Main (Source: //UE4/Dev-AnimPhys @ 3683440)
#lockdown Nick.Penwarden
#rb none

============================
  MAJOR FEATURES & CHANGES
============================

Change 3624599 by Thomas.Sarkanen

	Added the ability to rename shapes in the Physics Asset Editor

	Added "CanRenameItem" to skeleton tree item API so we are not limited to hard-coded bones/sockets
	Tweaked physics shape item widget to use editable text in the same vein as virtual bones etc.

	#jira UEAP-341 - Ability to name collision shapes

Change 3624765 by Benn.Gallagher

	Fixed bad blend profile references

	#jira UE-46227

Change 3624773 by Danny.Bouimad

	Content fix for #Jira UE-49191

Change 3625007 by Thomas.Sarkanen

	Fixed monolithinc game builds

	Moved new Name member to WITH_EDITORONLY_DATA, as the generated code still picks it up using WITH_EDITOR

Change 3625659 by Ori.Cohen

	Make sure that components being unwelded are always unwelded even if they are about to be deleted. This is needed for fixing dangling pointers.

Change 3625850 by Thomas.Sarkanen

	Fix for crash in physics asset editor after garbage collection

	Move bone proxies from rooting to FGCObject

Change 3625966 by Lina.Halper

	Instead of PinShownByDefault, changed to PinHiddenByDefault

	https://github.com/EpicGames/UnrealEngine/pull/3964

	#3964

	#jira: UE-49168

Change 3626020 by Martin.Wilson

	Protect against checkSlow when using post process instance without a main instance

	#jira UE-49275

Change 3627178 by Aaron.McLeran

	#jira UE-49322 Fixing background muting and preview sound

Change 3627179 by Aaron.McLeran

	Optimizing active sound by not processing active sounds if they are out of range.

	Allowing virtualized sounds to be exempt.

	Licensee says they saw a 6x improvement on active sound calculations in audio thread with this change.

Change 3627187 by Aaron.McLeran

	Allowing overriding the sample rate of synth components in C++.

	Useful for cases where synth component is being used to output media auido or VOIP.

Change 3627563 by Thomas.Sarkanen

	Tweaked tooltip so it isnt the same as other menus

	#jira UE-47817 - Two Viewport tooltips are the same in Physics Asset Editor

Change 3627580 by James.Golding

	PR #3974: UE-49200: Fixed typo in Physics Handle (Contributed by carloshellin)

	#jira UE-49264

Change 3627581 by James.Golding

	Reduce output verbosity during cooking

	#jira UE-47126

Change 3627584 by James.Golding

	PR #3954: Upgrade to V-HACD version 2.3 (Contributed by jratcliff63367)
	Auto-convex generation now exposes more useful 'max hulls' instead of 'accuracy'
	Auto-generation of convex collision is now done async in StaticMesh Editor

	#jira UE-49027

Change 3627599 by Martin.Wilson

	Make sure raw data debug bone rendering in the animation editors actually shows raw data in the case of additive track layers (used to show source instead)

Change 3627605 by James.Golding

	Forgot to remove Box2D from TargetRules.cs (see CL 3555437)

Change 3627627 by Martin.Wilson

	Change raw data evaluation so that virtual bone positions are built before interpolation is carried out

	#jira UE-42659

Change 3627663 by Martin.Wilson

	Fix typo

Change 3627730 by Martin.Wilson

	Allow notifies to be trigger on follower animations in a sync group

	#jira UE-46770

Change 3627852 by Thomas.Sarkanen

	Add warning to "Use Async Scene" property when shown in the physics asset editor, if the project doesn't currently use an async scene.

	#jira UE-47964 User is not told to Enable Async Scene in Project Settings when enabling it on a physics asset

Change 3627864 by Lina.Halper

	Fix issue where "reset to default" on search box for bone doesn't work

	#jira: UE-48874

Change 3627946 by Thomas.Sarkanen

	Prevent undo/redo breaking when moving both a constraint and a body at the same time

	#jira UE-49344 - Physics Asset Editor: Moving both a body and a constraint causes undo.redo to break for the whole editor

Change 3628091 by Thomas.Sarkanen

	Fix dangling lines, poor search focus and graph not refreshing when making new constraints

	Found by Nick D in Main.

	#jira UE-47812 - Physics Asset Graph wires sometimes get stuck to the window not attached to a node

Change 3628107 by Lina.Halper

	Fixed issue where Blendspace 1D can't scale due to the property not exposed
	https://udn.unrealengine.com/questions/389958/input-interpolationaxis-to-scale-in-1d-blendspace.html

Change 3628108 by Arciel.Rekman

	Update Linux VHACD.

	- Also removed arm 32-bit version (the library is editor-only).

Change 3628437 by Michael.Trepka

	Updated Mac VHACD libraries and Xcode project

Change 3628667 by Lina.Halper

	- Fixed issue of showing combo box multiple times
	- Fixed issue of inconsistent combo box width
	- Fixed text of pick bone to "select" for more general instruction
	- Fixed issue with struct displaying children when pin is enabled

	#jira: UE-49295, UE-46496, UE-47427

Change 3629744 by Aaron.McLeran

	#jira UE-49383 Fix for source bus loading in sound waves and playing without audio mixer

Change 3629846 by Aaron.McLeran

	#jira UE-49390 Required API change to spatialization interface for google

Change 3630322 by Thomas.Sarkanen

	Fix right-click not displaying context menu for constraints correctly

	Selection logic was lightly broken

	#jira UE-49399 - Physics Asset Editor: Right-clicking constraints in the viewport does not bring up the context menu

Change 3630463 by Martin.Wilson

	Remove accidently submitted debug code

Change 3630523 by Jurre.deBaare

	Paint threshold and fill value and can be set to negative numbers
	#fix Added metadata and default values for cloth fill tool
	#jira UE-48352

Change 3632009 by Aaron.McLeran

	#jira UE-49470 Fix for iOS master volume not getting set

	Recent changes to master volume resulted in platforms which don't have a headroom value defined will not get their master volume updated. IOS doesn't have a headroom value set so the master volume is never set and the fade in is never triggered.

Change 3632699 by Thomas.Sarkanen

	Fix crash undo-ing primitive regeneration while simullation is in progress & stopping simulation

	#jira UE-49283 - Editor crashes if you regenerate and manipulate a phys body, simulate, undo and then exit simulation

Change 3633336 by James.Golding

	PR #3978: effect is the noun. affect is the verb (Contributed by cdietschrun)
	#jira UE-49324

Change 3634665 by Aaron.McLeran

	#jira UE-49538 Fixing param interpolation

Change 3634922 by James.Golding

	Static analysis fix (PhysXCookHelper.cpp)

Change 3634926 by James.Golding

	Fix HTML5 build (which builds with PhysX, but without APEX)

Change 3636005 by Thomas.Sarkanen

	Constraint setup shortcuts are now undo-able

	Also fixed body-body collision as you couldnt undo this either.
	Added transaction and calls to Modify().

	#jira UE-49484 - Shortcut for Swing1Motion (2, and 3) do not change physics asset state dirty.

Change 3636018 by Thomas.Sarkanen

	Added back constraint shortcut to PhAT toolbar

	#jira UE-48859 - Constraint quick set buttons are missing in the new Physics Asset tool

Change 3636086 by Martin.Wilson

	Fix for enabling Live Link plugin in Orion

Change 3638367 by Thomas.Sarkanen

	Connection reporting is now more user-freindly in the physics asset editor graph view

	Expanded UEdGraphSchema API to allow for more specific feedback when dragging over a graph.
	Implemented node & pin feedback for physics asset graphs.
	Also fixed alignment of icon for drag feedback as it stretches with multi-line text.

	#jira UE-47984 - No node created when dragging off of Constraint node in Physics Asset Graph

Change 3640144 by Aaron.McLeran

	#jira UE-49409 Attenuation focus audio tests on TM-AnimPhys on Cooked mac doesn't play any audio

	Fixing the recent optimization to not play active sounds in range. Code attempts to check if there's any possibility for a sound to have it's distance affected before trying to prune by max distance.

Change 3640276 by Aaron.McLeran

	#jira UE-49606 Project does not cook with actors containing ModularSynth component

Change 3640313 by Aaron.McLeran

	#jira UE-49675 Fixing shutdown of audio mixer

	- Final queued commands aren't getting pumped during audio mixer shutdown, added a new interface to get a final shutdown callback back to audio mixer device. We can do any cleanup or final shutdown tasks in this callback. Added a call to pump the source manager one last time. For cases of audio mixer running without audio plugins, this won't have much of an effect, but is a good thing to do anyway. For the case of audio plugins, who are depending on paired init and release calls, this is valueable to avoid memory leaks between subsequent PIE sessions.

Change 3640941 by Martin.Wilson

	Add editor only animation loading debug data in the hope of diagnosing rare loading crash

	#jira UE-49335

Change 3641976 by Ethan.Geller

	#jira UE-49675 ensure that we pump both command queues

Change 3642613 by James.Golding

	Add NoPhysX sample, for CIS testing compilation without PhysX

Change 3644001 by Aaron.McLeran

	#jira UE-49805 looping sounds are, in rare cases, extremely loud

Change 3644124 by Aaron.McLeran

	#jira UE-49787 [CrashReport] Mac crash - UE4Editor-AudioEditor.dylib!FSoundCueEditor::DeleteInput()

	Adding ensure on returned ptr to avoid crash but keep getting some logging.

Change 3644157 by Aaron.McLeran

	Fixing build error

Change 3644163 by Aaron.McLeran

	Fixing build error (for real)

Change 3650331 by Aaron.McLeran

	#jira UE-49994 SoundMix Fade Time not fading audio properly

	Making sure we properly set passive mix modifier states.

Change 3652648 by Aaron.McLeran

	#jira UE-49994 SoundMix Fade Time not fading audio properly

Change 3652995 by Aaron.McLeran

	#jira UE-50053 Reduce log level of audio mixer debug category

	Turning down the log spam level of the underrun category by switching to debug category and reducing level of the debug category.

Change 3653461 by James.Golding

	V-HACD updates from JohnR @ NVIDIA (adding new functions for future use)

Change 3654056 by Aaron.McLeran

	Fixing an issue with caching node states for editor builds and adding optimization to cache if we should apply interior volumes.

Change 3654579 by Aaron.McLeran

	Allow sound submixes and sound classes to be a blueprint type

	Made all properties of sound classes BlueprintReadOnly.

Change 3662519 by James.Golding

	Merge CL 3575543 from //Fortnite/Main to Dev-AnimPhys
	Don't call into UpdateKinematicBones if there are no physx bodies

Change 3664976 by Aaron.McLeran

	#jira UE-50175 New Tap Delay Submix Pan parameter does not work in Surround Sound

Change 3665751 by Aaron.McLeran

	Adding a simple panner effect

Change 3665851 by Aaron.McLeran

	Fixing naming convention for new panner source effect

Change 3666894 by Thomas.Sarkanen

	Bone modifications via transform type-in can now be undone

	Added RF_Transactional & called Modify()

	#jira UE-47862 - Undoing Bone transformations in Physics Asset Editor does not work

Change 3666919 by Lina.Halper

	Fixed equal operator for bonereference to work when not initialized

Change 3668850 by Thomas.Sarkanen

	Skeleton tree now no longer allows selection of filtered items

	This fixes an issue where filtered-out constraints were being deselected after a select all operation because the tree thought it had no selection (all constraints were filtered).

	#jira UE-50200 - Constraint Details do not populate in the Details Panel if the Skeleton tree does not include Constraints

Change 3669028 by James.Golding

	Fix CIS error after merge-down

Change 3669053 by James.Golding

	Fix bad merge in SynthComponent.cpp

Change 3669273 by Lina.Halper

	- delete all tracks option
	- allow to opt out on bone track importing
	- fixed pose preview for fullbody to select weights that has pose from asset.

Change 3671396 by James.Golding

	Fix FSkelMeshComponentLODInfo cleaning up all override resources when it should only have been cleaning up one of them

Change 3671701 by Martin.Wilson

	Maya Live Link plugin
	- Added UI to Maya
	    - Display currently streamed subjects
	    - Allow add and removal of streamed subjects
	    - Display connection status to editor
	- Stream active camera as EditorActiveCamera
	- Refactored entire plugin so that streaming has a manager and streaming objects / interfaces
	- Reworked editor update hook so that streaming is more robust and facial rigs / leaf bones now correctly update.

Change 3672170 by Lina.Halper

	Remove track support for Animation Blueprint Library

Change 3675921 by Ethan.Geller

	Rollback invalidated check from copy down

Change 3677606 by Martin.Wilson

	Add live link driven component - allows an actor to take its rotation and translation from a live link subject

Change 3678594 by Lina.Halper

	Changed API name for clarification

Change 3680913 by Ethan.Geller

	#jira UE-50750 fix stuttering on AudioMixer on MacOS

Change 3681127 by Ethan.Geller

	#jira UE-50720 Fix invalidated audio clock time when audio device is unplugged on legacy audio engine

Change 3682729 by Ethan.Geller

	#jira UE-50832 Fix for null concurrency settings when removing active sounds from a concurrency group. [Dev-AnimPhys]

Change 3633185 by James.Golding

	Fix engine not compiling when WITH_PHYSX == 0
	PR #3691: 4.16_WITH_PHYSX_optional (Contributed by JacobNelsonGames)
	PR #3695: 4.16_PhysXVehicles_WITH_PHYSX_optional (Contributed by JacobNelsonGames)

Change 3637031 by Ethan.Geller

	#jira UE-49605 Platform Headroom fix for non-float devices.

Change 3642598 by James.Golding

	Change bCompileNvCloth to use same pattern as bCompileAPEX (on by default, disabled on some platforms). This allows game projects to disable it.

Change 3645224 by Martin.Wilson

	Fix for rare notify crash.

	For speed purposes Notify Queue caches a pointer to the notify, this is memory that is owned by the animation and if it gets garbage collected we have a pointer to invalid memory.
	This change caches a pointer to the owner of the notify memory to so we can track its validity.

	#jira UE-44869

Change 3668926 by James.Golding

	Merging //UE4/Dev-Main to Dev-AnimPhys (//UE4/Dev-AnimPhys) @ 3668712

Change 3674824 by James.Golding

	Merging //UE4/Dev-Main to Dev-AnimPhys (//UE4/Dev-AnimPhys) @ 3674368

[CL 3683447 by Thomas Sarkanen in Main branch]
2017-10-06 04:43:18 -04:00

1043 lines
30 KiB
C++

// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved.
#include "CoreMinimal.h"
#include "HAL/FileManager.h"
#include "Misc/CommandLine.h"
#include "Misc/Paths.h"
#include "Misc/OutputDeviceRedirector.h"
#include "Templates/ScopedPointer.h"
#include "Stats/Stats.h"
#include "Misc/ScopedSlowTask.h"
#include "Misc/MonitoredProcess.h"
#include "Modules/ModuleManager.h"
#include "Interfaces/ITargetPlatform.h"
#include "Interfaces/ITargetPlatformModule.h"
#include "Interfaces/ITargetPlatformManagerModule.h"
#include "Interfaces/IAudioFormat.h"
#include "Interfaces/IAudioFormatModule.h"
#include "Interfaces/IShaderFormat.h"
#include "Interfaces/IShaderFormatModule.h"
#include "Interfaces/ITextureFormat.h"
#include "Interfaces/ITextureFormatModule.h"
#include "PlatformInfo.h"
#include "DesktopPlatformModule.h"
#if WITH_PHYSX
#include "IPhysXCooking.h"
#include "IPhysXCookingModule.h"
#endif // WITH_PHYSX
DEFINE_LOG_CATEGORY_STATIC(LogTargetPlatformManager, Log, All);
// autosdks only function properly on windows right now.
#if !IS_MONOLITHIC && (PLATFORM_WINDOWS)
#define AUTOSDKS_ENABLED 1
#else
#define AUTOSDKS_ENABLED 0
#endif
/**
* Module for the target platform manager
*/
class FTargetPlatformManagerModule
: public ITargetPlatformManagerModule
{
public:
/** Default constructor. */
FTargetPlatformManagerModule()
: bRestrictFormatsToRuntimeOnly(false)
, bForceCacheUpdate(true)
, bIgnoreFirstDelegateCall(true)
{
#if AUTOSDKS_ENABLED
// AutoSDKs only enabled if UE_SDKS_ROOT is set.
if (IsAutoSDKsEnabled())
{
DECLARE_SCOPE_CYCLE_COUNTER( TEXT( "FTargetPlatformManagerModule.StartAutoSDK" ), STAT_FTargetPlatformManagerModule_StartAutoSDK, STATGROUP_TargetPlatform );
// amortize UBT cost by calling it once for all platforms, rather than once per platform.
if (FParse::Param(FCommandLine::Get(), TEXT("Multiprocess"))==false)
{
FString UBTParams(TEXT("-autosdkonly"));
int32 UBTReturnCode = -1;
FString UBTOutput;
if (!FDesktopPlatformModule::Get()->InvokeUnrealBuildToolSync(UBTParams, *GLog, true, UBTReturnCode, UBTOutput))
{
UE_LOG(LogTargetPlatformManager, Fatal, TEXT("Failed to run UBT to check SDK status!"));
}
}
// we have to setup our local environment according to AutoSDKs or the ITargetPlatform's IsSDkInstalled calls may fail
// before we get a change to setup for a given platform. Use the platforminfo list to avoid any kind of interdependency.
int32 NumPlatforms;
const PlatformInfo::FPlatformInfo* PlatformInfoArray = PlatformInfo::GetPlatformInfoArray(NumPlatforms);
for (int32 i = 0; i < NumPlatforms; ++i)
{
const PlatformInfo::FPlatformInfo& PlatformInfo = PlatformInfoArray[i];
if (PlatformInfo.AutoSDKPath.Len() > 0)
{
SetupAndValidateAutoSDK(PlatformInfo.AutoSDKPath);
}
}
}
#endif
SetupSDKStatus();
//GetTargetPlatforms(); redudant with next call
GetActiveTargetPlatforms();
GetAudioFormats();
GetTextureFormats();
GetShaderFormats();
bForceCacheUpdate = false;
FModuleManager::Get().OnModulesChanged().AddRaw(this, &FTargetPlatformManagerModule::ModulesChangesCallback);
}
/** Destructor. */
virtual ~FTargetPlatformManagerModule()
{
FModuleManager::Get().OnModulesChanged().RemoveAll(this);
}
public:
// ITargetPlatformManagerModule interface
virtual void Invalidate() override
{
bForceCacheUpdate = true;
SetupSDKStatus();
//GetTargetPlatforms(); redudant with next call
GetActiveTargetPlatforms();
GetAudioFormats();
GetTextureFormats();
GetShaderFormats();
bForceCacheUpdate = false;
}
virtual const TArray<ITargetPlatform*>& GetTargetPlatforms() override
{
if (Platforms.Num() == 0 || bForceCacheUpdate)
{
DiscoverAvailablePlatforms();
}
return Platforms;
}
virtual ITargetDevicePtr FindTargetDevice(const FTargetDeviceId& DeviceId) override
{
ITargetPlatform* Platform = FindTargetPlatform(DeviceId.GetPlatformName());
if (Platform != nullptr)
{
return Platform->GetDevice(DeviceId);
}
return nullptr;
}
virtual ITargetPlatform* FindTargetPlatform(FString Name) override
{
const TArray<ITargetPlatform*>& TargetPlatforms = GetTargetPlatforms();
for (int32 Index = 0; Index < TargetPlatforms.Num(); Index++)
{
if (TargetPlatforms[Index]->PlatformName() == Name)
{
return TargetPlatforms[Index];
}
}
return nullptr;
}
virtual const TArray<ITargetPlatform*>& GetCookingTargetPlatforms() override
{
static bool bInitialized = false;
static TArray<ITargetPlatform*> Results;
if ( !bInitialized || bForceCacheUpdate )
{
Results = GetActiveTargetPlatforms();
FString PlatformStr;
if (FParse::Value(FCommandLine::Get(), TEXT("TARGETPLATFORM="), PlatformStr))
{
if (PlatformStr == TEXT("None"))
{
Results = Platforms;
}
}
else
{
Results = Platforms;
}
}
return Results;
}
virtual const TArray<ITargetPlatform*>& GetActiveTargetPlatforms() override
{
static bool bInitialized = false;
static TArray<ITargetPlatform*> Results;
if (!bInitialized || bForceCacheUpdate)
{
bInitialized = true;
Results.Empty(Results.Num());
const TArray<ITargetPlatform*>& TargetPlatforms = GetTargetPlatforms();
FString PlatformStr;
if (FParse::Value(FCommandLine::Get(), TEXT("TARGETPLATFORM="), PlatformStr))
{
if (PlatformStr == TEXT("None"))
{
}
else if (PlatformStr == TEXT("All"))
{
Results = TargetPlatforms;
}
else
{
TArray<FString> PlatformNames;
PlatformStr.ParseIntoArray(PlatformNames, TEXT("+"), true);
// for nicer user response
FString AvailablePlatforms;
for (int32 Index = 0; Index < TargetPlatforms.Num(); Index++)
{
if (PlatformNames.Contains(TargetPlatforms[Index]->PlatformName()))
{
Results.Add(TargetPlatforms[Index]);
}
if(!AvailablePlatforms.IsEmpty())
{
AvailablePlatforms += TEXT(", ");
}
AvailablePlatforms += TargetPlatforms[Index]->PlatformName();
}
if (Results.Num() == 0)
{
// An invalid platform was specified...
// Inform the user and exit.
UE_LOG(LogTargetPlatformManager, Error, TEXT("Invalid target platform specified (%s). Available = { %s } "), *PlatformStr, *AvailablePlatforms);
UE_LOG(LogTargetPlatformManager, Fatal, TEXT("Invalid target platform specified (%s). Available = { %s } "), *PlatformStr, *AvailablePlatforms);
}
}
}
else
{
// if there is no argument, use the current platform and only build formats that are actually needed to run.
bRestrictFormatsToRuntimeOnly = true;
for (int32 Index = 0; Index < TargetPlatforms.Num(); Index++)
{
if (TargetPlatforms[Index]->IsRunningPlatform())
{
Results.Add(TargetPlatforms[Index]);
}
}
}
if (!Results.Num())
{
UE_LOG(LogTargetPlatformManager, Display, TEXT("Not building assets for any platform."));
}
else
{
for (int32 Index = 0; Index < Results.Num(); Index++)
{
UE_LOG(LogTargetPlatformManager, Display, TEXT("Building Assets For %s"), *Results[Index]->PlatformName());
}
}
}
return Results;
}
virtual bool RestrictFormatsToRuntimeOnly() override
{
GetActiveTargetPlatforms(); // make sure this is initialized
return bRestrictFormatsToRuntimeOnly;
}
virtual ITargetPlatform* GetRunningTargetPlatform() override
{
static bool bInitialized = false;
static ITargetPlatform* Result = nullptr;
if (!bInitialized || bForceCacheUpdate)
{
bInitialized = true;
Result = nullptr;
const TArray<ITargetPlatform*>& TargetPlatforms = GetTargetPlatforms();
for (int32 Index = 0; Index < TargetPlatforms.Num(); Index++)
{
if (TargetPlatforms[Index]->IsRunningPlatform())
{
// we should not have two running platforms
checkf((Result == nullptr),
TEXT("Found multiple running platforms.\n\t%s\nand\n\t%s"),
*Result->PlatformName(),
*TargetPlatforms[Index]->PlatformName()
);
Result = TargetPlatforms[Index];
}
}
}
return Result;
}
virtual const TArray<const IAudioFormat*>& GetAudioFormats() override
{
static bool bInitialized = false;
static TArray<const IAudioFormat*> Results;
if (!bInitialized || bForceCacheUpdate)
{
bInitialized = true;
Results.Empty(Results.Num());
TArray<FName> Modules;
FModuleManager::Get().FindModules(TEXT("*AudioFormat*"), Modules);
if (!Modules.Num())
{
UE_LOG(LogTargetPlatformManager, Error, TEXT("No target audio formats found!"));
}
for (int32 Index = 0; Index < Modules.Num(); Index++)
{
IAudioFormatModule* Module = FModuleManager::LoadModulePtr<IAudioFormatModule>(Modules[Index]);
if (Module)
{
IAudioFormat* Format = Module->GetAudioFormat();
if (Format != nullptr)
{
Results.Add(Format);
}
}
}
}
return Results;
}
virtual const IAudioFormat* FindAudioFormat(FName Name) override
{
const TArray<const IAudioFormat*>& AudioFormats = GetAudioFormats();
for (int32 Index = 0; Index < AudioFormats.Num(); Index++)
{
TArray<FName> Formats;
AudioFormats[Index]->GetSupportedFormats(Formats);
for (int32 FormatIndex = 0; FormatIndex < Formats.Num(); FormatIndex++)
{
if (Formats[FormatIndex] == Name)
{
return AudioFormats[Index];
}
}
}
return nullptr;
}
virtual const TArray<const ITextureFormat*>& GetTextureFormats() override
{
static bool bInitialized = false;
static TArray<const ITextureFormat*> Results;
if (!bInitialized || bForceCacheUpdate)
{
bInitialized = true;
Results.Empty(Results.Num());
TArray<FName> Modules;
FModuleManager::Get().FindModules(TEXT("*TextureFormat*"), Modules);
if (!Modules.Num())
{
UE_LOG(LogTargetPlatformManager, Error, TEXT("No target texture formats found!"));
}
for (int32 Index = 0; Index < Modules.Num(); Index++)
{
ITextureFormatModule* Module = FModuleManager::LoadModulePtr<ITextureFormatModule>(Modules[Index]);
if (Module)
{
ITextureFormat* Format = Module->GetTextureFormat();
if (Format != nullptr)
{
Results.Add(Format);
}
}
}
}
return Results;
}
virtual const ITextureFormat* FindTextureFormat(FName Name) override
{
const TArray<const ITextureFormat*>& TextureFormats = GetTextureFormats();
for (int32 Index = 0; Index < TextureFormats.Num(); Index++)
{
TArray<FName> Formats;
TextureFormats[Index]->GetSupportedFormats(Formats);
for (int32 FormatIndex = 0; FormatIndex < Formats.Num(); FormatIndex++)
{
if (Formats[FormatIndex] == Name)
{
return TextureFormats[Index];
}
}
}
return nullptr;
}
virtual const TArray<const IShaderFormat*>& GetShaderFormats() override
{
static bool bInitialized = false;
static TArray<const IShaderFormat*> Results;
if (!bInitialized || bForceCacheUpdate)
{
bInitialized = true;
Results.Empty(Results.Num());
TArray<FName> Modules;
FModuleManager::Get().FindModules(SHADERFORMAT_MODULE_WILDCARD, Modules);
if (!Modules.Num())
{
UE_LOG(LogTargetPlatformManager, Error, TEXT("No target shader formats found!"));
}
for (int32 Index = 0; Index < Modules.Num(); Index++)
{
IShaderFormatModule* Module = FModuleManager::LoadModulePtr<IShaderFormatModule>(Modules[Index]);
if (Module)
{
IShaderFormat* Format = Module->GetShaderFormat();
if (Format != nullptr)
{
Results.Add(Format);
}
}
}
}
return Results;
}
virtual const IShaderFormat* FindShaderFormat(FName Name) override
{
const TArray<const IShaderFormat*>& ShaderFormats = GetShaderFormats();
for (int32 Index = 0; Index < ShaderFormats.Num(); Index++)
{
TArray<FName> Formats;
ShaderFormats[Index]->GetSupportedFormats(Formats);
for (int32 FormatIndex = 0; FormatIndex < Formats.Num(); FormatIndex++)
{
if (Formats[FormatIndex] == Name)
{
return ShaderFormats[Index];
}
}
}
return nullptr;
}
virtual uint32 ShaderFormatVersion(FName Name) override
{
static TMap<FName, uint32> AlreadyFound;
uint32* Result = AlreadyFound.Find(Name);
if (!Result)
{
const IShaderFormat* SF = FindShaderFormat(Name);
if (SF)
{
Result = &AlreadyFound.Add(Name, SF->GetVersion(Name));
}
}
check(Result);
return *Result;
}
virtual const TArray<const IPhysXCooking*>& GetPhysXCooking() override
{
static bool bInitialized = false;
static TArray<const IPhysXCooking*> Results;
#if WITH_PHYSX
if (!bInitialized || bForceCacheUpdate)
{
bInitialized = true;
Results.Empty(Results.Num());
TArray<FName> Modules;
FModuleManager::Get().FindModules(TEXT("PhysXCooking*"), Modules);
if (!Modules.Num())
{
UE_LOG(LogTargetPlatformManager, Error, TEXT("No target PhysX formats found!"));
}
for (int32 Index = 0; Index < Modules.Num(); Index++)
{
IPhysXCookingModule* Module = FModuleManager::LoadModulePtr<IPhysXCookingModule>(Modules[Index]);
if (Module)
{
IPhysXCooking* Format = Module->GetPhysXCooking();
if (Format != nullptr)
{
Results.Add(Format);
}
}
}
}
#endif // WITH_PHYSX
return Results;
}
virtual const IPhysXCooking* FindPhysXCooking(FName Name) override
{
#if WITH_PHYSX
const TArray<const IPhysXCooking*>& PhysXCooking = GetPhysXCooking();
for (int32 Index = 0; Index < PhysXCooking.Num(); Index++)
{
TArray<FName> Formats;
PhysXCooking[Index]->GetSupportedFormats(Formats);
for (int32 FormatIndex = 0; FormatIndex < Formats.Num(); FormatIndex++)
{
if (Formats[FormatIndex] == Name)
{
return PhysXCooking[Index];
}
}
}
#endif // WITH_PHYSX
return nullptr;
}
protected:
/**
* Checks whether the AutoDesk software development kit (SDK) is enabled.
*
* @return true if the SDK is enabled, false otherwise.
*/
bool IsAutoSDKsEnabled()
{
static const FString SDKRootEnvFar(TEXT("UE_SDKS_ROOT"));
const int32 MaxPathSize = 16384;
TCHAR SDKPath[MaxPathSize] = { 0 };
FPlatformMisc::GetEnvironmentVariable(*SDKRootEnvFar, SDKPath, MaxPathSize);
// AutoSDKs only enabled if UE_SDKS_ROOT is set.
if (SDKPath[0] != 0)
{
return true;
}
return false;
}
/** Discovers the available target platforms. */
void DiscoverAvailablePlatforms()
{
DECLARE_SCOPE_CYCLE_COUNTER( TEXT( "FTargetPlatformManagerModule::DiscoverAvailablePlatforms" ), STAT_FTargetPlatformManagerModule_DiscoverAvailablePlatforms, STATGROUP_TargetPlatform );
Platforms.Empty(Platforms.Num());
TArray<FName> Modules;
FString ModuleWildCard = TEXT("*TargetPlatform");
#if WITH_EDITOR
// if we have the editor and we are using -game
// only need to instantiate the current platform
#if PLATFORM_WINDOWS
if (IsRunningGame())
{
ModuleWildCard = TEXT("Windows*TargetPlatform");
}
#endif
#endif
FModuleManager::Get().FindModules(*ModuleWildCard, Modules);
// remove this module from the list
Modules.Remove(FName(TEXT("TargetPlatform")));
if (!Modules.Num())
{
UE_LOG(LogTargetPlatformManager, Error, TEXT("No target platforms found!"));
}
FScopedSlowTask SlowTask(Modules.Num());
for (int32 Index = 0; Index < Modules.Num(); Index++)
{
SlowTask.EnterProgressFrame(1);
ITargetPlatformModule* Module = FModuleManager::LoadModulePtr<ITargetPlatformModule>(Modules[Index]);
if (Module)
{
ITargetPlatform* Platform = Module->GetTargetPlatform();
if (Platform != nullptr)
{
// would like to move this check to GetActiveTargetPlatforms, but too many things cache this result
// this setup will become faster after TTP 341897 is complete.
RETRY_SETUPANDVALIDATE:
if (SetupAndValidateAutoSDK(Platform->GetPlatformInfo().AutoSDKPath))
{
UE_LOG(LogTemp, Display, TEXT("Loaded TP %s"), *Modules[Index].ToString());
Platforms.Add(Platform);
}
else
{
// this hack is here because if you try and setup and validate autosdk some times it will fail because shared files are in use by another child cooker
static bool bIsChildCooker = FParse::Param(FCommandLine::Get(), TEXT("cookchild"));
if (bIsChildCooker)
{
static int Counter = 0;
++Counter;
if (Counter < 10)
{
goto RETRY_SETUPANDVALIDATE;
}
}
UE_LOG(LogTemp, Display, TEXT("Failed to SetupAndValidateAutoSDK for platform %s"), *Modules[Index].ToString());
}
}
else
{
UE_LOG(LogTemp, Display, TEXT("Failed to get target platform %s"), *Modules[Index].ToString());
}
}
}
}
bool UpdatePlatformEnvironment(FString PlatformName, TArray<FString> &Keys, TArray<FString> &Values) override
{
SetupEnvironmentVariables(Keys, Values);
return SetupSDKStatus(PlatformName);
}
bool SetupAndValidateAutoSDK(const FString& AutoSDKPath)
{
#if AUTOSDKS_ENABLED
bool bValidSDK = false;
if (AutoSDKPath.Len() > 0)
{
FName PlatformFName(*AutoSDKPath);
// cache result of the last setup attempt to avoid calling UBT all the time.
bool* bPreviousSetupSuccessful = PlatformsSetup.Find(PlatformFName);
if (bPreviousSetupSuccessful)
{
bValidSDK = *bPreviousSetupSuccessful;
}
else
{
bValidSDK = SetupEnvironmentFromAutoSDK(AutoSDKPath);
PlatformsSetup.Add(PlatformFName, bValidSDK);
}
}
else
{
// if a platform has no AutoSDKPath, then just assume the SDK is installed, we have no basis for determining it.
bValidSDK = true;
}
return bValidSDK;
#else
return true;
#endif // AUTOSDKS_ENABLED
}
bool SetupEnvironmentFromAutoSDK(const FString& AutoSDKPath)
{
#if AUTOSDKS_ENABLED
if (!IsAutoSDKsEnabled())
{
return true;
}
// Invoke UBT to perform SDK switching, or detect that a proper manual SDK is already setup.
#if PLATFORM_WINDOWS
FString HostPlatform(TEXT("HostWin64"));
#else
#error Fill in your host platform directory
#endif
static const FString SDKRootEnvFar(TEXT("UE_SDKS_ROOT"));
const int32 MaxPathSize = 16384;
FString SDKPath = FString::ChrN(16384, TEXT('\0'));
FPlatformMisc::GetEnvironmentVariable(*SDKRootEnvFar, SDKPath.GetCharArray().GetData(), MaxPathSize);
FString TargetSDKRoot = FPaths::Combine(*SDKPath, *HostPlatform, *AutoSDKPath);
static const FString SDKInstallManifestFileName(TEXT("CurrentlyInstalled.txt"));
FString SDKInstallManifestFilePath = FPaths::Combine(*TargetSDKRoot, *SDKInstallManifestFileName);
// If we are using a manual install, then it is valid for there to be no OutputEnvVars file.
TUniquePtr<FArchive> InstallManifestFile(IFileManager::Get().CreateFileReader(*SDKInstallManifestFilePath));
if (InstallManifestFile)
{
TArray<FString> FileLines;
int64 FileSize = InstallManifestFile->TotalSize();
int64 MemSize = FileSize + 1;
void* FileMem = FMemory::Malloc(MemSize);
FMemory::Memset(FileMem, 0, MemSize);
InstallManifestFile->Serialize(FileMem, FileSize);
FString FileAsString(ANSI_TO_TCHAR(FileMem));
FileAsString.ParseIntoArrayLines(FileLines);
FMemory::Free(FileMem);
InstallManifestFile->Close();
if (FileLines.Num() != 2)
{
UE_LOG(LogTargetPlatformManager, Warning, TEXT("Malformed install manifest file for Platform %s"), *AutoSDKPath);
return false;
}
static const FString ManualSDKString(TEXT("ManualSDK"));
if (FileLines[1].Compare(ManualSDKString, ESearchCase::IgnoreCase) == 0)
{
UE_LOG(LogTargetPlatformManager, Verbose, TEXT("Platform %s has manual sdk install"), *AutoSDKPath);
return true;
}
}
else
{
UE_LOG(LogTargetPlatformManager, Log, TEXT("Install manifest file for Platform %s not found. Platform not set up."), *AutoSDKPath);
return false;
}
static const FString SDKEnvironmentVarsFile(TEXT("OutputEnvVars.txt"));
FString EnvVarFileName = FPaths::Combine(*TargetSDKRoot, *SDKEnvironmentVarsFile);
// If we are using a manual install, then it is valid for there to be no OutputEnvVars file.
TUniquePtr<FArchive> EnvVarFile(IFileManager::Get().CreateFileReader(*EnvVarFileName));
if (EnvVarFile)
{
TArray<FString> FileLines;
{
int64 FileSize = EnvVarFile->TotalSize();
int64 MemSize = FileSize + 1;
void* FileMem = FMemory::Malloc(MemSize);
FMemory::Memset(FileMem, 0, MemSize);
EnvVarFile->Serialize(FileMem, FileSize);
FString FileAsString(ANSI_TO_TCHAR(FileMem));
FileAsString.ParseIntoArrayLines(FileLines);
FMemory::Free(FileMem);
EnvVarFile->Close();
}
TArray<FString> PathAdds;
TArray<FString> PathRemoves;
TArray<FString> EnvVarNames;
TArray<FString> EnvVarValues;
const FString VariableSplit(TEXT("="));
for (int32 i = 0; i < FileLines.Num(); ++i)
{
const FString& VariableString = FileLines[i];
FString Left;
FString Right;
VariableString.Split(VariableSplit, &Left, &Right);
if (Left.Compare(TEXT("strippath"), ESearchCase::IgnoreCase) == 0)
{
PathRemoves.Add(Right);
}
else if (Left.Compare(TEXT("addpath"), ESearchCase::IgnoreCase) == 0)
{
PathAdds.Add(Right);
}
else
{
// convenience for setup.bat writers. Trim any accidental whitespace from var names/values.
EnvVarNames.Add(Left.TrimStartAndEnd());
EnvVarValues.Add(Right.TrimStartAndEnd());
}
}
// don't actually set anything until we successfully validate and read all values in.
// we don't want to set a few vars, return a failure, and then have a platform try to
// build against a manually installed SDK with half-set env vars.
SetupEnvironmentVariables(EnvVarNames, EnvVarValues);
const int32 MaxPathVarLen = 32768;
FString OrigPathVar = FString::ChrN(MaxPathVarLen, TEXT('\0'));
FPlatformMisc::GetEnvironmentVariable(TEXT("PATH"), OrigPathVar.GetCharArray().GetData(), MaxPathVarLen);
// actually perform the PATH stripping / adding.
const TCHAR* PathDelimiter = FPlatformMisc::GetPathVarDelimiter();
TArray<FString> PathVars;
OrigPathVar.ParseIntoArray(PathVars, PathDelimiter, true);
TArray<FString> ModifiedPathVars;
ModifiedPathVars = PathVars;
// perform removes first, in case they overlap with any adds.
for (int32 PathRemoveIndex = 0; PathRemoveIndex < PathRemoves.Num(); ++PathRemoveIndex)
{
const FString& PathRemove = PathRemoves[PathRemoveIndex];
for (int32 PathVarIndex = 0; PathVarIndex < PathVars.Num(); ++PathVarIndex)
{
const FString& PathVar = PathVars[PathVarIndex];
if (PathVar.Find(PathRemove, ESearchCase::IgnoreCase) >= 0)
{
UE_LOG(LogTargetPlatformManager, Verbose, TEXT("Removing Path: '%s'"), *PathVar);
ModifiedPathVars.Remove(PathVar);
}
}
}
// remove all the of ADDs so that if this function is executed multiple times, the paths will be guarateed to be in the same order after each run.
// If we did not do this, a 'remove' that matched some, but not all, of our 'adds' would cause the order to change.
for (int32 PathAddIndex = 0; PathAddIndex < PathAdds.Num(); ++PathAddIndex)
{
const FString& PathAdd = PathAdds[PathAddIndex];
for (int32 PathVarIndex = 0; PathVarIndex < PathVars.Num(); ++PathVarIndex)
{
const FString& PathVar = PathVars[PathVarIndex];
if (PathVar.Find(PathAdd, ESearchCase::IgnoreCase) >= 0)
{
UE_LOG(LogTargetPlatformManager, Verbose, TEXT("Removing Path: '%s'"), *PathVar);
ModifiedPathVars.Remove(PathVar);
}
}
}
// perform adds, but don't add duplicates
for (int32 PathAddIndex = 0; PathAddIndex < PathAdds.Num(); ++PathAddIndex)
{
const FString& PathAdd = PathAdds[PathAddIndex];
if (!ModifiedPathVars.Contains(PathAdd))
{
UE_LOG(LogTargetPlatformManager, Verbose, TEXT("Adding Path: '%s'"), *PathAdd);
ModifiedPathVars.Add(PathAdd);
}
}
FString ModifiedPath = FString::Join(ModifiedPathVars, PathDelimiter);
FPlatformMisc::SetEnvironmentVar(TEXT("PATH"), *ModifiedPath);
}
else
{
UE_LOG(LogTargetPlatformManager, Warning, TEXT("OutputEnvVars.txt not found for platform: '%s'"), *AutoSDKPath);
return false;
}
UE_LOG(LogTargetPlatformManager, Verbose, TEXT("Platform %s has auto sdk install"), *AutoSDKPath);
return true;
#else
return true;
#endif
}
bool SetupSDKStatus()
{
return SetupSDKStatus(TEXT(""));
}
bool SetupSDKStatus(FString TargetPlatforms)
{
DECLARE_SCOPE_CYCLE_COUNTER( TEXT( "FTargetPlatformManagerModule::SetupSDKStatus" ), STAT_FTargetPlatformManagerModule_SetupSDKStatus, STATGROUP_TargetPlatform );
// run UBT with -validate -allplatforms and read the output
FString CmdExe, CommandLine;
if (PLATFORM_MAC)
{
CmdExe = TEXT("/bin/sh");
FString ScriptPath = FPaths::ConvertRelativePathToFull(FPaths::EngineDir() / TEXT("Build/BatchFiles/Mac/RunMono.sh"));
CommandLine = TEXT("\"") + ScriptPath + TEXT("\" \"") + FPaths::ConvertRelativePathToFull(FPaths::EngineDir() / TEXT("Binaries/DotNET/UnrealBuildTool.exe")) + TEXT("\" -validateplatform");
}
else if (PLATFORM_WINDOWS)
{
CmdExe = FPaths::ConvertRelativePathToFull(FPaths::EngineDir() / TEXT("Binaries/DotNET/UnrealBuildTool.exe"));
CommandLine = TEXT("-validateplatform");
}
else if (PLATFORM_LINUX)
{
CmdExe = TEXT("/bin/bash"); // bash and not sh because of pushd
FString ScriptPath = FPaths::ConvertRelativePathToFull(FPaths::EngineDir() / TEXT("Build/BatchFiles/Linux/RunMono.sh"));
CommandLine = TEXT("\"") + ScriptPath + TEXT("\" \"") + FPaths::ConvertRelativePathToFull(FPaths::EngineDir() / TEXT("Binaries/DotNET/UnrealBuildTool.exe")) + TEXT("\" -validateplatform");
}
else
{
checkf(false, TEXT("FTargetPlatformManagerModule::SetupSDKStatus(): Unsupported platform!"));
}
// Allow for only a subset of platforms to be reparsed - needed when kicking a change from the UI
CommandLine += TargetPlatforms.IsEmpty() ? TEXT(" -allplatforms") : (TEXT(" -platforms=") + TargetPlatforms);
TSharedPtr<FMonitoredProcess> UBTProcess = MakeShareable(new FMonitoredProcess(CmdExe, CommandLine, true));
UBTProcess->OnOutput().BindStatic(&FTargetPlatformManagerModule::OnStatusOutput);
SDKStatusMessage = TEXT("");
UBTProcess->Launch();
while(UBTProcess->Update())
{
FPlatformProcess::Sleep(0.01f);
}
TArray<FString> PlatArray;
SDKStatusMessage.ParseIntoArrayWS(PlatArray);
for (int Index = 0; Index < PlatArray.Num()-2; ++Index)
{
FString Item = PlatArray[Index];
if (PlatArray[Index].Contains(TEXT("##PlatformValidate:")))
{
PlatformInfo::EPlatformSDKStatus Status = PlatArray[Index+2].Contains(TEXT("INVALID")) ? PlatformInfo::EPlatformSDKStatus::NotInstalled : PlatformInfo::EPlatformSDKStatus::Installed;
FString PlatformName = PlatArray[Index+1];
if (PlatformName == TEXT("Win32") || PlatformName == TEXT("Win64"))
{
PlatformName = TEXT("Windows");
PlatformInfo::UpdatePlatformSDKStatus(PlatformName, Status);
PlatformName = TEXT("WindowsNoEditor");
PlatformInfo::UpdatePlatformSDKStatus(PlatformName, Status);
PlatformName = TEXT("WindowsClient");
PlatformInfo::UpdatePlatformSDKStatus(PlatformName, Status);
PlatformName = TEXT("WindowsServer");
PlatformInfo::UpdatePlatformSDKStatus(PlatformName, Status);
}
else if (PlatformName == TEXT("Mac"))
{
PlatformInfo::UpdatePlatformSDKStatus(PlatformName, Status);
PlatformName = TEXT("MacNoEditor");
PlatformInfo::UpdatePlatformSDKStatus(PlatformName, Status);
PlatformName = TEXT("MacClient");
PlatformInfo::UpdatePlatformSDKStatus(PlatformName, Status);
PlatformName = TEXT("MacServer");
PlatformInfo::UpdatePlatformSDKStatus(PlatformName, Status);
}
else if (PlatformName == TEXT("Linux"))
{
PlatformInfo::UpdatePlatformSDKStatus(PlatformName, Status);
PlatformName = TEXT("LinuxNoEditor");
PlatformInfo::UpdatePlatformSDKStatus(PlatformName, Status);
PlatformName = TEXT("LinuxClient");
PlatformInfo::UpdatePlatformSDKStatus(PlatformName, Status);
PlatformName = TEXT("LinuxServer");
PlatformInfo::UpdatePlatformSDKStatus(PlatformName, Status);
}
else if (PlatformName == TEXT("Desktop"))
{
// since Desktop is just packaging, we don't need an SDK, and UBT will return INVALID, since it doesn't build for it
PlatformInfo::UpdatePlatformSDKStatus(PlatformName, PlatformInfo::EPlatformSDKStatus::Installed);
}
else
{
PlatformInfo::UpdatePlatformSDKStatus(PlatformName, Status);
}
}
}
return true;
}
private:
void SetupEnvironmentVariables(TArray<FString> &EnvVarNames, const TArray<FString>& EnvVarValues)
{
for (int i = 0; i < EnvVarNames.Num(); ++i)
{
const FString& EnvVarName = EnvVarNames[i];
const FString& EnvVarValue = EnvVarValues[i];
UE_LOG(LogTargetPlatformManager, Verbose, TEXT("Setting variable '%s' to '%s'."), *EnvVarName, *EnvVarValue);
FPlatformMisc::SetEnvironmentVar(*EnvVarName, *EnvVarValue);
}
}
void ModulesChangesCallback(FName ModuleName, EModuleChangeReason ReasonForChange)
{
if (!bIgnoreFirstDelegateCall && ModuleName.ToString().Contains(TEXT("TargetPlatform")) && !ModuleName.ToString().Contains(TEXT("ProjectTargetPlatformEditor")))
{
Invalidate();
}
bIgnoreFirstDelegateCall = false;
}
static FString SDKStatusMessage;
static void OnStatusOutput(FString Message)
{
SDKStatusMessage += Message;
}
// If true we should build formats that are actually required for use by the runtime.
// This happens for an ordinary editor run and more specifically whenever there is no
// TargetPlatform= on the command line.
bool bRestrictFormatsToRuntimeOnly;
// Flag to force reinitialization of all cached data. This is needed to have up-to-date caches
// in case of a module reload of a TargetPlatform-Module.
bool bForceCacheUpdate;
// Flag to avoid redunant reloads
bool bIgnoreFirstDelegateCall;
// Holds the list of discovered platforms.
TArray<ITargetPlatform*> Platforms;
#if AUTOSDKS_ENABLED
// holds the list of Platforms that have attempted setup.
TMap<FName, bool> PlatformsSetup;
#endif
};
FString FTargetPlatformManagerModule::SDKStatusMessage = TEXT("");
IMPLEMENT_MODULE(FTargetPlatformManagerModule, TargetPlatform);