Dokumentation zu: event_daemon(WL)

HR Image


KONZEPT:
        Event-Daemon des Wunderlandes

	/secure/eventd.c
	/sys/events.h
	/etc/eventd.handlers
	/etc/eventd.secure
	/etc/eventd.trust
	/etc/eventd.globtrust

AUTOR:
	Holger@Wunderland 01.03.2003

EINLEITUNG:
	Der Event-Daemon dient zur zentralen Verwaltung des Event-Systems im
	Wunderland. Hier melden sich alle Objekte an, die Events empfangen
	wollen. Die Events selbst werden hier verteilt und an die Empfaenger
	zugestellt. Die Event-Informationen werden im /secure/memory.c 
	(memory(WL)) abgelegt, um ein Updaten des Daemons ohne Datenverlust
	zu ermoeglichen. Diese Dokumentation beschreibt die Funktionen des
	Daemons. Zur allgemeinen Dokumentation des Event-Systems dient als
	Einstieg die Manpage events(WL).

PHILOSOPHIE:
	Beim Design des Daemons wurde auf optimale Performance Wert gelegt.
	Das heisst vor allem, dass in zeitkritischen Funktionen keine
	call-other gemacht werden. Desweiteren wird oft Gebrauch von Alists,
	Mappings und Closures (lfun-closures und lambda closures) gemacht.
	Auch bei mehreren tausend Event-Lauschern erfolgt die Auswahl und
	Sortierung der richtigen Empfaenger mit aeusserst geringen Kosten.
	Die 'Performance' eines Events haengt damit im wesentlichen von der
	'Qualitaet' des jeweiligen Event-Handlers und seiner Lauscher ab.
	Diese sollten daher auch nicht unnoetig zeitaufwaendige Dinge tun. 

	Da ein Event einen anderen ausloesen kann, rufen sich manche Funk-
	tionen des Daemons rekursiv selbst auf und koennen daher zu einem
	Stack-Ueberlauf des Drivers fuehren (too deep recursion). Dies ist
	aber kein Fehler des Daemons, sondern in aller Regel ein Fehler in
	den Event-Lauschern. Der Daemon ist so aufgebaut, dass er derartige
	Fehler verkraften kann.
	
	Auch wenn die Handler und Lauscher, sowie das /secure/memory.c
	Objekt buggen oder die Einstellungsfiles korrupt sind, soll der
	Daemon selbst ladbar und weitgehend funktionstuechtig bleiben.

SEFUNS:
	Folgende simulierte Driverfunktionen (sefuns) dienen zur Verarbei-
	tung der Events. Alle sefuns haben eigne Manpages zur Beschreibung:

	Name                      | Kurzbeschreibung
	--------------------------+-----------------------------------------
	listen_event(...)         | Ein Objekt meldet sich als Lauscher an.
	unlisten_event(...)       | Ein Objekt meldet sich als Lauscher ab.
	set_global_listener(...)  | Ein Objekt will global lauschen.
	send_event(...)           | Ein Objekt erzeugt einen Event.
	cancel_event(...)         | Ein Objekt will einen Event abbrechen.
	handle_event(...)         | Ein Objekt verarbeitet einen Event.

	In aller Regel sollte zumindest <events.h> includet werden, um die
	darin enthaltenen Defines zu benutzen.

WICHTIGE DEFINES IM DAEMON:

	Name           | Kurzbeschreibung
	---------------+----------------------------------------------------
	PRELOADFILE    | Liste aller Default-Handler, die bei Bedarf vom 
	               | Daemon geladen werden.
	SECUREFILE     | Die Sicherheitseinstellungen einiger Events.
	TRUSTFILE      | Die 'erlaubten' Objekte bei geschuetzten Events.
	GLOBTRUSTFILE  | Die als globale Lauscher freigegebenen Objekte bei
	               | geschuetzten Events.
	LOGFILE        | Das Hauptlogfile des Daemons.
	CORE_LOGFILE   | Logfile in den der Event-Stack geschrieben wird bei
	               | einem Stackueberlauf (too deep recursion).
	GLOBAL_LOGFILE | Logfile in dem globale Lauscher erfasst werden.
	LISTEN_LOGFILE | Logfile in dem Lauscher bei geschuetzten Events
	               | erfasst werden.
	MAX_STACK      | Vorgegebene Maximal-Rekursion. Entspricht der
	               | maximalen Anzahl von Objekten auf dem Callerstack.
	               | Der Wert ist so gewaehlt (momentan 30), dass er
	               | einem 'harten Abbruch' durch den Driver zuvorkommt.
	               | Sollte der Driver-Stack erhoeht werden, kann auch
	               | MAX_STACK erhoeht werden, er sollte aber immer
	               | 'unter' dem Driver liegen, um das Debuggen zu
	               | vereinfachen. Siehe CORE_LOGFILE.

FUNKTIONEN DES DAEMONS:
	Im folgenden werden alle momentan im Event-Daemon enthaltenen
	Funktionen kurz erklaert. Bitte nur mit diesen Sefuns arbeiten und
	nicht die Funktionen direkt aufrufen. 

FUNKTION "create":

	void create()

	Hier werden die Einstellungsfiles ausgelesen (preload_handlers()
	und preload_security()) und die globalen Variablen initialisiert.
	Es wird versucht, bereits gespeicherte Daten aus dem secure/memory.c
	Objekt zu holen. Schlaegt dies fehl, wird zumindest eine Art
	'Notbetrieb' ermoeglicht.
	
	ACHTUNG: Sollte secure/memory.c buggen, gehen bei einem Neuladen des
	Daemons alle Informationen ueber die gerade angemeldeten Objekte
	verloren! Ein Reboot wird unvermeidlich!

FUNKTION allowed():

	private int allowed(object ob, string type, int prio,
		closure callback)
	
	ob       - das Objekt, das sich als Lauscher anmelden will
	type     - der gewuenschte Event
	prio	 - die gewuenschte Lauscher-Prioritaet
	callback - die lfun closure, die dann aufgerufen werden soll

	Rueckgabewerte:

	1	- Objekt darf lauschen
	0/Bug	- Objekt darf nicht lauschen
	
	Es werden verschiedene Ueberpruefungen vorgenommen, ob ein Objekt
	sich als Lauscher auf einen bestimmten Event anmelden darf. Dies
	haengt in erster Linie von den Einstellungen im SECUREFILE ab.
	
FUNKTION global_allowed():

	private int global_allowed(object ob, string type)
	
	ob       - das Objekt, das sich als Lauscher anmelden will
	type     - der gewuenschte Event

	Rueckgabewerte:

	1	- Objekt darf lauschen
	0/Bug	- Objekt darf nicht lauschen
	
	Es wird ueberprueft, ob ein Objekt sich als globaler Lauscher
	auf einen Event anmelden darf. Globale Lauscher koennen Events
	im ganzen MUD empfangen und sollten daher etwas restriktiv
	behandelt werden. Ein globaler Lauscher auf ET_DEATH koennte
	zum Beispiel jeden Tod eines Lebewesens absichtlich oder aufgrund
	eines Bugs verhindern!

FUNKTION preload_handlers():
	
	private mapping preload_handlers()
	
	Rueckgabewert:

	mapping	- ein Mapping der Default-Handler Namen

	Die Standard-Handler Objekte werden aus dem PRELOADFILE gelesen. Die
	Handler werden aber NICHT sofort geladen, sondern erst beim ersten
	Auftreten des Events. Dann muessen die Handler sich auch selbst als
	Lauscher mit Prioritaet EPRIO_DEF_HANDLE und ggf. als globale
	Lauscher anmelden. Die Preload-Funktion dient lediglich dazu die
	benoetigten Handler ueberhaupt zu laden, wenn sie benoetigt werden
	und macht damit einen Eintrag in die Mud-weiten preload-Listen des
	Masters ueberfluessig.

FUNKTION preload_security():

	private mapping preload_security()
	
	Rueckgabewert:

	mapping	- ein Mapping mit Sicherheitseinstellungen

	Wird einmalig beim Laden aufgerufen. Hier werden die Sicherheits-
	Einstellungen der Events werden aus dem SECUREFILE ausgelesen. Nicht
	jeder Event soll von jedem Objekt empfangen werden koennen. Welche
	Einstellungen moeglich sind, ist im SECUREFILE als Kommentar be-
	schrieben.

FUNKTION query_default_handlers():

	public varargs mixed query_default_handlers(string type)
	
	type     - der gewuenschte Event (optional)

	Rueckgabewert:

	0        - wenn 'type' angegeben wurde und es keinen handler gibt
	string	 - wenn 'type' angegeben wurde, der default-handler fuer
	           den Event 'type'
	mapping  - wenn 'type' nicht angegeben wurde alle defaulthandler

	Liefert eine Kopie der internen Liste der Standard-Handler fuer die
	einzelnen Event-Typen. Wird 'type' weggelassen wird die gesamte
	Liste als Mapping geliefert, ansonsten nur den default-Handler des
	jeweiligen Events.

FUNKTION listen():

	public int listen(string type, int prio, mixed callback)
	
	type     - der gewuenschte Event
	prio	 - die gewuenschte Lauscher-Prioritaet
	callback - die alien lfun closure, die dann aufgerufen werden soll

	Rueckgabewerte:

	 1       - erfolgreiche Anmeldung
	 0       - unvollstaendige Funktions-Argumente
	-1       - Event-Typ existiert nicht (derzeit unbenutzt, der Daemon
	           weiss nicht, welche Typen existieren)
	-2       - das Objekt darf sich nicht fuer diesen Event anmelden

	Die Funktion dient dazu, sich beim Event-Daemon als Lauscher auf
	einen bestimmten Event anzumelden. Angemeldet wird immer das
	aufrufende Objekt. Es wird ueberprueft, ob die Argumente voll-
	staendig sind und ob das Objekt berechtigt ist, dem Event zu
	lauschen. Danach wird es in die interne Liste des Event-Typs ent-
	sprechend seiner Prioritaet eingetragen (Vorsortierung fuer
	spaetere Auswahl). Eine doppelte Anmeldung des gleichen Objekts mit
	identischen Argumenten wird verhindert.

FUNKTION query_listeners():

	public varargs mapping query_listeners(string type)

	type     - der gewuenschte Event (optional)

	Rueckgabewerte:

	0        - wenn 'type' angegeben wurde und es keine Lauscher gibt
	mapping  - die Liste aller Event-Lauscher oder nur fuer einen
	           bestimmten Event, wenn 'type' angegeben wurde.

	Die Funktion liefert eine Kopie des kompletten Mappings aller Events
	mit all seinen angemeldeten Objekten, oder wenn 'type' angegeben
	wurde nur das Objekt-Mapping fuer den jeweiligen Event.

FUNKTION is_listening():

	public mapping is_listening(object ob)

	ob     - ein Objekt, ueber das man Informationen haben moechte

	Rueckgabewert:
	
	0        - das Objekt lauscht keinem Event
	mapping  - ([ string typ: mixed alist ]) wobei 'alist' wie folgt
	           aussieht: ({ int *prios, closure *cls})

	Die Funktion liefert Informationen darueber, welchen Events ein
	Objekt lauscht. Da ein Objekt verschiedenen Events mit verschiedenen
	Prioritaeten und Rueckruffunktionen angemeldet sein kann wird immer
	ein Mapping mit einer Alist als Wert zurueckgegeben, das alle Infor-
	mationen zu jedem Event-Typ (sortiert) enthaelt.
	
FUNKTION unlisten():

	public void unlisten(string type, int prio, mixed callback)

	type     - der gewuenschte Event
	prio	 - die gewuenschte Lauscher-Prioritaet
	callback - die alien lfun closure, die dann aufgerufen werden soll

	Ein Objekt meldet sich als Lauscher auf einen Event ab. Es wird
	immer das aufrufende Objekt abgemeldet. Da ein Objekt mit mehreren
	verschiedenen Prioritaeten und Rueckruffunktionen angemeldet sein
	kann, muessen diese Parameter auch bei der Abmeldung angegeben
	werden.	Es wird daher nur jeweils der Eintrag entfernt, der mit
	diesen Parametern (wie sie bei listen() angegeben wurden) ueberein-
	stimmt.

FUNKTION set_global():

	public int set_global(string type, status state)

	type     - der gewuenschte Event
	state    - 1 = global setzen, 0 = global loeschen
	
	Rueckgabewerte:

	 1       - erfolgreich (global gesetzt/entfernt)
	 0       - unvollstaendige Funktions-Argumente
	-1       - Event-Typ existiert nicht/nicht erlaubt
	-2       - das Objekt darf diesem Typ nicht global lauschen

	Die Funktion dient dazu das aufrufende Objekt als globalen Lauscher
	fuer diesen Event zu setzen. Dies ist nur moeglich, wenn das Objekt
	befugt ist, dem Event global zu lauschen. In aller Regel wird die
	Funktion daher von Event-Handlern benutzt und muss zusammen mit
	listen() aufgerufen werden.

FUNKTION query_global():

	public varargs mixed query_global(string type)

	type     - der gewuenschte Event (optional)

	Rueckgabewert:

	0        - wenn 'type' uebergeben und keine globalen Lauscher
	mapping  - wenn 'type' nicht uebergeben wurde das gesamte Mapping
	           aller globalen Lauscher auf alle Events
	object*  - wenn 'type' angegeben wurde ein Array aus Objekten
	
	Die Funktion liefert eine Kopie der globalen Lauscher entweder
	fuer einen bestimmten Event, wenn 'type' angegeben wurde oder ein
	Array aus Objekten der globalen Lauscher auf einen bestimmten Typ.

FUNKTION cancel_event():

	public int cancel_event(mixed info)

	info     - irgendeine Information, die bei jedem Event-Typ anders
	           sein kann. Entspricht dem Argument 'info' der sefun
	           cancel_event(S). Wird kein 'info' oder 0 uebergeben,
	           setzt der Daemon defaultmaessig 1.

	Rueckgabewert:
	
	0        - wenn der Event nicht abgebrochen werden konnte oder wenn
	           der Event bereits als abgebrochen markiert war.
	1        - wenn der Event als abgebrochen markiert wurde

	Die Funktion dient dazu, einen Event als abgebrochen zu markieren.
	Der Event ist damit aber noch nicht beendet, sondern wird erst noch
	beendet werden. Der Aufruf muss im gleichen Backend-Cycle wie das
	ausloesende send_event(S) aufgerufen werden. Ein Objekt, das nach
	dem Abbruch noch Aktionen ausfuehren will, muss sich auch mit
	Prioritaet EPRIO_C_HANDLE anmelden und empfaengt dann den Event,
	wenn er tatsaechlich abgebrochen wurde.
	
	Wurde der Event im Modus EM_NO_CANCEL gestartet, kann der Event
	nicht abgebrochen werden. Ebenso kann der Event nicht von Objekten
	abgebrochen werden, die nach dem 'handeln' (als Reagierer) lauschen.
	
	Wurde der Event im Modus EM_STOP_CANCEL gestartet wird der Event
	nach Aufruf von cancel_event() gestoppt werden, andere Objekte
	empfangen ihn dann nicht mehr. Das ist nur sinnvoll, wenn ein Objekt
	exklusiv den Event abbrechen koennen soll. Etwa bei 'privaten'
	Events.

	Wurde der Event NICHT im Modus EM_STOP_CANCEL gestartet (Standard)
	wird die Verarbeitung _zunaechst_ fortgesetzt, um weiteren Objekten
	die Moeglichkeit zu geben, den Event zu empfangen auch wenn er 
	abgebrochen werden wird (um Meldungen zu setzen etc.). Der Event
	wird aber letztlich nicht ausgefuehrt und eines der Objekte, die
	den Event abbrechen wollten (in aller Regel das letzte) bekommen
	dann ueber einen Aufruf mit EPRIO_C_HANDLE die Moeglichkeit den
	Abbruch zu verarbeiten. Siehe dazu auch die Konzeptseite events(WL)
	und die Manpage der entsprechenden Sefun cancel_event(S).

	Der Daemon haelt intern einen Zeiger auf den gerade laufenden Event
	(den 'letzten' im EventStack des Daemons) und setzt das aufrufende
	Objekt als Abbrecher in E_CANCELLER und 'info' als E_CANCELLED Wert.
	Wie der 'info' Wert weiter verarbeitet wird, liegt in der Hand des
	Handlers und kann variieren.

	Bitte an dieser Funktion nur Aenderungen vornehmen, wenn genau ver-
	standen wurde, wie die Rekursion im Daemon ablaeuft!

FUNKTION handle_event():

	public int handle_event(mixed info)

	info     - irgendeine Information, die bei jedem Event-Typ anders
	           sein kann. Entspricht dem Argument 'info' der sefun
	           handle_event(S). Wird kein 'info' oder 0 uebergeben,
	           setzt der Daemon defaultmaessig 1.

	Rueckgabewert:
	
	0        - wenn der Event bereits als gehandelt markiert war.
	1        - wenn der Event als gehandelt markiert wurde

	Die Funktion dient dazu, einen Event als gehandelt zu markieren und
	entspricht in seiner Funktionsweise weitgehend cancel_event(). Nur
	Event-Handler sollten handle_event() aufrufen. Vorlagen fuer Event-
	Handler finden sind in /global/handler/*.
	
	Zum besseren Verstaendnis bitte die Konzeptseite events(WL) lesen.

FUNKTION process():

	private mapping process(mixed *ev)
	
	ev       - Event-Daten
	
	Rueckgabewert:
	
	mapping  - geht an den Aufrufer von send_event() zurueck.

	DIE zentrale Funktion zu Arbeitung eines Events. Die Funktion laeuft
	durch eine while()-Schleife bis alle uebergebenen Event-Daten in 'ev'
	abgearbeitet worden sind. Es wird jeweils der letzte 'Datensatz' aus
	'ev' genommen und verarbeitet. Loest die Abarbeitung dabei einen
	weiteren Event aus, wird process() rekursiv vom Driver aufgerufen,
	die Daten des vorherigen Aufrufs landen dabei im normalen Driver-
	Stack und werden nach Abarbeitung der Rekursion fortgesetzt.

	Wird der Driver-Stack dabei zu gross, ist die Rekursion zu tief
	geworden. Das passiert jedoch sehr selten und in aller Regel nur
	dann, wenn eine echte unendliche Rekursion vorliegt, etwa wenn sich
	2 NPCs gegenseitig verfolgen und die ET_GO-Events sich verschach-
	teln. Dieser Fall ist an sich unkritisch, der Driver bricht mit
	einem 'too deep recursion' bug ab. Um das Debuggen zu erleichtern
	greift der Daemon jedoch selbst ein, wenn er zu viele Objekte auf
	dem caller_stack(E) des Drivers bemerkt. Die maximal moegliche
	Anzahl an Objekten im caller_stack(E) ist durch das Define MAX_STACK
	(siehe oben) vorgegeben. Stellt der Daemon eine Ueberschreitung von
	MAX_STACK fest, schreibt er den gesamten Inhalt in das CORE_LOGFILE.

	Nach mehrjaehrigem Test kann festgestellt werden, dass dieses Ver-
	fahren ausreichend tiefe Rekursion ermoeglicht. Eine eigne Imple-
	mentation des Stacks, der tiefere Rekursionen zulassen wuerde, ist
	getestet worden und hat zu viele Probleme mit sich gebracht, wie
	etwa den Umstand, dass der Stack nicht abgeraeumt werden kann, wenn
	ein Bug auftritt (wenn man catch() nicht verwenden will) und aehn-
	liches. Weiterhin waere die Performance eines Stacks auf LPC-Ebene
	fragwuerdig.
	Sollte es daher vorkommen, dass der Daemon zu oft die Verarbeitung
	abbricht, muss die Stelle die die Rekursion ausloest, optimiert
	werden. Alternativ kann natuerlich auch der Driver-Stack selbst er-
	hoeht werden. Aber selbst eine Optimierung bestimmter NPCs ist bis
	jetzt im WL nur ein einziges mal notwendig geworden in einem Fall
	bei dem 10 NPCs einen Spieler und sich gegenseitig verfolgen
	wollten. Dies sollte man dann eleganter loesen. :-)

	Die Daten in 'ev' werden von send() aufbereitet. Sie enthalten
	immer den aktuellen Event-Typ, die Event-Daten, den Sende-Modus und
	eine Alist aus vorsortierten Prioritaeten und Alien Lfun Closures.
	process() nimmt immer den letzten Eintrag in der Alist und ruft
	die entsprechende Closure mit dem Event-Daten, der Prioritaet und
	dem Modus als Argumente auf. Nach dem Aufruf werden die E_CANCELLED
	und E_HANDELED Werte in den Event-Daten ueberprueft und entschieden,
	ob die Verarbeitung fortgesetzt wird oder nicht. Wird sie fortge-
	setzt, wird der letzte Eintrag in der Alist entfernt und im folgen-
	den while()-Durchlauf der naechste 'letzte' Eintrag verwendet. Dies
	laeuft entweder so lang, bis festgestellt wird, dass der Event ab-
	gebrochen werden muss oder bis die Alist aus Prioritaeten und
	Closures keine Elemente mehr enthaelt.
	
	process() selbst sind die dabei verwendeten Prioriaeten und deren
	Bedeutung egal. Jeder Event-Lauscher (Modifizierer, Abbrecher,
	Handler, Reagierer, Abbruch-Reagierer) wird gleich behandelt. Die
	verwendeten Werte sind also frei definiert. Siehe dazu auch
	event_prioritaeten(WL). Aber Werte zwischen -1000 und +1000 haben
	sich als sinnvoll erwiesen und sollten ausreichend Spielraum lassen.

	Je nach Sende-Modus uebergibt der Daemon die Event-Daten an die
	Lauscher als Referenz, einfache Kopie oder komplette Kopie. Die
	Arbeit mit Referenzen ist dabei naturgemaess die schnellste, kann
	aber unerwuenscht sein, wenn man zum Beispiel vermeiden will, dass
	Daten im Event modifiziert werden (EM_COPY/EM_NO_MODIFY Modi). 

	Weiterhin bietet process() einige Debug-Modi bei dem Informationen
	ueber alle Empfaenger gesammelt werden koennen. Es kann auch ein
	'Fake-Event' (EM_FAKE in Verbindung mit EM_DEBUG) erzeugt werden,
	der ueberhaupt nichts tut und nur zurueckliefert, wer den Event
	empfangen haette, wenn er aufgetreten waere. EM_DEBUG ohne EM_FAKE
	liefert zudem auch die von den Lauschern konsumierten eval-costs
	und kann daher zum Optimieren oder zur Fehlersuche verwendet
	werden.

FUNKTION continue_event():

	public mapping continue_event(mapping data)

	data  - ein 'eingefrorenes' Ereignis

	Wenn ein Ereignis EM_STOP_HANDLE oder EM_STOP_CANCEL gesetzt
	hat, so wird das Ereignis an geeigneter Stelle eingefroren
	(siehe auch events(WL) und event_senders(WL)). Wird entschieden,
	dass dieses Ereignis nun 'wirklich' stattfinden soll, so kann dies
	mit dieser Funktion geschehen: Das uebergebene, eingefrorere
	Ereignis wird aufgetaut und endgueltig ausgefuehrt.
	EM_STOP_* und diese Funktion sollte nur die Lib selbst benutzen.

FUNKTION send():

	public mapping send(string type,mapping data,mixed dest,mixed mode)
	
        type  - der Event-Typ als String (event_types(WL))
        data  - die Event-Daten als Mapping (event_types(WL))
        dest  - Objekt oder Array aus Objekten an die der Event gesendet
                werden soll.
        mode  - Ein Sende-Modus. Wird kein Modus angegeben, wird EM_SIMPLE
                benutzt. Ansonsten:
                EM_SIMPLE      - Standard Modus - maximale Performance
                EM_COPY        - einfache Kopie des Daten-Mappings
                EM_DEEP_COPY   - echte Kopie des Daten-Mappings
                EM_NO_MODIFY   - macht genau das gleiche wie EM_DEEP_COPY. Ein
                                 Modifizieren der Event-Daten ist dadurch un-
                                 moeglich.
                EM_NO_CANCEL   - der Event kann durch niemanden abgebrochen
                                 werden. cancel_event() returnt 0.
                EM_FAKE        - Simuliert den Event nur intern im Daemon
                                 interessant i.V.m. EM_DEBUG, um alle Lauscher
                                 auf einen Event zu finden
                Einer der vorhergehenden Modi kann kombiniert werden mit:
                EM_COMPLEX     - Mehr Daten in E_RECEIVERS
                EM_DEBUG       - maximale Infos in E_DEBUG_INFO
                EM_STOP_CANCEL - 'spekulative Ausfuehrung', siehe hierzu
                                 auch event_senders(WL)
	
	Diese Funktion bereitet die Event-Daten auf. Es werden aus den an-
	gemeldeten Lauschern die herausgesucht, die sich im deep-inventory
	der Zielobjekte aus 'dest' befinden. Sendet man also einen ET_GO 
	Event an einen Raum, dann werden all die Objekte ausgesucht, die
	sich im deep-inventory des Raumes befinden UND sich als Lauscher
	auf diesen Event angemeldet haben. Objekte die sich als globale
	Lauscher angemeldet haben (z.B. Handler), muessen sich in keinem der
	Zielobjekte befinden, sie werden in jedem Fall auch ausgewaehlt.
	Gibt es keine Lauscher auf diesen Event, wird kein Event erzeugt,
	was aber auch keinem auffaellt, da niemand in der Lage ist, es zu
	bemerken. :-) Bei mehreren tausend Objekten im MUD und nur einigen
	hundert die Events empfangen, werden ein Grossteil der Events
	'abgearbeitet' ohne auch nur ein fremdes Objekt zu benachrichtigen.
	Statistisch gesehen lauschen bei jedem Event meist weniger als 3
	Objekte im 'Zielgebiet' einem Event.

	Wurden alle Objekte gefunden, die den Event empfangen sollen, wird
	die entstandende Alist aus Prioritaeten und Closures noch sortiert,
	damit Objekte mit hohen Prioritaeten vor denen mit geringerer
	Prioriaet den Event empfangen koennen. Die Sortierung erfolgt dabei
	in aufsteigender Reihenfolge, da die Alist in process() vom Ende
	beginnend abgearbeitet wird.

	Wurden alle Objekte gefunden und sortiert, wird process() aufge-
	rufen, das die eigentlich Abarbeitung und den Aufruf der Lauscher-
	Closures uebernimmt.

	Wird festgestellt, dass ein Objekt einen Event erzeugt, obwohl es
	selbst dazu noch nich berechtigt ist (weil der Event noch gar nicht
	gehandelt wurde), wird eine Warnung ausgegeben.

FUNKTION statistik():

	public string statistik()
	
	Diese Funktion liefert Informationen ueber die Event-Verarbeitung
	des Daemons. Sie Funktion ist nur aktiv, wenn STATISTIK definiert
	ist.

FUNKTION clean_me():

	private void clean_me()
	
	Diese Funktion wird durch reset() aufgerufen und dient als 'garbage
	collector' ueber die globalen Variablen. Sie entfernt leere und
	damit ueberfluessig gewordenen Eintraege um die Empfaenger-Suche
	zu beschleunigen.

FUNKTION reset():

	void reset()
	
	Ruft clean_me() auf.

SIEHE AUCH:
	events(WL), memory(WL), cancel_event(S), handle_event(S),
	listen_event(S), send_event(S), unlisten_event(S),
	event_prioritaeten(WL), event_listeners(WL), event_senders(WL), 
        event_types(WL), events_fuer_alle(WL), set_global_listener(S)
	


Start » Magierhandbuch » Docu » Konzepte » Event_daemon Letzte Generierung: 25.04.2021, 01:58
Email an: mud@wl.mud.de
Valid HTML 4.01!