Skip to main content

Getting Started

Prerequisites​

  • Docker (for Postgres, web apps, docs and the game server)
  • .NET 10 SDK (for local development of the web apps, which target net10.0)
  • Godot 4.7 .NET edition (for running the client)
  • Python 3 (for the contract guard, token minting and the divergence probe)

The game server targets net8.0 and its image builds the C# project and exports the Godot binary itself, so a host running only Docker needs neither Godot nor .NET installed. Running the exported binary directly instead needs the .NET 8 runtime.

Run the stack​

cp .env.example .env
# edit secrets/passwords
docker compose up -d --build
  • Player portal: http://localhost:8082
  • Admin panel: http://localhost:8081
  • Documentation: http://localhost:8083
  • Uptime monitoring: http://localhost:3001
  • PostgreSQL: localhost:5432

The default admin account is created from:

Seed__AdminEmail=admin@moondog.local
Seed__AdminPassword=ChangeMe!12345

Change these in production.

Run the game server​

The game server is behind the game profile so it can be run independently of the web apps:

docker compose --profile game build game-server
docker compose --profile game up -d game-server
docker logs -f moondog-game-server-1

It needs JWT_SECRET to match the portal's, since the portal signs tokens and the game server verifies them. If they diverge, an unset JWT_SECRET produces tokens that are all rejected with no useful error at the point of failure.

See Deployment for environment variables and hosting.

Run the example client​

Host and port come from environment variables:

export MOONDOG_HOST=127.0.0.1
export MOONDOG_PORT=7777
godot --path godot_client

A JWT is needed to authenticate — issue one from the portal, or mint one directly:

python3 scripts/mint_token.py --creds /tmp/moondog-creds.txt --out-dir /tmp/moondog-tokens
godot --path godot_client -- --token-file=/tmp/moondog-tokens/nyx.token

The client accepts --token= / --token-file= and --probe= / --probe-seconds= as command-line arguments. Host and port do not have CLI flags — they are environment variables only.

See Example Client.

Database behavior​

On startup, both web apps run Database.MigrateAsync() and seed:

  • a main server status row
  • Admin and Player roles
  • the configured admin user

Local development shortcuts​

cd Moondog.Portal && dotnet run
cd Moondog.Admin && dotnet run

Migrations are generated in Moondog.Core/Data/Migrations. To add one:

cd /root/Moondog
dotnet ef migrations add MigrationName \
--project Moondog.Core --startup-project Moondog.Portal

Working on the docs​

This site is Docusaurus, in website/, served by the docs compose service:

cd website
npm install
npm run start # local dev server with hot reload
npm run build # production build

Documentation lives in website/docs/. The sidebar is autogenerated from that directory, so a new page appears without touching sidebars.ts — but it should carry sidebar_position in its front matter to land in the right place.

Verifying the RPC contract​

The RPC surface and shared movement constants are guarded. Run this after any change to a method signature or a simulation constant:

python3 scripts/check_rpc.py --root .

A movement constant changed on one side only does not fail any RPC — it produces rubber-banding or unreachable speeds, which is much harder to notice. That is what the guard exists for.