Files
UnrealEngineUWP/Engine/Source/Developer/FunctionalTesting/Private/AutomationBlueprintFunctionLibrary.cpp
Thomas Sarkanen 67f958285a Copying //UE4/Dev-AnimPhys to //UE4/Dev-Main (Source: //UE4/Dev-AnimPhys @ 3436999)
#lockdown Nick.Penwarden

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

Change 3354003 on 2017/03/20 by Thomas.Sarkanen

	Back out changelist 3353914

Change 3355932 on 2017/03/21 by Thomas.Sarkanen

	Back out changelist 3354003

	Reinstating merge from Main:

	Merging //UE4/Dev-Main to Dev-AnimPhys (//UE4/Dev-AnimPhys) @ CL 3353839

Change 3385512 on 2017/04/07 by Aaron.McLeran

	Bringing changes over from FN that fix audio streaming on PC/Mac/XboxOne/PS4

	CL#3318457 - Fix crash when recycling PS4 sound sources.
	CL#3313213 - Allowing XboxOne to cook streaming audio
	CL#3313719 - GetWaveFormat now returns OPUS for streaming audio waves
	CL#3320066 - Added libopus for XboxOne
	CL#3320070 - libopus is now properly linked in XboxOne

	CL#3313219 - Allowing Mac to cook streaming audio
	CL#3315332 - Fixed audio streaming on Mac
	CL#3315335 - (additional file missed in previous CL)

	CL#3313207 - Sounds now register themselves with the audio streaming manager even if they are loaded before the audio device manager is created.
	CL#3313294 - Removed some accidental debugging code that was mistakenly added in CL#3313207
	CL#3318530 - Fix threading issues in FAudioStreamingManager

	CL#3340718 - Fix for crash with audio streaming
	CL#3340844 - Fix for more thread safety in audio streaming manager
	CL#3343794 - Added a check in destructor of loaded chunk
	CL#3343794 - Removing check in stopping a source
	CL#3355393 - Moving audio streaming callbacks to use indices rather than ptrs to elements in dynamic array
	CL#3369020 - bumping up size of compressed chunks for AT9 files when doing stream chunk compression
	CL#3369131 - bumping up AT9 version number to get new AT9 cooks for larger chunks

	CL#3373626 - Fixing ps4 streaming
	CL#3375110 - Reverting some changes from 3373626
	CL#3382078 - Making audio streaming decoding async to audio thread for xaudio2
	CL#3383214 - Fixing buffer order issue for audio streaming

Change 3386321 on 2017/04/10 by Lina.Halper

	#ANIM : preview
	- Attache preview mesh to use copy mesh pose

	#jira: UE-43114, UEAP-186
	#rb: Thomas.Sarkanen

Change 3386415 on 2017/04/10 by Ori.Cohen

	Improve the cost of UpdateKinematicBodies - added the ability to defer non simulating bodies.

	#JIRA UEAP-79

Change 3386418 on 2017/04/10 by Ori.Cohen

	Fix physx memory leak when a commandlet loads many assets without ticking scene

	#JIRA UE-43378

Change 3386569 on 2017/04/10 by dan.reynolds

	Updated dummy platform generated by standalone AEOverview tests to distinguish floor materials between the platform and the test zone.

Change 3386714 on 2017/04/10 by Ori.Cohen

	Improve stats extensibility and expose it to the automation framework.

Change 3386805 on 2017/04/10 by Lina.Halper

	Fix build error for editor

	#rb: none

Change 3386854 on 2017/04/10 by Lina.Halper

	build fix for clang

	#rb:none

Change 3387198 on 2017/04/10 by Aaron.McLeran

	#jira UE-43699 Deleting unused velocity variable.

	OpenAL's velocity is not supported in WebAudio.

	Removing dead code in AndroidAudioSource.cpp

Change 3387346 on 2017/04/10 by Ori.Cohen

	Added performance regression map for physics (update kinematic bones and postBroadPhase)

	#JIRA UEAP-79

Change 3387409 on 2017/04/10 by Ori.Cohen

	Fix build, forgot to update this code

Change 3387536 on 2017/04/10 by Lina.Halper

	Merging using AnimPhys-Fortnite-Main
	- fix preview mesh selection/animation

	#code review: Thomas.Sarkanen
	#rb: none

	#i_need_autocorrect

Change 3387995 on 2017/04/11 by Martin.Wilson

	Live link updates
	- Refactor of provider api (separate update of hierarchy and transforms)
	- multi connection streaming from provider
	- provider maintains internal state so that new connections can be updated without interaction with streaming source.
	- Lifetime changes (connection timeout)

Change 3388241 on 2017/04/11 by Lina.Halper

	Merging using AnimPhys-Fortnite-Main

	- merge CL of 3388238
	#rb: Thomas.Sarkanen

Change 3388294 on 2017/04/11 by Lina.Halper

	build fix

	#rb: none

Change 3388341 on 2017/04/11 by Ori.Cohen

	Turn off vs2013 for physx

Change 3389115 on 2017/04/11 by Ori.Cohen

	Forgot missing blueprint for perf test

Change 3389224 on 2017/04/11 by Ori.Cohen

	Added sweep multi tests to perf regression

	#JIRA UEAP-79

Change 3389984 on 2017/04/12 by Martin.Wilson

	CIS Fix

Change 3390315 on 2017/04/12 by Lina.Halper

	- fix on crash of component array when shutting down anim blueprint

	#jira: UE-43868
	#rb: Thomas.Sarkanen

Change 3390402 on 2017/04/12 by Martin.Wilson

	Fix update not being called on post process instances when the main anim instance does not do a parallel update

	#jira UE-43906

Change 3390772 on 2017/04/12 by Lina.Halper

	Fix crash on importing LOD with lesser # of joints

	#rb: Benn.Gallagher

Change 3394850 on 2017/04/14 by Aaron.McLeran

	Adjusting how wavetable generation works for custom wavetables.

	- Changed wavetable creation to use a TSharedPtr vs a raw ptr.

Change 3394853 on 2017/04/14 by Aaron.McLeran

	Bringing from Odin the ability to set the lowpass filter frequency on an audio component from BP

Change 3395684 on 2017/04/17 by Ori.Cohen

	Make debugdraw for line traces const correct.

Change 3396680 on 2017/04/17 by Ori.Cohen

	Added a total scene query stat and the ability to trace all scene queries

Change 3397564 on 2017/04/18 by Benn.Gallagher

	Added clothing functional and performance test map + assets.

Change 3397769 on 2017/04/18 by Thomas.Sarkanen

	CIS fix

	Fixup incorrect AudioStreaming.cpp merge when bringing Main into Dev-AnimPhys

Change 3398518 on 2017/04/18 by Lina.Halper

	Mirroring fix on set world rotation

	#rb: Zak.Middleton
	#jira: UE-43830

Change 3400400 on 2017/04/19 by Chad.Garyet

	adding switch physx build to anim-phys

Change 3400416 on 2017/04/19 by Chad.Garyet

	updated email targets to include switch

Change 3402005 on 2017/04/20 by Ori.Cohen

	Pass stats into scene queries. Not all call sites are updated yet, waiting on Jon for uber search/replace script.

Change 3402264 on 2017/04/20 by Ori.Cohen

	CIS fix

Change 3402344 on 2017/04/20 by Ori.Cohen

	Turn off find unknown (was on by mistake)

Change 3403311 on 2017/04/21 by Benn.Gallagher

	Clothing changes from Dev-General. Fixed LOD pops, mesh swap crashes and convex collision locations

Change 3403399 on 2017/04/21 by Benn.Gallagher

	Lighting build, content cleanup and reorganization for clothing test map

Change 3403401 on 2017/04/21 by Benn.Gallagher

	Clothing test ground truth updates after lighting build.

Change 3403813 on 2017/04/21 by danny.bouimad

	Adding everything needed for our multiplat map TM-AnimPhys

Change 3403900 on 2017/04/21 by mason.seay

	Added WIP text to tests that need fixup

Change 3405383 on 2017/04/24 by Ori.Cohen

	Fix typo where complex flag was not being passed in  to constructor.

	#JIRA UE-44278, UE-44279

Change 3405389 on 2017/04/24 by Martin.Wilson

	Live link:
	- Added support for sending curve data across live link and applying it via the Live Link node
	- Added pose snapshots which are built in the live link clients tick and read by the rest of the engine, save reading live data.

Change 3405569 on 2017/04/24 by Martin.Wilson

	Missed file from CL 3405389

Change 3405810 on 2017/04/24 by Chad.Garyet

	fixing busted target for dev-animphys stream

Change 3406566 on 2017/04/24 by Aaron.McLeran

	#jira UE-44272 Fixing granular synth with packaged builds

	- Changed the way granular synth component and wave table component get PCM data from USoundWave assets. No duplication, just precache directly.

Change 3406694 on 2017/04/24 by Aaron.McLeran

	Update to phonon/steam audio plugin from valve

Change 3407794 on 2017/04/25 by Aaron.McLeran

	#jira UE-44357 Fix for attenuation settings in sequencer

Change 3407848 on 2017/04/25 by Jon.Nabozny

	Add stats to FCollisionQueryParams (continued from CL-3402005).

Change 3407857 on 2017/04/25 by Jon.Nabozny

	Disable FIND_UNKNOWN_SCENE_QUERIES.

Change 3407915 on 2017/04/25 by Lina.Halper

	Animation Automation Test for curve and simple notify

Change 3408164 on 2017/04/25 by Ori.Cohen

	Expose the physx tree rebuild rate.

Change 3408174 on 2017/04/25 by Lina.Halper

	- Changed 1, 2, 3, 4 for ordering of timing
	- Made sure the notify test takes more time between shots.

Change 3408359 on 2017/04/25 by Jon.Nabozny

	Fix FConfigFile::Write for arrays of different sizes.
	(Looks like it is still broke for arrays of the same same, with different values).

Change 3408633 on 2017/04/25 by Aaron.McLeran

	#jira UE-44297 Fix for animating sound cue graph when editor "non-realtime" button is checked

	- Fix is to explicitely register an active timer lambda that queries the preview audio component while the sound cue is playing

Change 3408768 on 2017/04/25 by Aaron.McLeran

	Fixing UHT crash

Change 3409225 on 2017/04/26 by Lina.Halper

	Increase tolerance for the shot test. It's very sensitive otherwise.

Change 3409313 on 2017/04/26 by Benn.Gallagher

	Refactor of clothing paint tool framework to create a more extensible editor and get rid of some GDC techdebt

Change 3409478 on 2017/04/26 by danny.bouimad

	Moved Text Actor forwards as it was causing zFighting

Change 3409572 on 2017/04/26 by Benn.Gallagher

	CIS fix after cloth painter changes

Change 3409585 on 2017/04/26 by danny.bouimad

	Updated Tm-AnimPhys to utilize the AEOverview maps, also found a crash with viewing shader complexity that only occurs on this map.

Change 3410948 on 2017/04/27 by Martin.Wilson

	Live Link:
	- Add subject clearing support to client / message bus protocol
	- Update ref skeleton when subject changes.
	- Remove old classes

Change 3413305 on 2017/04/28 by Danny.Bouimad

	Disabled audio tests on AnimPhys Testmap to hopefuly stop the lighting crashes during launch on (content problem)

Change 3413408 on 2017/04/28 by mason.seay

	Resaving to clear empty engine version warnings

Change 3413418 on 2017/04/28 by Benn.Gallagher

	CIS fix, #pragma once in wrong place (after an include)

Change 3413737 on 2017/04/28 by Martin.Wilson

	Rename Live Link Message Bus messages to contain the word message to avoid future name clashes

Change 3414121 on 2017/04/28 by Ori.Cohen

	Added task batching for physx tasks. Set fortnite to 8 as we already have a lot of thread contention during that time and it's best to just do it all in a single task.

Change 3417833 on 2017/05/02 by Thomas.Sarkanen

	Fix bad merge in SynthComponentGranulator.cpp

Change 3418174 on 2017/05/02 by Jon.Nabozny

	Fix memory leak in UDestructibleComponent::SetSkeletalMesh

Change 3418907 on 2017/05/02 by Aaron.McLeran

	#jira UE-44599 Fixing active sound un-pause issue.

	- While paused, active sounds were updating their active playbacktime.

Change 3419001 on 2017/05/02 by Ori.Cohen

	Added GetNumSimulatedAndAwake so that we can easily test for jitter.

Change 3419079 on 2017/05/02 by Ori.Cohen

	Added a jitter automated test.

Change 3419213 on 2017/05/02 by mason.seay

	Reaving content to remove empty engine version warnings

Change 3419351 on 2017/05/02 by Ori.Cohen

	Added automated test for raycasting against landscape from underneath (JIRA UE-39819)
	It looks like this is currently broken

Change 3419356 on 2017/05/02 by Ori.Cohen

	Updated test with associated JIRA where we first saw this

Change 3419478 on 2017/05/02 by Ori.Cohen

	Added automated test for origin shift regression crash when using aggregates.

Change 3420736 on 2017/05/03 by Ori.Cohen

	Added automated test for moving objects during an overlap callback for UE-41450
	#rnx

Change 3420803 on 2017/05/03 by Ori.Cohen

	Added automated test for JIRA UE-18019
	#rnx

Change 3420835 on 2017/05/03 by Jurre.deBaare

	Anim modifier BP for release notes

Change 3421185 on 2017/05/03 by Ori.Cohen

	Missing file

Change 3422673 on 2017/05/04 by danny.bouimad

	Fixed the cooked/uncooked lighting issue with AEO_StageFloor. The lights should no longer repeatidly spawn when loading in as sub levels.

Change 3422898 on 2017/05/04 by Danny.Bouimad

	Updating QA Audio Content

Change 3422908 on 2017/05/04 by Danny.Bouimad

	Fixing Automation CIS error 'Can't find file for asset. /Game/Tests/Physics/ISMCStaticSweep_BuiltData'

Change 3423508 on 2017/05/04 by Danny.Bouimad

	Replacing ground truth and adding build data for nonissue Automation CIS failure OverlapCallback

Change 3423634 on 2017/05/04 by danny.bouimad

	Made updates to TM-AnimPhys testmap

Change 3423870 on 2017/05/04 by Ori.Cohen

	Fix wheels separating from vehicle due to world kinematic refactor. Added temp variable for now

	#jira UE-44624

Change 3423917 on 2017/05/04 by Ori.Cohen

	Assert_Equal for int returns a bool

Change 3425267 on 2017/05/05 by Martin.Wilson

	Live Link

	- Add interpolation to subjects
	- Add connection settings that can be modified in client panel. All subjects modified by a connection use its connection settings
	- Give live link sources their client Guid so that they can send it with subject data

Change 3425303 on 2017/05/05 by Martin.Wilson

	Missed file from CL 3425267

Change 3430351 on 2017/05/09 by Martin.Wilson

	Crash fix for live link interpolation

Change 3430601 on 2017/05/09 by Benn.Gallagher

	Disabled clothing perf test temporarily due to stats issues

Change 3432669 on 2017/05/10 by Ori.Cohen

	Temporarily turn off line trace under heightfield test. This is a known bug which won't be fixed until 4.17

Change 3432679 on 2017/05/10 by Ori.Cohen

	Temporarily turn off check during TLS release on Switch.

Change 3434960 on 2017/05/11 by danny.bouimad

	Disabled content on TM-AnimPhys that was casuing a out of memory when drawing debug lines on switch.

Change 3436639 on 2017/05/12 by Danny.Bouimad

	Updating ground truths and map for OverlapCallBack to fix CIS error.

[CL 3437043 by Thomas Sarkanen in Main branch]
2017-05-12 11:21:11 -04:00

583 lines
19 KiB
C++

// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved.
#include "AutomationBlueprintFunctionLibrary.h"
#include "HAL/IConsoleManager.h"
#include "Misc/AutomationTest.h"
#include "EngineGlobals.h"
#include "UnrealClient.h"
#include "Camera/CameraActor.h"
#include "Camera/PlayerCameraManager.h"
#include "Engine/Texture.h"
#include "Engine/GameViewportClient.h"
#include "Kismet/GameplayStatics.h"
#include "Engine/Engine.h"
#include "Tests/AutomationCommon.h"
#include "Logging/MessageLog.h"
#include "TakeScreenshotAfterTimeLatentAction.h"
#include "HighResScreenshot.h"
#include "Slate/SceneViewport.h"
#include "Tests/AutomationTestSettings.h"
#include "Slate/WidgetRenderer.h"
#include "DelayAction.h"
#include "Widgets/SViewport.h"
#include "Framework/Application/SlateApplication.h"
#include "ShaderCompiler.h"
#include "AutomationBlueprintFunctionLibrary.h"
#include "BufferVisualizationData.h"
#include "Engine/LocalPlayer.h"
#include "ContentStreaming.h"
#include "Stats/StatsData.h"
#define LOCTEXT_NAMESPACE "Automation"
DEFINE_LOG_CATEGORY_STATIC(BlueprintAssertion, Error, Error)
DEFINE_LOG_CATEGORY_STATIC(AutomationFunctionLibrary, Log, Log)
static TAutoConsoleVariable<int32> CVarAutomationScreenshotResolutionWidth(
TEXT("AutomationScreenshotResolutionWidth"),
0,
TEXT("The width of automation screenshots."),
ECVF_Default);
static TAutoConsoleVariable<int32> CVarAutomationScreenshotResolutionHeight(
TEXT("AutomationScreenshotResolutionHeight"),
0,
TEXT("The height of automation screenshots."),
ECVF_Default);
void FinishLoadingBeforeScreenshot()
{
// Force all shader compiling to finish.
GShaderCompilingManager->FinishAllCompilation();
// Force all mip maps to load before taking the screenshot.
UTexture::ForceUpdateTextureStreaming();
IStreamingManager::Get().StreamAllResources(0.0f);
}
#if (WITH_DEV_AUTOMATION_TESTS || WITH_PERF_AUTOMATION_TESTS)
class FConsoleVariableSwapper
{
public:
FConsoleVariableSwapper(FString InConsoleVariableName)
: bModified(false)
, ConsoleVariableName(InConsoleVariableName)
{
}
void Set(int32 Value)
{
IConsoleVariable* ConsoleVariable = IConsoleManager::Get().FindConsoleVariable(*ConsoleVariableName);
if ( ensure(ConsoleVariable) )
{
if ( bModified == false )
{
bModified = true;
OriginalValue = ConsoleVariable->GetInt();
}
ConsoleVariable->Set(Value);
}
}
void Restore()
{
if ( bModified )
{
IConsoleVariable* ConsoleVariable = IConsoleManager::Get().FindConsoleVariable(*ConsoleVariableName);
if ( ensure(ConsoleVariable) )
{
ConsoleVariable->Set(OriginalValue);
}
bModified = false;
}
}
private:
bool bModified;
FString ConsoleVariableName;
int32 OriginalValue;
};
class FAutomationScreenshotTaker
{
public:
FAutomationScreenshotTaker(UWorld* InWorld, const FString& InName, FAutomationScreenshotOptions InOptions)
: World(InWorld)
, Name(InName)
, Options(InOptions)
, DefaultFeature_AntiAliasing(TEXT("r.DefaultFeature.AntiAliasing"))
, DefaultFeature_AutoExposure(TEXT("r.DefaultFeature.AutoExposure"))
, DefaultFeature_MotionBlur(TEXT("r.DefaultFeature.MotionBlur"))
, PostProcessAAQuality(TEXT("r.PostProcessAAQuality"))
, MotionBlurQuality(TEXT("r.MotionBlurQuality"))
, ScreenSpaceReflectionQuality(TEXT("r.SSR.Quality"))
, EyeAdaptationQuality(TEXT("r.EyeAdaptationQuality"))
, ContactShadows(TEXT("r.ContactShadows"))
{
GEngine->GameViewport->OnScreenshotCaptured().AddRaw(this, &FAutomationScreenshotTaker::GrabScreenShot);
check(IsInGameThread());
if ( Options.bDisableNoisyRenderingFeatures )
{
DefaultFeature_AntiAliasing.Set(0);
DefaultFeature_AutoExposure.Set(0);
DefaultFeature_MotionBlur.Set(0);
PostProcessAAQuality.Set(0);
MotionBlurQuality.Set(0);
ScreenSpaceReflectionQuality.Set(0);
EyeAdaptationQuality.Set(0);
ContactShadows.Set(0);
}
Options.SetToleranceAmounts(Options.Tolerance);
if ( UGameViewportClient* ViewportClient = GEngine->GameViewport )
{
static IConsoleVariable* ICVar = IConsoleManager::Get().FindConsoleVariable(FBufferVisualizationData::GetVisualizationTargetConsoleCommandName());
if ( ICVar )
{
if ( ViewportClient->GetEngineShowFlags() )
{
ViewportClient->GetEngineShowFlags()->SetVisualizeBuffer(InOptions.VisualizeBuffer == NAME_None ? false : true);
ViewportClient->GetEngineShowFlags()->SetTonemapper(InOptions.VisualizeBuffer == NAME_None ? true : false);
ICVar->Set(*InOptions.VisualizeBuffer.ToString());
}
}
}
}
virtual ~FAutomationScreenshotTaker()
{
check(IsInGameThread());
DefaultFeature_AntiAliasing.Restore();
DefaultFeature_AutoExposure.Restore();
DefaultFeature_MotionBlur.Restore();
PostProcessAAQuality.Restore();
MotionBlurQuality.Restore();
ScreenSpaceReflectionQuality.Restore();
EyeAdaptationQuality.Restore();
ContactShadows.Restore();
if ( UGameViewportClient* ViewportClient = GEngine->GameViewport )
{
static IConsoleVariable* ICVar = IConsoleManager::Get().FindConsoleVariable(FBufferVisualizationData::GetVisualizationTargetConsoleCommandName());
if ( ICVar )
{
if ( ViewportClient->GetEngineShowFlags() )
{
ViewportClient->GetEngineShowFlags()->SetVisualizeBuffer(false);
ViewportClient->GetEngineShowFlags()->SetTonemapper(true);
ICVar->Set(TEXT(""));
}
}
}
GEngine->GameViewport->OnScreenshotCaptured().RemoveAll(this);
FAutomationTestFramework::Get().NotifyScreenshotTakenAndCompared();
}
void GrabScreenShot(int32 InSizeX, int32 InSizeY, const TArray<FColor>& InImageData)
{
check(IsInGameThread());
FAutomationScreenshotData Data = AutomationCommon::BuildScreenshotData(GWorld->GetName(), Name, InSizeX, InSizeY);
// Copy the relevant data into the metadata for the screenshot.
Data.bHasComparisonRules = true;
Data.ToleranceRed = Options.ToleranceAmount.Red;
Data.ToleranceGreen = Options.ToleranceAmount.Green;
Data.ToleranceBlue = Options.ToleranceAmount.Blue;
Data.ToleranceAlpha = Options.ToleranceAmount.Alpha;
Data.ToleranceMinBrightness = Options.ToleranceAmount.MinBrightness;
Data.ToleranceMaxBrightness = Options.ToleranceAmount.MaxBrightness;
Data.bIgnoreAntiAliasing = Options.bIgnoreAntiAliasing;
Data.bIgnoreColors = Options.bIgnoreColors;
Data.MaximumLocalError = Options.MaximumLocalError;
Data.MaximumGlobalError = Options.MaximumGlobalError;
FAutomationTestFramework::Get().OnScreenshotCaptured().ExecuteIfBound(InImageData, Data);
UE_LOG(AutomationFunctionLibrary, Log, TEXT("Screenshot captured as %s"), *Data.Path);
if ( GIsAutomationTesting )
{
FAutomationTestFramework::Get().OnScreenshotCompared.AddRaw(this, &FAutomationScreenshotTaker::OnComparisonComplete);
}
else
{
delete this;
}
}
void OnComparisonComplete(bool bWasNew, bool bWasSimilar, double MaxLocalDifference, double GlobalDifference, FString ErrorMessage)
{
FAutomationTestFramework::Get().OnScreenshotCompared.RemoveAll(this);
if ( bWasNew )
{
UE_LOG(AutomationFunctionLibrary, Warning, TEXT("New Screenshot '%s' was discovered! Please add a ground truth version of it."), *Name);
}
else
{
if ( bWasSimilar )
{
UE_LOG(AutomationFunctionLibrary, Display, TEXT("Screenshot '%s' was similar! Global Difference = %f, Max Local Difference = %f"), *Name, GlobalDifference, MaxLocalDifference);
}
else
{
if ( ErrorMessage.IsEmpty() )
{
UE_LOG(AutomationFunctionLibrary, Error, TEXT("Screenshot '%s' test failed, Screnshots were different! Global Difference = %f, Max Local Difference = %f"), *Name, GlobalDifference, MaxLocalDifference);
}
else
{
UE_LOG(AutomationFunctionLibrary, Error, TEXT("Screenshot '%s' test failed; Error = %s"), *Name, *ErrorMessage);
}
}
}
delete this;
}
private:
TWeakObjectPtr<UWorld> World;
FString Name;
FAutomationScreenshotOptions Options;
FConsoleVariableSwapper DefaultFeature_AntiAliasing;
FConsoleVariableSwapper DefaultFeature_AutoExposure;
FConsoleVariableSwapper DefaultFeature_MotionBlur;
FConsoleVariableSwapper PostProcessAAQuality;
FConsoleVariableSwapper MotionBlurQuality;
FConsoleVariableSwapper ScreenSpaceReflectionQuality;
FConsoleVariableSwapper EyeAdaptationQuality;
FConsoleVariableSwapper ContactShadows;
};
#endif
UAutomationBlueprintFunctionLibrary::UAutomationBlueprintFunctionLibrary(const class FObjectInitializer& Initializer)
: Super(Initializer)
{
}
bool UAutomationBlueprintFunctionLibrary::TakeAutomationScreenshotInternal(UObject* WorldContextObject, const FString& Name, FAutomationScreenshotOptions Options)
{
FinishLoadingBeforeScreenshot();
// Fallback resolution if all else fails for screenshots.
uint32 ResolutionX = 1280;
uint32 ResolutionY = 720;
// First get the default set for the project.
UAutomationTestSettings const* AutomationTestSettings = GetDefault<UAutomationTestSettings>();
if ( AutomationTestSettings->DefaultScreenshotResolution.GetMin() > 0 )
{
ResolutionX = (uint32)AutomationTestSettings->DefaultScreenshotResolution.X;
ResolutionY = (uint32)AutomationTestSettings->DefaultScreenshotResolution.Y;
}
// If there's an override resolution, use that instead.
if ( Options.Resolution.GetMin() > 0 )
{
ResolutionX = (uint32)Options.Resolution.X;
ResolutionY = (uint32)Options.Resolution.Y;
}
else
{
// Failing to find an override, look for a platform override that may have been provided through the
// device profiles setup, to configure the CVars for controlling the automation screenshot size.
int32 OverrideWidth = CVarAutomationScreenshotResolutionWidth.GetValueOnGameThread();
int32 OverrideHeight = CVarAutomationScreenshotResolutionHeight.GetValueOnGameThread();
if ( OverrideWidth > 0 )
{
ResolutionX = (uint32)OverrideWidth;
}
if ( OverrideHeight > 0 )
{
ResolutionY = (uint32)OverrideHeight;
}
}
#if (WITH_DEV_AUTOMATION_TESTS || WITH_PERF_AUTOMATION_TESTS)
FAutomationScreenshotTaker* TempObject = new FAutomationScreenshotTaker(WorldContextObject ? WorldContextObject->GetWorld() : nullptr, Name, Options);
#endif
//static IConsoleVariable* HighResScreenshotDelay = IConsoleManager::Get().FindConsoleVariable(TEXT("r.HighResScreenshotDelay"));
//check(HighResScreenshotDelay);
//HighResScreenshotDelay->Set(10);
if ( FPlatformProperties::HasFixedResolution() )
{
FScreenshotRequest::RequestScreenshot(false);
return true;
}
else
{
FHighResScreenshotConfig& Config = GetHighResScreenshotConfig();
if ( Config.SetResolution(ResolutionX, ResolutionY, 1.0f) )
{
if ( !GEngine->GameViewport->GetGameViewport()->TakeHighResScreenShot() )
{
// If we failed to take the screenshot, we're going to need to cleanup the automation screenshot taker.
#if (WITH_DEV_AUTOMATION_TESTS || WITH_PERF_AUTOMATION_TESTS)
delete TempObject;
#endif
return false;
}
return true; //-V773
}
}
return false;
}
void UAutomationBlueprintFunctionLibrary::TakeAutomationScreenshot(UObject* WorldContextObject, FLatentActionInfo LatentInfo, const FString& Name, const FAutomationScreenshotOptions& Options)
{
if ( GIsAutomationTesting )
{
if ( UWorld* World = GEngine->GetWorldFromContextObject(WorldContextObject) )
{
FLatentActionManager& LatentActionManager = World->GetLatentActionManager();
if ( LatentActionManager.FindExistingAction<FTakeScreenshotAfterTimeLatentAction>(LatentInfo.CallbackTarget, LatentInfo.UUID) == nullptr )
{
LatentActionManager.AddNewAction(LatentInfo.CallbackTarget, LatentInfo.UUID, new FTakeScreenshotAfterTimeLatentAction(LatentInfo, Name, Options));
}
}
}
else
{
UE_LOG(AutomationFunctionLibrary, Log, TEXT("Screenshot not captured - screenshots are only taken during automation tests"));
}
}
void UAutomationBlueprintFunctionLibrary::TakeAutomationScreenshotAtCamera(UObject* WorldContextObject, FLatentActionInfo LatentInfo, ACameraActor* Camera, const FString& NameOverride, const FAutomationScreenshotOptions& Options)
{
if ( Camera == nullptr )
{
FMessageLog("PIE").Error(LOCTEXT("CameraRequired", "A camera is required to TakeAutomationScreenshotAtCamera"));
return;
}
APlayerController* PlayerController = UGameplayStatics::GetPlayerController(WorldContextObject, 0);
if ( PlayerController == nullptr )
{
FMessageLog("PIE").Error(LOCTEXT("PlayerRequired", "A player controller is required to TakeAutomationScreenshotAtCamera"));
return;
}
// Move the player, then queue up a screenshot.
// We need to delay before the screenshot so that the motion blur has time to stop.
PlayerController->SetViewTarget(Camera, FViewTargetTransitionParams());
FString ScreenshotName = Camera->GetName();
if ( !NameOverride.IsEmpty() )
{
ScreenshotName = NameOverride;
}
if ( UWorld* World = GEngine->GetWorldFromContextObject(WorldContextObject) )
{
ScreenshotName = FString::Printf(TEXT("%s_%s"), *World->GetName(), *ScreenshotName);
FLatentActionManager& LatentActionManager = World->GetLatentActionManager();
if ( LatentActionManager.FindExistingAction<FTakeScreenshotAfterTimeLatentAction>(LatentInfo.CallbackTarget, LatentInfo.UUID) == nullptr )
{
LatentActionManager.AddNewAction(LatentInfo.CallbackTarget, LatentInfo.UUID, new FTakeScreenshotAfterTimeLatentAction(LatentInfo, ScreenshotName, Options));
}
}
}
void UAutomationBlueprintFunctionLibrary::TakeAutomationScreenshotOfUI(UObject* WorldContextObject, FLatentActionInfo LatentInfo, const FString& Name, const FAutomationScreenshotOptions& Options)
{
FinishLoadingBeforeScreenshot();
if ( UWorld* World = WorldContextObject->GetWorld() )
{
if ( UGameViewportClient* GameViewport = WorldContextObject->GetWorld()->GetGameViewport() )
{
TSharedPtr<SViewport> Viewport = GameViewport->GetGameViewportWidget();
if ( Viewport.IsValid() )
{
TArray<FColor> OutColorData;
FIntVector OutSize;
if ( FSlateApplication::Get().TakeScreenshot(Viewport.ToSharedRef(), OutColorData, OutSize) )
{
#if (WITH_DEV_AUTOMATION_TESTS || WITH_PERF_AUTOMATION_TESTS)
FAutomationScreenshotTaker* TempObject = new FAutomationScreenshotTaker(GEngine->GetWorldFromContextObject(WorldContextObject), Name, Options);
FAutomationScreenshotData Data = AutomationCommon::BuildScreenshotData(GWorld->GetName(), Name, OutSize.X, OutSize.Y);
// Copy the relevant data into the metadata for the screenshot.
Data.bHasComparisonRules = true;
Data.ToleranceRed = Options.ToleranceAmount.Red;
Data.ToleranceGreen = Options.ToleranceAmount.Green;
Data.ToleranceBlue = Options.ToleranceAmount.Blue;
Data.ToleranceAlpha = Options.ToleranceAmount.Alpha;
Data.ToleranceMinBrightness = Options.ToleranceAmount.MinBrightness;
Data.ToleranceMaxBrightness = Options.ToleranceAmount.MaxBrightness;
Data.bIgnoreAntiAliasing = Options.bIgnoreAntiAliasing;
Data.bIgnoreColors = Options.bIgnoreColors;
Data.MaximumLocalError = Options.MaximumLocalError;
Data.MaximumGlobalError = Options.MaximumGlobalError;
GEngine->GameViewport->OnScreenshotCaptured().Broadcast(OutSize.X, OutSize.Y, OutColorData);
#endif
} //-V773
FLatentActionManager& LatentActionManager = World->GetLatentActionManager();
if ( LatentActionManager.FindExistingAction<FTakeScreenshotAfterTimeLatentAction>(LatentInfo.CallbackTarget, LatentInfo.UUID) == nullptr )
{
LatentActionManager.AddNewAction(LatentInfo.CallbackTarget, LatentInfo.UUID, new FWaitForScreenshotComparisonLatentAction(LatentInfo));
}
}
}
}
}
void UAutomationBlueprintFunctionLibrary::EnableStatGroup(UObject* WorldContextObject, FName GroupName)
{
#if STATS
if (FGameThreadStatsData* StatsData = FLatestGameThreadStatsData::Get().Latest)
{
const FString GroupNameString = FString(TEXT("STATGROUP_")) + GroupName.ToString();
const FName GroupNameFull = FName(*GroupNameString, EFindName::FNAME_Find);
if(StatsData->GroupNames.Contains(GroupNameFull))
{
return;
}
}
if (APlayerController* TargetPC = UGameplayStatics::GetPlayerController(WorldContextObject, 0))
{
TargetPC->ConsoleCommand( FString(TEXT("stat ")) + GroupName.ToString() + FString(TEXT(" -nodisplay")), /*bWriteToLog=*/false);
}
#endif
}
void UAutomationBlueprintFunctionLibrary::DisableStatGroup(UObject* WorldContextObject, FName GroupName)
{
#if STATS
if (FGameThreadStatsData* StatsData = FLatestGameThreadStatsData::Get().Latest)
{
const FString GroupNameString = FString(TEXT("STATGROUP_")) + GroupName.ToString();
const FName GroupNameFull = FName(*GroupNameString, EFindName::FNAME_Find);
if (!StatsData->GroupNames.Contains(GroupNameFull))
{
return;
}
}
if (APlayerController* TargetPC = UGameplayStatics::GetPlayerController(WorldContextObject, 0))
{
TargetPC->ConsoleCommand(FString(TEXT("stat ")) + GroupName.ToString() + FString(TEXT(" -nodisplay")), /*bWriteToLog=*/false);
}
#endif
}
template <EComplexStatField::Type ValueType, bool bCallCount = false>
float HelperGetStat(FName StatName)
{
#if STATS
if (FGameThreadStatsData* StatsData = FLatestGameThreadStatsData::Get().Latest)
{
if (const FComplexStatMessage* StatMessage = StatsData->GetStatData(StatName))
{
if(bCallCount)
{
return StatMessage->GetValue_CallCount(ValueType);
}
else
{
return FPlatformTime::ToMilliseconds(StatMessage->GetValue_Duration(ValueType));
}
}
}
#if WITH_EDITOR
FText WarningOut = FText::Format(LOCTEXT("StatNotFound", "Could not find stat data for {0}, did you call ToggleStatGroup with enough time to capture data?"), FText::FromName(StatName));
FMessageLog("PIE").Warning(WarningOut);
UE_LOG(AutomationFunctionLibrary, Warning, TEXT("%s"), *WarningOut.ToString());
#endif
#endif
return 0.f;
}
float UAutomationBlueprintFunctionLibrary::GetStatIncAverage(FName StatName)
{
return HelperGetStat<EComplexStatField::IncAve>(StatName);
}
float UAutomationBlueprintFunctionLibrary::GetStatIncMax(FName StatName)
{
return HelperGetStat<EComplexStatField::IncMax>(StatName);
}
float UAutomationBlueprintFunctionLibrary::GetStatExcAverage(FName StatName)
{
return HelperGetStat<EComplexStatField::ExcAve>(StatName);
}
float UAutomationBlueprintFunctionLibrary::GetStatExcMax(FName StatName)
{
return HelperGetStat<EComplexStatField::ExcMax>(StatName);
}
float UAutomationBlueprintFunctionLibrary::GetStatCallCount(FName StatName)
{
return HelperGetStat<EComplexStatField::IncAve, /*bCallCount=*/true>(StatName);
}
bool UAutomationBlueprintFunctionLibrary::AreAutomatedTestsRunning()
{
return GIsAutomationTesting;
}
FAutomationScreenshotOptions UAutomationBlueprintFunctionLibrary::GetDefaultScreenshotOptionsForGameplay(EComparisonTolerance Tolerance)
{
FAutomationScreenshotOptions Options;
Options.Tolerance = Tolerance;
Options.bDisableNoisyRenderingFeatures = true;
Options.bIgnoreAntiAliasing = true;
Options.SetToleranceAmounts(Tolerance);
return Options;
}
FAutomationScreenshotOptions UAutomationBlueprintFunctionLibrary::GetDefaultScreenshotOptionsForRendering(EComparisonTolerance Tolerance)
{
FAutomationScreenshotOptions Options;
Options.Tolerance = Tolerance;
Options.bDisableNoisyRenderingFeatures = true;
Options.bIgnoreAntiAliasing = true;
Options.SetToleranceAmounts(Tolerance);
return Options;
}
#undef LOCTEXT_NAMESPACE