In case you didn’t notice, we’re building a game. The game of course runs “without any bugs 🫣” in the Unreal Editor, but it is necessary to test the game on various local devices as quickly as possible. We could use our CI/CD, but that is a touch slower: it runs all the tests, it does all the work. Especially in tuning and debugging, it is useful to have a faster & isolated local build and release environment.
Here is how we are using the default WSL Ubuntu instance with:
- Unreal Engine Linux
https://www.unrealengine.com/en-US/linux - Steamworks SDK
https://partner.steamgames.com/downloads/list - nginx
- Powershell
Additionally, you will need a local-depot-configured Steam [Deck] client
Configure WSL
First, download Unreal Engine and Steamworks SDK, uncompress to /opt
, make sure both directories are writable for the current user.
/opt$ ls -la
drwxr-xr-x 7 you root 4096 Jul 29 10:52 steamworks_sdk
drwxr-xr-x 6 you root 4096 Jun 24 15:09 ue5_4
Unreal Engine need C++ development tools and other packages, install
sudo apt install libatk1.0-0
sudo apt install libatk-bridge2.0-0
sudo apt install libxkbcommon-x11-0
sudo apt install libgbm-dev
sudo apt install libpangocairo-1.0-0
sudo apt install libasound2
With the unreal pre-requisites done, move on to install Powershell:
# Install pre-requisite packages.
sudo apt-get install -y wget apt-transport-https software-properties-common
# Get the version of Ubuntu
source /etc/os-release
# Download the Microsoft repository keys
wget -q https://packages.microsoft.com/config/ubuntu/$VERSION_ID/packages-microsoft-prod.deb
# Register the Microsoft repository keys
sudo dpkg -i packages-microsoft-prod.deb
# Delete the Microsoft repository keys file
rm packages-microsoft-prod.deb
# Update the list of packages after we added packages.microsoft.com
sudo apt-get update
# Install PowerShell
sudo apt-get install -y powershell
Next, install i386 packages for Steamworks SDK.
sudo dpkg --add-architecture i386
To host Steam Local Content Server, you will also need first install nginx.
sudo apt install nginx
After installing, configure the nginx by creating /etc/nginx/sites-available/steam
with the following content
server {
listen 80;
listen [::]:80;
root /var/www/steam;
index index.html index.htm;
server_name _;
client_max_body_size 2000M;
autoindex on;
}
Then create symbolic link to this file in /etc/nginx/sites-enabled
:
/etc/nginx/sites-available$ ln -s ../sites-available/steam steam
Make sure nginx
is running sudo service nginx start
.
Finally, create the working directories for build files and the content server in /var
; these directories must be writable for your current user.
/var$
drwxr-xr-x 3 you root 4096 Jul 29 13:38 ue5_4
drwxr-xr-x 2 you root 4096 Jul 30 10:00 steam
drwxr-xr-x 3 you root 4096 Jul 29 13:02 www/steam
Verify prerequisites
If everything is installed as expected, these commands should work:
# Powershell
pwsh
... exit
# Steam C
/opt/steamworks_sdk/tools/ContentBuilder/builder_linux/steamcmd.sh
... login <username> <password>
... < <steam-verify-code>
... exit
Configure WSL host
To allow Steam Deck [on your local network] to access the Steam depot on WSL, you will need to add port forwarding to the WSL instance. On the Windows host, run
~ >
sudo netsh interface portproxy add v4tov4
listenport=80
listenaddress=0.0.0.0
connectport=80
connectaddress=(wsl hostname -I)
Additionally, make sure the firewall allows connections to port 80 [from non-public networks]. On another computer, verify that you can access the local depot.
Configure Steam [Deck]
For the Steam client to know where to look for your game, you’ll need to create the file steam_dev.cfg
in the same directory that contains the Steam executable with the following content:
@LocalContentServer ...dreamonastick.com
- Either the server IP or server hostname can be used.
- If you need to specify another port then 80, it must be
ip:port
in quotes, e.g."192.168.12.34:1234"
- Don’t add
http://
in front, HTTPS is not supported - Save this file, ensuring it is readable by the Steam user [on Steam OS, the
deck
user] in
For Windows:C:\Program Files (x86)\Steam\
For macOS:Steam.app/contents/macOS/
For Linux or Steam OS:~/.local/share/Steam/
Build
To build KOPI, we copy [or clone] its source code, then run
KopiNeo$
dos2unix ./Build.ps1 ; ./Build.ps1 -Target Development
Optionally replacing the -Target
parameter with Shipping
if desired. If you do not want to use up another Perforce workspace, and wish to treat the Linux source code as a read-only clone of the Windows directory, you can enable source code synchronisation with the Windows host by adding the file KopNeo/.wslsource
with one line specifying the WSL host mount where the “source-of-truth” source code lives, for example
/mnt/d/Games/KopiNeo/
Then add -Sync
parameter to Build.ps1
:
KopiNeo$
dos2unix ./Build.ps1 ; ./Build.ps1 -Sync -Target Development
Run build, verifying that the output indicates success
KopiNeo$
dos2unix ./Build.ps1 ; ./Build.ps1 -Sync -Target Development
...
##teamcity[message text='|[ |] UAT: |[RAW|] Stage command time: 20.39 s' status='NORMAL' timestamp='2024-07-30T09:58:30.000']
##teamcity[message text='|[ |] UAT: |[RAW|] ********** STAGE COMMAND COMPLETED **********' status='NORMAL' timestamp='2024-07-30T09:58:30.000']
##teamcity[message text='|[ |] UAT: |[RAW|] ********** PACKAGE COMMAND STARTED **********' status='NORMAL' timestamp='2024-07-30T09:58:30.000']
##teamcity[message text='|[ |] UAT: |[RAW|] Package command time: 0.00 s' status='NORMAL' timestamp='2024-07-30T09:58:30.000']
##teamcity[message text='|[ |] UAT: |[RAW|] ********** PACKAGE COMMAND COMPLETED **********' status='NORMAL' timestamp='2024-07-30T09:58:30.000']
##teamcity[message text='|[ |] UAT: |[RAW|] ********** ARCHIVE COMMAND STARTED **********' status='NORMAL' timestamp='2024-07-30T09:58:30.000']
##teamcity[message text='|[ |] UAT: |[RAW|] Archiving to /var/ue5_4' status='NORMAL' timestamp='2024-07-30T09:58:30.000']
##teamcity[message text='|[ |] UAT: |[RAW|] Archive command time: 6.98 s' status='NORMAL' timestamp='2024-07-30T09:58:30.000']
##teamcity[message text='|[ |] UAT: |[RAW|] ********** ARCHIVE COMMAND COMPLETED **********' status='NORMAL' timestamp='2024-07-30T09:58:30.000']
##teamcity[message text='|[ |] UAT: |[RAW|] BuildCookRun time: 82.20 s' status='NORMAL' timestamp='2024-07-30T09:58:30.000']
##teamcity[message text='|[ |] UAT: |[RAW|] BUILD SUCCESSFUL' status='NORMAL' timestamp='2024-07-30T09:58:30.000']
##teamcity[message text='|[ |] UAT: |[RAW|] AutomationTool executed for 0h 1m 22s' status='NORMAL' timestamp='2024-07-30T09:58:30.000']
##teamcity[message text='|[ |] UAT: |[RAW|] AutomationTool exiting with ExitCode=0 (Success)' status='NORMAL' timestamp='2024-07-30T09:58:30.000']
##teamcity[message text='|[*|] CI : Skipping tests in Development.' status='NORMAL' timestamp='0001-01-01T00:00:00.000']
The /var/ue5_4
directory should contain the newly built binaries:
/var/ue5_4$
du -h
873M ./Linux/Kopi/Content/Paks
873M ./Linux/Kopi/Content
536M ./Linux/Kopi/Binaries/Linux
536M ./Linux/Kopi/Binaries
1.4G ./Linux/Kopi
260K ./Linux/Engine/Content/Renderer
5.2M ./Linux/Engine/Content/SlateDebug/Fonts
5.2M ./Linux/Engine/Content/SlateDebug
5.5M ./Linux/Engine/Content
188K ./Linux/Engine/Extras/GPUDumpViewer
192K ./Linux/Engine/Extras
2.0G ./Linux/Engine/Binaries/ThirdParty/Vulkan/Linux
2.0G ./Linux/Engine/Binaries/ThirdParty/Vulkan
23M ./Linux/Engine/Binaries/ThirdParty/CEF3/Linux/Resources/locales
41M ./Linux/Engine/Binaries/ThirdParty/CEF3/Linux/Resources
13M ./Linux/Engine/Binaries/ThirdParty/CEF3/Linux/swiftshader
1.2G ./Linux/Engine/Binaries/ThirdParty/CEF3/Linux
1.2G ./Linux/Engine/Binaries/ThirdParty/CEF3
9.3M ./Linux/Engine/Binaries/ThirdParty/MsQuic/v220/linux
9.3M ./Linux/Engine/Binaries/ThirdParty/MsQuic/v220
9.3M ./Linux/Engine/Binaries/ThirdParty/MsQuic
412K ./Linux/Engine/Binaries/ThirdParty/Steamworks/Steamv157/x86_64-unknown-linux-gnu
416K ./Linux/Engine/Binaries/ThirdParty/Steamworks/Steamv157
420K ./Linux/Engine/Binaries/ThirdParty/Steamworks
3.2G ./Linux/Engine/Binaries/ThirdParty
9.6M ./Linux/Engine/Binaries/Linux
3.2G ./Linux/Engine/Binaries
3.2G ./Linux/Engine
4.6G ./Linux
Publish
Use the Steamworks SDK to publish the build to the local depot. First make sure that your Steamworks user has the privileges to publish and edit metadata, then run
$ /opt/steamworks_sdk/tools/ContentBuilder/builder_linux/steamcmd.sh
Steam> login user password
... Steam Verify CODE: ABC123
Steam> run_app_build -preview ~/Games/KopiNeo/Platforms/Steam/app_build_2909960.vdf
Optionally replacing ~/Games/KopiNeo
with the directory where you cloned or copied the KopiNeo source code to.
Once completed, you should see the new build appearing at https://partner.steamgames.com/apps/builds/$app-id, and the Steam clients should automatically download the latest version [from the local depot].
Common Traps
- Steam ContentBuilder fails with “ERROR”:
– verify that the depot and app IDs are correct and verify that changes are published on Steamworks. - Steam Deck fails to download the newly published game:
– Verify that thesteam_dev.cfg
is in the correct location and readable by thedeck
user.
– Verify that nginx is serving the right content and that it is accessible from another computer; if not, verifynetsh interface portproxy show all
and verify firewall allows incoming connection
– Restart Steam Deck
Leave a Reply