blob: 5852704b71199b595d5443ef4038fa78c65f1828 [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
20#define NEED_PROTOTYPES
21
22#include "/sys/thing/properties.h"
23#include "/secure/wizlevels.h"
24
MG Mud User88f12472016-06-24 23:31:02 +020025// the mapping where the actual properties are stored. Direct initialization.
Zesstra375df1e2021-04-21 11:09:06 +020026// Indexed with F_VALUE, F_MODE, F_SET_METHOD and F_QUERY_METHOD
27// F_MODE, F_SET_METHOD and F_QUERY_METHOD are usually 'sparse' (i.e. there is
28// no entry for most properties), therefore it is more memory-efficient to
29// store them like this than in one mapping, although it requires more
30// mapping lookups.
MG Mud User88f12472016-06-24 23:31:02 +020031private nosave mapping *prop = ({ ([]), ([]), ([]), ([]) });
32
Zesstra375df1e2021-04-21 11:09:06 +020033// the mapping that is used for saving. During save_object/restore_object it
34// contains the properties with SAVE flag.
35// This is empty outside of a save_object() or restore_object() call!
MG Mud User88f12472016-06-24 23:31:02 +020036private mapping properties;
37
38// security-flag
39private nosave int closure_call;
40
MG Mud User88f12472016-06-24 23:31:02 +020041
Zesstraf971f3a2021-04-13 11:48:37 +020042// Z.Zt. nur Abschalten des Resets noetig.
MG Mud User88f12472016-06-24 23:31:02 +020043protected void create() {
44 // Blueprints in /std benoetigenkeinen Reset ....
45 if (object_name()=="/std/thing/properties")
46 set_next_reset(-1);
47}
48
49protected void create_super() {
50 set_next_reset(-1);
51}
52
53// Welche externen Objekte duerfen zugreifen?
54nomask private int allowed()
55{
56 if ( (previous_object() && IS_ARCH(getuid(previous_object())) &&
57 this_interactive() && IS_ARCH(this_interactive())) ||
58 (previous_object() && getuid(previous_object()) == ROOTID &&
59 geteuid(previous_object()) == ROOTID) )
60 return 1;
61 return 0;
62}
63
64
65// Set() -- provides direct access to a property, no filters
Zesstra5c0c4092021-09-08 23:27:54 +020066// Type=F_VALUE und drop_priv=extern_call() by default
67public mixed Set(string name, mixed Value, int Type, int drop_priv)
MG Mud User88f12472016-06-24 23:31:02 +020068{
MG Mud User88f12472016-06-24 23:31:02 +020069 if (!objectp(this_object()))
70 return 0;
71
72 // Properties, die SECURED oder PROTECTED sind, duerfen nur vom Objekt
Zesstra5c0c4092021-09-08 23:27:54 +020073 // selber, EM+ oder ROOT veraendert werden.
74 // Es ist verfuehrerisch, das 'drop_priv||extern_call()' durch 'drop_priv'
75 // zu ersetzen, weil extern_call() das default-argument fuer <drop_priv>
76 // ist. Das ist keine gute Idee, weil <drop_priv> unter der Kontrolle des
77 // Aufrufers ist und dieser 0 uebergeben kann. Sprich: wenn es 0 ist,
78 // muessen wir dennoch selber pruefen. Wir glauben aber immer, wenn es 1
79 // ist und der Aufrufer Privilegien abgeben will.
MG Mud User88f12472016-06-24 23:31:02 +020080 if ((prop[F_MODE][name]&(PROTECTED|SECURED))&&
Zesstra5c0c4092021-09-08 23:27:54 +020081 (closure_call||drop_priv||extern_call()) &&
MG Mud User88f12472016-06-24 23:31:02 +020082 previous_object() != this_object() && !allowed())
83 return -1;
Zesstra5c0c4092021-09-08 23:27:54 +020084
MG Mud User88f12472016-06-24 23:31:02 +020085 // Das SECURED-Flag darf bei Properties nicht mehr geloescht werden
86 if ((prop[F_MODE][name]&SECURED)&&
87 (Type==F_MODE||Type==F_MODE_AD)&&(Value & SECURED))
88 return -2;
Zesstra5c0c4092021-09-08 23:27:54 +020089
MG Mud User88f12472016-06-24 23:31:02 +020090 // Setzen duerfen das SECURED-Flag nur das Objekt selber, EM+ oder ROOT
Zesstra5c0c4092021-09-08 23:27:54 +020091 // 'drop_priv||extern_call()' ist Absicht, s.o.
MG Mud User88f12472016-06-24 23:31:02 +020092 if ((Type==F_MODE||Type==F_MODE_AS)&&(Value&SECURED)&&
Zesstra5c0c4092021-09-08 23:27:54 +020093 (closure_call || drop_priv || extern_call()) &&
MG Mud User88f12472016-06-24 23:31:02 +020094 previous_object() != this_object() && !allowed() )
95 return -3;
96
97 switch(Type)
98 {
99 // Je nach Modus Flags veraendern
100 case F_MODE_AS: prop[F_MODE][name]|= Value;
101 return prop[F_MODE][name];
102 case F_MODE_AD: prop[F_MODE][name]&= ~Value;
103 if (!prop[F_MODE][name]) prop[F_MODE]-=([name]);
104 return prop[F_MODE][name];
105 case F_MODE: prop[F_MODE][name]^= Value;
106 if (!prop[F_MODE][name]) prop[F_MODE]-=([name]);
107 return prop[F_MODE][name];
108 case F_SET_METHOD:
109 // -1 als Setz-Methode: Nosetmethod setzen
110 if (Value == -1)
111 {
112 prop[F_SET_METHOD]-=([name]);
113 prop[F_MODE][name] |= NOSETMETHOD;
114 return 0;
115 }
116 // Kein break!
117 case F_QUERY_METHOD:
Zesstra746046c2018-11-04 11:44:44 +0100118 // Ungebundene Lambda_Closure? Heutzutage ein Fehler.
119 if (closurep(Value) && !query_closure_object(Value))
MG Mud User88f12472016-06-24 23:31:02 +0200120 {
Zesstra746046c2018-11-04 11:44:44 +0100121 raise_error("Ungebundene Lambdas sind als Querymethoden "
122 "nicht mehr unterstuetzt.\n");
MG Mud User88f12472016-06-24 23:31:02 +0200123 }
124 // Kein break!
125 default:
126 if (!Value) prop[Type]-=([name]);
127 else prop[Type][name] = Value;
128 }
129
130 // Gesamtwert zurueckgeben
131 return prop[Type][name];
132}
133
134
135// Direktes Auslesen der Property ohne Filter ...
Zesstra5c0c4092021-09-08 23:27:54 +0200136// Type = F_VALUE by default
137public mixed Query( string name, int Type )
MG Mud User88f12472016-06-24 23:31:02 +0200138{
139 if (pointerp(prop)) return prop[Type][name];
140 return 0;
141}
142
143// Property setzen unter Verwendung evtl. vorhandener Zugriffsfunktionen
Zesstraffcd0fe2021-09-08 23:33:17 +0200144public mixed SetProp( string name, mixed Value, int drop_priv)
MG Mud User88f12472016-06-24 23:31:02 +0200145{
MG Mud User88f12472016-06-24 23:31:02 +0200146 mixed result;
Zesstra10412ed2019-11-23 15:54:09 +0100147
MG Mud User88f12472016-06-24 23:31:02 +0200148 // NOSETMETHOD: Darf nicht gesetzt werden
149 if (prop[F_MODE][name] & NOSETMETHOD ) return -1;
150
151 // Set-Method abfragen, so vorhanden
Zesstra10412ed2019-11-23 15:54:09 +0100152 // TODO: nachdem alle moeglichen Werte als Set-Methode illegal sind, auf
153 // closure aendern.
154 mixed func = prop[F_SET_METHOD][name];
155 if (func)
MG Mud User88f12472016-06-24 23:31:02 +0200156 {
157 int flag;
158
159 // Wert als Set-Method? gleich zurueckgeben
160 if (!closurep(func)) return func;
161
162 // An dieser Stelle muss func eine Closure sein. Da Set() ungebundene
163 // Lambdas bindet, kann es auch nur eine gebundene Closure sein und das
164 // Objekt existiert auch noch (sonst waere func == 0).
165
166 // closure_call setzen, falls noch nicht gesetzt
167 if ((flag=closure_call<time()))
168 closure_call = time()+59;
169
170 // Dann mal die Closure aufrufen. Bei Fehler selbige loeschen
171 if (catch(result=funcall(func, Value, name);publish))
172 {
173 prop[F_SET_METHOD]-=([name]);
174 }
Zesstraffcd0fe2021-09-08 23:33:17 +0200175
MG Mud User88f12472016-06-24 23:31:02 +0200176 // Wenn closure_call gesetzt wurde, wieder loeschen
177 if (flag) closure_call = 0;
178
179 // Und zurueckgeben
180 return result;
181 }
182
Zesstraffcd0fe2021-09-08 23:33:17 +0200183 // _set_*-Methode vorhanden? falls ja, aufrufen.
MG Mud User88f12472016-06-24 23:31:02 +0200184 if (call_resolved(&result,this_object(),"_set_"+name,Value ))
185 return result;
186
187 // Letzte Moeglichkeit: Muss eine 'normale' Property sein
Zesstraffcd0fe2021-09-08 23:33:17 +0200188 // Es ist verfuehrerisch, das 'drop_priv||extern_call()' durch 'drop_priv'
189 // zu ersetzen, weil extern_call() das default-argument fuer <drop_priv>
190 // ist. Das ist keine gute Idee, weil <drop_priv> unter der Kontrolle des
191 // Aufrufers ist und dieser 0 uebergeben kann. Sprich: wenn es 0 ist,
192 // muessen wir dennoch selber pruefen. Wir glauben aber immer, wenn es 1
193 // ist und der Aufrufer Privilegien abgeben will.
194 return Set( name, Value, F_VALUE, drop_priv||extern_call() );
MG Mud User88f12472016-06-24 23:31:02 +0200195}
196
197
198// Property auslesen unter Verwendung evtl. vorhandener Zugriffsfunktionen
199public mixed QueryProp( string name )
200{
MG Mud User88f12472016-06-24 23:31:02 +0200201 mixed result;
MG Mud User88f12472016-06-24 23:31:02 +0200202 // Query-Methode vorhanden?
Zesstra10412ed2019-11-23 15:54:09 +0100203 mixed func = prop[F_QUERY_METHOD][name];
204 if (func)
MG Mud User88f12472016-06-24 23:31:02 +0200205 {
206 int flag;
207
208 // Wert als Query-Method? Gleich zurueckgeben ...
209 if (!closurep(func)) return func;
210
211 // An dieser Stelle muss func eine Closure sein. Da Set() ungebundene
212 // Lambdas bindet, kann es auch nur eine gebundene Closure sein und das
213 // Objekt existiert auch noch (sonst waere func == 0).
214
215 // closure_call setzen, falls noch nicht gesetzt
216 if ((flag=closure_call<time()))
217 closure_call = time()+59;
218
219 // Dann Mal die Closure aufrufen. Bei Fehler selbige loeschen
220 if (catch(result=funcall(func);publish))
221 {
222 prop[F_QUERY_METHOD]-=([name]);
223 }
224 // Wenn closure_call gesetzt wurde, wieder loeschen
225 if (flag) closure_call = 0;
226
227 // Und zurueckgeben
228 return result;
229 }
230
231 // _query_*-Methode vorhanden? falls ja, aufrufen.
MG Mud User88f12472016-06-24 23:31:02 +0200232 if (call_resolved(&result,this_object(),"_query_"+name))
233 return result;
234
235 // Hilft alles nichts. Es ist eine 'normale' Property ...
236 return prop[F_VALUE][name];
237}
238
Zesstrafaebc152021-07-06 22:21:47 +0200239// Addiert einen Wert zu einer Prop. Eigentlich ist es nur ein Short-Cut fuer
240// QueryProp und += und SetProp. Dementsprechend gehen auch hier nur
241// Typ-Kombinationen, die += auch kann.
242public mixed AddToProp(string pname,
243 <int|float|string|mixed*|mapping|bytes> add_value)
244{
245 mixed value = QueryProp(pname);
246 string err = catch(value += add_value; nolog);
247 if (err)
248 raise_error(sprintf("Nicht unterstuetzter Typ des Summanden: %s\n",
249 err[strstr(err,":")+2..]));
250
251 return SetProp(pname, value, extern_call());
252}
253
254// "subtrahiert" einen Wert von einer Prop. Eigentlich ist es nur ein
255// Short-Cut fuer QueryProp und -= und SetProp. Dementsprechend gehen auch
256// hier nur Typ-Kombinationen, die -= auch kann.
257public mixed SubFromProp(string pname,
258 <int|float|string|mixed*|mapping|bytes> sub_value)
259{
260 mixed value = QueryProp(pname);
261 string err = catch(value -= sub_value; nolog);
262 if (err)
263 raise_error(sprintf("Nicht unterstuetzter Typ des Subtrahenden: %s\n",
264 err[strstr(err,":")+2..]));
265
266 return SetProp(pname, value, extern_call());
267}
MG Mud User88f12472016-06-24 23:31:02 +0200268
Zesstra375df1e2021-04-21 11:09:06 +0200269// Viele Properties auf einen Schlag setzen.
270// genutzt von simul_efun zum Setzen aller Properties, welche im
271// restore_object() eingelesen wurden.
272// Andere objekt-externe Nutzung ausdruecklich **NICHT** supportet!
MG Mud User88f12472016-06-24 23:31:02 +0200273public void SetProperties( mapping props )
274{
275 string *names;
276 int i, j, same_object;
277
278 // Kein Mapping? Schlecht ...
279 if(!mappingp(props)) return;
280
281 // Setzen wir selber?
282 same_object = (!closure_call &&
283 (!extern_call()||previous_object()==this_object()||
284 allowed()));
285 names = m_indices(props);
286
287 // Das SECURED-Flag darf nur durch das Objekt selber gesetzt werden:
288 // Alle SECURED-Flags aus props loeschen
289 if (!same_object)
290 {
291 j=sizeof(names);
292 while(j--) props[names[j], F_MODE] &= ~SECURED;
293 }
294
295 j=sizeof(names);
296 while(j--)
297 {
298 // Properties, die schon SECURED oder PROTECTED sind, duerfen
299 // nur vom Objekt selber manipuliert werden
300 if (same_object||!(prop[F_MODE][names[j]] & (PROTECTED|SECURED)) )
301 {
302 i=4;
303 while(i--)
304 {
305 if(props[names[j],i])
306 prop[i][names[j]] = props[names[j], i];
307 else
308 prop[i]-=([names[j]]);
309 }
310 }
311 }
312 return;
313}
314
315
316// Ein Mapping mit allen Properties zurueckgeben
Zesstra375df1e2021-04-21 11:09:06 +0200317// genutzt von simul_efun im save_object() zur Abfrage aller Properties, um
318// hieraus die gespeicherten zu bestimmen.
319// Andere objekt-externe Nutzung ausdruecklich **NICHT** supportet!
MG Mud User88f12472016-06-24 23:31:02 +0200320public mapping QueryProperties()
321{
322 mapping props;
323 int i, j;
324 string *names;
325
326 props = m_allocate( 0, 4 );
327
328 if (pointerp(prop))
329 {
330 i=4;
331 while(i--)
332 {
333 names = m_indices(prop[i]);
334 j=sizeof(names);
335 while(j--) props[names[j], i] = prop[i][names[j]];
336 }
337 }
338 return props;
339}
340
341// Die Properties als urspruengliches Array zurueckgeben
342public mixed *__query_properties()
343{
344 if ( pointerp(prop) )
345 return(deep_copy(prop));
346 else
347 return ({ ([]),([]),([]),([]) });
348}
349
350
351// mapping Properties setzen zum Speichern (per save_object())
Zesstra375df1e2021-04-21 11:09:06 +0200352// Aufruf nur aus simul_efun heraus (sinnvoll). Diese fragt alle Properties
353// via QueryProperties() ab, filtert alle nicht-gespeicherten Properties aus
354// und setzt ueber diese Funktion die gespeicherten in der tatsaechlich von
355// save_object() gespeicherten Variable <properties>.
MG Mud User88f12472016-06-24 23:31:02 +0200356public void _set_save_data(mixed data) { properties = data; }
357
358// mapping Properties zum Restoren zurueckgeben
Zesstra375df1e2021-04-21 11:09:06 +0200359// Aufruf nur aus simul_efun heraus (sinnvoll). Diese ruft nach dem
360// restore_object die restaurierten Properties hiermit ab und schreibt sie
361// nach Konditionierung via SetProperties() zurueck, damit die Daten (wieder)
362// in <prop> zur Verfuegung steheh.
MG Mud User88f12472016-06-24 23:31:02 +0200363public mixed _get_save_data() { return properties; }
364