MIDGARDAudhumbla 0.7

Kapitel 2: Werkzeuge im Midgard MUD

Jetzt wird’s praktisch: Du erstellst deine erste LPC-Datei, lädst sie als Objekt, erzeugst einen Clone und testest alles Schritt für Schritt – aber korrekt für das Midgard MUD: mit der Lupe.c (Lens/Stack-Tool) und dem MGtool (Xtool).

Weiter zu Kapitel 3

Als Nächstes: Datentypen, Variablen und einfache Logik.

2.1 Ziel dieses Kapitels

Nach diesem Kapitel kannst du:

  • eine neue .c-Datei anlegen und sauber strukturieren
  • verstehen, was Masterobjekt und Clone sind
  • ein Objekt laden und klonen
  • Änderungen zuverlässig aktivieren (Update/Reload)
  • erste Tests durchführen: Funktionen aufrufen, Ergebnisse prüfen
  • die zwei wichtigsten Werkzeugwelten unterscheiden: Lupe.c vs. MGtool

Wir machen alles in kleinen Schritten. Du musst nicht „alles können“ – aber du brauchst einen stabilen Workflow.

2.2 Die zwei wichtigsten Werkzeuge: Lupe.c & MGtool

Lupe.c (Lens-Objekt): Stack-basiert

Die Lupe ist ein Objekt, das dir eine Sammlung von Befehlen gibt, um Objekte zu laden, zu klonen, im Stack zu halten und Funktionen darauf aufzurufen. Das Herzstück ist ein Stack: Manche Befehle pushen Objekte drauf, andere poppen sie wieder runter und arbeiten damit.

Wichtig für Anfänger:

  • Du kannst mehrere Lupe-Kommandos in einer Zeile schreiben (durch Leerzeichen getrennt).
  • Die Anzahl der Leerzeichen ist egal.
  • Wenn ein Argument Leerzeichen oder Punkte enthält, musst du es in "...", '...' oder |...| setzen.
Lupe: Notation (Merken!)

<filename>  kann sein:
  /pfad/objekt          (absolut)
  ~/work/objekt         (relativ zu deinem Home)
  ~name/work/objekt     (Home eines anderen Magiers)

Wenn der Name Punkte oder Leerzeichen hat:
  me."bag 2" inv
  me.'bag 2' inv
  me.|bag 2| inv
        

MGtool (Xtool): Kommandos mit x...

Das MGtool ist ein mächtiges Werkzeugpaket mit vielen Befehlen wie xload, xclone, xupdate, xcall, xlook, xgrep usw. Es hat außerdem eine History/Quicktype-Funktion (sehr praktisch, sobald du öfter testest).

MGtool: schnelle Orientierung

xhelp
xman xload
xman xclone
xman xupdate
xman xcall
        

In diesem Kurs nutzen wir beide Tools – aber so, dass du nie durcheinanderkommst: Lupe ist super für „Objekt auf den Stack → untersuchen → Funktion testen“. MGtool ist super für „Alltagsarbeit“ (laden, klonen, updaten, suchen, Skripten).

2.3 Vorbereitung: Arbeitsordner & Dateiname

Wir arbeiten in einem klaren Übungsordner. Falls du ihn noch nicht hast:

Arbeitsordner anlegen

cd
mkdir work
cd work
pwd
        

Achte auf einfache Dateinamen: Kleinbuchstaben, Zahlen, Unterstrich. Wir nehmen: hello.c.

2.4 Masterobjekt & Clone – die eine Sache, die du wirklich verstehen musst

Eine LPC-Datei ist erst einmal nur Text. Wenn der Driver sie lädt, entsteht ein Objekt im Speicher: das Masterobjekt. Wenn du daraus ein „Exemplar“ brauchst, erzeugst du einen Clone.

Merkschema

~/work/hello.c            = Datei (Quelltext)
hello (master)            = geladener Bauplan im Speicher
hello#12345               = Clone (ein Exemplar)
hello#12346               = Clone (noch ein Exemplar)
        

Der typische Anfängerfehler ist: „Ich habe die Datei geändert, aber mein Clone macht noch das Alte.“ Das ist normal – denn der Clone ist schon im Speicher. Lösung: Update/Reload oder neu klonen.

2.5 Deine erste Datei: hello.c

Wir bauen ein Minimalobjekt, das zwei Dinge kann: es initialisiert sich und es liefert eine Testausgabe. Zusätzlich bauen wir eine Debug-Abfrage ein, damit du jederzeit prüfen kannst, ob du wirklich die neue Version testest.

~/work/hello.c (Startversion)

#pragma strict_types

int Inited;
int CreateCount;

void create()
{
  Inited = 1;
  CreateCount++;
}

int query_inited()
{
  return Inited;
}

int query_create_count()
{
  return CreateCount;
}

string hello()
{
  return "Hallo! Dein erstes Objekt lebt.\n";
}
        

Speichern. Fertig. Jetzt testen wir – erst mit der Lupe (Stack), dann mit dem MGtool (X-Kommandos).

2.6 Testen mit der Lupe.c (Stack-Workflow)

Die Lupe arbeitet mit einem Stack. Du „pushst“ ein Objekt auf den Stack und kannst dann Aktionen darauf ausführen. Hier sind die wichtigsten Befehle für den Start:

  • me – pusht dich selbst auf den Stack
  • here – pusht den Raum, in dem du bist
  • ob <file> – lädt und pusht das Objekt (Masterobjekt)
  • new <file> – klont und pusht (und bewegt den Clone in dein Inventory)
  • = – zeigt das Top-of-Stack (TOS)
  • info – detaillierte Infos zum TOS
  • stk – zeigt den ganzen Stack
  • [<function>] – ruft eine Funktion im TOS auf
  • make – zerstört TOS und baut es aus der Datei neu (Update)

Schritt 1: Masterobjekt laden und anschauen

Lupe: hello laden → anzeigen → Infos

ob ~/work/hello
=
info
stk
        

Du solltest jetzt sehen, dass das Objekt auf dem Stack liegt.

Schritt 2: Funktionen aufrufen (die echten „Tests“)

Lupe: Funktionen im Top-of-Stack aufrufen

ob ~/work/hello [query_inited]
ob ~/work/hello [hello]
ob ~/work/hello [query_create_count]
        

Erwartung:

  • query_inited1
  • hello → dein Text
  • query_create_count → beim Laden typischerweise 1 (bei erneutem Neuaufbau kann sich das ändern)

Schritt 3: Clone erzeugen (damit du ein Exemplar im Inventory hast)

Lupe: Clone erzeugen (landet im Inventory)

new ~/work/hello
        

Jetzt liegt ein Clone in deinem Inventory. (Je nach MUD-Befehl z.B. i/inv anzeigen.)

Schritt 4: Den Clone auf den Stack holen und testen

Der Trick bei der Lupe ist: Du kannst aus einem bekannten Objekt (z.B. du selbst) Dinge „auswählen“.

Lupe: dein Inventory anzeigen

me inv
        

Wenn dein neuer Clone z.B. der 4. Gegenstand im Inventory ist, kannst du ihn so auswählen:

Lupe: 4. Objekt aus deinem Inventory auswählen und Funktion rufen

me .4 [hello]
        

Falls du nicht sicher bist, welches Objekt welche Nummer hat: nutze me inv und/oder info auf dem ausgewählten Objekt.

2.7 Änderungen übernehmen (Update richtig machen)

Jetzt kommt der wichtigste Praxispart. Änderst du den Text in hello(), musst du dafür sorgen, dass dein Testobjekt im Speicher wirklich neu gebaut wird.

Variante A: Masterobjekt neu bauen (Lupe: make)

make zerstört das Top-of-Stack-Objekt und baut es aus der Datei neu. Für Räume ist das extrem praktisch; für Lernobjekte ebenso.

Lupe: Master laden → update

ob ~/work/hello
make
[hello]
        

Variante B: Neuen Clone erzeugen

Wenn du einen Clone testest, ist der einfachste Weg oft: alten Clone ignorieren, neuen Clone erzeugen.

Lupe: nach Änderung neu klonen

new ~/work/hello
        

Profi-Tipp für Anfänger: Nutze den Debug-Zähler query_create_count(), um zu sehen, ob du wirklich die neue Instanz hast.

Debug: Bin ich wirklich „neu“?

ob ~/work/hello [query_create_count]
        

2.8 Dasselbe mit MGtool (Xtool) – der Alltag

Viele Entwickler nutzen im Alltag oft das MGtool, weil es extrem viel kann (History, Pipelines, Grep, Skripte, …). Die konkreten Befehle und Optionen können je nach Version variieren – aber diese „Grundfamilie“ ist typisch:

  • xload – laden
  • xclone – klonen
  • xupdate – updaten
  • xcall – Funktion aufrufen
  • xlook – Objekt/Container ansehen
MGtool: Hilfe zu einem Befehl

xman xload
xman xclone
xman xupdate
xman xcall
        

Und die Magier-Shell hat eine eingebaute History — die kannst du unabhängig vom Tool nutzen, sie funktioniert für alle Befehle:

Shell-History (siehe [ Hilfe: History ])

history             // (oder kurz: hist) — letzte Befehle anzeigen
&<nr>               // Befehl Nummer nr aus der History wiederholen
&<text>             // letzten Befehl, der mit <text> anfaengt
^alt^neu^           // letzten Befehl mit Ersetzung wiederholen
histlen <n>         // History-Länge setzen
histmin <n>         // minimale Länge für History-Eintrag
        

Praktisch ist auch [ alias ] — damit kannst du dir Kurzformen für oft genutzte Befehle anlegen (und mit [ unalias ] wieder entfernen).

Für diesen Kurs gilt: Wenn du mit der Lupe sicher bist, wirst du MGtool lieben – aber die Lupe ist der perfekte Einstieg, weil sie das „Objekt-denken“ sehr klar macht.

2.8a Lupe-Befehle im Detail

Die Lupe (/obj/tools/lupe) ist ein Stack-Werkzeug. Du legst Objekte oben drauf (Push), schaust sie an, rufst Funktionen, nimmst sie wieder runter (Pop). Das ist deutlich anders als ein normaler Befehlsstil — aber wenn man es einmal verstanden hat, ist es unschlagbar schnell. Die volle Befehlsreferenz bekommst du im MUD mit hilfe lupe oder in /doc/wiz/lupe.

Stack-Operationen


me              // ich selbst auf den Stack
here            // der aktuelle Raum auf den Stack
=               // TOS anzeigen (Stack bleibt erhalten)
stk             // ganzen Stack zeigen (Stack bleibt erhalten)
pop             // TOS entfernen
swap            // TOS und Element darunter tauschen
dup             // TOS verdoppeln
clr             // Stack komplett leeren
copy            // Kopie von TOS anlegen (geht ins eigene Inventar)
over            // Element unter TOS nochmal pushen
@<n>            // n-tes Element von oben (0 = TOS) nochmal pushen
      

Objekte auf den Stack schieben


ob <file>        // load_object - Blueprint laden und pushen
new <file>       // clone_object - klonen, pushen, ins eigene Inventar
creat <file>     // wie new, aber NICHT ins Inventar
push <file>      // findet existierendes Objekt und pusht es
pl <name>        // Spieler mit Namen pushen (auch netztote)
lv <name>        // Lebewesen mit living_name pushen
env              // environment(TOS) auf Stack (TOS wird ersetzt)
result           // letztes Objekt-Ergebnis einer Funktion pushen
      

Inventar von TOS


inv             // Inventar von TOS auflisten (TOS bleibt)
.<n>            // n-tes Objekt im Inventar von TOS pushen (TOS weg)
.<id>           // Objekt mit ID im Inventar von TOS pushen
me .knochennadel    // Knochennadel im eigenen Inventar
here .ork           // Ork im aktuellen Raum
      

Funktionen aufrufen


[funktion]              // funktion() auf TOS
[funktion arg1 arg2]    // funktion(arg1, arg2) auf TOS
[QueryProp P_NAME]      // QueryProp(P_NAME)
[SetProp P_HP 100]      // SetProp(P_HP, 100)
      

Updaten und zerstören


make            // TOS destructen und neu laden (Update)
                // Achtung: NICHT für Spieler — dafür: renew
renew           // Update für Spieler (vorsichtig benutzen!)
dest            // remove() + destruct() von TOS
Dest            // hartes destruct() (KEIN Spieler/Lupe)
cln             // alle Objekte aus TOS-Inventar entfernen (außer Spieler)
clnof <arg>     // alle Objekte mit ID <arg> aus TOS-Inv entfernen
      

Variablen (10 Slots: 0..9)


><n>            // TOS in Variable n speichern (z.B. >0)
<<n>            // Variable n auf den Stack pushen (z.B. <0)
      

Info-Befehle


info            // Standardinfos zu TOS
dinfo           // Driver-interne Infos (next reset, eval_cost)
minfo           // Speicherverbrauch von TOS
inherit_list    // Vererbungsbaum von TOS
stat / sc       // Spieler-/NPC-Status (Equipment, Quests etc.)
idle            // Idle-Zeit (TOS muss Spieler sein)
      

Quoting bei Sonderzeichen

Wenn IDs Punkte oder Leerzeichen haben, musst du quoten:


me ."bag 2" inv         // doppelte Anführungszeichen
me .'bag 2' inv         // einfache Anführungszeichen
me .|bag 2| inv         // Pipe-Quoting (praktisch in Shells)
      

Mehrere Befehle in einer Zeile

Lupe-Befehle werden durch Whitespace getrennt. Du kannst lange Pipelines bauen:


me here inv .1 [QueryProp P_SHORT]
// 1. me        - ich auf Stack
// 2. here      - Raum auf Stack
// 3. inv       - Raum-Inventar auf Stack
// 4. .1        - 1. Element davon
// 5. [QueryProp P_SHORT]  - dessen Kurzbeschreibung
      

2.8b MGtool / Xtool im Detail

Das MGtool (im Code /obj/tools/MGtool, früher Xtool genannt) ist das Schweizer Taschenmesser des Magiers. Anders als die Lupe ist es nicht stack-basiert, sondern arbeitet mit benannten Variablen wie $me, $here, $result, $clone und einer langen Liste spezialisierter x*-Befehle.

Die wichtigsten X-Befehle (existieren wirklich!)


xhelp                            // Befehlsübersicht
xman <befehl>                    // Detail-Hilfe (z.B. xman xcall)
xtool                            // Tool selbst konfigurieren / save / load

// Objekte erzeugen und updaten
xclone <file>                    // klont, setzt $clone, bewegt in dein Inventar
xload <file>                     // lädt/aktualisiert (Räume: Spieler in /std/void)
xupdate <file>                   // remove() + destruct() für ein Objekt
xdes <file>                      // hartes destruct()
xclean                           // alle eigenen Clones aufräumen

// Funktionen aufrufen — Syntax: xcall <obj>-><fun>(<args>)
xcall $me->QueryProp(P_LEVEL)
xcall $here->QueryProp(P_INT_LONG)
xcall /std/thing#145->SetProp(P_SHORT,"a small thing")
xcall $clone->DoWield()
xeval ...                        // wie xcall, aber freier LPC-Ausdruck

// Inspektion
xlook [<obj>]                    // Objekt anschauen (default: hier)
xprops [<obj>]                   // alle Properties auflisten
xids [<obj>]                     // alle IDs eines Objekts
xinherit [<obj>]                 // Vererbungsbaum anzeigen
xscan [<obj>]                    // tiefes Scannen eines Objekts
xtrace <obj>                     // Funktion/Aufruf tracen
xgoto <ziel>                     // teleportieren

// Code-Suche und Doku
xgrep <pattern> <datei>          // Code-Suche
xman <name>                      // sucht in /doc/efun/, /doc/lfun/, /doc/std/, ...

// Variablen merken (eigene)
xset $deep=deepthought           // $deep = Spieler "deepthought"
xset $tuer=$here.tuer            // $tuer = Tür im aktuellen Raum
xset                             // alle Variablen anzeigen
      

Vordefinierte Variablen

  • $me — du selbst
  • $here — der aktuelle Raum
  • $clone — der zuletzt geklonte Clone (wird von xclone gesetzt)
  • $result — Ergebnis des letzten xcall

Praxisbeispiel: Loop „klone, prüfe, ändere“


xclone /players/odin/work/hello
xcall $clone->QueryProp(P_SHORT)
xcall $clone->SetProp(P_SHORT, "Eine andere Beschreibung")
xprops $clone
      

Die volle Befehlsreferenz mit allen X-Befehlen, Aliases und der eigenen kleinen Skriptsprache findest du im MUD mit xhelp. Eine vollständige Liste der verfügbaren xman-Seiten liegt unter /obj/tools/MGtool/man.d/.

2.8c Magier-Standardbefehle (außerhalb der Tools)

Das Midgard MUD bringt einige eingebaute Befehle mit, die du auch ohne Lupe/MGtool kennen solltest. Sie funktionieren in der Magiershell direkt:

Dateisystem


pwd                     // Aktuelles Verzeichnis
cd <pfad>               // wechseln
ls [<pfad>]             // Verzeichnis listen
cat <datei>             // Inhalt anzeigen
more <datei>            // seitenweise
head <datei>            // Anfang anzeigen
tail <datei>            // Ende anzeigen
ed <datei>              // im ed-Editor öffnen (siehe hilfe editor)
mv <alt> <neu>          // umbenennen
cp <quelle> <ziel>      // kopieren
rm <datei>              // löschen (Vorsicht!)
mkdir <name>            // Verzeichnis anlegen
rmdir <name>            // leeres Verzeichnis löschen
grep <muster> <datei>   // Code-Suche
man <befehl>            // Doku zu LPC-Funktion / Befehl
      

Objekte


load <file>             // Blueprint laden (siehe hilfe load)
clone <file>            // Clone erzeugen (siehe hilfe clone)
upd  <file>             // destructen + neu laden (siehe hilfe upd)
destruct <objekt>       // Objekt zerstören
goto <raum|spieler>     // teleportieren
home                    // ins eigene Home teleportieren
people                  // Spieler online auflisten
do <befehl>             // Befehl als anderer Spieler/NPC ausführen
zwinge <wer> zu <was>   // jemanden zu einem Befehl zwingen
trans <wen> [zu]        // Spieler zu sich teleportieren
      

Eine komplette Liste aller Magier-Befehle findest du unter /doc/mcmd/ oder im MUD mit hilfe magierbefehle.

Driver-Status (im Driver eingebaut)

Der LDMud-Driver kennt einen eingebauten status-Befehl, der Speicher, Eval-Costs und Tabellen anzeigt:


status                  // Driver-Status (Memory, Objekte, Eval-Limits)
status tables           // Hashtables, Speicher-Auslastung
status malloc           // Detail-Memory
      

Welche Befehle es genau gibt, hängt vom Level ab (Spieler/Seher/Magier/EM). hilfe magierbefehle oder ein Blick in /doc/mcmd/ zeigen die volle Liste.

2.8d Debugging-Workflow: Wenn etwas nicht funktioniert

Statt blind zu raten, geh systematisch vor. Dieser Ablauf erspart dir endlose Frustration:

Schritt 1: Compile-Errors zuerst

Beim Laden gibt der Driver Fehlermeldungen aus. Lies die oberste Fehlermeldung — alle weiteren sind oft Folgefehler.


*Compiler error: /players/dein/work/hello.c line 12: parse error
// Zeile 12 angucken — meist fehlt ; oder } davor
      

Schritt 2: Existiert das Objekt überhaupt?


xinfo                              // im MGtool
[find_object "/players/.../hello"] // in der Lupe
      

Wenn nicht: load oder xob erst.

Schritt 3: Werte schrittweise prüfen


// In der Lupe:
ob ~/work/hello [QueryProp P_HP]
ob ~/work/hello [QueryProp P_NAME]

// Im MGtool:
xob /players/dein/work/hello
xqp P_HP
xqp P_NAME
xlook                       // alle Properties auf einen Blick
      

Schritt 4: Logging

Wenn du nicht siehst, was passiert, lass dein Code es selbst sagen:


log_file("debug/hello", sprintf("create() ran at %d\n", time()));
log_file("debug/hello", sprintf("hp=%d, name=%s\n", hp, name));
      

Anschauen mit cat /log/debug/hello. Das ist im MUD oft schneller als jeder Online-Debugger.

Schritt 5: Eval-Cost messen

Wenn dein Code „too long evaluation“ wirft:


int prev = get_eval_cost();
// dein Code
write("Hat " + (prev - get_eval_cost()) + " Ticks gebraucht.\n");
      

2.8e Master-Update vs. Clone-Update — die wichtige Unterscheidung

Das ist eine der häufigsten Verwirrungen am Anfang. Wenn du eine .c-Datei änderst, sind alte Objekte im MUD nicht automatisch auf dem neuen Stand.

Was passiert beim update/make?

  1. Driver zerstört das alte Master-Objekt im Speicher.
  2. Beim nächsten Zugriff wird die Datei neu kompiliert und geladen.
  3. Bestehende Clones behalten den alten Code, bis sie selbst neu erzeugt werden.

Konsequenz: Wenn du das Verhalten von Items ändern willst, die Spieler bereits im Inventar haben, musst du sie zerstören und neu erzeugen — oder du baust Versionierung ein. Bei Räumen ist das einfacher, weil Räume meist als Blueprint genutzt werden.

Trick mit query_create_count()

Bau in dein Lernobjekt einen Versionszähler ein, dann siehst du sofort, ob du die neue Version testest:


private int CreateCount;

protected void create() {
  ::create();
  CreateCount++;
  log_file("debug/hello", "create #" + CreateCount + "\n");
}

public int query_create_count() { return CreateCount; }
      

2.9 Typische Anfängerfehler (und schnelle Lösungen)

„File not found“

Meist falscher Pfad. Nutze pwd, ls und arbeite anfangs lieber mit ~/work/....

„Ich teste noch die alte Version“

Klassiker. Lösung: make (Lupe) oder neu klonen. Nutze query_create_count().

„Compile error“

Meist Syntax: Semikolon vergessen, Klammern falsch, Tippfehler.

Semikolon vergessen (Klassiker)

// falsch
int x = 1

// richtig
int x = 1;
        

„Runtime error“

Kompiliert, aber zur Laufzeit stimmt etwas nicht (z.B. 0 statt Objekt). Lösung: kleiner testen, Werte abfragen, Zwischenschritte sichtbar machen.

2.10 Mini-Aufgaben (zum Festigen)

  1. Ändere den Text in hello() und aktualisiere sauber mit make oder neuem Clone.
  2. Füge eine Funktion int add(int a, int b) hinzu und rufe sie über die Lupe auf.
  3. Füge eine Variable string Name hinzu, setze sie in create() und gib sie per query_name() zurück.
Beispiel: add-Funktion

int add(int a, int b)
{
  return a + b;
}
        

Tipp: Wenn du add testen willst, kannst du in der Lupe Argumente mitgeben:

Lupe: Funktionsaufruf mit Argumenten

ob ~/work/hello [add 2 40]
        

2.11 Checkliste: Der sichere Anfänger-Workflow

Wenn du unsicher bist: mach genau das

  1) pwd / ls (bin ich im richtigen Verzeichnis?)
  2) Datei editieren und speichern
  3) Lupe: ob ~/work/objekt
  4) Lupe: make   (wenn du updaten willst)
  5) Lupe: new ~/work/objekt   (neuen Clone zum Testen)
  6) Tests: [funktion] aufrufen, info/=/stk nutzen
        

Damit bist du für die nächsten Kapitel stabil aufgestellt. Ab jetzt geht’s mehr um LPC selbst – und weniger um „wo ist meine Datei?!“.

Ausblick

In Kapitel 3 gehen wir in die Sprache: Datentypen, Variablen, Arrays, Mappings – und wie du sie im Midgard-Stil sauber einsetzt (mit Übungen).

Weiter zu Kapitel 3

Jetzt wird’s richtig LPC.