3D PvP Tower Defense game built with C++20. Features client-server architecture with deterministic lockstep networking, custom bit-level serialization, and an ECS using EnTT.
git clone --recurse-submodules -j8 git@github.com:robinwils/wato.git
cd wato
git lfs pull- CMake 3.29+
- Ninja
- C++20 compiler (GCC 12+, Clang 16+, or MSVC 17+)
- Git LFS
- vcpkg (included as submodule)
sudo apt-get install -y \
zip unzip curl ca-certificates git git-lfs \
build-essential ninja-build cmake pkg-config \
autoconf automake libtool \
libgl1-mesa-dev libglu1-mesa-dev libvulkan-dev \
libxinerama-dev libxcursor-dev xorg-dev libx11-dev \
libwayland-dev libxkbcommon-dev wayland-protocolsautoconf, automake, libtool are needed by vcpkg to build libsodium from source.
The libvulkan-dev, X11 and Wayland packages are only needed when building the client (ENABLE_CLIENT=ON).
Xcode Command Line Tools provide clang and system headers. Install additional tools via Homebrew:
xcode-select --install
brew install cmake ninja autoconf automake libtool- Install Visual Studio 2022 (Community or Build Tools) with the "Desktop development with C++" workload
- Install CMake 3.29+ and Ninja (or via
choco install cmake ninja) - Install the Vulkan SDK
Run builds from a Developer Command Prompt (or use vcvarsall.bat) so MSVC is on PATH.
CMake presets handle all configuration:
# Configure
cmake --preset unixlike-gcc-debug # Linux GCC
cmake --preset unixlike-clang-debug # Linux/macOS Clang
cmake --preset windows-msvc-debug # Windows MSVC
# Build
cmake --build --preset <preset-name>Append -sccache to any preset name to use sccache (e.g. unixlike-clang-debug-sccache).
Replace debug with release for optimized builds.
| Target | Description | Option |
|---|---|---|
wato |
Game client | ENABLE_CLIENT=ON |
watod |
Dedicated server | ENABLE_SERVER=ON |
wato_tests |
Test suite | ENABLE_TESTS=ON |
./out/build/<preset-name>/test/wato_testsThree services run via docker-compose.yml at the project root:
| Service | Description | Port |
|---|---|---|
watohttpd |
PocketBase backend (auth, matchmaking) | internal :8090 |
caddy |
Reverse proxy with automatic TLS | :443 |
watod |
Dedicated game server | :7777/udp |
All variables come from the shell environment (use direnv with .envrc):
| Variable | Description | Dev default |
|---|---|---|
DOMAIN |
Domain for Caddy TLS | localhost |
CADDYFILE |
Path to Caddyfile | ./Caddyfile.dev |
AUTOMIGRATE |
Auto-run PocketBase migrations | 1 |
ADMIN_EMAIL |
PocketBase admin email | admin@wato.com |
ADMIN_PASSWORD |
PocketBase admin password | Wato1234! |
PB_TOKEN |
PocketBase admin token for watod | (set in .envrc) |
direnv allow
docker compose up --build
# Verify
docker compose ps # 3 services running
curl -k https://localhost/api/health # PocketBase OK
docker compose logs watod # watod connectedIn development, Caddy generates a local CA. For the game client (running outside Docker) to connect via HTTPS:
docker compose cp caddy:/data/caddy/pki/authorities/local/root.crt /tmp/caddy-root.crt
# Linux
sudo cp /tmp/caddy-root.crt /usr/local/share/ca-certificates/caddy-local.crt
sudo update-ca-certificates
# macOS
sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain /tmp/caddy-root.crt| Dev | Prod | |
|---|---|---|
DOMAIN |
localhost |
wato.example.com |
CADDYFILE |
./Caddyfile.dev |
./Caddyfile.prod |
| TLS | Internal (self-signed) | Let's Encrypt |
AUTOMIGRATE |
1 |
(empty) |