Start Info Community Spielen
 
 

Morgengrauner Dokumentation

Dateipfad: /home/mud/mudlib/doc//std/hooks

Das neue Hooksystem
(Implementierung von Muadib, ueberarbeitet von Zesstra)

EINLEITUNG
==========
Das neue Hooksystem baut nicht mehr auf der Eintragung eines Hooks in einer
Property auf. Dadurch wird es moeglich, dass nicht nur ein Objekt sich als
Hook eintraegt.

Es gibt verschiedenen Arten von Hooks, die man eintragen kann:
* Listener (H_LISTENER)
            diese Hooks werden ueber ein Ereignis nur informiert,
            koennen aber nicht eingreifen oder aendern.
            max. Anzahl: 5
* Data-Modifier (H_DATA_MODIFICATOR)
            diese Hooks duerfen die Daten eines Ereignisses aendern.
            max. Anzahl: 3
* Hook-Modifier (H_HOOK_MODIFICATOR)
            diese Hooks duerfen die Daten des Ereignisses aendern und
            zusaetzlich das Ereignis auch abbrechen.
            max. Anzahl: 2
* Surveyor (H_HOOK_SURVEYOR)
            diese Hooks duerfen alles oben beschriebene. Zusaetzlich werden
            sie aber auch gefragt, wenn andere Objekte einen Hook eintragen
            wollen, einen Hook abbrechen wollen oder Daten aendern wollen.
            Oder anders: Surveyorhooks entscheiden, was andere duerfen.
            Kein normales Objekte sollte diese Art von Hook eintragen. Der RM
            muss die Verwendung eines Surveyors genehmigen.
            max. Anzahl: 1

Ausserdem lassen sich Hooks noch mit unterschiedlicher Prioritaet eintragen,
welche dann in der entsprechenden Reihenfolge abgearbeitet werden. Wenn ein
neuer Hook eingetragen wird, aber eigentlich die max. Anzahl schon erreicht
wird, wird der Konsument mit der niedrigsten Prioritaet geloescht. In diesem
Fall wird die superseededHook() im verdraengten Konsumenten gerufen.

Um das neue Hook-System zu realisieren, gibt es zwei wesentliche Klassen.
Die Objekte, die die Eintragung von Hooks erlauben, erben hierzu von
hook_provider. Objekte, die einen Surveyor-Hook eintragen wollen, sollten von
der Klasse hook_surveyor erben. Objekte mit normalen Hooks brauchen nichts zu
erben.


Welche Hooks gibt es zur Zeit in der Basis-Mudlib?
=================================================
* H_HOOK_MOVE
  Bei Bewegung eines Objektes ausgeloest. Kann Bewegung beeinflussen oder
  abbrechen.
* H_HOOK_DIE
  Beim Tod eines Lebewesens ausgeloest. Kann den Tod abbrechen oder
   abaendern.
* H_HOOK_DEFEND
  Im Defend() eines Lebenwesens ausgeloest. Kann das Defend() abbrechen und
  Daten des Defend() aendern.
* H_HOOK_ATTACK
  Im Attack() eines Lebenwesens ausgeloest. Kann das Attack() abbrechen.
* H_HOOK_HP
  Bei Veraenderung der HP (LP) eines Lebewesens gerufen. (Zur Zeit keine
  Datenveraenderung moeglich)
* H_HOOK_SP
  Bei Veraenderung der SP (KP) eines Lebewesens gerufen. (Zur Zeit keine
  Datenveraenderung moeglich)
* H_HOOK_ATTACK_MOD
  Wird im Attack() ausgeloest, nachdem die fuer den Angriff wichtigen Daten
  ermittelt und berechnet wurden. Diese koennen dann vom Hookonsumenten
  nochmal geaendert werden. Auch ein Abbruch des Attack() ist hier noch
  moeglich.
* H_HOOK_ALCOHOL
  Bei Veraenderung von P_ALCOHOL im Lebewesens gerufen.
* H_HOOK_FOOD
  Bei Veraenderung von P_FOOD im Lebewesens gerufen.
* H_HOOK_DRINK
  Bei Veraenderung von P_DRINK im Lebewesens gerufen.
* H_HOOK_POISON
  Bei Veraenderung von P_POISON im Lebewesens gerufen.
* H_HOOK_CONSUME
  Beim Konsumieren von Speisen und Getraenken in Kneipen im Lebewesens
  gerufen.
* H_HOOK_TEAMROWCHANGE
  Bei Teamreihenwechsel vom Lebewesen ausgeloest.
* H_HOOK_INSERT
  Wird von Spielerobjekten ausgeloest, wenn ein Objekt ins Spielerinventar
  bewegt wird. (Keine Datenveraenderung moeglich)
* H_HOOK_EXIT_USE
  Wird von einem Raum ausgeloest, wenn ein Lebewesen einen Ausgang benutzt.
  Abbruch und Aenderung der Daten des Ausgangs moeglich.
* H_HOOK_EXIT_USE
  Wird von einem Raum ausgeloest, wenn init() gerufen wird (d.h. ein Lebewesen
  den Raum betritt). Hat keine Daten.
  Abbruch moeglich.
  ACHTUNG: bei Abbruch von init() sind schwere Bugs moeglich!


HOOK-KONSUMENTEN
================
Der Hook-Provider ruft bei Ausloesen des Hooks in allen Konsumenten eine
bestimmte Methode auf. Wenn bei der Registrierung eines Objekts keine Closure
angeben wurde, die in diesem Fall gerufen werden, wird standardmaessig die
lfun HookCallback() gerufen (gibt man eine Closure an, bekommt sie die
gleichen Argumente und es werden die beschriebenen Rueckgabewerte erwartet):
  * mixed HookCallback(object hookSource, int hookid, mixed hookData)
  Diese Methode wird in jedem Hook-Konsumenten eines Hook-Providers
  aufgerufen, solange die Verarbeitung nicht vorher abgebrochen wurde.
  Die Reihenfolge der Abarbeitung wird nach Liste (Surveyor,
  Hook-Modifikator, Data-Modifikator, Listener) und dort nach Prioritaet
  durchgefuehrt.
  Ein Surveyor-Hook kann verhindern, dass Hooks bestimmte Aenderungen
  durchfuehren.

  Rueckgabewert ist ein Array, das die folgenden Werte beinhaltet.

  H_RETCODE Gibt an, welcher Hook-Typ verwendet wurde.
      H_NO_MOD => Nichts wurde veraendert.
      H_ALTERED => Daten wurden veraendert.
      H_CANCELLED => Hook-Kette soll abgebrochen werden.
                  => Ausserdem soll die Hook-ausloesende Stelle
                     abgebrochen werden. Z.B. wird das Defend()
                     abgebrochen, wenn ein H_HOOK_DEFEND
                     mit cancelled beantwortet wird.
  H_RETDATA Gibt die (evtl. geaenderten) Daten an.
      mixed-Objekt, das wie der Parameter hookData aufgebaut ist.

Ein Objekt darf sich mehrfach fuer den gleichen Hook registrieren. Allerdings
ist fuer jede Registrierung eine andere Closure noetig.

  * void superseededHook(int hookid, object hookprovider)
    Wird gerufen, wenn der Konsument von einem anderen mit hoeherer Prioritaet
    verdraengt wurde.


HOOK-PROVIDER
=============
  Der Hook-Provider bietet eine Menge von Methoden an, die eine Konfiguration
  ermoeglichen und die Eintragung von Hook-Konsumenten erlauben. Im
  Normalfall sollte er geerbt und nicht modifiziert werden (ausser natuerlich,
  die vom Objekte bereitgestellten Hooks einzutragen).

  * int* HListHooks();
  Diese Methode liefert eine Liste von Hooktypen, fuer die das Objekt
  Eintragungen annimmt. Hier koennte beispielsweise eine Liste mit den
  Eintraegen fuer Attack-, Defend- und Move-Hooks stehen.


  * protected void offerHook(int hookid, int offerstate);
  Diese Methode dient dazu, einen bestimmten Hook (z.B. H_HOOK_MOVE)
  anzubieten. Nur Hooks, die hiermit angeboten wurden, stehen zur
  Registrierung zur Verfuegung.
  'offerstate': 0 (nicht verfuegbar), 1 (verfuegbar/angeboten)


  * int HRegisterToHook(int hookid, mixed consumer, int hookprio,
                       int consumertype, int timeInSeconds);
  Registriert ein Objekt oder eine Closure als Hook-Konsument.
  Parameter:
  'hookid'        gibt den Hook-Typ an, z.B. den Defend-Hook.
                  Man kann sich nur fuer Hooktypen eintragen, die die Methode
                  HListHooks() angeboten hat.
  'consumer'      Wenn ein Objekt, wird das Objekt eingetragen und spaeter
                  HookCallback() gerufen.
                  Wenn eine Closure, wird das Objekt der Closure eingetragen
                  und spaeter diese Closure gerufen.
  'hookprio'      Gibt die Prioritaet an, mit der der Hook laufen soll.
                  Diese Angabe bestimmt die Reihenfolge, in der die Hooks
                  in der Liste der Hooks eingetragen werden. Die Prioritaet
                  ist H_HOOK_LIBPRIO(x), H_HOOK_GUILDPRIO(x) oder
                  H_HOOK_OTHERPRIO(x). x darf 0, 1 oder 2 sein (je niedriger,
                  desto hoeher die Prioritaet).
  'consumertype'  Gibt an, um welche Art von Hook es sich handelt.
                  Es gibt vier festgelegten Typen, die fuer alle Hooks
                  existieren koennen. Die Methode HConsumerTypeIsAllowed()
                  gibt Aufschluss darueber, welche Hook-Typen existieren.
                  Die Hook-Typen sind in hook.h definiert.
  'timeInSeconds' gibt die Laufzeit des Hooks an. Falls 0 eingetragen wird,
                  laeuft der Hook ewig.
  Rueckgabewerte:
    1 - Registrierung erfolgreich
  <=0 - Registrierung fehlgeschlagen:
        -1 : Hook unbekannt
        -2 : consumer ist keine closure und es konnte kein Callback auf
             HookCallback im consumer erstellt werden.
        -3 : consumer ist bereits registriert
        -4 : consumertyp ist nicht erlaubt
        -5 : hookprio ist nicht erlaubt
        -6 : Surveyor hat Registrierung nicht erlaubt
        -7 : zuviele Hooks registriert / kein Hookeintrag frei

  * int HUnregisterFromHook(int hookid, mixed consumer);
  Hebt die Registrierung von  fuer einen bestimmten Hook-Typ wieder
  auf.
  Parameter:
  'hookid'    Die Kennung des Hook-Typs, z.B. die Kennung des Attack-Hooks.
  'consumer'  Das Objekt oder die Closure, die/das nicht mehr registriert sein
              soll. Bei einer Closure wird genau diese ausgetragen. Bei der
              Angabe eines Objekts wird versucht, die Closure auf
              HookCallback() in diesem Objekt auszutragen.
  Rueckgabewerte:
  0 - 'consumer' nicht als Konsument gefunden
  1 - Austragen erfolgreich

  * int HConsumerTypeIsAllowed(int type, object consumer);
  Diese Methode liefert 1 zurueck, wenn ein bestimmter Konsumenten-Typ
  (fuer diesen Konsumenten) erlaubt wird.
  Die Standardmethode liefert immer 1 (true) zurueck. Erbende Objekte
  koennen diese Methode ueberschreiben, wenn sie nicht alle Hooktypen
  anbieten.


  * int HPriorityIsAllowed(int prio, object consumer);
  Diese Methode gibt an, ob eine bestimmte Prioritaet (fuer den angegebenen
  Konsumenten) erlaubt ist. Die Standardmethode liefert immer 1 (true)
  zurueck. Erbende Objekte koennen diese Methode ueberschreiben, wenn
  sie die verfuegbaren Hook-Prioritaeten einschraenken wollen.


  * int HIsHookConsumer(int hookid, mixed consumer);
  Ist  ein Objekt, liefert die Methode die Anzahl, wie oft dieses
  Objekt (mit verschiedenen Closures) fuer den Hook  eingetragen ist.
  Ist  eine Closure, liefert diese Methode 1, wenn diese
  Closure fuer den Hook  eingetragen ist.


  * protected mapping HCopyHookMapping();
  Diese Methode liefert eine Kopie des Hook-Mappings.
  ACHTUNG: diese Daten sollten das Objekt NIEMALS verlassen. (Ausser fuer
           Debugzwecke)



HOOK-SURVEYOR
=============
  Objekte mit Surveyorhooks muessen eine Menge von Methoden definieren, die
  der Hookprovider aufruft:

  * status HookRegistrationCallback(
                object registringObject,
                int hookid,
                object hookSource,
                int registringObjectsPriority,
                int registringObjectsType)
  Diese Methode wird vom Hook-Provider aufgerufen, wenn der Hook-Konsument
  als Surveyor eingetragen ist und ein weiterer Hook eingetragen werden soll.
  Gibt diese Methode 0 zurueck, dann verbietet der Konsument, dass der
  andere Konsument als Hook eingetragen wird.

  * int HookCancelAllowanceCallback(
                object cancellingObject,
                int hookid,
                object hookSource,
                int cancellingObjectsPriority,
                mixed hookData)
  Diese Methode wird aufgerufen, um herauszufinden, ob ein bestimmter
  anderer Hook die Ausfuehrung der Hook-Kette unterbrechen darf.
  Nur Hooks im Bereich H_HOOK_MODIFICATOR werden der Methode uebergeben.

  * int HookModificationAllowanceCallback(
                object modifyingObject,
                int hookid,
                object hookSource,
                int modifyingObjectsPriority,
                mixed hookData)
  Diese Methode wird aufgerufen, um herauszufinden, ob ein bestimmter
  anderer Hook die Daten des Hooks veraendern darf oder nicht.
  Es werden die Hooks in den Bereichen H_HOOK_MODIFICATOR und
  H_DATA_MODIFICATOR (in dieser Reihenfolge) aufgerufen.


WAS KOSTET DAS?
  Das Ausloesen eines Hooks per HookFlow() kostet 111 Ticks und ca. 7 us, wenn
  es gar keinen gibt, der drauf lauscht (sozusagen Fixkosten).
  Pro H_LISTENER kommen dann 31 Ticks und ca. 2 us dazu.

  Gibts einen Surveyor-Hook (der wird dann gefragt, ob andere Objekte die
  Daten des Hooks aendern oder die Hookverarbeitung abbrechen duerfen):
  Fixkosten: 155 Ticks, 11 us.
  Plus pro Data-Modifier:
  106 Ticks, 5.6 us
  Plus pro Hook-Modifier, der aber nur Daten aendert:
  112 Ticks, 6.4 us
  Und ein Hook-Modifier, der den Hook abbricht:
  76 Ticks, 4 us

  (Macht der Surveyor natuerlich irgendwas anderes als 'return 1;', wirds
  natuerlich entsprechend teurer.)


zurück zur Übersicht

FEEDBACK | IMPRESSUM | DATENSCHUTZ 1992–2019 © MorgenGrauen. Alle Rechte vorbehalten.