blob: d910b41a545fba0f00f622add6430dc0a0b154de [file] [log] [blame]
MG Mud User88f12472016-06-24 23:31:02 +02001// MorgenGrauen MUDlib
2//
3// thing/properties.c -- most general class (property handling)
4//
5// $Id: properties.c 6951 2008-08-09 23:08:31Z Zesstra $
6
7// Properties.c -- Propertyverwaltung
8// (c) 1993 Hate@MorgenGrauen, Mateese@NightFall
9// Idea and Code Flames and Destructions
10// -> *grin* thats the point actually :)
11//
12// Ueberarbeitet von Jof am 12.06.1994
13// Ueberarbeitet von Mandragon am 11.05.2003
14
15#pragma strict_types
16#pragma save_types
17#pragma range_check
18#pragma no_clone
MG Mud User88f12472016-06-24 23:31:02 +020019
Zesstra830b2af2021-12-29 16:44:09 +010020#include <driver_info.h>
21
MG Mud User88f12472016-06-24 23:31:02 +020022#define NEED_PROTOTYPES
23
24#include "/sys/thing/properties.h"
25#include "/secure/wizlevels.h"
26
MG Mud User88f12472016-06-24 23:31:02 +020027// the mapping where the actual properties are stored. Direct initialization.
Zesstra3f3e7842022-01-16 22:33:03 +010028// Indexed with F_VALUE, F_MODE, F_SET_METHOD, F_QUERY_METHOD, F_VALIDATOR
29// F_MODE, F_SET_METHOD, F_QUERY_METHOD and F_VALIDATOR are usually 'sparse'
30// (i.e. there is no entry for most properties), therefore it is more
31// memory-efficient to store them like this than in one mapping, although it
32// requires more mapping lookups.
33private nosave mapping *prop = allocate(F_PROP_ENTRIES, ([]));
MG Mud User88f12472016-06-24 23:31:02 +020034
Zesstra375df1e2021-04-21 11:09:06 +020035// the mapping that is used for saving. During save_object/restore_object it
36// contains the properties with SAVE flag.
37// This is empty outside of a save_object() or restore_object() call!
MG Mud User88f12472016-06-24 23:31:02 +020038private mapping properties;
39
MG Mud User88f12472016-06-24 23:31:02 +020040
Zesstraf971f3a2021-04-13 11:48:37 +020041// Z.Zt. nur Abschalten des Resets noetig.
MG Mud User88f12472016-06-24 23:31:02 +020042protected void create() {
43 // Blueprints in /std benoetigenkeinen Reset ....
44 if (object_name()=="/std/thing/properties")
45 set_next_reset(-1);
46}
47
48protected void create_super() {
49 set_next_reset(-1);
50}
51
Zesstrad2c193e2022-01-16 22:49:38 +010052// Prueft, ob ein Zugriff auf eine Property erlaubt ist.
53// Properties, die SECURED oder PROTECTED sind, duerfen nur vom Objekt
54// selber, EM+ oder ROOT veraendert werden.
55#define SAVE_OBJECT 1
56#define PROP_SET 2
57#define PROTECTED_SET 3
58#define PROTECTED_DELETE 4
59#define SECURED_SET 5
60#define SECURED_DELETE 6
Zesstra5a9cc652022-01-20 00:24:50 +010061#define RAW_ACCESS 7
Zesstrad2c193e2022-01-16 22:49:38 +010062nomask private int prop_check_privilege(int drop_priv, int mode,
63 int op=PROP_SET)
MG Mud User88f12472016-06-24 23:31:02 +020064{
Zesstrad2c193e2022-01-16 22:49:38 +010065 // Interne Calls oder eigenes Objekt (als letzter 'externer' Aufrufer via
66 // Callother) darf alles
67 if (!drop_priv || previous_object() == this_object())
Zesstra0c38e162022-01-20 00:00:39 +010068
Zesstrad2c193e2022-01-16 22:49:38 +010069 return 1;
70
71 // Ab hier nur noch fremde Objekte
72 switch(op)
73 {
74 case SAVE_OBJECT:
75 // Eigentlich nur vom jeweils aktiven simul_efun-Objekt gerufen, aber
76 // der einfacheit halber sind alle ROOT-Objekte erlaubt. Aber nur
77 // direkten Caller pruefen, *nicht* ROOT_SECURITY!
Zesstra68a28c22025-06-28 15:04:35 +020078 if (geteuid(previous_object()) == ROOTID)
Zesstrad2c193e2022-01-16 22:49:38 +010079 return 1;
80
81 case SECURED_DELETE:
82 // Das SECURED-Flag darf bei Properties nicht mehr geloescht werden
83 return 0;
84
85 case SECURED_SET:
86 if (geteuid(previous_object()) == ROOTID || ARCH_SECURITY)
87 return 1;
88
Zesstra5a9cc652022-01-20 00:24:50 +010089 case RAW_ACCESS:
90 // RAW_ACCESS grants access to all properties and their raw, uncopied
91 // data. It is only for very specific objects and they *MUST NOT* change
92 // it or give user-code (or any other) access to it.
93 if (load_name(previous_object()) == "/obj/tools/MGtool")
94 return 1;
95 return 0;
96
Zesstrad2c193e2022-01-16 22:49:38 +010097 case PROTECTED_DELETE:
98 case PROTECTED_SET:
99 case PROP_SET:
100 // Properties, die schon SECURED oder PROTECTED sind, duerfen
101 // nur vom Objekt selber manipuliert werden
102 if (!(mode & (PROTECTED|SECURED)) // nicht geschuetzt
103 || (geteuid(previous_object()) == ROOTID || ARCH_SECURITY))
104 return 1;
105 }
106 return 0;
107}
MG Mud User88f12472016-06-24 23:31:02 +0200108
109// Set() -- provides direct access to a property, no filters
Zesstra5c0c4092021-09-08 23:27:54 +0200110// Type=F_VALUE und drop_priv=extern_call() by default
111public mixed Set(string name, mixed Value, int Type, int drop_priv)
MG Mud User88f12472016-06-24 23:31:02 +0200112{
Zesstrad2c193e2022-01-16 22:49:38 +0100113 int mode = prop[F_MODE][name];
Zesstra830b2af2021-12-29 16:44:09 +0100114 // Es ist verfuehrerisch, das 'drop_priv||extern_call()' durch 'drop_priv' zu
115 // ersetzen, weil extern_call() das default-argument fuer <drop_priv> ist.
116 // Das ist keine gute Idee, weil <drop_priv> unter der Kontrolle des Aufrufers
117 // ist und dieser 0 uebergeben kann. Sprich: wenn es 0 ist, muessen wir
118 // dennoch selber pruefen. Wir glauben aber immer, wenn es 1 ist, der
119 // Aufrufer hat nichts davon und das eigene Objekt darf Privilegien abgeben.
Zesstrad2c193e2022-01-16 22:49:38 +0100120 drop_priv = drop_priv||extern_call();
Zesstra5c0c4092021-09-08 23:27:54 +0200121
Zesstrad2c193e2022-01-16 22:49:38 +0100122 // Erstmal pruefen, ob Aenderung der Prop erlaubt ist.
123 if (!prop_check_privilege(drop_priv, mode, PROP_SET))
124 return -1;
125 // Bemerkung: aktuell koennen alle Objekte PROTECTED setzen. Loeschen
126 // koennen es ROOT, EM+ und ME ueber den Check oben.
127
128 // Soll SECURED geloescht werden und ist das erlaubt?
Zesstra1b2205b2025-06-28 15:56:05 +0200129 if ( (Type==F_MODE||Type==F_MODE_AD) && (Value & SECURED)
130 && (prop[F_MODE][name] & SECURED)
Zesstrad2c193e2022-01-16 22:49:38 +0100131 && !prop_check_privilege(drop_priv, mode, SECURED_DELETE))
MG Mud User88f12472016-06-24 23:31:02 +0200132 return -2;
Zesstra5c0c4092021-09-08 23:27:54 +0200133
Zesstrad2c193e2022-01-16 22:49:38 +0100134 // Soll SECURED gesetzt werden und ist das erlaubt?
Zesstra1b2205b2025-06-28 15:56:05 +0200135 if ( (Type==F_MODE||Type==F_MODE_AS) && (Value&SECURED)
136 && !(prop[F_MODE][name] & SECURED)
Zesstrad2c193e2022-01-16 22:49:38 +0100137 && !prop_check_privilege(drop_priv, mode, SECURED_SET) )
MG Mud User88f12472016-06-24 23:31:02 +0200138 return -3;
139
140 switch(Type)
141 {
142 // Je nach Modus Flags veraendern
Zesstra785c1082025-07-03 00:37:40 +0200143 case F_MODE_AS:
144 prop[F_MODE][name]|= Value;
145 return prop[F_MODE][name];
146 case F_MODE_AD:
147 prop[F_MODE][name]&= ~Value;
148 if (!prop[F_MODE][name]) prop[F_MODE]-=([name]);
149 return prop[F_MODE][name];
150 case F_MODE:
151 prop[F_MODE][name]^= Value;
152 if (!prop[F_MODE][name]) prop[F_MODE]-=([name]);
153 return prop[F_MODE][name];
Zesstraf54f03a2021-12-29 19:55:08 +0100154
MG Mud User88f12472016-06-24 23:31:02 +0200155 case F_SET_METHOD:
Zesstra785c1082025-07-03 00:37:40 +0200156 if (!Value)
157 {
158 prop[Type]-=([name]);
159 break;
160 }
161 // Ungebundene Lambda_Closure? Heutzutage ein Fehler.
162 if (closurep(Value) && !query_closure_object(Value))
163 {
164 raise_error("Ungebundene Lambdas sind als Setmethoden "
165 "nicht mehr unterstuetzt.\n");
166 }
167 // -1 als Setz-Methode: Stattdessen NOSETMETHOD setzen (deprecated!)
MG Mud User88f12472016-06-24 23:31:02 +0200168 if (Value == -1)
169 {
170 prop[F_SET_METHOD]-=([name]);
171 prop[F_MODE][name] |= NOSETMETHOD;
172 return 0;
173 }
Zesstra785c1082025-07-03 00:37:40 +0200174 // Zur Sicherheit SETMAPPED loeschen
175 prop[F_MODE][name] &= ~SETMAPPED;
176 prop[Type][name] = Value;
177 break;
178
179 case F_SET_MAPPER:
180 // Als Type F_SET_METHOD speichern/eintragen.
181 Type = F_SET_METHOD;
182 if (!Value)
183 {
184 prop[F_MODE][name] &= ~SETMAPPED;
185 prop[Type]-=([name]);
186 break;
187 }
188 // Da wir hier keine Ruecksicht auf historischen Kram nehmen muessen,
189 // werden nur Closures akzeptiert. Und auch keine -1 als Alias fuer
190 // NOSETMETHOD.
191 if (!closurep(Value))
192 {
193 raise_error("Fuer F_SET_MAPPER werden nur Closures unterstuetzt.\n");
194 }
195 // Und keine ungebundenen Lambda-Closures.
196 if (!query_closure_object(Value))
197 {
198 raise_error("Ungebundene Lambdas sind als Mapper "
199 "nicht unterstuetzt.\n");
200 }
201 // SETMAPPED setzen
202 prop[F_MODE][name] |= SETMAPPED;
203 prop[Type][name] = Value;
204 break;
205
MG Mud User88f12472016-06-24 23:31:02 +0200206 case F_QUERY_METHOD:
Zesstra785c1082025-07-03 00:37:40 +0200207 if (!Value)
208 {
209 prop[Type]-=([name]);
210 break;
211 }
212 // Jetzt wirklich mal nen Fehler werfen und den Zopf abschneiden.
213 if (!closurep(Value))
214 {
215 raise_error("Fuer F_QUERY_METHOD werden nur noch Closures "
216 "unterstuetzt.\n");
217 }
218 // Ungebundene Lambda-Closure? Heutzutage ein Fehler.
219 if (!query_closure_object(Value))
MG Mud User88f12472016-06-24 23:31:02 +0200220 {
Zesstra746046c2018-11-04 11:44:44 +0100221 raise_error("Ungebundene Lambdas sind als Querymethoden "
222 "nicht mehr unterstuetzt.\n");
MG Mud User88f12472016-06-24 23:31:02 +0200223 }
Zesstra785c1082025-07-03 00:37:40 +0200224 prop[Type][name] = Value;
225 break;
226
MG Mud User88f12472016-06-24 23:31:02 +0200227 default:
228 if (!Value) prop[Type]-=([name]);
229 else prop[Type][name] = Value;
230 }
231
232 // Gesamtwert zurueckgeben
233 return prop[Type][name];
234}
235
236
237// Direktes Auslesen der Property ohne Filter ...
Zesstra5c0c4092021-09-08 23:27:54 +0200238// Type = F_VALUE by default
239public mixed Query( string name, int Type )
MG Mud User88f12472016-06-24 23:31:02 +0200240{
241 if (pointerp(prop)) return prop[Type][name];
242 return 0;
243}
244
245// Property setzen unter Verwendung evtl. vorhandener Zugriffsfunktionen
Zesstraffcd0fe2021-09-08 23:33:17 +0200246public mixed SetProp( string name, mixed Value, int drop_priv)
MG Mud User88f12472016-06-24 23:31:02 +0200247{
MG Mud User88f12472016-06-24 23:31:02 +0200248 mixed result;
Zesstra10412ed2019-11-23 15:54:09 +0100249
Zesstraf54f03a2021-12-29 19:55:08 +0100250 int mode = prop[F_MODE][name];
MG Mud User88f12472016-06-24 23:31:02 +0200251 // NOSETMETHOD: Darf nicht gesetzt werden
Zesstraf54f03a2021-12-29 19:55:08 +0100252 if (mode & NOSETMETHOD ) return -1;
MG Mud User88f12472016-06-24 23:31:02 +0200253
254 // Set-Method abfragen, so vorhanden
Zesstra10412ed2019-11-23 15:54:09 +0100255 // TODO: nachdem alle moeglichen Werte als Set-Methode illegal sind, auf
256 // closure aendern.
257 mixed func = prop[F_SET_METHOD][name];
258 if (func)
MG Mud User88f12472016-06-24 23:31:02 +0200259 {
MG Mud User88f12472016-06-24 23:31:02 +0200260 // Wert als Set-Method? gleich zurueckgeben
261 if (!closurep(func)) return func;
262
263 // An dieser Stelle muss func eine Closure sein. Da Set() ungebundene
264 // Lambdas bindet, kann es auch nur eine gebundene Closure sein und das
265 // Objekt existiert auch noch (sonst waere func == 0).
266
MG Mud User88f12472016-06-24 23:31:02 +0200267 // Dann mal die Closure aufrufen. Bei Fehler selbige loeschen
268 if (catch(result=funcall(func, Value, name);publish))
269 {
270 prop[F_SET_METHOD]-=([name]);
271 }
Zesstraf54f03a2021-12-29 19:55:08 +0100272 else // Erfolgreicher call
273 {
274 if (mode & SETMAPPED) // SM hat noch nicht selber gesetzt
Zesstrad2c193e2022-01-16 22:49:38 +0100275 result = Set( name, result, F_VALUE, drop_priv||extern_call() );
Zesstraf54f03a2021-12-29 19:55:08 +0100276 }
Zesstraffcd0fe2021-09-08 23:33:17 +0200277
MG Mud User88f12472016-06-24 23:31:02 +0200278 // Und zurueckgeben
Zesstraf54f03a2021-12-29 19:55:08 +0100279 return result;
MG Mud User88f12472016-06-24 23:31:02 +0200280 }
281
Zesstraffcd0fe2021-09-08 23:33:17 +0200282 // _set_*-Methode vorhanden? falls ja, aufrufen.
MG Mud User88f12472016-06-24 23:31:02 +0200283 if (call_resolved(&result,this_object(),"_set_"+name,Value ))
284 return result;
285
286 // Letzte Moeglichkeit: Muss eine 'normale' Property sein
Zesstraffcd0fe2021-09-08 23:33:17 +0200287 // Es ist verfuehrerisch, das 'drop_priv||extern_call()' durch 'drop_priv'
288 // zu ersetzen, weil extern_call() das default-argument fuer <drop_priv>
289 // ist. Das ist keine gute Idee, weil <drop_priv> unter der Kontrolle des
290 // Aufrufers ist und dieser 0 uebergeben kann. Sprich: wenn es 0 ist,
291 // muessen wir dennoch selber pruefen. Wir glauben aber immer, wenn es 1
292 // ist und der Aufrufer Privilegien abgeben will.
293 return Set( name, Value, F_VALUE, drop_priv||extern_call() );
MG Mud User88f12472016-06-24 23:31:02 +0200294}
295
296
297// Property auslesen unter Verwendung evtl. vorhandener Zugriffsfunktionen
298public mixed QueryProp( string name )
299{
MG Mud User88f12472016-06-24 23:31:02 +0200300 mixed result;
MG Mud User88f12472016-06-24 23:31:02 +0200301 // Query-Methode vorhanden?
Zesstra10412ed2019-11-23 15:54:09 +0100302 mixed func = prop[F_QUERY_METHOD][name];
303 if (func)
MG Mud User88f12472016-06-24 23:31:02 +0200304 {
MG Mud User88f12472016-06-24 23:31:02 +0200305 // Wert als Query-Method? Gleich zurueckgeben ...
306 if (!closurep(func)) return func;
307
308 // An dieser Stelle muss func eine Closure sein. Da Set() ungebundene
309 // Lambdas bindet, kann es auch nur eine gebundene Closure sein und das
310 // Objekt existiert auch noch (sonst waere func == 0).
311
MG Mud User88f12472016-06-24 23:31:02 +0200312 // Dann Mal die Closure aufrufen. Bei Fehler selbige loeschen
Zesstraa81eb292021-12-29 19:46:25 +0100313 if (catch(result=funcall(func, prop[F_VALUE][name]);publish))
MG Mud User88f12472016-06-24 23:31:02 +0200314 {
315 prop[F_QUERY_METHOD]-=([name]);
316 }
MG Mud User88f12472016-06-24 23:31:02 +0200317
318 // Und zurueckgeben
319 return result;
320 }
MG Mud User88f12472016-06-24 23:31:02 +0200321 // _query_*-Methode vorhanden? falls ja, aufrufen.
Zesstrad2c193e2022-01-16 22:49:38 +0100322 else if (call_resolved(&result,this_object(),"_query_"+name))
MG Mud User88f12472016-06-24 23:31:02 +0200323 return result;
Zesstrad2c193e2022-01-16 22:49:38 +0100324
MG Mud User88f12472016-06-24 23:31:02 +0200325 // Hilft alles nichts. Es ist eine 'normale' Property ...
326 return prop[F_VALUE][name];
327}
328
Zesstrafaebc152021-07-06 22:21:47 +0200329// Addiert einen Wert zu einer Prop. Eigentlich ist es nur ein Short-Cut fuer
330// QueryProp und += und SetProp. Dementsprechend gehen auch hier nur
331// Typ-Kombinationen, die += auch kann.
332public mixed AddToProp(string pname,
333 <int|float|string|mixed*|mapping|bytes> add_value)
334{
335 mixed value = QueryProp(pname);
336 string err = catch(value += add_value; nolog);
337 if (err)
338 raise_error(sprintf("Nicht unterstuetzter Typ des Summanden: %s\n",
339 err[strstr(err,":")+2..]));
340
341 return SetProp(pname, value, extern_call());
342}
343
344// "subtrahiert" einen Wert von einer Prop. Eigentlich ist es nur ein
345// Short-Cut fuer QueryProp und -= und SetProp. Dementsprechend gehen auch
346// hier nur Typ-Kombinationen, die -= auch kann.
347public mixed SubFromProp(string pname,
348 <int|float|string|mixed*|mapping|bytes> sub_value)
349{
350 mixed value = QueryProp(pname);
351 string err = catch(value -= sub_value; nolog);
352 if (err)
353 raise_error(sprintf("Nicht unterstuetzter Typ des Subtrahenden: %s\n",
354 err[strstr(err,":")+2..]));
355
356 return SetProp(pname, value, extern_call());
357}
MG Mud User88f12472016-06-24 23:31:02 +0200358
Zesstra375df1e2021-04-21 11:09:06 +0200359// Viele Properties auf einen Schlag setzen.
Zesstra7426b7f2022-01-17 13:04:27 +0100360// Wurde genutzt von simul_efun zum Setzen aller Properties, welche im
Zesstra375df1e2021-04-21 11:09:06 +0200361// restore_object() eingelesen wurden.
Zesstra7426b7f2022-01-17 13:04:27 +0100362// Nutzer in Lib: Magiershell (upd), Spellbooks Zaubis, Klerus, Lupe
Zesstra375df1e2021-04-21 11:09:06 +0200363// Andere objekt-externe Nutzung ausdruecklich **NICHT** supportet!
Zesstra7426b7f2022-01-17 13:04:27 +0100364// Problem: ggf. Verlust von SECURED, wenn Props kopiert werden (im alten
365// SECURED; im neuen nicht und nicht-privilegiertes Objekt
366// Problem 2: beim Kopieren von einem alten in ein neues Objekt gehen alle
367// internen QM/SM auf das eigene Objekt ersatzlos kaputt.
368// Problem 3: beim "Clonen" von Objekten haben beide Clones dann geteilte
369// Referenztypen wie Mappings/Structs/Arrays
370public deprecated void SetProperties( mapping props )
MG Mud User88f12472016-06-24 23:31:02 +0200371{
Zesstrad2c193e2022-01-16 22:49:38 +0100372 int i, j;
373
MG Mud User88f12472016-06-24 23:31:02 +0200374 // Kein Mapping? Schlecht ...
375 if(!mappingp(props)) return;
376
Zesstrad2c193e2022-01-16 22:49:38 +0100377 string *names = m_indices(props);
378
MG Mud User88f12472016-06-24 23:31:02 +0200379 // Das SECURED-Flag darf nur durch das Objekt selber gesetzt werden:
Zesstrad2c193e2022-01-16 22:49:38 +0100380 // mode ist hier egal. Antwort cachen fuer den Loop
381 int no_secure = !prop_check_privilege(extern_call(), 0, SECURED_SET);
MG Mud User88f12472016-06-24 23:31:02 +0200382
383 j=sizeof(names);
384 while(j--)
385 {
Zesstrad2c193e2022-01-16 22:49:38 +0100386 if (prop_check_privilege(extern_call(), prop[F_MODE][names[j]],
387 PROP_SET))
MG Mud User88f12472016-06-24 23:31:02 +0200388 {
Zesstrad2c193e2022-01-16 22:49:38 +0100389 // Prop-Setzen erlaubt, aber ggf. SECURED flag loeschen, wenn nicht
390 // das nicht erlaubt ist (s.o.).
391 if (no_secure)
392 props[names[j], F_MODE] &= ~SECURED;
393 // jetzt die einzelnen Teile der Prop seztzen.
Zesstra3f3e7842022-01-16 22:33:03 +0100394 i=F_PROP_ENTRIES;
MG Mud User88f12472016-06-24 23:31:02 +0200395 while(i--)
396 {
397 if(props[names[j],i])
398 prop[i][names[j]] = props[names[j], i];
399 else
400 prop[i]-=([names[j]]);
401 }
402 }
403 }
MG Mud User88f12472016-06-24 23:31:02 +0200404}
405
406
407// Ein Mapping mit allen Properties zurueckgeben
Zesstra7426b7f2022-01-17 13:04:27 +0100408// Wurde genutzt von simul_efun im save_object() zur Abfrage aller Properties,
409// um hieraus die gespeicherten zu bestimmen.
410// Nutzer in Lib: Magiershell (upd), Spellbooks Zaubis, Klerus, Lupe,
411// Listmaster-Zaubis, Fingerdaemon, Kaempfergilde (Karteikarten)
Zesstra375df1e2021-04-21 11:09:06 +0200412// Andere objekt-externe Nutzung ausdruecklich **NICHT** supportet!
Zesstrad2c193e2022-01-16 22:49:38 +0100413// TODO fuer zukuenftige Features (wie private Properties) auf die simul_efun
414// beschraenken.
Zesstra7426b7f2022-01-17 13:04:27 +0100415// Problem: QueryProperties: die Werte entsprechen Query, nicht QueryProp und
416// Abfragende werten die QMs in der Regel nicht aus (und waere auch nicht
417// dieselbe Abfragesituation und wuerde daher nicht funktionieren).
418// Problem 2: Herausgabe interner Daten wie Closures, Referenztypen wie
419// Mappings/Arrays/Structs etc. Diese koennen dann geaendert werden oder im
420// Falle von Closures sind ggf. private lfuns rufbar (stimmt: momentan koennen
421// die auch per Query abgefragt werden).
422public deprecated mapping QueryProperties()
MG Mud User88f12472016-06-24 23:31:02 +0200423{
424 mapping props;
425 int i, j;
426 string *names;
427
Zesstra3f3e7842022-01-16 22:33:03 +0100428 props = m_allocate( sizeof(prop[F_VALUE]), F_PROP_ENTRIES );
Zesstrad2c193e2022-01-16 22:49:38 +0100429
MG Mud User88f12472016-06-24 23:31:02 +0200430 if (pointerp(prop))
431 {
Zesstra3f3e7842022-01-16 22:33:03 +0100432 i=F_PROP_ENTRIES;
MG Mud User88f12472016-06-24 23:31:02 +0200433 while(i--)
434 {
435 names = m_indices(prop[i]);
436 j=sizeof(names);
437 while(j--) props[names[j], i] = prop[i][names[j]];
438 }
439 }
440 return props;
441}
442
Zesstra7426b7f2022-01-17 13:04:27 +0100443// Die Properties als urspruengliches Array zurueckgeben, wird fuers MG-Tool
444// benoetigt.
MG Mud User88f12472016-06-24 23:31:02 +0200445public mixed *__query_properties()
446{
Zesstra5a9cc652022-01-20 00:24:50 +0100447 // RAW_ACCESS grants access to all properties and their raw, uncopied data.
448 // It is only for very specific objects.
449 if (!prop_check_privilege(extern_call(), 0, RAW_ACCESS))
450 return 0;
451
MG Mud User88f12472016-06-24 23:31:02 +0200452 if ( pointerp(prop) )
Zesstra5a9cc652022-01-20 00:24:50 +0100453 return prop;
MG Mud User88f12472016-06-24 23:31:02 +0200454 else
Zesstra3f3e7842022-01-16 22:33:03 +0100455 return allocate(F_PROP_ENTRIES, ([]));
MG Mud User88f12472016-06-24 23:31:02 +0200456}
457
458
Zesstra7426b7f2022-01-17 13:04:27 +0100459// Wird aus simul_efun (und nur von dort) gerufen, sollte die Properties aufs
460// Speichern vorbereiten und alle *gespeicherten* Props in passender Form in
461// der gespeicherten Variable <properties> ablegen.
462public void _prop_prepare_save()
463{
464 // 2 Werte pro Prop (Wert + Modusflags) speichern
465 // F_SET_METHOD, F_QUERY_METHOD werden nicht gespeichert.
466 // Anzahl gespeicherter Props raten, 20% der Props mit Modusflags
Zesstra68a28c22025-06-28 15:04:35 +0200467 properties = m_allocate(sizeof(prop[F_MODE])/5, 2);
468 foreach(string pname, int mode: prop[F_MODE])
Zesstra7426b7f2022-01-17 13:04:27 +0100469 {
470 if (mode & SAVE)
471 {
472 // Uralte, ungenutzte Flags loeschen sowie SETMAPPED (F_SET_METHOD wird
473 // nicht gespeichert)
474 properties[pname, F_MODE] = mode &
475 (~(SETMNOTFOUND|QUERYMNOTFOUND|QUERYCACHED|SETCACHED|SETMAPPED));
Zesstra68a28c22025-06-28 15:04:35 +0200476 properties[pname, F_VALUE] = prop[F_VALUE][pname];
Zesstra7426b7f2022-01-17 13:04:27 +0100477 }
478 }
479}
MG Mud User88f12472016-06-24 23:31:02 +0200480
Zesstra7426b7f2022-01-17 13:04:27 +0100481// Wird nach dem Speichern gerufen und kann ggf. aufraeumen. Vor allem wird
482// der Inhalt von <properties> geloescht, da dies nur beim Speichern relevant
483// ist (und auch nicht gecached werden kann!).
484public void _prop_finalize_save()
485{
486 properties = 0;
487}
MG Mud User88f12472016-06-24 23:31:02 +0200488
Zesstra7426b7f2022-01-17 13:04:27 +0100489// Konvertiert die Daten in <properties> wieder in die Laufzeitform und mergt
490// sie mit den bereits existierenden Props.
491public void _prop_finalize_restore()
492{
493 // Da wir das eigene Savefile oder Savestring restaurieren, koennen wir
494 // alle Rechte ignorieren. Wer das Savefile schreiben kann, hat gewonnen...
495 // Und Savestrings muss das Objekt selber in seinen restore_object()-Aufruf
496 // schreiben.
497 foreach(string pname, mixed value, int mode: properties)
498 {
Zesstra68a28c22025-06-28 15:04:35 +0200499 prop[F_VALUE][pname] = value;
Zesstra7426b7f2022-01-17 13:04:27 +0100500 // mode aus dem Savefile wird uebernommen, ausser SETMAPPED, was vom
501 // bisher gueltigem mode uebernommen werden muss.
Zesstra68a28c22025-06-28 15:04:35 +0200502 if (prop[F_MODE][pname] & SETMAPPED)
Zesstra7426b7f2022-01-17 13:04:27 +0100503 mode &= SETMAPPED;
Zesstra68a28c22025-06-28 15:04:35 +0200504 prop[F_MODE][pname] = mode;
Zesstra7426b7f2022-01-17 13:04:27 +0100505 // F_SET_METHOD und F_QUERY_METHOD werden beibehalten, sollten sie vor dem
506 // restore bereits gesetzt sein. Aus dem Savefile kommen beide nie.
507 }
508 properties = 0;
509}