update README.md

This commit is contained in:
2026-11-04 22:25:34 +01:00
parent d589dd4d64
commit 644b860145
2 changed files with 98 additions and 65 deletions
+97 -64
View File
@@ -19,15 +19,18 @@ docker compose up -d --build
Danach im Browser öffnen: **http://localhost:8090**
Der erste Start dauert ein paar Minuten (Image-Build inkl. `npm install`). Beim
ersten Start laufen zwei Hilfs-Container: `mongo-init` initialisiert das
Replica-Set, `seed` importiert die 49 Kartendaten. Erst danach starten Backend
ersten Start laufen zwei Hilfs-Container: `al-mongo-init` initialisiert das
Replica-Set, `al-seed` importiert die 49 Kartendaten. Erst danach starten Backend
und Game-Server. Bei späteren Starts überspringt sich der Seed selbst.
**Konto anlegen:** Auf der Startseite unter „Steam“ auf **„Registrieren
[Zum Entwickeln]“** klicken, E-Mail + Passwort eingeben. Danach Charakter
erstellen und auf den Charakter klicken – man landet direkt im Spiel.
**Charakter Limits anheben** Folgendes Kommando setzt für alle existierenden Spieler das Charakter Limit auf 18.
**Charakterplätze anheben:** Folgendes Kommando setzt für alle bestehenden
Konten die Zahl der Charakterplätze (`info.slots`) auf das Maximum von 18. Neue
Konten starten weiterhin mit 5 Plätzen (mit verknüpfter Steam-ID `pid`: 8):
```sh
docker compose exec al-mongo mongosh adventureland --eval \
'db.user.updateMany({}, { $set: { "info.slots": 18 } })'
@@ -42,9 +45,10 @@ docker compose exec al-mongo mongosh adventureland --eval \
'db.user.updateOne({"info.email": "du@example.com"}, { $set: { admin: true } })'
```
Alternativ in `config/options.js` `unsecure_admin: true` setzen – dann gilt
**jeder** Besucher als Admin (`/admin/executor` erlaubt Code-Ausführung), daher
nur bei rein lokalem Zugriff sinnvoll.
Alternativ in `files/config/options.js` `unsecure_admin: true` setzen – dann
gilt **jeder** Besucher als Admin, solange `Local: true` ist
(`/admin/executor` erlaubt Code-Ausführung). Daher nur bei rein lokalem Zugriff
sinnvoll.
**GM werden (Game):** Der Web-Admin ist **kein** Game-GM. Die GM-Rolle hängt am
Charakter, nicht am Benutzerkonto: Der Game-Server prüft `player.role` bzw.
@@ -79,46 +83,49 @@ docker compose exec al-mongo mongosh adventureland --eval \
## Aufbau
| Service | Image | Aufgabe |
| ------------ | ------------------- | ------------------------------------------------------------- |
| `mongo` | `mongo:8.0` | Datenbank, läuft als Single-Node-Replica-Set `rs0` (Transaktionen) |
| `mongo-init` | `mongo:8.0` | Einmalig: `rs.initiate()` falls noch nicht geschehen |
| `seed` | `adventureland:local` | Einmalig: importiert die Kartengeometrie, überspringt sich selbst |
| `backend` | `adventureland:local` | Express-Backend, Web-Client, API – Port 8090 |
| `game` | `adventureland:local` | Socket.IO-Game-Server – Port 7192 |
| Service | Image | Aufgabe |
| -------------- | --------------------------------------------- | ------------------------------------------------------------- |
| `al-mongo` | `mongo:8.0` | Datenbank, läuft als Single-Node-Replica-Set `rs0` (Transaktionen) |
| `al-mongo-init` | `mongo:8.0` | Einmalig: `rs.initiate()` falls noch nicht geschehen |
| `al-seed` | `git.ao-it.net/gaming/adventureland:latest` | Einmalig: importiert die Kartengeometrie, überspringt sich selbst |
| `al-backend` | `git.ao-it.net/gaming/adventureland:latest` | Express-Backend, Web-Client, API – Port 8090 |
| `al-game` | `git.ao-it.net/gaming/adventureland:latest` | Socket.IO-Game-Server – Port 7192 |
Die Spieldaten (Image) werden beim Build aus drei Repositories geklont und
liegen im Container unter `/app` – es wird nichts in diesen Ordner geklont.
Das Image klont beim Build die drei Upstream-Repositories nach `/app`. Die
Submodule unter `source-repos/` sind lokale Arbeitskopien zur Kontrolle und
werden nicht ins Image kopiert; die Build-Patches liegen unter `docker/`.
## Konfiguration
`config/` wird als `/app/secretsandconfig` in die Container gemountet und
`files/config/` wird als `/app/secretsandconfig` in die Container gemountet und
ersetzt das Template aus dem Upstream-Repo:
- `config/keys.js` – MongoDB-URI, Master-Keys, Stripe/Steam/SES (alles leer bzw.
feste Entwicklungs-Defaults). Die Werte sind absichtlich stabil, damit
Sitzungen und Serverdatensätze Neustarts überleben.
- `config/options.js` – `base_url`, Ports, Serverdefinition `local`,
- `files/config/keys.js` – MongoDB-Verbindung, Master-Keys, Stripe/Steam/SES,
Discord und Apple. Externe Dienste sind leer, die Master-Keys haben lokale
Entwicklungs-Defaults. Die Werte sollten stabil bleiben: Login-Sitzungen
liegen in MongoDB und hängen nicht an den Keys, aber `SERVER_MASTER`
verschlüsselt die gespeicherten MCP-Token-Geheimnisse.
- `files/config/options.js` – `base_url`, Ports, Serverdefinition `local`,
Multi-Account-Limits.
Beide Dateien sind normale Node-Module; nach Änderungen Container neu starten:
```sh
docker compose restart backend game
docker compose restart al-backend al-game
```
> Wenn du die Ports änderst, passe sie an **drei** Stellen an:
> `docker-compose.yml` (`ports`), `config/options.js` (`port`, `local_port`,
> `address`) und `base_url` (inkl. Port).
> Wenn du die Ports änderst, passe sie in `docker-compose.yml` (`ports`) und
> `files/config/options.js` (`port`, `local_port`, `address`; `local_ip` nur bei
> Bedarf) sowie `base_url` (inkl. Port) an.
### Multi-Account-Limits
`config/options.js` steuert, wie viele Charaktere gleichzeitig online sein
`files/config/options.js` steuert, wie viele Charaktere gleichzeitig online sein
dürfen:
| Option | Bedeutung | aktuell |
| --- | --- | --- |
| `ip_limit` | Nicht-Händler pro IP (mal `ipx` einer IP-Ausnahme) | `9` |
| `ip_limit` | Nicht-Händler pro IP (multipliziert mit dem `info.limit` einer `IP_<ip>`-Ausnahme) | `9` |
| `character_limit` | Nicht-Händler pro Konto | `3` |
| `merchant_ip_limit` | Händler pro IP | `3` |
| `merchant_owner_limit` | Händler pro Konto | `1` |
@@ -128,7 +135,7 @@ Die Werte gelten beim Login (`is_player_allowed`) und im Backend-Cron
`docker/patch-multi-account-limits.js` ersetzt dabei die früher fest codierten
Grenzen (3 Nicht-Händler, 1 Händler). Mit den aktuellen Werten können z. B. drei
Konten von derselben IP jeweils drei Nicht-Händler-Charaktere online haben
(9 insgesamt); ein zehntes Nicht-Händler-Charakter bzw. ein vierter Händler wird
(9 insgesamt); ein zehnter Nicht-Händler-Charakter bzw. ein vierter Händler wird
abgewiesen. `character_limit` ist die Zahl der **gleichzeitig online** erlaubten
Charaktere, nicht die Zahl der Charakterplätze (`info.slots`); `ip_limit` ist
ebenfalls keine Slotzahl. Eine `IP_<ip>`-Ausnahme mit
@@ -156,31 +163,42 @@ docker compose exec al-mongo mongosh adventureland --eval 'db.getCollectionNames
```sh
docker compose ps
docker compose logs -f backend game
docker compose logs -f al-backend al-game
```
## Stoppen, Zurücksetzen, Sichern
```sh
docker compose stop # anhalten
docker compose down # Container entfernen, Daten behalten
docker compose down -v # ALLES löschen, inkl. Konten, Charakteren, Karten
docker compose stop # Container anhalten, Daten bleiben
docker compose down # Container entfernen, Daten in ./files/db bleiben
docker compose down -v # zusätzlich benannte/anonyme Volumes; ./files/db bleibt
```
Nach `down -v` importiert der `seed`-Container die Karten beim nächsten Start
wieder. Backup/Restore des Datenbank-Volumes:
`./files/db` ist ein Bind-Mount, kein Docker-Volume. `down -v` löscht es
deshalb **nicht**. Für einen vollständigen Reset:
```sh
docker compose stop backend game
docker run --rm -v adventureland_mongo-data:/data -v "$PWD":/backup alpine \
tar czf /backup/mongo-data-$(date +%F).tar.gz -C /data .
docker compose start backend game
docker compose down
sudo find files/db -mindepth 1 -delete
docker compose up -d
```
Restore: `docker compose down`, das Volume leeren und das Archiv
(`tar xzf mongo-data-….tar.gz -C <volume-mountpoint>`) zurückkopieren, dann
`docker compose up -d` – `seed` erkennt die vorhandenen Collections und
überspringt den Import.
Beim nächsten Start ist die Datenbank leer; `al-mongo-init` initialisiert das
Replica-Set und `al-seed` importiert die Karten neu.
Backup/Restore über `mongodump`/`mongorestore` (beide sind im MongoDB-Image):
```sh
mkdir -p backups
docker compose exec -T al-mongo mongodump --db adventureland --archive --gzip \
> backups/adventureland-$(date +%F-%H%M).dump.gz
# Restore (vorher Backend und Game stoppen):
docker compose stop al-backend al-game
docker compose exec -T al-mongo mongorestore --archive --gzip --drop \
< backups/adventureland-….dump.gz
docker compose start al-backend al-game
```
## Aktualisieren
@@ -227,7 +245,7 @@ bricht der Build ab.
Limits konfigurierbar. Upstream prüft beim Login `options.ip_limit` und
`options.character_limit`, würgt im Backend-Cron aber pauschal nach 3
Nicht-Händlern bzw. 1 Händler ab. Der Patch liest beide Stellen aus
`config/options.js` (`ip_limit`, `character_limit`, `merchant_ip_limit`,
`files/config/options.js` (`ip_limit`, `character_limit`, `merchant_ip_limit`,
`merchant_owner_limit`). Fehlt ein Anker in `node/server_functions.js` oder
`adventure_functions.js`, bricht der Build ab.
@@ -247,8 +265,10 @@ Aufbau (alle Angaben optional):
- `items`, `monsters`, `npcs`, `maps`, `sets`, `craft`, `skills`, `conditions`,
`classes`, `levels`, `upgrades`, `compounds`, `multipliers`, `titles`,
`tokens`, `dismantle`: Objekte werden tief zusammengeführt, Arrays ersetzt.
Neue IDs sind erlaubt, wenn sie eine vorhandene Grafik aus
`design/dimensions.js` nutzen (Items und Monster brauchen ein `skin`).
Neue IDs sind erlaubt, wenn sie vorhandene Grafiken wiederverwenden: Monster
aus `design/dimensions.js`, Items und Condition-Icons aus dem Sprite-Atlas
(`design/positions.js`). Items brauchen ein `skin`; bei Monstern dient die ID
als Fallback, Conditions dürfen ohne `skin` bleiben.
Neue Karten gehen nicht: ihre Geometrie liegt in MongoDB (`MP_*`).
- `drops`: `{ main: [[0.001, "item_id"]] }` hängt Zeilen an die Tabelle an.
- `gold`: überschreibt `drops.gold`, z. B. `{ base: 0.8 }`.
@@ -259,17 +279,19 @@ Aufbau (alle Angaben optional):
Beim Start loggen beide Container `custom-game: loaded ...`; neue IDs stehen
als `(new: ...)` dabei. Unbekannte Top-Level-Schlüssel, unbekannte Drop-Tabellen,
fehlende Items und fehlende Grafiken brechen den Start mit einer klaren Meldung
ab, statt das Spiel halb gepatcht zu starten.
fehlende Items und bei neuen IDs fehlende Grafiken brechen den Start mit einer
klaren Meldung ab, statt das Spiel halb gepatcht zu starten.
Enthaltenes Beispiel: Der Buff „Lone Wolf“ gibt 10× XP statt 3×. Die
Multiplikatoren liest der Game-Server aus der Condition-Definition (Patch in
`docker/patch-custom-game.js`), der Tooltip-Text kommt aus `phrases`. Die Datei
ist versioniert (`files/custom/`), `files/db` bleibt von Git ausgenommen.
Grenzen: Alles, was in `design/*.js` als Datum steht, ist überschreibbar.
Konstanten, die im Code stehen (z. B. andere Encouragement-Raten), brauchen
weiterhin einen Patch wie den für Lone Wolf. Endet ein Season-Event zur
Grenzen: Überschreibbar sind genau die oben gelisteten Design-Globals sowie
`drops`, `gold` und `phrases`. Andere `design/*.js`-Dateien (z. B.
`positions.js`, `dimensions.js`, `animations.js`) lassen sich darüber nicht
ersetzen. Konstanten, die im Code stehen (z. B. andere Encouragement-Raten),
brauchen weiterhin einen Patch wie den für Lone Wolf. Endet ein Season-Event zur
Laufzeit, können eventmodifizierte Monsterfelder auf den Stand vor der
Custom-Datei zurückgesetzt werden; dann den Game-Server neu starten.
@@ -280,7 +302,8 @@ Custom-Datei zurückgesetzt werden; dann den Game-Server neu starten.
nächsten Login auf „verifiziert“; die Verifikationsmail wird übersprungen. Der
„Not Verified“-Debuff (Gold/Glück −25 %) tritt damit nicht mehr auf. Auf
`false` gestellt, gilt wieder der Upstream-Ablauf: Im Backend-Log erscheint
`send_email error InvalidClientTokenId`, und der Verifizierungslink muss
ein SES-Fehler (bei leeren Credentials typischerweise
`send_email error InvalidClientTokenId`), und der Verifizierungslink muss
manuell geöffnet werden:
```sh
@@ -289,9 +312,16 @@ Custom-Datei zurückgesetzt werden; dann den Game-Server neu starten.
print("http://localhost:8090/ev/" + u._id + "/" + u.info.everification))'
```
Link im Browser öffnen, danach neu einloggen. Alternativ `info.verified` direkt
auf `true` setzen (siehe Admin-Befehl oben). Die `/ev`-Route bleibt in beiden
Fällen funktionsfähig.
Die URL ggf. an `base_url` aus `files/config/options.js` anpassen. Link im
Browser öffnen, danach neu einloggen. Alternativ `info.verified` direkt auf
`true` setzen:
```sh
docker compose exec al-mongo mongosh adventureland --eval \
'db.user.updateOne({"info.email": "du@example.com"}, { $set: { "info.verified": true } })'
```
Die `/ev`-Route bleibt in beiden Fällen funktionsfähig.
- **Tutorial-Belohnung (`c0`):** Jedes verifizierte Konto kann nach
abgeschlossenem Tutorial einmal `c0` abholen. Die Belohnung ist ein zufälliger
@@ -317,22 +347,25 @@ Custom-Datei zurückgesetzt werden; dann den Game-Server neu starten.
- **Der Relay in `docker/entrypoint.sh`:** Das Backend spricht Game-Server über
die Adresse an, die auch der Browser benutzt (`localhost:7192`). Innerhalb des
Backend-Containers wäre das es selbst, deshalb leitet ein kleines
`socat`-Relay `127.0.0.1:7192` an den `game`-Container weiter. Ohne das
schlagen Admin-/Server-Funktionen (`server_eval`) fehl.
Backend-Containers wäre das der Backend-Container selbst, deshalb leitet ein
kleines `socat`-Relay `127.0.0.1:7192` an den `al-game`-Container weiter. Ohne
das schlagen Admin-/Server-Funktionen (`server_eval`) fehl.
- **Lizenz/Attribution:** Die AdventureLandOnlyUse-Lizenz verlangt einen
crawlable Link auf https://adventure.land. Der ersetzt deshalb die
crawlable Link auf https://adventure.land. Der Link ersetzt deshalb die
„E-Mail, für alles“-Zeile im Login (siehe `docker/patch-attribution.js`).
Zusätzlich ist einmalig eine kurze Mail an hello@adventure.land fällig, wenn
die Instanz öffentlich erreichbar geht – das ist keine Code-Änderung.
- **Nur lokal erreichbar:** Die Ports sind standardmäßig an `127.0.0.1` des
Hosts gebunden. Für Zugriff aus dem LAN in `docker-compose.yml` die
`127.0.0.1:`-Präfixe entfernen und `base_url` (sowie ggf.
`servers.local.address`) in `config/options.js` auf die Host-IP bzw. den
Hostnamen umstellen. Der Browser verbindet sich direkt mit
`servers.local.address`.
- **Passwort-/Key-Änderungen:** `config/keys.js` enthält
- **Netzwerk/Ports:** Die Ports sind in `docker-compose.yml` derzeit an alle
Host-Interfaces gebunden (`8090:8090`, `7192:7192`). Für rein lokalen Betrieb
in `docker-compose.yml` `127.0.0.1:` voranstellen. Für Caddy auf einem anderen
Host müssen die Ports erreichbar bleiben; dann per Firewall auf die
Caddy-/LAN-Adresse beschränken. `base_url` und ggf. `servers.local.address`
in `files/config/options.js` auf die öffentliche URL bzw. den Hostnamen
umstellen. Der Browser verbindet sich direkt mit `servers.local.address`.
- **Passwort-/Key-Änderungen:** `files/config/keys.js` enthält
Entwicklungs-Platzhalter. Vor einem öffentlich erreichbaren Betrieb ersetzen.
Die Datei wird read-only gemountet; nach einer Änderung genügt ein Neustart
von `al-backend` und `al-game`, kein Rebuild. Echte Secrets nicht committen.
- **Quellcode anpassen:** Der Code liegt im Image, nicht im Host-Ordner. Für
eigene Änderungen im `Dockerfile` über die Build-Args `AL_REPO`, `AL_REF`,
`COMMON_REPO`/`COMMON_REF` bzw. `CONFIG_REPO`/`CONFIG_REF` einen Fork oder