Files
2026-11-08 02:16:03 +01:00

257 lines
7.1 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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