Files
adventureland/README.md
T
anima d589dd4d64
build container / build (push) Failing after 2s
fix rewards and bypass ip limits
2026-11-02 02:49:23 +01:00

16 KiB
Raw Blame History

Adventure Land – Docker-Setup

Lokale Installation des Adventure Land MongoDB Ports mit Docker Compose: MongoDB, Backend (Web-Client) und Game-Server, inklusive automatischem Datenbank-Seed.

Voraussetzungen

  • Docker Engine mit Compose v2 (docker compose version)
  • Ports 8090 (Web) und 7192 (Game-Server) müssen auf dem Host frei sein
  • Internetzugang beim ersten Build (die Quellcode-Repos werden geklont, Node-Pakete installiert)

Start

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 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.

docker compose exec al-mongo mongosh adventureland --eval \
  'db.user.updateMany({}, { $set: { "info.slots": 18 } })'

Admin werden: Die Admin-Seiten (/admin/executor, /admin/renderer) sind standardmäßig gesperrt. is_admin in common/admin.js prüft das Feld user.admin; setzen lässt es sich direkt in MongoDB:

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.

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. player.p.role auf "gm". Charakter vorher ausloggen, dann in MongoDB setzen:

docker compose exec al-mongo mongosh adventureland --eval \
  'db.character.updateOne(
    { name: "CharName" },
    { $set: { role: "gm", "info.p.role": "gm" } }
  )'

Danach den Charakter neu einloggen. role: "gm" gibt die In-Game-GM-Rechte und ist unabhängig von user.admin (Web-Admin). Wer nur von den Multi-Account- Limits ausgenommen werden will, aber keine GM-Rechte braucht, setzt stattdessen info.p.free:

docker compose exec al-mongo mongosh adventureland --eval \
  'db.character.updateOne(
    { name: "CharName" },
    { $set: { "info.p.free": true } }
  )'
Feld Wirkung
user.admin: true Web-Admin: /admin/executor, /admin/renderer; keine In-Game-GM-Rechte
Charakter role: "gm" In-Game-GM; wird außerdem von den Limits ausgenommen
Charakter info.p.free: true nur Limit-Ausnahme; keine GM-Rechte

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

Die Spieldaten (Image) werden beim Build aus drei Repositories geklont und liegen im Container unter /app – es wird nichts in diesen Ordner geklont.

Konfiguration

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, Multi-Account-Limits.

Beide Dateien sind normale Node-Module; nach Änderungen Container neu starten:

docker compose restart backend 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).

Multi-Account-Limits

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
character_limit Nicht-Händler pro Konto 3
merchant_ip_limit Händler pro IP 3
merchant_owner_limit Händler pro Konto 1

Die Werte gelten beim Login (is_player_allowed) und im Backend-Cron (enforce_limitations). Der Patch 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 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 { exception: true, info: { limit: N } } multipliziert nur ip_limit für Nicht-Händler, nicht die Händler-Limits. Nicht-freie Händler zählen; p.free und GM-Charaktere fallen heraus. merchant_owner_limit: 1 erlaubt einen Händler pro Konto; Admin- und User-Händler auf getrennten Konten sind damit kein Problem. Sollen beide auf demselben Konto laufen, merchant_owner_limit auf 2 setzen.

Hinter einem Reverse-Proxy (Caddy) muss die echte Client-IP als X-Forwarded-For ankommen. Sonst sieht der Server nur die Proxy-/Docker-IP und alle Spieler teilen sich dieselben Limits. Siehe deploy/Caddyfile.example.

MongoDB-Zugriff

Die Datenbank ist nur im Compose-Netz erreichbar. Für einen Blick hinein:

docker compose exec al-mongo mongosh adventureland --eval 'db.getCollectionNames()'

Logs & Status

docker compose ps
docker compose logs -f backend game

Stoppen, Zurücksetzen, Sichern

docker compose stop            # anhalten
docker compose down            # Container entfernen, Daten behalten
docker compose down -v         # ALLES löschen, inkl. Konten, Charakteren, Karten

Nach down -v importiert der seed-Container die Karten beim nächsten Start wieder. Backup/Restore des Datenbank-Volumes:

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

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.

Aktualisieren

Das Image klont beim Build den jeweils aktuellen main-Branch:

docker compose build --pull --no-cache
docker compose up -d

Ein Neu-Seed ist nicht nötig; bestehende Konten, Charaktere und Karten bleiben erhalten.

Der Build wendet zusätzlich den lokalen Patch aus docker/patch-drm-check.js an (siehe „Gut zu wissen“). Verschiebt Upstream die betroffene Zeile in node/server.js, bricht der Build mit einer klaren Meldung ab – dann das Suchmuster im Skript anpassen.

Ebenso ersetzt docker/patch-attribution.js die Hilfe-Zeile im Login („E-Mail, für alles“) durch einen Self-Host-Hinweis mit Link auf https://adventure.land. Die Texte liegen in docker/attribution/en.js und docker/attribution/de.json, alle anderen Sprachen fallen auf Englisch zurück. Auch dieser Patch bricht den Build ab, wenn die Upstream-Vorlage nicht mehr passt.

docker/patch-custom-game.js hakt den Loader für files/custom/game.js in Backend und Game-Server ein und macht die Lone-Wolf-Raten datengetrieben (siehe „Spieldaten anpassen“). Fehlt ein Anker, bricht der Build ebenfalls ab.

docker/patch-auto-verify-email.js markiert bei aktivem options.auto_verify_email neue Konten beim Signup und bestehende beim nächsten Login als verifiziert und überspringt die Verifikationsmail. Ohne den Schalter bleibt das Upstream-Verhalten unverändert. Auch dieser Patch bricht den Build ab, wenn ein Anker in api.js fehlt.

docker/patch-tutorial-reward-auth.js macht die auth_id-Pflicht der Tutorial- und Klassenbelohnungen abschaltbar. Bei options.tutorial_reward_requires_auth_id: false können auch reine Web-Accounts c0 und Klassenbelohnungen abholen; fehlt die Option oder steht sie auf true, gilt das Upstream-Verhalten. Fehlt einer der beiden Anker in node/server.js, bricht der Build ab.

docker/patch-multi-account-limits.js macht die Händler- und Nicht-Händler- 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, merchant_owner_limit). Fehlt ein Anker in node/server_functions.js oder adventure_functions.js, bricht der Build ab.

Spieldaten anpassen (files/custom/game.js)

Werte bestehender Elemente und neue Elemente lassen sich ohne Quelltextänderung über files/custom/game.js setzen. Die Datei wird in beide Spielcontainer als /app/custom/game.js gemountet und beim Start gelesen; Änderungen brauchen nur einen Neustart, keinen Rebuild:

docker compose restart al-backend al-game

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 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 }.
  • phrases: überschreibt Anzeigetexte. "*" gilt für alle Sprachen, ein Sprachcode (de, en, ...) hat Vorrang. Nötig, wenn sich Zahlen in einem Tooltip ändern.
  • apply(game): Funktion für Sonderfälle, läuft nach dem Zusammenführen.

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.

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 Laufzeit, können eventmodifizierte Monsterfelder auf den Stand vor der Custom-Datei zurückgesetzt werden; dann den Game-Server neu starten.

Gut zu wissen

  • E-Mail-Verifizierung: AWS SES ist nicht konfiguriert. Deshalb setzt options.auto_verify_email: true neue Konten beim Signup und bestehende beim 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 manuell geöffnet werden:

    docker compose exec al-mongo mongosh --quiet adventureland --eval \
      'db.user.find({}, {"info.email": 1, "info.everification": 1}).forEach((u) =>
        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.

  • Tutorial-Belohnung (c0): Jedes verifizierte Konto kann nach abgeschlossenem Tutorial einmal c0 abholen. Die Belohnung ist ein zufälliger kosmetischer Look aus dem cosmo0-Pool (über 100 Varianten). Der Game-Server prüft player.verified und normalerweise player.auth_id (Steam/MAS, node/server.js, ureward/creward). Bei reinen Web-Accounts ist auth_id leer; deshalb steht options.tutorial_reward_requires_auth_id hier auf false, damit auch sie die Belohnung erhalten. Auf true gestellt, gilt wieder die Upstream-Sperre für Web-Accounts. Die alten Klassen-Belohnungen (creward) nutzen denselben Schalter, sind aber in design/classes.js auskommentiert und werden vom Client nicht angefragt; Hardcore-Rewards gelten nur auf dem Hardcore-Server.

  • „Authorization Failure“ (Gold/Glück −85 %, XP −20 %): Das ist die DRM-Prüfung des Game-Servers. Sie verlangt für jedes Konto ab 2019 eine Steam-/Mac-App-Store-ID, die nur der jeweilige Game-Client ausstellen kann. Eine selbst gehostete Instanz kann das nicht: Steam-Tickets brauchen den privaten Publisher-Key, und die Steam-Anmeldung im Browser setzt diese ID nicht. Deshalb patcht das Image die Prüfung über docker/patch-drm-check.js und Compose setzt AL_DRM_CHECK: "0"; nach dem nächsten Login verschwindet die Bedingung. Mit AL_DRM_CHECK: "1" (oder ohne die Variable) gilt wieder das Upstream-Verhalten.

  • 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.

  • Lizenz/Attribution: Die AdventureLandOnlyUse-Lizenz verlangt einen crawlable Link auf https://adventure.land. Der 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 Entwicklungs-Platzhalter. Vor einem öffentlich erreichbaren Betrieb ersetzen.

  • 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 Branch eintragen und mit docker compose build neu bauen. Alternativ in docker-compose.override.yml einen Checkout nach /app mounten und dabei node_modules aus dem Image in ein eigenes Volume auslagern.

docker-builder

setup

Set Repo / Org vars:

  • AOIT_GIT_URL
  • NTFY_HOST
  • NTFY_USER
  • NTFY_CHANNEL

Set Repo / Org Secrets

  • TOKEN_SVC_CI (for download repo)
  • TOKEN_SVC_DOCKER (for upload container)
  • REGISTRY_USER (for upload container)
  • NTFY_PASS