> For the complete documentation index, see [llms.txt](https://docs.edgegap.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.edgegap.com/docs/sample-projects/godot/nakama-fish-game.md).

# Nakama Fish Game

Host Heroic Labs' Fish Game for Godot 4 on Edgegap dedicated servers, started by the Nakama matchmaker through the nakama-edgegap plugin.

Explore how to host Godot projects on Edgegap with [Nakama](https://heroiclabs.com) matchmaking, using techniques from the [Fish Game](https://github.com/heroiclabs/fishgame-godot) 2-4 player sample by Heroic Labs, ported to Godot 4.

Upstream ran each match on one player's machine, relayed through Nakama. In [our fork](https://github.com/edgegap/fishgame-godot) no player hosts - Nakama keeps accounts, matchmaking and leaderboard, and starts a headless Godot server near matched players through [Edgegap Fleet Manager for Nakama](https://github.com/edgegap/nakama-edgegap).

This sample shows:

* **Godot 4.7** game with GDScript, run as a headless dedicated server over ENet on UDP port `7777`,
* **Nakama 3.39** with a Go module - matchmaker hook starts one deployment per match, and sends each player the server address once the server reports `READY`,
* **server-authoritative match rules** - server decides hits, deaths, pickups, spawns, rounds and the winner,
* **player checks** - server only admits players with a valid Nakama session who were matched to it,
* **server-to-server leaderboard** - server records the win in an authoritative Nakama leaderboard, which players can't write to,
* **server self-stop** - server asks Nakama to stop its deployment when the match is over.

{% hint style="success" %}
See [Deploy from Nakama](/docs/tools-and-integrations/deploy-from-nakama.md) for an overview of Nakama integration, and [EDGEGAP.md](https://github.com/edgegap/fishgame-godot/blob/main/EDGEGAP.md) in the sample repository for the full list of Edgegap files, tests and known limits.
{% endhint %}

{% hint style="warning" %}
Most of the game's art and music are licensed [CC BY-NC 4.0](https://creativecommons.org/licenses/by-nc/4.0/) by Heroic Labs (see `assets/LICENSE.txt`). The code is Apache 2.0.
{% endhint %}

## ✔️ Preparation

Before we start, you will need:

* Fish Game Sample project (modified for Edgegap) - [download from GitHub](https://github.com/edgegap/fishgame-godot),
* Godot 4.7 (4.3 or later should work) - [download from official source](https://godotengine.org/),
* Edgegap API token - for Nakama only,
* public HTTPS address for Nakama - Edgegap servers call Nakama back, so `localhost` won't work (a tunnel is enough for testing, see step 2).

<details>

<summary><a href="https://www.docker.com/products/docker-desktop/">Install Docker Desktop (or Docker CLI)</a></summary>

* [Install Docker Desktop from the official source](https://www.docker.com/products/docker-desktop/) (no account required).
* Restart your computer after completing the installation.

</details>

## ⚡ Deploy and Connect

### 1. Build the Server Image

☑️ To get started, you'll need to [create a free account with Edgegap](https://app.edgegap.com/auth/register). No credit card required.

☑️ Find your [Container Registry](/learn/advanced-features/edgegap-container-registry.md#getting-your-credentials) project name and credentials, then log in with `docker login registry.edgegap.com`.

☑️ Build and push your server image from the repository root. `server/Dockerfile` exports the "Linux Server" preset to a `.pck` and runs it with headless Godot:

{% code collapsedlinecount="10" %}

```bash
docker build --platform linux/amd64 -f server/Dockerfile -t registry.edgegap.com/<project>/fishgame-godot:1.0.0 .
docker push registry.edgegap.com/<project>/fishgame-godot:1.0.0
```

{% endcode %}

{% hint style="danger" %}
:x: **DO NOT - overwrite existing tags or use `latest` tag** - this will deploy an outdated cache.\
:white\_check\_mark: **DO - always increase your version tag** and deploy the new build.
{% endhint %}

☑️ [Create an application](https://app.edgegap.com/application-management/applications/list) named `fishgame-godot`, and a version named `1.0.0` with:

* image `<project>/fishgame-godot`, tag `1.0.0`, with your registry username and token,
* resources 0.5 vCPU and 512 MB memory,
* [port](/learn/orchestration/application-and-versions.md#port-mapping) `7777`, named `gameport`, protocol **UDP**,
* [max duration](/learn/orchestration/application-and-versions.md#safety-guardrails) 30 minutes (the server also stops itself).

Your server needs no environment variables of its own - Fleet Manager passes it Nakama's callback URLs on every deployment.

✅ You may now proceed to the next step.

### 2. Run Nakama

☑️ Copy `nakama/.env.example` to `nakama/.env` and fill in:

* `EDGEGAP_API_TOKEN` - your Edgegap API token, with its `token` prefix,
* `EDGEGAP_APPLICATION`, `INITIAL_EDGEGAP_VERSION`, `EDGEGAP_PORT_NAME` - application, version and port name from step 1,
* `NAKAMA_ACCESS_URL` - Nakama's public HTTPS address,
* `NAKAMA_HTTP_KEY` - a long random string, game servers receive it inside their callback URLs.

{% hint style="danger" %}
Your Edgegap API token gives access to your whole organization. Keep it in `nakama/.env` and Nakama only. **Never put it in the game client or server image.**
{% endhint %}

☑️ For testing on your machine, start a Cloudflare quick tunnel to give Nakama a public address. Put the printed `https://….trycloudflare.com` URL in `NAKAMA_ACCESS_URL`:

{% code collapsedlinecount="10" %}

```bash
docker run -d --name fishgame-tunnel cloudflare/cloudflared:latest tunnel --no-autoupdate --url http://host.docker.internal:7350
```

{% endcode %}

☑️ Start Nakama and Postgres. `nakama/Dockerfile` builds the Go module with Edgegap Fleet Manager into Nakama:

{% code collapsedlinecount="10" %}

```bash
docker compose -p fishgame -f nakama/docker-compose.yml up -d --build
```

{% endcode %}

✅ You may now proceed to the next step.

### 3. Play

☑️ Point your game to Nakama, either by editing defaults at the top of `autoload/Online.gd`, or on the command line:

{% code collapsedlinecount="10" %}

```bash
godot --path . -- --nakama-host=your-tunnel.trycloudflare.com --nakama-port=443 --nakama-scheme=https
```

{% endcode %}

{% hint style="info" %}
Players should reach Nakama through its public address too. Nakama stores the IP each player signs in from, and Edgegap uses these IPs to [deploy close to players](/learn/orchestration/deployments.md#server-placement).
{% endhint %}

☑️ Start two game instances, pick **Online**, create an account in each, and press **Match** in both.

After "Match found! Starting a game server...", both players land on the ready screen of the same Edgegap server. The first fish to win 5 rounds wins the match and gets +1 on the leaderboard.

🙌 Congratulations on your first matchmade Deployment on Edgegap!

## 🔄 Match Lifecycle

1. Players sign in to Nakama with email, then submit a matchmaker ticket.
2. When Nakama matches them, the module's matchmaker hook asks Fleet Manager to create a deployment, with matched user IDs in its metadata.
3. Game server boots, listens on UDP `7777`, and sends `READY` to Nakama with its own IP and external port. Nakama notifies each matched player with the server address.
4. Players connect over ENet. Server checks each player's Nakama session with Nakama's `/v2/account` and only accepts players matched to it. It reports connected user IDs to Nakama every 5 seconds when they change.
5. When the match is won, server calls `report_match_result` RPC server-to-server with Nakama's HTTP key, and Nakama adds the win to `fish_game_wins` leaderboard. The RPC refuses player sessions, and counts each deployment only once.
6. Server sends `STOP`, and Nakama stops the deployment. It also stops when fewer than 2 players are left mid-match, when everyone leaves, when nobody joins within 60 seconds, or after 20 minutes.

Each player still owns their fish's movement, as in upstream. Moving movement to the server with client prediction is the next step for a competitive game.

See [Deploy from Nakama](/docs/tools-and-integrations/deploy-from-nakama.md), [Matchmaking](/learn/matchmaking.md) and [Deployments](/learn/orchestration/deployments.md) to learn more.

## ⚠️ Known Issues

* HTML5 export can't play online - ENet uses UDP, which browsers can't use. A web build would need Godot's WebSocket peer and a [WS port with TLS Upgrade](/learn/orchestration/deployments.md#websockets-ws-and-secure-websockets-wss).
