Compare commits

...
2 Commits
Author SHA1 Message Date
anima 5e98395b5d update gitignore 2026-11-08 02:17:00 +01:00
anima b70127a57b add admin docs 2026-11-08 02:16:03 +01:00
4 changed files with 637 additions and 1 deletions
+1
View File
@@ -1,3 +1,4 @@
ai/*
files/* files/*
!files/config !files/config
!files/config/** !files/config/**
+130
View File
@@ -0,0 +1,130 @@
# Game-Server-API (`/server.api/...`)
Der Game-Server läuft separat vom Backend und lauscht lokal auf Port `7192`.
Seine Admin-Endpunkte liegen unter `/server.api/` und sind **nicht** die
öffentliche JSON-API des Backends (`/api`).
## Endpunkte
| Methode | Endpunkt | Zweck |
|---|---|---|
| `POST` | `/server.api/eval` | JavaScript im Game-Server ausführen |
| `POST` | `/server.api/cupdate` | Shells eines online Characters setzen |
| `POST` | `/server.api/shutdown` | Game-Server herunterfahren |
| `POST` | `/server.api/new_friend` | intern: Freund hinzufügen |
| `POST` | `/server.api/lost_friend` | intern: Freund entfernen |
Alle diese Endpunkte verlangen `spass` = `keys.ACCESS_MASTER`. Der Key erlaubt
beliebige Codeausführung im Game-Server und darf niemals öffentlich werden.
## `ACCESS_MASTER` lesen
```sh
cd /data/ai/gaming/adventureland
ACCESS_MASTER="$(docker compose exec -T al-game node -e \
'process.stdout.write(require("/app/secretsandconfig/keys").ACCESS_MASTER)')"
```
Den Wert nicht in Chat, Logs oder Commits schreiben.
## `/server.api/eval`
Felder:
- `spass` – `ACCESS_MASTER`
- `code` – JavaScript, wird im Game-Server ausgeführt
- `data` – JSON-String, im Code als `data` verfügbar
Der Code läuft im Modul-Scope des Game-Servers. Verfügbar sind unter anderem
`players`, `name_to_id`, `get_player(name)`, `add_item`, `resend`,
`calculate_player_stats` und `output`.
### Gold geben (live)
```sh
curl -sS -X POST http://127.0.0.1:7192/server.api/eval \
--data-urlencode "spass=$ACCESS_MASTER" \
--data-urlencode 'code=var p=get_player("CharName"); if(p){ p.gold += 100000; resend(p,"reopen+u+cid"); output={ok:true,gold:p.gold}; } else { output={ok:false,reason:"offline"}; }' \
--data-urlencode 'data={}'
```
### Item geben (live)
```sh
curl -sS -X POST http://127.0.0.1:7192/server.api/eval \
--data-urlencode "spass=$ACCESS_MASTER" \
--data-urlencode 'code=var p=get_player("CharName"); if(p){ var n=add_item(p,{name:"hpot0",q:100},{announce:false}); resend(p,"reopen+u+cid"); output={ok:true,slot:n}; } else { output={ok:false,reason:"offline"}; }' \
--data-urlencode 'data={}'
```
`add_item` prüft Inventarplatz und stapelt stackbare Items. `announce:false`
verhindert eine globale Fundmeldung.
### XP geben (live)
```sh
curl -sS -X POST http://127.0.0.1:7192/server.api/eval \
--data-urlencode "spass=$ACCESS_MASTER" \
--data-urlencode 'code=var p=get_player("CharName"); if(p){ p.xp += 100000; resend(p,"reopen"); output={ok:true,level:p.level,xp:p.xp}; } else { output={ok:false,reason:"offline"}; }' \
--data-urlencode 'data={}'
```
`resend(p,"reopen")` ruft `calculate_player_stats` auf und führt Level-Ups aus.
## `/server.api/cupdate`
Felder:
- `spass` – `ACCESS_MASTER`
- `id` – Character-Name (`player.id` ist der Name, nicht `CH_...`)
- `cash` – neuer Gesamtstand der Shells
- `ncash` – Betrag für die „received shells“-Meldung; wird **nicht** addiert
`cupdate` setzt `player.cash` auf `cash`. Es ist kein Inkrement. Deshalb zuerst
den neuen Gesamtstand in MongoDB schreiben und dann `cupdate` aufrufen.
```sh
# 1. Account-Cash erhöhen
docker compose exec al-mongo mongosh adventureland --eval \
'db.user.updateOne({"info.email":"du@example.com"}, { $inc: { cash: 1000 } })'
# 2. Neuen Gesamtstand lesen
NEW_TOTAL="$(docker compose exec -T al-mongo mongosh adventureland --quiet --eval \
'db.user.findOne({"info.email":"du@example.com"},{cash:1}).cash')"
# 3. Online-Character aktualisieren
curl -sS -X POST http://127.0.0.1:7192/server.api/cupdate \
--data-urlencode "spass=$ACCESS_MASTER" \
--data-urlencode 'id=CharName' \
--data-urlencode "cash=$NEW_TOTAL" \
--data-urlencode 'ncash=1000'
```
Ohne online Character reicht der MongoDB-Wert; beim nächsten Login wird
`user.cash` geladen.
## Wichtige Hinweise
- **Shells** sind accountweit (`user.cash`). Ein `/cupdate` ändert nur die
laufende Kopie im Game-Server; die DB muss separat aktualisiert werden.
- **Gold** ist pro Character (`character.info.gold` / `player.gold`) oder
accountweit in der Bank (`user.info.gold`).
- `eval` ist mächtig und ungefiltert. Nur lokal oder hinter einer
vertrauenswürdigen Admin-Schicht betreiben.
- `aadd_item` nicht verwenden: Es ruft `reopen()` auf, das im Node-Port nicht
definiert ist. Stattdessen `add_item` + `resend`.
- Der Game-Server speichert live geänderte Character-Daten regelmäßig. Für
dauerhafte Änderungen an Offline-Characters die MongoDB-Variante verwenden;
für laufende Characters `eval`.
- `ACCESS_MASTER` rotieren, bevor der Port öffentlich erreichbar ist. Der
Default steht in `files/config/keys.js`.
## Quellen
- `source-repos/adventureland_mongodb/node/server.js` – `server_api`-Router,
`/eval`, `/cupdate`, `/shutdown`; `add_item`, `resend`
- `source-repos/adventureland_mongodb/adventure_functions.js` –
`server_url`, `server_eval`, `server_eval_safe`, `character_eval`
- `files/config/options.js` – `api_path: "/server.api/"`, `local_port: 7192`
- `source-repos/adventureland_mongodb/README.md` – Admin-/Executor-Hinweise
+249
View File
@@ -0,0 +1,249 @@
# Docker- und MongoDB-Admin
Diese Variante arbeitet direkt auf den Containern und der MongoDB. Sie ist
nützlich für Offline-Änderungen, Recovery und Prüfungen. Für laufende
Characters ist die Game-Server-API (`docs/admin/api.md`) oder der
Admin-Executor (`docs/admin/executor.md`) meist besser geeignet.
## Stack
| Service | Aufgabe | Port |
|---|---|---|
| `al-mongo` | MongoDB mit Replica-Set `rs0` | intern `27017` |
| `al-backend` | Express-Backend, Web-Client, `/api` | `8090` |
| `al-game` | Socket.IO-Game-Server, `/server.api` | `7192` |
MongoDB ist im Compose-Setup **nicht** auf den Host veröffentlicht. Der Zugriff
läuft über `docker compose exec`.
## MongoDB-Shell
```sh
cd /data/ai/gaming/adventureland
docker compose exec al-mongo mongosh adventureland
```
Einzelnes Kommando:
```sh
docker compose exec al-mongo mongosh adventureland --eval \
'db.user.findOne({ "info.email": "du@example.com" }, { _id: 1, name: 1, cash: 1, "info.slots": 1 })'
```
## Account und Character finden
```sh
docker compose exec al-mongo mongosh adventureland --eval \
'db.user.findOne(
{ "info.email": "du@example.com" },
{ _id: 1, name: 1, cash: 1, "info.gold": 1, "info.slots": 1, "info.characters": 1 }
)'
```
```sh
docker compose exec al-mongo mongosh adventureland --eval \
'db.character.findOne(
{ "info.name": "CharName" },
{ _id: 1, owner: 1, level: 1, xp: 1, online: 1, server: 1, "info.gold": 1, "info.items": 1 }
)'
```
## Shells geben
Shells sind accountweit und liegen in `user.cash`.
```sh
docker compose exec al-mongo mongosh adventureland --eval \
'db.user.updateOne(
{ "info.email": "du@example.com" },
{ $inc: { cash: 1000 } }
)'
```
Danach neu einloggen oder den neuen Stand per `/server.api/cupdate` an online
Characters schicken (siehe `docs/admin/api.md`).
## Bank-Gold geben
Bank-Gold ist accountweit und liegt in `user.info.gold`.
```sh
docker compose exec al-mongo mongosh adventureland --eval \
'db.user.updateOne(
{ "info.email": "du@example.com" },
{ $inc: { "info.gold": 100000 } }
)'
```
Neu einloggen bzw. Bank betreten. Ist der Character bereits in der Bank, wird
`player.user.gold` live nicht automatisch aktualisiert.
## Character-Gold geben
Character-Gold liegt in `character.info.gold`.
> Nur bearbeiten, solange der Character **offline** ist (`online: false`,
> `server: ""`). Sonst überschreibt der Game-Server den Wert beim nächsten Sync.
```sh
docker compose exec al-mongo mongosh adventureland --eval \
'db.character.updateOne(
{ "info.name": "CharName" },
{ $inc: { "info.gold": 100000 } }
)'
```
## Item ins Character-Inventar
Item-Namen stehen in `design/items.js` (`G.items`), zum Beispiel `hpot0`,
`mpot0`, `helmet`, `shoes`. Das Inventar fasst maximal 42 Einträge.
```sh
docker compose exec al-mongo mongosh adventureland --eval \
'db.character.updateOne(
{ "info.name": "CharName" },
{ $push: { "info.items": { name: "hpot0", q: 100 } } }
)'
```
Das ist ein roher Push: kein Stacking, keine Inventarprüfung. Für laufende
Characters `add_item` per Game-Server-API verwenden.
## Item in die Bank
Bank-Packs liegen in `user.info.items0` bis `user.info.items47`.
```sh
docker compose exec al-mongo mongosh adventureland --eval \
'db.user.updateOne(
{ "info.email": "du@example.com" },
{ $push: { "info.items0": { name: "hpot0", q: 100 } } }
)'
```
Pack-Größe beachten (bis 42). Neu einloggen bzw. Bank betreten.
## Charakterplätze setzen
```sh
docker compose exec al-mongo mongosh adventureland --eval \
'db.user.updateOne(
{ "info.email": "du@example.com" },
{ $set: { "info.slots": 18 } }
)'
```
Maximum 18. Der Wert wird bei jeder Anfrage gelesen; kein Neustart nötig.
## Admin setzen
```sh
docker compose exec al-mongo mongosh adventureland --eval \
'db.user.updateOne(
{ "info.email": "du@example.com" },
{ $set: { admin: true } }
)'
```
Danach neu einloggen. Der Admin-Executor ist dann unter
`http://localhost:8090/admin/executor` erreichbar.
## GM setzen
GM ist eine Character-Rolle, kein Web-Admin.
```sh
docker compose exec al-mongo mongosh adventureland --eval \
'db.character.updateOne(
{ "info.name": "CharName" },
{ $set: { role: "gm", "info.p.role": "gm" } }
)'
```
Danach den Character neu einloggen.
## Keys lesen
`ACCESS_MASTER`, `BOT_MASTER` und `SERVER_MASTER` stehen in
`files/config/keys.js` und sind im Container unter
`/app/secretsandconfig/keys.js` gemountet.
```sh
docker compose exec -T al-game node -e \
'console.log(require("/app/secretsandconfig/keys").ACCESS_MASTER)'
```
Den Wert nicht in Chat, Logs oder Commits schreiben. Vor öffentlichem Betrieb
rotieren und `al-backend` sowie `al-game` neu starten.
## Backup und Restore
Backup:
```sh
docker compose exec -T al-mongo mongodump \
--db adventureland --archive=/tmp/al-backup.gz
docker compose cp al-mongo:/tmp/al-backup.gz ./al-backup.gz
```
Restore (destruktiv, überschreibt die aktuelle DB):
```sh
docker compose cp ./al-backup.gz al-mongo:/tmp/al-backup.gz
docker compose exec -T al-mongo mongorestore \
--archive=/tmp/al-backup.gz --drop
```
Vor jedem Restore den aktuellen Stand sichern. `--drop` entfernt vorhandene
Collections.
## Logs und Status
```sh
docker compose ps
docker compose logs -f al-backend
docker compose logs -f al-game
docker compose logs -f al-mongo
```
## Neustart und Rebuild
Nach Änderungen an `files/config/`:
```sh
docker compose restart al-backend al-game
```
Nach Änderungen am Image oder an Build-Patches:
```sh
docker compose build
docker compose up -d
```
Nach Änderungen an `files/custom/game.js` reicht in der Regel ein Neustart der
beiden App-Container.
## Sicherheit
- MongoDB ist nicht auf dem Host veröffentlicht; nicht zusätzlich exposen.
- `ACCESS_MASTER` erlaubt Codeausführung im Game-Server. Nicht öffentlich
erreichbar machen.
- `al-backend` und `al-game` sind im Compose-Setup an alle Host-Interfaces
gebunden. Für öffentlichen Betrieb Firewall/Caddy davorsetzen.
- Default-Keys aus `files/config/keys.js` vor öffentlichem Zugriff ersetzen.
- Offline-Characters vor DB-Änderungen ausloggen; sonst überschreibt der
Game-Server die Werte.
## Quellen
- `docker-compose.yml` – Services, Ports, Volumes
- `Dockerfile` – Build-Patches und Runtime
- `files/config/keys.js` – Admin-Keys
- `files/config/options.js` – Ports, Serverdefinition, Limits
- `source-repos/adventureland_mongodb/adventure_functions.js` –
`character_to_info`, `update_character`, `update_user_data`, `user_to_server`
- `source-repos/adventureland_mongodb/api.js` – `create_character_api`
+256
View File
@@ -0,0 +1,256 @@
# Admin-Executor (`/admin/executor`)
Der Admin-Executor ist die bequemste Variante für administrative Änderungen.
Er führt **Backend-JavaScript** aus – nicht Game-Server-JavaScript – und hat
Zugriff auf die Backend-Funktionen und die MongoDB.
## Zugang
Voraussetzung ist `user.admin = true` oder `Local: true` zusammen mit
`unsecure_admin: true` in `files/config/options.js`.
`user.admin` direkt setzen:
```sh
cd /data/ai/gaming/adventureland
docker compose exec al-mongo mongosh adventureland --eval \
'db.user.updateOne({"info.email": "du@example.com"}, { $set: { admin: true } })'
```
Danach im Browser neu einloggen und öffnen:
```text
http://localhost:8090/admin/executor
```
Der frühere Weg `/admin/make/user/admin` ist im Code deaktiviert
(`common_engine/admin.js` enthält ein frühes `return;`).
> **Sicherheit:** Der Executor erlaubt beliebige Codeausführung im Backend.
> `unsecure_admin: true` macht jeden lokalen Besucher zum Admin. Niemals
> zusammen mit öffentlichem Zugriff verwenden.
## Was im Executor verfügbar ist
Neben normalem JavaScript stehen unter anderem zur Verfügung:
- `req` – der Express-Request des Executor-Aufrufs
- `output` – wird als `[OUTPUT]` an die Oberfläche zurückgegeben
- `inspect` – wird als JSON zurückgegeben
- `console.log()` / `console.error()` – landen in `[LOGS]`
- `db` – MongoDB-Handle
- `get_user_by_email(email)`, `get_character(name)`, `get(id)`
- `save(entity)`, `tx()`, `tx_get()`, `tx_save()`
- `update_characters(user, reason, name, shells)`
- `character_eval(character, code, data)`
- `server_eval(server, code, data)`, `server_eval_safe(server, code, data)`
- `keys` – die Server-Keys, inklusive `ACCESS_MASTER`
`character_eval` führt Code auf dem Game-Server aus. Dort heißt der laufende
Character `player`. Ist der Character offline, passiert nichts.
## Beispiele
### Shells geben (accountweit)
Shells liegen in `user.cash`. `update_characters` schickt den neuen Stand an
alle online Characters.
```js
var u = await get_user_by_email("du@example.com");
if (!u) throw new Error("user not found");
var amount = 1000;
u.cash = (u.cash || 0) + amount;
await save(u);
await update_characters(u, "", "", amount);
output = { email: u.info.email, cash: u.cash };
```
### Bank-Gold geben (accountweit)
Bank-Gold liegt in `user.info.gold`.
```js
var u = await get_user_by_email("du@example.com");
if (!u) throw new Error("user not found");
var amount = 100000;
u.info.gold = (u.info.gold || 0) + amount;
await save(u);
output = { bank_gold: u.info.gold };
```
Danach neu einloggen bzw. die Bank betreten. Steht der Character bereits in der
Bank, ist `player.user.gold` live veraltet; dann zusätzlich per
`character_eval` aktualisieren oder neu einloggen.
### Character-Gold geben
Character-Gold liegt in `character.info.gold`.
```js
var ch = await get_character("CharName");
if (!ch) throw new Error("character not found");
var amount = 100000;
if (ch.online || ch.server) {
await character_eval(
ch,
"player.gold += " + amount + "; resend(player, 'reopen+u+cid');"
);
output = { character: ch.info.name, mode: "live" };
} else {
ch.info.gold = (ch.info.gold || 0) + amount;
await save(ch);
output = { character: ch.info.name, gold: ch.info.gold, mode: "db" };
}
```
### Item geben
Live nutzt `add_item` Stacking und Inventarprüfung. Offline wird direkt in
`character.info.items` geschrieben; dort gibt es keine Prüfung.
```js
var ch = await get_character("CharName");
if (!ch) throw new Error("character not found");
var item = { name: "hpot0", q: 100 };
if (ch.online || ch.server) {
await character_eval(
ch,
"add_item(player, " + JSON.stringify(item) + ", {announce:false});" +
"resend(player, 'reopen+u+cid');"
);
output = { character: ch.info.name, item: item, mode: "live" };
} else {
ch.info.items = ch.info.items || [];
ch.info.items.push(item);
await save(ch);
output = { character: ch.info.name, item: item, mode: "db" };
}
```
Item-Namen stehen in `design/items.js` (`G.items`), zum Beispiel `hpot0`,
`mpot0`, `helmet`, `shoes`. Das Inventar fasst maximal 42 Einträge.
### XP geben
```js
var ch = await get_character("CharName");
if (!ch) throw new Error("character not found");
var amount = 100000;
if (ch.online || ch.server) {
await character_eval(
ch,
"player.xp += " + amount + "; resend(player, 'reopen');"
);
output = { character: ch.info.name, mode: "live" };
} else {
ch.xp = (ch.xp || 0) + amount;
ch.info.xp = ch.xp;
await save(ch);
output = { character: ch.info.name, xp: ch.xp, mode: "db" };
}
```
`resend(player, "reopen")` ruft `calculate_player_stats` auf und führt
Level-Ups aus. Offline passiert das beim nächsten Login.
### Item in die Bank legen
Bank-Packs liegen in `user.info.items0` bis `user.info.items47`.
```js
var u = await get_user_by_email("du@example.com");
if (!u) throw new Error("user not found");
u.info.items0 = u.info.items0 || [];
u.info.items0.push({ name: "hpot0", q: 100 });
await save(u);
output = { pack: "items0", count: u.info.items0.length };
```
Danach neu einloggen bzw. die Bank betreten. Pack-Größe beachten (bis 42).
### Charakterplätze setzen
```js
var u = await get_user_by_email("du@example.com");
if (!u) throw new Error("user not found");
u.info.slots = 18;
await save(u);
output = { slots: u.info.slots };
```
`info.slots` wird bei jeder Anfrage gelesen; ein Neustart ist nicht nötig.
Maximum sind 18.
### Account verifizieren
```js
var u = await get_user_by_email("du@example.com");
if (!u) throw new Error("user not found");
u.info.verified = true;
await save(u);
output = { verified: true };
```
### GM setzen
GM ist eine Character-Rolle, kein Web-Admin.
```js
var ch = await get_character("CharName");
if (!ch) throw new Error("character not found");
ch.role = "gm";
ch.info.p = ch.info.p || {};
ch.info.p.role = "gm";
await save(ch);
output = { character: ch.info.name, role: "gm" };
```
Danach den Character neu einloggen.
## Grenzen
- Der Executor ist **kein** Satz benannter Befehle wie `/give shells`.
Es ist eine Codebox.
- Er läuft im Backend. Für Funktionen, die es nur im Game-Server gibt
(`players`, `add_item`, `resend`), `character_eval` bzw. `server_eval`
verwenden.
- Offline-Änderungen an `character.info.*` werden beim nächsten Sync des
Game-Servers überschrieben, wenn der Character online ist. Dann live
arbeiten oder den Character vorher ausloggen.
- `aadd_item` aus `node/server.js` nicht verwenden: Es ruft eine nicht
definierte `reopen()`-Funktion auf. Stattdessen `add_item(...)` +
`resend(...)`.
## Quellen
- `source-repos/common_engine/admin.js` – `/admin/executor`, `execute_api`,
`is_admin`
- `source-repos/common_engine/htmls/admin_executor.html` – Oberfläche
- `source-repos/adventureland_mongodb/adventure_functions.js` –
`get_user_by_email`, `get_character`, `update_characters`,
`character_eval`, `server_eval`, `update_character`, `update_user_data`,
`user_to_server`
- `source-repos/adventureland_mongodb/node/server.js` – `add_item`,
`calculate_player_stats`, `resend`
- `source-repos/adventureland_mongodb/design/items.js` – Item-Definitionen