Skip to content

Instantly share code, notes, and snippets.

@hach-que
Last active May 20, 2024 21:10
Show Gist options
  • Save hach-que/8a736c37bc6a17e10a2a039f4b228467 to your computer and use it in GitHub Desktop.
Save hach-que/8a736c37bc6a17e10a2a039f4b228467 to your computer and use it in GitHub Desktop.
Scripts to use Gauntlet in Unreal Engine 4 (UE4) - this is for testing a plugin in a host demo project
call "GetMSBuildPath.bat"
cd ../../
%MSBUILD_EXE% /nologo /verbosity:quiet Source\Programs\AutomationTool\Gauntlet\Gauntlet.Automation.csproj /property:Configuration=Development /property:Platform=AnyCPU
param()
$ErrorActionPreference = "Stop"
if ($env:CI_COMMIT_BRANCH -eq $null) {
Write-Output "Not running on GitLab - skipping build."
return
}
$ProjectRoot = (Resolve-Path -Path $PSScriptRoot\..).Path
$UE4_VERSION = $env:CI_COMMIT_BRANCH.Substring($env:CI_COMMIT_BRANCH.Length-2, 2)
$SDK_ROOT = "C:\Program Files (x86)\Android\android-sdk"
$env:PATH = "$env:PATH;$SDK_ROOT\tools\bin;$SDK_ROOT\emulator;$SDK_ROOT\platform-tools"
if ($env:CI_JOB_ID -ne $null) {
# Really running on GitLab, always do a fresh clone of the Demo project.
if (Test-Path $ProjectRoot\Demo) {
Remove-Item -Force -Recurse $ProjectRoot\Demo
}
}
if (!(Test-Path $ProjectRoot\Demo)) {
git clone --branch $env:CI_COMMIT_BRANCH https://github.com/RedpointGames/RSIDemo "$ProjectRoot\Demo"
if ($LASTEXITCODE -ne 0) {
exit $LASTEXITCODE
}
}
else {
Push-Location "$ProjectRoot\Demo"
try {
git fetch --all
if ($LASTEXITCODE -ne 0) {
exit $LASTEXITCODE
}
git checkout -f origin/$env:CI_COMMIT_BRANCH
if ($LASTEXITCODE -ne 0) {
exit $LASTEXITCODE
}
} finally {
Pop-Location
}
}
# Add our test to Gauntlet so we can run it.
Set-Content -Force -Path "C:\Program Files\Epic Games\UE_4.$UE4_VERSION\Engine\Source\Programs\AutomationTool\Gauntlet\Unreal\Game\ReplicatedSublevelInstancesTest.cs" -Value @"
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using AutomationTool;
using UnrealBuildTool;
using Gauntlet;
using System.IO;
using System.IO.Compression;
namespace UE4Game
{
public class ReplicatedSublevelInstancesTest : UnrealTestNode<UE4TestConfig>
{
public ReplicatedSublevelInstancesTest(UnrealTestContext InContext) : base(InContext)
{
}
public override UE4TestConfig GetConfiguration()
{
UE4TestConfig Config = base.GetConfiguration();
// Create four Win64 roles, with one as the listen server.
List<UnrealTestRole> Roles = Config.RequireRoles(UnrealTargetRole.Client, UnrealTargetPlatform.Win64, 4).ToList();
var ServerRole = Roles[0];
var ClientRole1 = Roles[1];
var ClientRole2 = Roles[2];
var ClientRole3 = Roles[3];
// The -testrsiserver and -testrsiclient flags below are custom flags that are detected in blueprints
// with the "Has Launch Option" node. This allows the game to activate special testing logic when it's
// launched through Gauntlet.
//
// For Gauntlet tests, you need to make sure all of the created roles exit normally before MaxDuration
// is elapsed.
// Set up the listen server.
ServerRole.MapOverride = "/Game/DemoWorld?listen";
ServerRole.CommandLine += " -testrsiserver";
// Set up the clients.
ClientRole1.MapOverride = "127.0.0.1:7777";
ClientRole1.CommandLine += " -testrsiclient";
ClientRole2.MapOverride = "127.0.0.1:7777";
ClientRole2.CommandLine += " -testrsiclient";
ClientRole3.MapOverride = "127.0.0.1:7777";
ClientRole3.CommandLine += " -testrsiclient";
// Launch an Android device as a client as well.
// todo: We currently need to find a suitable Android N device.
//UnrealTestRole AndroidRole = Config.RequireRole(UnrealTargetRole.Client, UnrealTargetPlatform.Android);
//AndroidRole.MapOverride = "<todo find IP>";
//AndroidRole.CommandLine += " -testrsiclient";
// 1 minute (60 seconds)
Config.MaxDuration = 60;
return Config;
}
}
}
"@
$GauntletProjectPath = "C:\Program Files\Epic Games\UE_4.$UE4_VERSION\Engine\Source\Programs\AutomationTool\Gauntlet\Gauntlet.Automation.csproj"
if (Test-Path $GauntletProjectPath) {
$GauntletProject = Get-Content -Raw -Path $GauntletProjectPath
if (!$GauntletProject.Contains("ReplicatedSublevelInstancesTest.cs")) {
$GauntletProject = $GauntletProject.Replace(
"<Compile Include=`"Unreal\Game\Samples\ElementalDemoTest.cs`" />",
"<Compile Include=`"Unreal\Game\Samples\ElementalDemoTest.cs`" /><Compile Include=`"Unreal\Game\ReplicatedSublevelInstancesTest.cs`" />"
)
Set-Content -Force -Path $GauntletProjectPath -Value $GauntletProject
}
}
# We need to patch a file in Gauntlet, because it's not designed to handle listen servers, which require the presence of a ? character
# in the command line. By default, Gauntlet will replace ? characters with spaces.
$GauntletUnrealBuildSourcePath = "C:\Program Files\Epic Games\UE_4.$UE4_VERSION\Engine\Source\Programs\AutomationTool\Gauntlet\Unreal\BuildSource\Gauntlet.UnrealBuildSource.cs"
if (Test-Path $GauntletUnrealBuildSourcePath) {
$GauntletUnrealBuildSource = Get-Content -Raw -Path $GauntletUnrealBuildSourcePath
$Old = 'MatchCollection Matches = Regex.Matches(InCommandLine, "(?<option>\\-?[\\w\\d.:\\[\\]\\/\\\\]+)(=(?<value>(\"([^\"]*)\")|(\\S+)))?");'
$New = 'MatchCollection Matches = Regex.Matches(InCommandLine, "(?<option>\\-?[\\w\\d.:\\[\\]\\/\\\\\\?]+)(=(?<value>(\"([^\"]*)\")|(\\S+)))?");'
if (!$GauntletUnrealBuildSource.Contains($New)) {
$GauntletUnrealBuildSource = $GauntletUnrealBuildSource.Replace($Old, $New)
Set-Content -Force -Path $GauntletUnrealBuildSourcePath -Value $GauntletUnrealBuildSource
}
}
if (!(Test-Path $ProjectRoot\Demo\Plugins)) {
New-Item -ItemType Directory -Path $ProjectRoot\Demo\Plugins
}
if (Test-Path $ProjectRoot\Demo\Plugins\ReplicatedSublevelInstances) {
Remove-Item -Force -Recurse $ProjectRoot\Demo\Plugins\ReplicatedSublevelInstances
}
Copy-Item -Force -Recurse $ProjectRoot\Packaged $ProjectRoot\Demo\Plugins\ReplicatedSublevelInstances
# Open the firewall to allow mobile devices to connect to the listen server.
netsh advfirewall firewall add rule name="Unreal Engine Game" dir=in action=allow protocol=UDP localport=7777
Push-Location "C:\Program Files\Epic Games\UE_4.$UE4_VERSION\Engine\Build\BatchFiles"
try {
#
# For Windows targets, the staging directory *MUST* be prefixed with "Windows", otherwise Gauntlet won't find them. By default
# both Win32 and Win64 builds share the same directory (WindowsNoEditor), so we override each here.
#
Write-Output "Building for Win32 ... "
.\runuat.bat BuildCookRun -project="$ProjectRoot\Demo\RSIDemo.uproject" -targetplatform=Win32 -target=Game -clientconfig=Development -build -cook -allmaps -stage -pak -rocket -stagingdirectory="$ProjectRoot\Demo\Saved\StagedBuilds\Windows_Win32"
if ($LASTEXITCODE -ne 0) {
exit $LASTEXITCODE
}
Write-Output "Building for Win64 ... "
.\runuat.bat BuildCookRun -project="$ProjectRoot\Demo\RSIDemo.uproject" -targetplatform=Win64 -target=Game -clientconfig=Development -build -cook -allmaps -stage -pak -rocket -stagingdirectory="$ProjectRoot\Demo\Saved\StagedBuilds\Windows_Win64"
if ($LASTEXITCODE -ne 0) {
exit $LASTEXITCODE
}
#
# For Android targets, Gauntlet requires the batch files to *NOT* contain "armv7", so we do a little post-build work to rename them into
# something that Gauntlet will accept (see below).
#
Write-Output "Building for Android ... "
.\runuat.bat BuildCookRun -project="$ProjectRoot\Demo\RSIDemo.uproject" -targetplatform=Android -target=Game -clientconfig=Development -build -cook -cookflavor=Multi -allmaps -stage -pak -package -rocket
if ($LASTEXITCODE -ne 0) {
exit $LASTEXITCODE
}
Move-Item -Force "$ProjectRoot\Demo\Binaries\Android\Install_RSIDemo-armv7-es2.bat" "$ProjectRoot\Demo\Binaries\Android\Install_RSIDemoClient-arm.bat"
Move-Item -Force "$ProjectRoot\Demo\Binaries\Android\Uninstall_RSIDemo-armv7-es2.bat" "$ProjectRoot\Demo\Binaries\Android\Uninstall_RSIDemoClient-arm.bat"
Move-Item -Force "$ProjectRoot\Demo\Binaries\Android\RSIDemo-armv7-es2.apk" "$ProjectRoot\Demo\Binaries\Android\RSIDemoClient-arm.apk"
# If you need to put the Android device into TCP/IP mode so that it can be connected to over the network:
#
# adb -s 43000d8eb244a04b tcpip 5555
# adb connect android-test.agent.build.redpoint.games:5555
#
# You can only use device IDs or IPv4 addresses in the Address field for Android devices, so here we resolve
# the DNS name in Powershell first.
Write-Host "Writing device list..."
$AndroidDevice = (Resolve-DnsName -Name "android-test.agent.build.redpoint.games" -Type "A")[0].IPAddress
Set-Content -Force -Path $ProjectRoot\BuildScripts\DeviceList.json -Value @"
[
{
"Name": "Win64",
"Address": "default",
"Platform": { "Name": "Win64" }
},
{
"Name": "Win32",
"Address": "default",
"Platform": { "Name": "Win32" }
},
{
"Name": "Android",
"Address": "${AndroidDevice}:5555",
"Platform": { "Name": "Android" }
}
]
"@
Write-Output "Running Gauntlet automation test ..."
& $ProjectRoot\BuildScripts\ForceRebuildUAT.bat
.\runuat.bat RunUnreal -project="$ProjectRoot\Demo\RSIDemo.uproject" -platform=Win64 -configuration=Development -build=local -test=ReplicatedSublevelInstancesTest -devices="$ProjectRoot\BuildScripts\DeviceList.json"
if ($LASTEXITCODE -ne 0) {
exit $LASTEXITCODE
}
exit 0
} finally {
Pop-Location
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment