add admin docs

This commit is contained in:
2026-11-08 02:16:03 +01:00
parent 793797dacb
commit b70127a57b
3 changed files with 635 additions and 0 deletions
+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