blob: de308bdefcd14c78d7423714d22a7093ad705d8a [file] [log] [blame]
MG Mud User88f12472016-06-24 23:31:02 +02001Das neue Hooksystem
2(Implementierung von Muadib, ueberarbeitet von Zesstra)
3
4EINLEITUNG
5==========
6Das neue Hooksystem baut nicht mehr auf der Eintragung eines Hooks in einer
7Property auf. Dadurch wird es moeglich, dass nicht nur ein Objekt sich als
8Hook eintraegt.
9
10Es gibt verschiedenen Arten von Hooks, die man eintragen kann:
11* Listener (H_LISTENER)
12 diese Hooks werden ueber ein Ereignis nur informiert,
13 koennen aber nicht eingreifen oder aendern.
14 max. Anzahl: 5
15* Data-Modifier (H_DATA_MODIFICATOR)
16 diese Hooks duerfen die Daten eines Ereignisses aendern.
17 max. Anzahl: 3
18* Hook-Modifier (H_HOOK_MODIFICATOR)
19 diese Hooks duerfen die Daten des Ereignisses aendern und
20 zusaetzlich das Ereignis auch abbrechen.
21 max. Anzahl: 2
22* Surveyor (H_HOOK_SURVEYOR)
23 diese Hooks duerfen alles oben beschriebene. Zusaetzlich werden
24 sie aber auch gefragt, wenn andere Objekte einen Hook eintragen
25 wollen, einen Hook abbrechen wollen oder Daten aendern wollen.
26 Oder anders: Surveyorhooks entscheiden, was andere duerfen.
27 Kein normales Objekte sollte diese Art von Hook eintragen. Der RM
28 muss die Verwendung eines Surveyors genehmigen.
29 max. Anzahl: 1
30
31Ausserdem lassen sich Hooks noch mit unterschiedlicher Prioritaet eintragen,
32welche dann in der entsprechenden Reihenfolge abgearbeitet werden. Wenn ein
33neuer Hook eingetragen wird, aber eigentlich die max. Anzahl schon erreicht
34wird, wird der Konsument mit der niedrigsten Prioritaet geloescht. In diesem
35Fall wird die superseededHook() im verdraengten Konsumenten gerufen.
36
37Um das neue Hook-System zu realisieren, gibt es zwei wesentliche Klassen.
38Die Objekte, die die Eintragung von Hooks erlauben, erben hierzu von
39hook_provider. Objekte, die einen Surveyor-Hook eintragen wollen, sollten von
40der Klasse hook_surveyor erben. Objekte mit normalen Hooks brauchen nichts zu
41erben.
42
43
44Welche Hooks gibt es zur Zeit in der Basis-Mudlib?
45=================================================
46* H_HOOK_MOVE
47 Bei Bewegung eines Objektes ausgeloest. Kann Bewegung beeinflussen oder
48 abbrechen.
49* H_HOOK_DIE
50 Beim Tod eines Lebewesens ausgeloest. Kann den Tod abbrechen oder
51 <poisondeath> abaendern.
52* H_HOOK_DEFEND
53 Im Defend() eines Lebenwesens ausgeloest. Kann das Defend() abbrechen und
54 Daten des Defend() aendern.
55* H_HOOK_ATTACK
56 Im Attack() eines Lebenwesens ausgeloest. Kann das Attack() abbrechen.
57* H_HOOK_HP
58 Bei Veraenderung der HP (LP) eines Lebewesens gerufen. (Zur Zeit keine
59 Datenveraenderung moeglich)
60* H_HOOK_SP
61 Bei Veraenderung der SP (KP) eines Lebewesens gerufen. (Zur Zeit keine
62 Datenveraenderung moeglich)
63* H_HOOK_ATTACK_MOD
64 Wird im Attack() ausgeloest, nachdem die fuer den Angriff wichtigen Daten
65 ermittelt und berechnet wurden. Diese koennen dann vom Hookonsumenten
66 nochmal geaendert werden. Auch ein Abbruch des Attack() ist hier noch
67 moeglich.
68* H_HOOK_ALCOHOL
69 Bei Veraenderung von P_ALCOHOL im Lebewesens gerufen.
70* H_HOOK_FOOD
71 Bei Veraenderung von P_FOOD im Lebewesens gerufen.
72* H_HOOK_DRINK
73 Bei Veraenderung von P_DRINK im Lebewesens gerufen.
74* H_HOOK_POISON
75 Bei Veraenderung von P_POISON im Lebewesens gerufen.
76* H_HOOK_CONSUME
77 Beim Konsumieren von Speisen und Getraenken in Kneipen im Lebewesens
78 gerufen.
79* H_HOOK_TEAMROWCHANGE
80 Bei Teamreihenwechsel vom Lebewesen ausgeloest.
81* H_HOOK_INSERT
82 Wird von Spielerobjekten ausgeloest, wenn ein Objekt ins Spielerinventar
83 bewegt wird. (Keine Datenveraenderung moeglich)
84* H_HOOK_EXIT_USE
85 Wird von einem Raum ausgeloest, wenn ein Lebewesen einen Ausgang benutzt.
86 Abbruch und Aenderung der Daten des Ausgangs moeglich.
87
88HOOK-KONSUMENTEN
89================
90Der Hook-Provider ruft bei Ausloesen des Hooks in allen Konsumenten eine
91bestimmte Methode auf. Wenn bei der Registrierung eines Objekts keine Closure
92angeben wurde, die in diesem Fall gerufen werden, wird standardmaessig die
93lfun HookCallback() gerufen (gibt man eine Closure an, bekommt sie die
94gleichen Argumente und es werden die beschriebenen Rueckgabewerte erwartet):
95 * mixed HookCallback(object hookSource, int hookid, mixed hookData)
96 Diese Methode wird in jedem Hook-Konsumenten eines Hook-Providers
97 aufgerufen, solange die Verarbeitung nicht vorher abgebrochen wurde.
98 Die Reihenfolge der Abarbeitung wird nach Liste (Surveyor,
99 Hook-Modifikator, Data-Modifikator, Listener) und dort nach Prioritaet
100 durchgefuehrt.
101 Ein Surveyor-Hook kann verhindern, dass Hooks bestimmte Aenderungen
102 durchfuehren.
103
104 Rueckgabewert ist ein Array, das die folgenden Werte beinhaltet.
105
106 H_RETCODE Gibt an, welcher Hook-Typ verwendet wurde.
107 H_NO_MOD => Nichts wurde veraendert.
108 H_ALTERED => Daten wurden veraendert.
109 H_CANCELLED => Hook-Kette soll abgebrochen werden.
110 => Ausserdem soll die Hook-ausloesende Stelle
111 abgebrochen werden. Z.B. wird das Defend()
112 abgebrochen, wenn ein H_HOOK_DEFEND
113 mit cancelled beantwortet wird.
114 H_RETDATA Gibt die (evtl. geaenderten) Daten an.
115 mixed-Objekt, das wie der Parameter hookData aufgebaut ist.
116
117Ein Objekt darf sich mehrfach fuer den gleichen Hook registrieren. Allerdings
118ist fuer jede Registrierung eine andere Closure noetig.
119
120 * void superseededHook(int hookid, object hookprovider)
121 Wird gerufen, wenn der Konsument von einem anderen mit hoeherer Prioritaet
122 verdraengt wurde.
123
124
125HOOK-PROVIDER
126=============
127 Der Hook-Provider bietet eine Menge von Methoden an, die eine Konfiguration
128 ermoeglichen und die Eintragung von Hook-Konsumenten erlauben. Im
129 Normalfall sollte er geerbt und nicht modifiziert werden (ausser natuerlich,
130 die vom Objekte bereitgestellten Hooks einzutragen).
131
132 * int* HListHooks();
133 Diese Methode liefert eine Liste von Hooktypen, fuer die das Objekt
134 Eintragungen annimmt. Hier koennte beispielsweise eine Liste mit den
135 Eintraegen fuer Attack-, Defend- und Move-Hooks stehen.
136
137
138 * protected void offerHook(int hookid, int offerstate);
139 Diese Methode dient dazu, einen bestimmten Hook (z.B. H_HOOK_MOVE)
140 anzubieten. Nur Hooks, die hiermit angeboten wurden, stehen zur
141 Registrierung zur Verfuegung.
142 'offerstate': 0 (nicht verfuegbar), 1 (verfuegbar/angeboten)
143
144
145 * int HRegisterToHook(int hookid, mixed consumer, int hookprio,
146 int consumertype, int timeInSeconds);
147 Registriert ein Objekt oder eine Closure als Hook-Konsument.
148 Parameter:
149 'hookid' gibt den Hook-Typ an, z.B. den Defend-Hook.
150 Man kann sich nur fuer Hooktypen eintragen, die die Methode
151 HListHooks() angeboten hat.
152 'consumer' Wenn ein Objekt, wird das Objekt eingetragen und spaeter
153 HookCallback() gerufen.
154 Wenn eine Closure, wird das Objekt der Closure eingetragen
155 und spaeter diese Closure gerufen.
156 'hookprio' Gibt die Prioritaet an, mit der der Hook laufen soll.
157 Diese Angabe bestimmt die Reihenfolge, in der die Hooks
158 in der Liste der Hooks eingetragen werden. Die Prioritaet
159 ist H_HOOK_LIBPRIO(x), H_HOOK_GUILDPRIO(x) oder
160 H_HOOK_OTHERPRIO(x). x darf 0, 1 oder 2 sein (je niedriger,
161 desto hoeher die Prioritaet).
162 'consumertype' Gibt an, um welche Art von Hook es sich handelt.
163 Es gibt vier festgelegten Typen, die fuer alle Hooks
164 existieren koennen. Die Methode HConsumerTypeIsAllowed()
165 gibt Aufschluss darueber, welche Hook-Typen existieren.
166 Die Hook-Typen sind in hook.h definiert.
167 'timeInSeconds' gibt die Laufzeit des Hooks an. Falls 0 eingetragen wird,
168 laeuft der Hook ewig.
169 Rueckgabewerte:
170 1 - Registrierung erfolgreich
171 <=0 - Registrierung fehlgeschlagen:
172 -1 : Hook unbekannt
173 -2 : consumer ist keine closure und es konnte kein Callback auf
174 HookCallback im consumer erstellt werden.
175 -3 : consumer ist bereits registriert
176 -4 : consumertyp ist nicht erlaubt
177 -5 : hookprio ist nicht erlaubt
178 -6 : Surveyor hat Registrierung nicht erlaubt
179 -7 : zuviele Hooks registriert / kein Hookeintrag frei
180
181 * int HUnregisterFromHook(int hookid, mixed consumer);
182 Hebt die Registrierung von <consumer> fuer einen bestimmten Hook-Typ wieder
183 auf.
184 Parameter:
185 'hookid' Die Kennung des Hook-Typs, z.B. die Kennung des Attack-Hooks.
186 'consumer' Das Objekt oder die Closure, die/das nicht mehr registriert sein
187 soll. Bei einer Closure wird genau diese ausgetragen. Bei der
188 Angabe eines Objekts wird versucht, die Closure auf
189 HookCallback() in diesem Objekt auszutragen.
190 Rueckgabewerte:
191 0 - 'consumer' nicht als Konsument gefunden
192 1 - Austragen erfolgreich
193
194 * int HConsumerTypeIsAllowed(int type, object consumer);
195 Diese Methode liefert 1 zurueck, wenn ein bestimmter Konsumenten-Typ
196 (fuer diesen Konsumenten) erlaubt wird.
197 Die Standardmethode liefert immer 1 (true) zurueck. Erbende Objekte
198 koennen diese Methode ueberschreiben, wenn sie nicht alle Hooktypen
199 anbieten.
200
201
202 * int HPriorityIsAllowed(int prio, object consumer);
203 Diese Methode gibt an, ob eine bestimmte Prioritaet (fuer den angegebenen
204 Konsumenten) erlaubt ist. Die Standardmethode liefert immer 1 (true)
205 zurueck. Erbende Objekte koennen diese Methode ueberschreiben, wenn
206 sie die verfuegbaren Hook-Prioritaeten einschraenken wollen.
207
208
209 * int HIsHookConsumer(int hookid, mixed consumer);
210 Ist <consumer> ein Objekt, liefert die Methode die Anzahl, wie oft dieses
211 Objekt (mit verschiedenen Closures) fuer den Hook <hookid> eingetragen ist.
212 Ist <consumer> eine Closure, liefert diese Methode 1, wenn diese
213 Closure fuer den Hook <hookid> eingetragen ist.
214
215
216 * protected mapping HCopyHookMapping();
217 Diese Methode liefert eine Kopie des Hook-Mappings.
218 ACHTUNG: diese Daten sollten das Objekt NIEMALS verlassen. (Ausser fuer
219 Debugzwecke)
220
221
222
223HOOK-SURVEYOR
224=============
225 Objekte mit Surveyorhooks muessen eine Menge von Methoden definieren, die
226 der Hookprovider aufruft:
227
228 * status HookRegistrationCallback(
229 object registringObject,
230 int hookid,
231 object hookSource,
232 int registringObjectsPriority,
233 int registringObjectsType)
234 Diese Methode wird vom Hook-Provider aufgerufen, wenn der Hook-Konsument
235 als Surveyor eingetragen ist und ein weiterer Hook eingetragen werden soll.
236 Gibt diese Methode 0 zurueck, dann verbietet der Konsument, dass der
237 andere Konsument als Hook eingetragen wird.
238
239 * int HookCancelAllowanceCallback(
240 object cancellingObject,
241 int hookid,
242 object hookSource,
243 int cancellingObjectsPriority,
244 mixed hookData)
245 Diese Methode wird aufgerufen, um herauszufinden, ob ein bestimmter
246 anderer Hook die Ausfuehrung der Hook-Kette unterbrechen darf.
247 Nur Hooks im Bereich H_HOOK_MODIFICATOR werden der Methode uebergeben.
248
249 * int HookModificationAllowanceCallback(
250 object modifyingObject,
251 int hookid,
252 object hookSource,
253 int modifyingObjectsPriority,
254 mixed hookData)
255 Diese Methode wird aufgerufen, um herauszufinden, ob ein bestimmter
256 anderer Hook die Daten des Hooks veraendern darf oder nicht.
257 Es werden die Hooks in den Bereichen H_HOOK_MODIFICATOR und
258 H_DATA_MODIFICATOR (in dieser Reihenfolge) aufgerufen.
259
260
261WAS KOSTET DAS?
262 Das Ausloesen eines Hooks per HookFlow() kostet 111 Ticks und ca. 7 us, wenn
263 es gar keinen gibt, der drauf lauscht (sozusagen Fixkosten).
264 Pro H_LISTENER kommen dann 31 Ticks und ca. 2 us dazu.
265
266 Gibts einen Surveyor-Hook (der wird dann gefragt, ob andere Objekte die
267 Daten des Hooks aendern oder die Hookverarbeitung abbrechen duerfen):
268 Fixkosten: 155 Ticks, 11 us.
269 Plus pro Data-Modifier:
270 106 Ticks, 5.6 us
271 Plus pro Hook-Modifier, der aber nur Daten aendert:
272 112 Ticks, 6.4 us
273 Und ein Hook-Modifier, der den Hook abbricht:
274 76 Ticks, 4 us
275
276 (Macht der Surveyor natuerlich irgendwas anderes als 'return 1;', wirds
277 natuerlich entsprechend teurer.)
278