| 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 |
| <poisondeath> 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_INIT |
| 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 wahrscheinlich! |
| |
| |
| 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 <consumer> 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 <consumer> ein Objekt, liefert die Methode die Anzahl, wie oft dieses |
| Objekt (mit verschiedenen Closures) fuer den Hook <hookid> eingetragen ist. |
| Ist <consumer> eine Closure, liefert diese Methode 1, wenn diese |
| Closure fuer den Hook <hookid> 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.) |
| |