Contributing to ATC and ATO
Development Setup Environment¶
While ATC can be installed and used by itself, ATO depends on ATC. When contributing to either, your development environment needs to include both to ensure a change in ATC doesn't break ATO.
ATO and ATC work on Windows, Mac, and Linux. Windows and Linux users may follow this guide. macOS users need to change a
few things from this tutorial. See Setting up in other environments to see what other steps need to be made on other
environments.
The folder structure will look like this:
ATC_TEST_ENV/
└── TemplateProject/
├── ATO/
│ └── Packages/
│ ├── ato/
│ ├── unreal-lag/
│ └── buildgraph/ (real folder)
│
├── BuildGraph/ (symlink → ATO/Packages/buildgraph)
│
├── TemplateProject.uproject
├── package.json
└── tsconfig.json
Create a root folder. We'll use ATC_TEST_ENV.
Within the root folder, create a project based on the Third Person C++ template. We'll put it under the folder TemplateProject.
Setup pnpm-workspace.yaml in TemplateProject/
# TemplateProject/pnpm-workspace.yaml
packages:
- ATO/packages/*
onlyBuiltDependencies:
- esbuild
- nx
Setup ATO
# Within `ATC_TEST_ENV`
cd TemplateProject
git clone https://github.com/MaximDevoir/ATO.git
cd ATO
pnpm install --frozen-lockfile
Setup NPM within Template Project
# Within `ATC_TEST_ENV`
cd TemplateProject
npm init -y
npx tsc --init
pnpm add -D file:./ATO/packages/ato
pnpm add -D file:./ATO/packages/unreal-lag
pnpm add -D typescript tsx @types/node vitest
mklink /D BuildGraph .\ATO\Packages\buildgraph # Windows only
# ln -s ./ATO/Packages/buildgraph BuildGraph # Linux/macOS
pnpm add -D c8 # needed for typescript code coverage
Within TemplateProject/tsconfig.json replace contents with
{
"compilerOptions": {
"target": "esnext",
"module": "esnext",
"moduleResolution": "Bundler",
"lib": [
"esnext"
],
"types": [
"node"
],
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"resolveJsonModule": true,
"baseUrl": ".",
"paths": {
"@ATO/UnrealLag": [
"./ATO/packages/unreal-lag/src/UnrealLag.ts"
],
"@ATO/ATO": [
"./ATO/packages/ato/src/index.ts"
]
}
},
"include": [
"BuildGraph/Scripts/**/*.ts"
],
"exclude": [
"node_modules"
]
}
Within TemplateProject/package.json change from "type": "commonjs" to "type": "module".
Within TemplateProject/package.json add these scripts
{
"scripts": {
// For All Environments
"test": "npm run test:ci",
"ue:uat": "tsx BuildGraph\\RunUAT.ts",
"test:directStandalone": "tsx buildgraph/Scripts/RunStandaloneTest.ts --SimpleAutoBuild",
"test:directDedicated": "tsx buildgraph/Scripts/RunDedicated.tests.ts --SimpleAutoBuild",
"test:directListen": "tsx buildgraph/Scripts/RunListenServerTest.ts --SimpleAutoBuild",
"test:directPIE": "tsx buildgraph/Scripts/RunPIETest.ts --SimpleAutoBuild",
//
// For Windows
"test:ci": "npm run ue:uat -- BuildGraph -Script=%CD%\\BuildGraph\\ATCTests.generated.xml -Target=ATCTests",
"test:standalone": "npm run ue:uat -- BuildGraph -Script=%CD%\\BuildGraph\\ATCTests.generated.xml -Target=Standalone",
"test:standaloneUI": "node --import tsx BuildGraph\\Scripts\\RunStandaloneUI.ts",
"test:standaloneAssertions": "npm run ue:uat -- BuildGraph -Script=%CD%\\BuildGraph\\ATCTests.generated.xml -Target=StandaloneAssertions",
"test:standaloneWithExceptions": "npm run ue:uat -- BuildGraph -Script=%CD%\\BuildGraph\\ATCTests.generated.xml -Target=StandaloneWithExceptions",
"test:dedicated": "npm run ue:uat -- BuildGraph -Script=%CD%\\BuildGraph\\ATCTests.generated.xml -Target=Dedicated",
"test:listen": "npm run ue:uat -- BuildGraph -Script=%CD%\\BuildGraph\\ATCTests.generated.xml -Target=Listen",
"test:PIE": "npm run ue:uat -- BuildGraph -Script=%CD%\\BuildGraph\\ATCTests.generated.xml -Target=PIE"
// For macOS/Linux
"test:ci": "npm run ue:uat -- BuildGraph -Script=\"$PWD/BuildGraph/ATCTests.generated.xml\" -Target=ATCTests",
"test:standalone": "npm run ue:uat -- BuildGraph -Script=\"$PWD/BuildGraph/ATCTests.generated.xml\" -Target=Standalone",
"test:standaloneUI": "node --import tsx BuildGraph/Scripts/RunStandaloneUI.ts",
"test:standaloneAssertions": "npm run ue:uat -- BuildGraph -Script=\"$PWD/BuildGraph/ATCTests.generated.xml\" -Target=StandaloneAssertions",
"test:standaloneWithExceptions": "npm run ue:uat -- BuildGraph -Script=\"$PWD/BuildGraph/ATCTests.generated.xml\" -Target=StandaloneWithExceptions",
"test:dedicated": "npm run ue:uat -- BuildGraph -Script=\"$PWD/BuildGraph/ATCTests.generated.xml\" -Target=Dedicated",
"test:listen": "npm run ue:uat -- BuildGraph -Script=\"$PWD/BuildGraph/ATCTests.generated.xml\" -Target=Listen",
"test:PIE": "npm run ue:uat -- BuildGraph -Script=\"$PWD/BuildGraph/ATCTests.generated.xml\" -Target=PIE"
}
}
Setup ATC
# Within `ATC_TEST_ENV`
cd TemplateProject
mkdir Plugins
cd Plugins
git clone https://github.com/MaximDevoir/ATC.git
cd ATC
npm install
Add ATC to the template project
Within TemplateProject/Source you should have two *.Target.cs files. We need a third for file for the server. You can copy
TemplateProject.Target.cs, rename it to TemplateProjectServer.Target.cs and change class and method names from TemplateProjectTarget to
TemplateProjectServerTarget and set line set Type = TargetType.Server.
- Source
-- TemplateProject.Target.cs
-- TemplateProjectEditor.Target.cs
-- TemplateProjectServer.Target.cs
We need to modify TemplateProject.Build.cs to optionally include exception handling
// Add header
using System.Linq;
// Within template project method add
bool bUseATCExceptions = Target.GlobalDefinitions.Contains("ATC_WITH_CPP_EXCEPTIONS=1");
bEnableExceptions = bUseATCExceptions;
if (bUseATCExceptions) {
PublicDefinitions.Add("ATC_WITH_CPP_EXCEPTIONS=1");
} else {
PublicDefinitions.Add("ATC_WITH_CPP_EXCEPTIONS=0");
}
Setting up the BuildGraph file.
cd TemplateProject
copy .\ATO\BuildGraph\.env.sample .env # Windows
cp ./ATO/BuildGraph/.env.sample .env # macOS / Linux
Open the .env file. The only setting that is required is ENGINE_DIR and the rest will be auto-discovered.
After setting up .env run
Finally, since we are using the Third Person Template, we need to set some settings to engine-level content in
TemplateProject/Config/DefaultEngine.ini
[/Script/EngineSettings.GameMapsSettings]
GlobalDefaultGameMode=/Script/Engine.GameModeBase
GameDefaultMap=/Engine/Maps/Templates/Template_Default.Template_Default
EditorStartupMap=/Engine/Maps/Templates/Template_Default.Template_Default
ServerDefaultMap=/Engine/Maps/Templates/Template_Default.Template_Default
+MapsToCook = (FilePath="/Engine/Maps/Templates/Template_Default")
+MapsToCook = (FilePath="/Engine/Maps/Templates/OpenWorld")
bUseSplitscreen=False
Your project should now be setup and you should run npm run test:ci. This will orchestrate all tests for each
coordinator (Standalone, Listen Server, Dedicated Server, and PIE).
Note:
npm run test:ciwill take a while the first time.
Setting up in other environments¶
This tutorial was completed on Windows, but all the tools, scripts, and auto-discovery were designed to be compatible with Linux and macOS but haven't been tested.
macOS¶
- BuildGraph's
Cooknode doesn't support macOS ( see available target platforms). You will have to instrument your own BuildGraph workflow. However, I am seeing conflicting information on whatCooksupports on macOS. As such, testing may only be available to PIE coordinator or within the editor. Please let me know if you have any information on this topic. I will update the tutorial accordingly. - Dedicated server support with platform
MacServermay not be supported.
Testing and Development Requirements¶
- Avoid compiler-specific or platform-specific code.
- All features must be compatible with macOS, Linux, and Windows.
- ATC must support Clang and MSVC. Avoid compiler-specific macros and platform-specific code.
- Tests within ATC and ATO must be platform agnostic.
- Tests within ATC should be template-agnostic. We setup using the Third Person Template. However, any resources used
should be engine-level only. Example: Use
MAP_WORLD("/Engine/Maps/Templates/OpenWorld");instead ofMAP_WORLD("/Game/Maps/ThirdPerson");. -
ATO and ATC source files need to be platform-agnostic.
-
Only use default engine-level content.
Development Requirements and Tips¶
- Avoid opening symlinked files (e.g. modifying anything in
TemplateProject/BuildGraph) and instead open the actual file. You will get accurate type inference, static analysis, and better code completion. - Dirty PIE packages preventing PIE testing? When reopening an engine-level map, you may see it as
Untitled. Reopen the engine-level map to see the correct name and prevent test execution due to dirty PIE packages. - When updating
ATCTests.template.xmlruncd TemplateProject && npx tsx BuildGraph/GenerateBuildGraphFromTemplate.tsto update your generated file.
ATO¶
- When updating ATO files, run
pnpm update -rwithinTemplateProjectso that the changes roll into your development environment. Otherwise, stale references will be used. - Before submitting a PR, run
pnpm changeto build a changeset. - Run
pnpm verifyto ensure tests, formatting, and linting pass. - Use
pnpm formatto automatically format the files.
Generating Coverage Reports¶
Add required packages to TemplateProject
Inside TemplateProject add .c8rc.json
{
"all": true,
"include": [
"ATO/packages/**/src/**/*.ts"
],
"exclude": [
"**/node_modules/**",
"**/dist/**",
"**/*.test.ts",
"BuildGraph/**"
],
"extension": [
".ts"
],
"reporter": [
"text",
"json",
"lcov"
]
}
Add scripts to TemplateProject/package.json
"coverage:ts": "c8 --all --reporter=lcov --reporter=text --reporter=json tsx buildgraph/Scripts/RunAllWithTSCodeCov.ts",
"coverage:oneReport": "node --import tsx buildgraph/MergeAllCoverage.ts",
Generate the coverage report
cd TemplateProject
cd ATO
pnpm coverage
# Back to root
cd TemplateProject
npm run coverage:ts
# Normalize the paths in each lcov report
cd TemplateProject
npm run coverage:oneReport
Uploading the Report for ATO¶
Inside a PowerShell environment
cd TemplateProject
$ProgressPreference = 'SilentlyContinue'
Invoke-WebRequest -Uri https://keybase.io/codecovsecurity/pgp_keys.asc -OutFile codecov.asc
gpg.exe --import codecov.asc
Invoke-WebRequest -Uri https://cli.codecov.io/latest/windows/codecov.exe -Outfile codecov.exe
Invoke-WebRequest -Uri https://cli.codecov.io/latest/windows/codecov.exe.SHA256SUM -Outfile codecov.exe.SHA256SUM
Invoke-WebRequest -Uri https://cli.codecov.io/latest/windows/codecov.exe.SHA256SUM.sig -Outfile codecov.exe.SHA256SUM.sig
gpg.exe --verify codecov.exe.SHA256SUM.sig codecov.exe.SHA256SUM
if (
(Compare-Object
-ReferenceObject $(($(certUtil -hashfile codecov.exe SHA256)[1], "codecov.exe") -join " ")
-DifferenceObject $(Get-Content codecov.exe.SHA256SUM)
).Length -eq 0
) { "SHASUM verified" } else { exit 1 }
Back in cmd.exe, add some environment variables
cd TemplateProject
set CODECOV_TOKEN=xxx-xxx-xxx-xxx-xxx
cd ATO
for /f %i in ('git rev-parse HEAD') do set GIT_SHA=%i
for /f %i in ('git branch --show-current') do set GIT_BRANCH=%i
cd TemplateProject
codecov.exe upload-process ^
--file "coverage/merged/lcov.info" ^
--network-root-folder ATO ^
--network-filter packages ^
--disable-search ^
--exclude "Intermediate" ^
--sha %GIT_SHA% ^
--branch %GIT_BRANCH% ^
--token %CODECOV_TOKEN% ^
--git-service github ^
--slug MaximDevoir/ATO ^
--fail-on-error
Uploading Coverage Report for ATC¶
Add a --codecov argument to every action in .generated.xml. The produced coverage reports will automatically be merged.
Add a .covlcov file under TemplateProject, this will normalize the paths for the coverage report.
Then, run every script that has the new --codecov argument.
cd TemplateProject
npm run test:standaloneWithExceptions
npm run test:standaloneAssertions
npm run test:ci
Then you need can run the unit tests to further build the coverage report.
Once you are ready to upload, move the merged atc file from coverage/atc/merged.info to inside the TemplateProject/Plugins/ATC/Source folder.