# 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