Hallihallo,
wie ich letztens schon auf dem D-Code erzaehlte, habe ich mich in letzter
Zeit damit beschaeftigt, InterMUD-Portale zu bauen, mit denen es moeglich
ist, von einem MUD in das naechste zu wandern. Ich suche jetzt 1 oder 2
echte MUDs, um das ganze zur Serienreife auszubauen.
Das Prinzip hinter den Portalen ist einfach, im Ursprungs-MUD wird der
Charakter in irgendeiner finsteren Ecke geparkt und alle seine Eingaben
an das Gast-MUD geschickt. Im Gast-MUD laeuft dann ein ferngesteuerter
Charakter herum, erhaelt die Befehle aus dem Ursprungs-MUD, fuehrt sie aus
und liefert alle empfangenen Meldungen zurueck an das Ursprungs-MUD.
Die Herausforderungen liegen darin, im Ursprungs-MUD den geparkten Charakter
vom MUD abzuschirmen (man sollte ihm keine Bomben zustecken koennen, nicht
an Krankheiten sterben lassen, etc.) und im Ziel-MUD den ferngesteuerten
Charakter echt aussehen zu lassen (d.h. wie ein interaktives Objekt), damit
alle anderen Objekte ihn als Player erkennen.
Kommunikation zwischen den MUDs
-------------------------------
Ich hatte zuerst eine Variante entwickelt, welcher den Datenaustausch via
InterMUD2 durchfuehrte. Hat auch prima funktioniert, allerdings wollte ich
die Kommunikation sicher gestalten, so dass ich auf TLS-Verbindungen setze.
(Fuer LDMud mit OpenSSL funktioniert das sehr gut, bei GnuTLS braucht man
die allerneueste LDMud-Version.) Ich habe dazu eine eigene CA eingerichtet,
welche die Zertifikate eigens fuer diese Portalsverbindungen ausstellt,
damit man sich als 'Morgengrauen' statt '
mg.mud.de' ausweisen kann.
(Ich habe eine Erweiterung fuer LDMud programmiert, welche mit mehreren
Zertifikaten umgehen kann, so dass man sich bei Telnet mit dem DNS-Namen
und bei den Portalen mit dem MUD-Namen identifiziert. Ich denke, dass dies
demnaechst in den Hauptentwicklungszweig einfliessen wird.)
Die MUDs schicken sich gegenseitig Anforderungen, welche nicht bestaetigt
werden. (Denn das sendende MUD kann ja eh nicht auf die Antwort warten,
sondern muss weitermachen.) Im Fehlerfalle sendet das MUD einfach eine
QUIT- oder LEAVE-Anforderung zurueck. Gesendet wird ein Mapping mit
Anforderungstyp und Parametern, welches via save_value() serialisiert wird.
(Hier kann man sich spaeter auch z.B. JSON vorstellen, fuer LDMud gibt's ja
bereits eine entsprechende Erweiterung.) Folgende Anforderungen habe ich mir
da bisher ausgedacht:
Vom Ursprungs- und Gast-MUD:
- P_TYPE_HELLO: Begruessung, dient derzeit nur zur Kontrolle der
Identitaet. Kann auch zum Aushandeln von
Verbindungsparametern dienen.
Vom Ursprungs-MUD:
- P_TYPE_ENTER: Ein Spieler wuerde gern im Gast-MUD wandeln. Gesendet
werden Name, Geschlecht, Save-Daten von frueheren
Besuchen.
- P_TYPE_LEAVE: Der Gast soll die Welt verlassen (er hat das
Ursprungs-MUD verlassen). Dient auch als Fehlermeldung,
dass der Spieler gar nicht mehr im Ursprungs-MUD ist.
- P_TYPE_COMMAND: Der Spieler hat einen Befehl eingegeben.
Vom Gast-MUD:
- P_TYPE_MOVE: Der Gast ist durch ein weiteres Portal gewandelt.
Gesendet werden Ziel-MUD und -Portal. Das Ursprungs-MUD
darf dann selbst eine Verbindung dahin aufbauen.
Wenn das Ziel-MUD das Ursprungs-MUD ist, kommt er
einfach nur wieder zurueck.
- P_TYPE_QUIT: Der Gast hat das Gast-MUD abrupt verlassen (ohne
Betreten eines Portals). Dient auch als Fehlermeldung,
dass der Spieler dort gar nicht mehr ist oder sein kann.
- P_TYPE_MESSAGE: Der Gast hat eine Meldung erhalten.
- P_TYPE_SAVE_DATA: Das Ursprungs-MUD moege bitte diese Daten fuer den
naechsten Besuch sichern (statt eines Savefiles im
Gast-MUD).
Das Interface ist also bewusst spartanisch gehalten. Ein Spieler bekommt im
Gast-MUD einen neuen eigentlich unabhaengigen Charakter, er kann keine
Gegenstaende oder Stats mitnehmen, er behaelt nur seinen Namen. (Dies ist
natuerlich ausbaufaehig. Ich habe z.B. unser Test-MUD Orbit so angebunden,
dass der Gast eines UNItopia-Gottes auch dort Gott ist, die Information
zum Level wird also uebertragen und von unserem Test-MUD honoriert.)
Mudlib im Ursprungs-MUD
-----------------------
Wer sich's anschauen will, die Dateien, auf die ich mich beziehe, sind alle
in unserer oeffentlichen Mudlib vorhanden:
http://www.unitopia.de/pub/UNItopia/mudlib.tar.gz
Beide MUDs brauchen statt des Player-Ob ein eigenes Objekt fuer die
InterMUD-Verbindung (/secure/portal/obj/connection.c), welche vom Master
dezu befugt ist, via net_connect() eine Verbindung ins Internet aufzubauen
(es muss auch Telnet via set_telnet() abschalten koennen und das passende
Zertifikat via configure_driver() auswaehlen duerfen, wenn es mehrere
Zertifikate gibt). Dazu gibt es den Portal-Master (/secure/portal/portal.c),
welcher alle Verbindungen und Reisende verwaltet. Alle Anforderungen der
eigenen Seite und der Gegenseite schlagen hier auf, werden geprueft und
weitergeleitet.
Der Abstellraum fuer Reisende (/room/portal.c) ist entsprechend abgesichert,
dass man da nicht aus Versehen reinkommt, denn der Raum faengt alle Eingaben
ab (doppelt, einmal via input_to und einmal via add_action("cmd", "",
AA_NOSPACE)) und sendet sie ueber den Master zur Gegenseite. Spieler in
diesem Raum muessen nun vom MUD abgekoppelt werden. Das beginnt allein da
schon, wenn ein zweiter Spieler in den Portal-Raum bewegt wird und eine
Ankommensmeldung bewirkt. In UNItopia haben wir ein Message-System, welches
bewirkt, dass alle Meldungen in einer Lfun des Spielers aufschlagen. Dort
habe ich einen Filter eingebaut, wenn der Spieler in diesem Raum steht.
Zudem muss man auch mudlib-spezifisch zeitliche Effekte (z.B. Krankheiten)
ausschliessen, dies geht nur von Fall zu Fall und wird man wohl erst im
Dauertest eliminieren koennen. Wobei ich ueberlege, ob diese Player-Objekte
nicht einen net-dead simulieren sollten, damit duerfte man einiges
erschlagen.
Ansonsten benoetigt der Player noch eine Ablage fuer die Sicherungsdaten aus
den MUDs und eine Funktion zur Wiedergabe der Meldungen (/i/player/intermud.c,
ganz unten). Die Meldungen habe ich uebrigens um UNIlib-spezifische
Attribute ergaenzt, so dass die Meldungsart (Kommunikation, Emote, Kampf,
Debug) mit uebertragen wird.
In UNItopia haben wir zudem die Moeglichkeit, dass man eine getrennte
Eingabezeile einstellen kann (/i/player/vt100client.c), diese arbeitet
aehnlich wie der Abstellraum, indem sie alle Eingaben des Spielers abfaengt
und verarbeitet. Auch wenn das prinzipiell kein Problem ist (diese
Eingabezeile hat Vorrang), so bietet sich hier ein kurzer Dienstweg an,
dass die Eingabezeile die entgegengenommene Eingabe direkt ans Portal
weiterreicht.
Zur Infrastruktur gehoeren noch die Portale selbst (/i/object/portal.c)
und eine Liste aller verfuegbaren (erlaubten) Portale (/static/adm/PORTALS,
in der mudlib.tar.gz unter /static/adm/examples/PORTALS).
Mudlib im Gast-MUD
------------------
Der Gast-Char ist bei uns ein regulaeres Player-Ob, welches aber gesondert
initialisiert wird (/i/player/intermud.c, setup_intermud_player()). Es liest
seine Daten nicht aus dem Savefile, sondern vom Portal, setzt die Variablen
dementsprechend und beginnt dann die normale Setup-Routine. Ich hatte zuerst
'Gnomi@UNItopia' als Namen gesetzt, aber fand dies in den dadurch
generierten Meldungen stoerend und bin daher erstmal bei 'Gnomi' als Namen
mit 'Gnomi aus UNItopia' als Titel geblieben. Dadurch kann es zu
Verwechslungen kommen, wenn zwei Gnomis unterwegs sind, inwiefern das zu
Problemem fuehrt oder ob man sich daran gewoehnt, werden wir sehen. Dies
kann natuerlich jedes MUD handhaben, wie es beliebt.
Nicht nur die Laderoutine, sondern auch die Saveroutine muss angepasst
werden, dass die Daten nicht abgespeichert, sondern via Portal
zurueckgesandt werden. Wobei ein MUD sich auch entscheiden kann, die Daten
nicht zu senden, sondern lokal zu speichern. Dann hat man weiterhin die
volle Kontrolle ueber Savefiles, bekommt aber ggf. Charloeschungen nicht
mit.
Die groesste Herausforderung fuer die Mudlib des Gast-MUDs ist aber, einen
interaktiven Player zu simulieren. Bei uns sind daher folgende Efuns in die
Simul-Efun gewandert:
- input_to, query_input_pending:
(/secure/simul_efun/input_to.inc, /i/player/input_to.c)
Wir hatten schon frueher eine input_to-Sefun zur Umlautkonvertierung,
welche um die Callback-Funktion eine Closure herumpackt. Daher werden
bei uns find_input_to, remove_input_to und input_to_info nicht
unterstuetzt und muessen auch nicht simuliert werden. input_to und
query_input_pending werden gleichermassen fuer unsere getrennte
Eingabezeile (die ja ein eigenes staendiges input_to unterhaelt und
daher andere input_tos simulieren muss) wie fuer InterMUD-Gaeste
simuliert. Der Player verwaltet hier also selbst eine Liste aller
input_tos mit ihren Prompts.
- caller_stack, caller_stack_depth, this_interactive:
(/secure/simul_efun/interactive.inc)
Diese Funktionen simulieren, dass der Aufruf eines Befehls nicht vom
Connection-Objekt ueber den Portal-Master bis zum Player-Ob und dann
zur Action gelaufen ist, sondern direkt vom Player-Ob kam.
- interactive, query_once_interactive, remove_interactive, query_idle,
set_prompt, users:
(/secure/simul_efun/interactive.inc)
Diese Funktionen behaupten, dass es bei dem Player-Ob tatsaechlich um
einen interaktiven Spieler handelt.
Bei uns sind zudem tell_object, tell_room, say, write, printf noch sefuns,
(/secure/simul_efun/comm.inc), die alle Meldungen zur Lfun receive_message()
schicken, von wo sie dann zum Ursprungs-MUD geschickt werden koennen.
Stattdessen kann man aber genauso gut catch_tell() implementieren.
Ansonsten wird noch benoetigt, dass der Master Verbindungen ueber einen
speziellen Port als Portalverbindungen erkennt und annimmt
(/secure/master/connections.inc).
Schlusswort
-----------
Ich hoffe natuerlich langfristig moeglichst viele MUDs derart anbinden zu
koennen, denn ich denke, dass dies ein riesiger Gewinn fuer alle Seiten
darstellt. Aber am Anfang moechte ich erst mit einem oder zwei anderen MUDs
(abgesehen von HomeMUDs) beginnen und wuerde mich freuen, wenn sich da
jemand meldet. Der von mir fuer die Portale programmierte Code (Alles unter
/secure/portal, /i/player/input_to.c und intermud.c, /i/object/portal.c,
/room/portal.c und /secure/simul_efun/interactive.inc) steht unabhaengig
vom UNItopia-Copyright zur freien Verfuegung, sofern die Autoren genannt
bleiben (entsprechend dem LDLib-Copyright). Und ich stehe natuerlich bei
der Implementierung mit Rat und Tat zur Verfuegung.
Gruss
Gnomi@UNItopia