Quake III Arena
You can play Quake III Arena in SCION! We maintain a fork of ioquake3 that can use SCION connections. In order to play you will need to build C bindings to SCION and our fork. Additionally you need the commercial game assets. If you do not have a copy of Quake III, you can use the assets from the game’s demo instead.
PAN Bindings: https://github.com/lschulz/pan-bindings
ioq3-scion: https://github.com/lschulz/ioq3-scion
SCION Game Servers: If you set it up like described below, Quake will find SCION-enabled public game servers automatically and show them in the server browser. To enable others to find your server, read Running a Server.
Build from Source
We support ioq3-scion on Linux (Ubuntu 24.04.1 LTS) and Windows. Compiling for other operating systems may work, but is untested.
Installation Script
We provide a script for building and installing ioq3-scion in one command on Ubuntu.
Usage: ./install-ioq3-scion [OPTION]...
Installs ioq3-scion
--basepath DIR Set the binary installation directory
--homepath DIR Set the user directory (must be writeable by user)
--assets DIR Path to Quake 3 assets
--tmp DIR Temporary build directory
--keep Keep the build directory when finished
-h, --help Print this text
For example:
./install-ioq3-scion --basepath /opt/games/quake3 --homepath ~/.q3a
See below for a description of what basepath and homepath mean. By default the script will
install the Quake 3 demo. To install the full game, specify the path to the installation folder as
--assets <path>.
Linux
Install the dependencies (example for Ubuntu).
sudo apt-get update
sudo apt-get install -y build-essential cmake git libsdl2-dev libsodium-dev libasio-dev
A Go compiler is needed to compile SCION code. Install the latest version as described in the
instructions. PAN has only a narrow range of supported Go versions
with every release. Check the README in scion-apps
and pan-bindings to learn which version should work. If
you need an older version than you just installed, install it with the go command.
go install golang.org/dl/go1.22.9@latest
go1.22.9 download # make sure ~/go/bin/ is in PATH
Include -D GO_BINARY=$(which go1.22.8) (with the correct version) in the cmake configuration
command below to build with the correct Go.
Build PAN and the C bindings.
git clone https://github.com/lschulz/pan-bindings.git
cd pan-bindings
mkdir -p build/release
cmake -D CMAKE_BUILD_TYPE=Release -D BUILD_SHARED_LIBS=ON -B build/release
cmake --build build/release
For the next step, the C compiler has to be able to find the compiled PAN C libraries and headers.
The easiest way to accomplish that is by installing them in /usr/local.
sudo cmake --install build/release
sudo ldconfig
If you want to install in a different directory, specify it in the cmake configuration step as
-DCMAKE_INSTALL_PREFIX=<path> or in the install command with --prefix <path>. The
configuration above will also install C++ bindings and example programs. If you do not want to build
them, you can run cmake with -D BUILD_CPP=OFF -D BUILD_EXAMPLES=OFF. When you run Quake,
libpan.so must be in the library search path.
Now you can clone and build ioq3-scion.
git clone https://github.com/lschulz/ioq3-scion.git
cd ioq3-scion
make release -j $(nproc)
You can make local changes to the Makefile (e.g., to set the header and library paths in CFLAGS) by
creating a file called Makefile.local next to Makefile. The binaries should be in
build/release-linux-x86_64. Continue with installing the game assets as described in
Installation.
Windows
On Windows, the PAN C bindings and ioq3-scion must be compiled with MinGW. Start by installing MSYS2. Using an MSYS2 UCRT64 environment, the following packets are required:
pacman -Sy
pacman -S \
mingw-w64-ucrt-x86_64-gcc \
mingw-w64-ucrt-x86_64-cmake \
mingw-w64-ucrt-x86_64-ninja \
mingw-w64-ucrt-x86_64-asio \
mingw-w64-ucrt-x86_64-libsodium \
mingw-w64-ucrt-x86_64-SDL2 \
make git
A Go compiler is needed to compile SCION code. Install the latest version as described in the instructions. The same note about supported Go version as in the Linux build process applies.
Clone the PAN bindings, and build in an MSYS2 UCRT64 shell.
git clone https://github.com/lschulz/pan-bindings.git
cd pan-bindings
mkdir build
cmake -D BUILD_SHARED_LIBS=ON -D GO_BINARY="$PROGRAMFILES/Go/bin/go.exe" -G 'Ninja Multi-Config' -B build
cmake --build build --config Release
Install libpan and its headers.
cmake --install build --config Release --prefix /usr/local
Clone and build ioq3-scion in MSYS2.
git clone https://github.com/lschulz/ioq3-scion.git
cd ioq3-scion
make release -j $(nproc)
You may need to modify some make variables for the build to succeed by creating a file called
Makefile.local next to Makefile. For example:
CFLAGS=-I/usr/local/include -L/usr/local/lib
USE_CURL=0
Installation
Quake III uses two important search paths: basepath and homepath. basepath is set to the
working directory from which Quake was started by default. homepath is usually ~/.q3a on Linux
and %appdata%\Quake3 on Windows. basepath must be writeable. Both paths can be overridden on
the command line like so +set fs_basepath <basepath> +set fs_homepath <homepath>. For a simple
setup, you can install all required files in homepath.
Create your homepath directory and copy baseq3/vm from ioq3-scion/build/release-linux-x86_64
to homepath keeping the directory structure intact. If you have the assets for Team Arena, do the
same with missionpack/vm. Copy the binaries from ioq3-scion/build/release-linux-x86_64 to
homepath or to a separate basepath (or leave them where they are to use the build directory as
basepath). For example:
cd ioq3-scion
homepath=~/.q3a
mkdir "${homepath}"
mkdir "${homepath}/baseq3"
mkdir "${homepath}/missionpack"
cp -r baseq3/vm "${homepath}/baseq3"
cp -r missionpack/vm "${homepath}/missionpack"
cp ioq* *.so "${homepath}"
If you are on Windows, copy libpan.dll from the PAN bindings build directory and
libsodium-26.dll from MSYS2 to basepath.
Obtaining the Game Assets
In order to run the game you need the original games assets (3d models, textures, animations, levels, sound effects, etc.). You can copy them from the original games installation directory or download the original game’s demo for free (with limited content).
Full Game
Copy the .pk3 files from the original game’s baseq3 and missionpack directories
into the same diretories in ioq3-scion’s homepath. By providing the .qvm files in the vm
subdirectories we override the code from the original game while keeping the remaining assets.
Demo
The Quake III Arena demo and game patches can still be found online (look for archives of ftp.idsoftware.com). You need the following files with the given SHA256 hashes:
64dee3f69b6e792d1da4fe0ac98fedc7eb1e37ea1027fb609a9fadd06150a4ec linuxq3ademo-1.11-6.x86.gz.sh
c36132c5556b35e01950f1e9c646235033a5130f87ad776ba2bc7becf4f4f186 linuxq3apoint-1.32b-3.x86.run
Extract the .pk3 from the installers you downloaded.
tail +165 linuxq3ademo-1.11-6.x86.gz.sh | tar -zx demoq3/pak0.pk3
tail +356 linuxq3apoint-1.32b-3.x86.run | tar -zx baseq3
Configuration
Create an autoexec.cfg in ${homepath}/baseq3:
set com_hunkmegs 256 // increase memory pool size
snaps 40 // snapshots per second requested from server
// enable network
// bitmask of 1=IPv4, 2=IPv6, 4=Prio6, 8=NoMcast, 16=SCION
set net_enabled 19 // set 16 for SCION only
// PAN often uses the wrong source address, set them explicitly
set net_scion x.y.z.w // SET TO YOUR PUBLIC IP
set net_scion_port 31796 // MUST BE DIFFERENT FROM net_port AND net_port6
// optional: configure IP addresses and ports for non-SCION connections
set net_ip 0.0.0.0
set net_port 27960
set net_ip6 ::0
set net_port6 27960
// bind voice-chat push-to-talk to the q key
bind q "+voiprecord"
// optional: list of keys that open the console
set cl_consoleKeys ~ ` 0x7e 0x60 F12
// if set to 0 commands are recognized without a slash
set con_autochat 1
// use ANSI escape codes in terminal
com_ansiColor 1
// bind SCION path selection to page up and page down key
bind PGDN "nextpath"
bind PGUP "prevpath"
// master servers
set sv_master1 "141.44.25.150:27950"
set sv_master2 "[71-2:0:4a,141.44.25.150]:31795"
set sv_master3 ""
set sv_master4 ""
set sv_master5 ""
net_scion_port should be set to a port from the dispatched_ports range of your SCION AS.
Usually that means 31000-32767. Prefer the lower end of the range as the upper end is used for
ephemeral ports.
Directory Structure
You should now have to following directory structure.
Linux
~/.q3a
├── baseq3
│ ├── autoexec.cfg
│ ├── pak0.pk3
│ ├── pak1.pk3
│ ├── pak2.pk3
│ ├── pak3.pk3
│ ├── pak4.pk3
│ ├── pak5.pk3
│ ├── pak6.pk3
│ ├── pak7.pk3
│ ├── pak8.pk3
│ └── vm
│ ├── cgame.qvm
│ ├── qagame.qvm
│ └── ui.qvm
└── missionpack
├── pak0.pk3
├── pak1.pk3
├── pak2.pk3
├── pak3.pk3
└── vm
├── cgame.qvm
├── qagame.qvm
└── ui.qvm
You may also want to copy ioquake3.x86_64, ioq3ded.x86_64 and the shared libraries into
~/.ioq3 or store them in /opt/games/quake3.
Windows
%APPDATA%\Quake3
| ioq3ded.x86_64.exe
| ioquake3.x86_64.exe
| libpan.dll
| libsodium-26.dll
| renderer_opengl1_x86_64.dll
| renderer_opengl2_x86_64.dll
| SDL264.dll
+---baseq3
| | autoexec.cfg
| | pak0.pk3
| | pak1.pk3
| | pak2.pk3
| | pak3.pk3
| | pak4.pk3
| | pak5.pk3
| | pak6.pk3
| | pak7.pk3
| | pak8.pk3
| \---vm
| cgame.qvm
| qagame.qvm
| ui.qvm
\---missionpack
| pak0.pk3
| pak1.pk3
| pak2.pk3
| pak3.pk3
\---vm
cgame.qvm
qagame.qvm
ui.qvm
Running the Game
Start the game by running ${basepath}/ioquake3.x86_64 or ${basepath}/ioquake3.x86_64.exe.
If you are not using the default homepath, set the path on the command line:
${basepath}/ioquake3.x86_64 +set +set fs_homepath ${homepath}
Running a Server
You can run a server directly from the main menu by selecting “Multiplayer” and “Create”. If you set “dedicated” to Internet, the server will be registered at the master server(s) so others on the Internet can find it.
To run a dedicated server on a headless machine, create a file called server.cfg (the exact name
is not important) with your servers settings in ${homepath}/baseq3. The server will still parse
autoexec.cfg, so there is no need to repeat commands.
Example configuration for a server:
set sv_hostname "Server Name"
set g_motd "Server message of the day"
set sv_maxclients 16 // maximum number of clients
set sv_pure 0 // allow clients to use different file versions
set sv_fps 40 // server tick rate (default is 20)
set sv_voip 1 // enable voice chat
set g_log "" // disable logging
// free for all
set g_gametype 0
set timelimit 10
set fraglimit 15
set g_forcerespawn 0
// bots
set bot_enable 1
set bot_nochat 1
set g_spskill 2
set bot_minplayers 4
// map rotation
set map1 "map q3dm1; set nextmap vstr map2"
set map2 "map q3dm7; set nextmap vstr map3"
set map3 "map q3dm17; set nextmap vstr map4"
set map4 "map q3tourney2; set nextmap vstr map1"
vstr map1
rehashbans // reload the banlist
Start the dedicated server as ioq3ded.x86_64 +exec server.cfg +set dedicated 2. Setting
dedicated to 2 causes the server to register itself at the master server(s).
Docker
It might also be useful to run the server in a Docker container. A simple Dockerfile could look like this:
FROM ubuntu:24.04
WORKDIR /root
RUN apt-get update && apt-get -y upgrade && apt-get -y install sudo git wget
RUN git clone https://gist.github.com/193f985977c4b4228cd501b589092130.git installer
RUN chmod +x installer/install-ioq3-scion && installer/install-ioq3-scion --scion-ip 0.0.0.0
ENTRYPOINT ["/opt/games/quake3/ioq3ded.x86_64"]
Build and run the image as follows, assuming autoexec.cfg, server.cfg, and secret_key
are in the current working directory. You can initialize secret_key to an empty file. We store
the key file outside the container to ensure clients can recognize the server even after the
container has been deleted and recreated.
docker build -t ioq3-scion .
docker run -it --network=host --env SCION_DAEMON_ADDRESS=127.0.0.1:30255 \
-v $PWD/autoexec.cfg:/root/.q3a/baseq3/autoexec.cfg:ro \
-v $PWD/server.cfg:/root/.q3a/baseq3/server.cfg:ro \
-v $PWD/secret_key:/root/.q3a/secret_key \
ioq3-scion \
+exec server.cfg +set dedicated 2
The same can also be achieved with docker compose.
services:
ioq3-scion:
build: .
container_name: ioq3-scion
stdin_open: true
tty: true
environment:
- SCION_DAEMON_ADDRESS=127.0.0.1:30255
command: ["+exec", "server.cfg", "+set", "dedicated", "2"]
network_mode: "host"
volumes:
- type: bind
source: ./autoexec.cfg
target: /root/.q3a/baseq3/autoexec.cfg
read_only: true
- type: bind
source: ./server.cfg
target: /root/.q3a/baseq3/server.cfg
read_only: true
- type: bind
source: ./secret_key
target: /root/.q3a/secret_key
Bring the container up with docker compose -d. In order to interact with the console, you can
attach to the container with docker attach ioq3-scion. When attached Ctrl-c stops the container.
In order to detach and keep the container running use Ctrl-p + Ctrl-q.
Useful Cvars and Commands
Quake 3 and ioquake have many console variables and commands controlling everything from rendering
to keybindings. Below you find a list of some useful variables and commands that can be used in the
the drop-down console or added to the autoexec.cfg file. Commands entered in the drop-down
console must usually be prefixed with /, except if you set con_autochat to 0.
Client Commands
Command:
clientinfoPrint client state information.Command:
serverstatusGet status information from server.Command:
ping [-4|-6|-scion4|-scion6] serverPing a server via IPv4/IPv6/SCION-IPv4/SCION-IPv6.Command:
connect [-4|-6|-scion4|-scion6] serverConnect to a server.Command:
disconnectDisconnect from server.Command:
localserversScan for servers on LAN using multicast.Command:
globalservers <master# 0-5> <protocol> [keywords]Contact master server(s). Server 0 queries all servers. Protocol should be 68 for Quake 3. Keywords are sent to the master server for filtering (e.g.,empty,full,scion).Command:
showpathsList available network paths to the server.Command:
selectpathSelect a path by specifying a unique prefix of the 8 digit hash value of every path listed byshowpaths.Command:
nextpathSelect the next path in the list. Useful for binding to a key.Command:
prevpathSelect the previous path in the list. Useful for binding to a key.Command:
toggleToggle the value of a binary variable. Useful for keybindings.Cvar:
cg_drawtimerDraw the elapsed round time.Cvar:
cg_lagometerDraw lag-o-meter.
Server Commands
Command:
statusShow server status.Command:
showclientpathsPrint last path to connected SCION clients.Command:
clearclientpathsClear the remote host cache of the server’s path selector.Command:
heartbeatSend heartbeat to master servers.Command:
kick <player name>Kick a player from the server.Command:
banaddr (ip[/subnet] | clientnum [subnet])Band an IP or ISD-ASN,IP.Command:
exceptaddr (ip[/subnet] | clientnum [subnet])Exclude an IP or ISD-ASN,IP from a ban.Command:
bandel (ip[/subnet] | num)Remove a ban.Command:
exceptdel (ip[/subnet] | num)Remove an exception.Command:
listbansList bans and excpetions.
Network
Command:
net_restartReopen all sockets. Necessary to apply changes in IP addresses or ports.Cvar:
net_oobTimeoutOut-of-band messages to servers the client is not currently connected to require separate SCION connections. This cvar controls how long these connections are kept active after the last time they have been used. Value in milliseconds.Cvar:
net_safeMSSMaximum segment size (MSS) assumed for SCION paths that don’t have MTU metadata. Paths that do have MTU metadata and would have a MSS below this value are ignored. The MSS is the MTU minus the overhead due to IP, SCION, and UDP headers. The default value is 1000 bytes. Setting a lower value increases the tolerance for long SCION paths with low MTUs, but will lead to more packet fragmentation.Cvar:
sv_encryptionandcl_encryptionenable encryption on the server and on the client, respectively. Possible values:0Disable encryption.1Enable encryption, but fall back to unencrypted connection if opposite site does not support/enable encryption.2Enable encryption, connection fails if other side does not support/enable encryption.
Rendering
Cvar:
cg_fovHorizontal FOV in degrees.Cvar:
cg_drawfpsDraw frames per second counter.Cvar:
cl_rendereropengl1oropengl2(apply withvid_restart).Command:
vid_restartRestart video output.
Rate and Timing Settings
Server
Cvar:
sv_fpsControls server refresh rate. Sets the maximum value forsnapsthat clients can request. (Default: 20)Cvar:
sv_minRate,sv_maxRateMinimum and maximum rate the client settingrateis clamped to. Disabled when zero. (Default: 0, 0)
Client
Command:
snapsSnapshots per second requested by the client. Part of the userinfo string sent to the server. (Default: 20)Command:
rateMaximum bitrate the client can accept in byte/s. Part of the userinfo string sent to the server. (Default: 25000)Cvar:
cl_maxpacketsLimits the maximum number of packets per second from client to server. (Range: 15-125) (Default: 30)Cvar:
cl_packetdupIn how many additional packets the same usercmd is included in to counteract packet loss. (Range: 0-5) (Default: 1)Cvar:
com_maxfpsFramerate limit. (Default: 85)Cvar:
cl_timenudgeTime offset for snapshot interpolation. Negative values will extrapolate more for better responsiveness, positive values add more latency for better smoothness to counter jitter. (Range -30 to 30) (Default: 0)Cvar:
r_displayrefreshFull-screen refresh rate. Passed to SDL. (Default: 0)Cvar:
r_swapinterval0 disables vsync, 1 enables vsync. Passed to SDL. (Default: 0)