blob: 25d601c77a65699560a09bfc65f9336899a3126e [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
25
26// the mapping where the actual properties are stored. Direct initialization.
Zesstra375df1e2021-04-21 11:09:06 +020027// Indexed with F_VALUE, F_MODE, F_SET_METHOD and F_QUERY_METHOD
28// F_MODE, F_SET_METHOD and F_QUERY_METHOD are usually 'sparse' (i.e. there is
29// no entry for most properties), therefore it is more memory-efficient to
30// store them like this than in one mapping, although it requires more
31// mapping lookups.
MG Mud User88f12472016-06-24 23:31:02 +020032private nosave mapping *prop = ({ ([]), ([]), ([]), ([]) });
33
Zesstra375df1e2021-04-21 11:09:06 +020034// the mapping that is used for saving. During save_object/restore_object it
35// contains the properties with SAVE flag.
36// This is empty outside of a save_object() or restore_object() call!
MG Mud User88f12472016-06-24 23:31:02 +020037private mapping properties;
38
39// security-flag
40private nosave int closure_call;
41
MG Mud User88f12472016-06-24 23:31:02 +020042
Zesstraf971f3a2021-04-13 11:48:37 +020043// Z.Zt. nur Abschalten des Resets noetig.
MG Mud User88f12472016-06-24 23:31:02 +020044protected void create() {
45 // Blueprints in /std benoetigenkeinen Reset ....
46 if (object_name()=="/std/thing/properties")
47 set_next_reset(-1);
48}
49
50protected void create_super() {
51 set_next_reset(-1);
52}
53
54// Welche externen Objekte duerfen zugreifen?
55nomask private int allowed()
56{
57 if ( (previous_object() && IS_ARCH(getuid(previous_object())) &&
58 this_interactive() && IS_ARCH(this_interactive())) ||
59 (previous_object() && getuid(previous_object()) == ROOTID &&
60 geteuid(previous_object()) == ROOTID) )
61 return 1;
62 return 0;
63}
64
65
66// Set() -- provides direct access to a property, no filters
67public varargs mixed Set( string name, mixed Value, int Type, int extern )
68{
69
70 if (!objectp(this_object()))
71 return 0;
72
73 // Properties, die SECURED oder PROTECTED sind, duerfen nur vom Objekt
74 // selber, EM+ oder ROOT veraendert werden
75 if ((prop[F_MODE][name]&(PROTECTED|SECURED))&&
76 (closure_call||extern||extern_call()) &&
77 previous_object() != this_object() && !allowed())
78 return -1;
79
80 // Das SECURED-Flag darf bei Properties nicht mehr geloescht werden
81 if ((prop[F_MODE][name]&SECURED)&&
82 (Type==F_MODE||Type==F_MODE_AD)&&(Value & SECURED))
83 return -2;
84
85 // Setzen duerfen das SECURED-Flag nur das Objekt selber, EM+ oder ROOT
86 if ((Type==F_MODE||Type==F_MODE_AS)&&(Value&SECURED)&&
87 (closure_call ||extern || extern_call()) &&
88 previous_object() != this_object() && !allowed() )
89 return -3;
90
91 switch(Type)
92 {
93 // Je nach Modus Flags veraendern
94 case F_MODE_AS: prop[F_MODE][name]|= Value;
95 return prop[F_MODE][name];
96 case F_MODE_AD: prop[F_MODE][name]&= ~Value;
97 if (!prop[F_MODE][name]) prop[F_MODE]-=([name]);
98 return prop[F_MODE][name];
99 case F_MODE: prop[F_MODE][name]^= Value;
100 if (!prop[F_MODE][name]) prop[F_MODE]-=([name]);
101 return prop[F_MODE][name];
102 case F_SET_METHOD:
103 // -1 als Setz-Methode: Nosetmethod setzen
104 if (Value == -1)
105 {
106 prop[F_SET_METHOD]-=([name]);
107 prop[F_MODE][name] |= NOSETMETHOD;
108 return 0;
109 }
110 // Kein break!
111 case F_QUERY_METHOD:
Zesstra746046c2018-11-04 11:44:44 +0100112 // Ungebundene Lambda_Closure? Heutzutage ein Fehler.
113 if (closurep(Value) && !query_closure_object(Value))
MG Mud User88f12472016-06-24 23:31:02 +0200114 {
Zesstra746046c2018-11-04 11:44:44 +0100115 raise_error("Ungebundene Lambdas sind als Querymethoden "
116 "nicht mehr unterstuetzt.\n");
MG Mud User88f12472016-06-24 23:31:02 +0200117 }
118 // Kein break!
119 default:
120 if (!Value) prop[Type]-=([name]);
121 else prop[Type][name] = Value;
122 }
123
124 // Gesamtwert zurueckgeben
125 return prop[Type][name];
126}
127
128
129// Direktes Auslesen der Property ohne Filter ...
130public varargs mixed Query( string name, int Type )
131{
132 if (pointerp(prop)) return prop[Type][name];
133 return 0;
134}
135
136// Property setzen unter Verwendung evtl. vorhandener Zugriffsfunktionen
137public mixed SetProp( string name, mixed Value )
138{
MG Mud User88f12472016-06-24 23:31:02 +0200139 mixed result;
Zesstra10412ed2019-11-23 15:54:09 +0100140
MG Mud User88f12472016-06-24 23:31:02 +0200141 // nur fuer heute
142 if (!objectp(this_object()))
143 return 0;
144
145 // NOSETMETHOD: Darf nicht gesetzt werden
146 if (prop[F_MODE][name] & NOSETMETHOD ) return -1;
147
148 // Set-Method abfragen, so vorhanden
Zesstra10412ed2019-11-23 15:54:09 +0100149 // TODO: nachdem alle moeglichen Werte als Set-Methode illegal sind, auf
150 // closure aendern.
151 mixed func = prop[F_SET_METHOD][name];
152 if (func)
MG Mud User88f12472016-06-24 23:31:02 +0200153 {
154 int flag;
155
156 // Wert als Set-Method? gleich zurueckgeben
157 if (!closurep(func)) return func;
158
159 // An dieser Stelle muss func eine Closure sein. Da Set() ungebundene
160 // Lambdas bindet, kann es auch nur eine gebundene Closure sein und das
161 // Objekt existiert auch noch (sonst waere func == 0).
162
163 // closure_call setzen, falls noch nicht gesetzt
164 if ((flag=closure_call<time()))
165 closure_call = time()+59;
166
167 // Dann mal die Closure aufrufen. Bei Fehler selbige loeschen
168 if (catch(result=funcall(func, Value, name);publish))
169 {
170 prop[F_SET_METHOD]-=([name]);
171 }
172
173 // Wenn closure_call gesetzt wurde, wieder loeschen
174 if (flag) closure_call = 0;
175
176 // Und zurueckgeben
177 return result;
178 }
179
180 // _set_*-Methode vorhanden? falls ja, aufrufen.i
MG Mud User88f12472016-06-24 23:31:02 +0200181 if (call_resolved(&result,this_object(),"_set_"+name,Value ))
182 return result;
183
184 // Letzte Moeglichkeit: Muss eine 'normale' Property sein
185 return Set( name, Value, F_VALUE, extern_call() );
186}
187
188
189// Property auslesen unter Verwendung evtl. vorhandener Zugriffsfunktionen
190public mixed QueryProp( string name )
191{
MG Mud User88f12472016-06-24 23:31:02 +0200192 mixed result;
Zesstra10412ed2019-11-23 15:54:09 +0100193
MG Mud User88f12472016-06-24 23:31:02 +0200194 // nur fuer heute
195 if (!objectp(this_object()))
196 return;
197
198 // Query-Methode vorhanden?
Zesstra10412ed2019-11-23 15:54:09 +0100199 mixed func = prop[F_QUERY_METHOD][name];
200 if (func)
MG Mud User88f12472016-06-24 23:31:02 +0200201 {
202 int flag;
203
204 // Wert als Query-Method? Gleich zurueckgeben ...
205 if (!closurep(func)) return func;
206
207 // An dieser Stelle muss func eine Closure sein. Da Set() ungebundene
208 // Lambdas bindet, kann es auch nur eine gebundene Closure sein und das
209 // Objekt existiert auch noch (sonst waere func == 0).
210
211 // closure_call setzen, falls noch nicht gesetzt
212 if ((flag=closure_call<time()))
213 closure_call = time()+59;
214
215 // Dann Mal die Closure aufrufen. Bei Fehler selbige loeschen
216 if (catch(result=funcall(func);publish))
217 {
218 prop[F_QUERY_METHOD]-=([name]);
219 }
220 // Wenn closure_call gesetzt wurde, wieder loeschen
221 if (flag) closure_call = 0;
222
223 // Und zurueckgeben
224 return result;
225 }
226
227 // _query_*-Methode vorhanden? falls ja, aufrufen.
MG Mud User88f12472016-06-24 23:31:02 +0200228 if (call_resolved(&result,this_object(),"_query_"+name))
229 return result;
230
231 // Hilft alles nichts. Es ist eine 'normale' Property ...
232 return prop[F_VALUE][name];
233}
234
235
Zesstra375df1e2021-04-21 11:09:06 +0200236// Viele Properties auf einen Schlag setzen.
237// genutzt von simul_efun zum Setzen aller Properties, welche im
238// restore_object() eingelesen wurden.
239// Andere objekt-externe Nutzung ausdruecklich **NICHT** supportet!
MG Mud User88f12472016-06-24 23:31:02 +0200240public void SetProperties( mapping props )
241{
242 string *names;
243 int i, j, same_object;
244
245 // Kein Mapping? Schlecht ...
246 if(!mappingp(props)) return;
247
248 // Setzen wir selber?
249 same_object = (!closure_call &&
250 (!extern_call()||previous_object()==this_object()||
251 allowed()));
252 names = m_indices(props);
253
254 // Das SECURED-Flag darf nur durch das Objekt selber gesetzt werden:
255 // Alle SECURED-Flags aus props loeschen
256 if (!same_object)
257 {
258 j=sizeof(names);
259 while(j--) props[names[j], F_MODE] &= ~SECURED;
260 }
261
262 j=sizeof(names);
263 while(j--)
264 {
265 // Properties, die schon SECURED oder PROTECTED sind, duerfen
266 // nur vom Objekt selber manipuliert werden
267 if (same_object||!(prop[F_MODE][names[j]] & (PROTECTED|SECURED)) )
268 {
269 i=4;
270 while(i--)
271 {
272 if(props[names[j],i])
273 prop[i][names[j]] = props[names[j], i];
274 else
275 prop[i]-=([names[j]]);
276 }
277 }
278 }
279 return;
280}
281
282
283// Ein Mapping mit allen Properties zurueckgeben
Zesstra375df1e2021-04-21 11:09:06 +0200284// genutzt von simul_efun im save_object() zur Abfrage aller Properties, um
285// hieraus die gespeicherten zu bestimmen.
286// Andere objekt-externe Nutzung ausdruecklich **NICHT** supportet!
MG Mud User88f12472016-06-24 23:31:02 +0200287public mapping QueryProperties()
288{
289 mapping props;
290 int i, j;
291 string *names;
292
293 props = m_allocate( 0, 4 );
294
295 if (pointerp(prop))
296 {
297 i=4;
298 while(i--)
299 {
300 names = m_indices(prop[i]);
301 j=sizeof(names);
302 while(j--) props[names[j], i] = prop[i][names[j]];
303 }
304 }
305 return props;
306}
307
308// Die Properties als urspruengliches Array zurueckgeben
309public mixed *__query_properties()
310{
311 if ( pointerp(prop) )
312 return(deep_copy(prop));
313 else
314 return ({ ([]),([]),([]),([]) });
315}
316
317
318// mapping Properties setzen zum Speichern (per save_object())
Zesstra375df1e2021-04-21 11:09:06 +0200319// Aufruf nur aus simul_efun heraus (sinnvoll). Diese fragt alle Properties
320// via QueryProperties() ab, filtert alle nicht-gespeicherten Properties aus
321// und setzt ueber diese Funktion die gespeicherten in der tatsaechlich von
322// save_object() gespeicherten Variable <properties>.
MG Mud User88f12472016-06-24 23:31:02 +0200323public void _set_save_data(mixed data) { properties = data; }
324
325// mapping Properties zum Restoren zurueckgeben
Zesstra375df1e2021-04-21 11:09:06 +0200326// Aufruf nur aus simul_efun heraus (sinnvoll). Diese ruft nach dem
327// restore_object die restaurierten Properties hiermit ab und schreibt sie
328// nach Konditionierung via SetProperties() zurueck, damit die Daten (wieder)
329// in <prop> zur Verfuegung steheh.
MG Mud User88f12472016-06-24 23:31:02 +0200330public mixed _get_save_data() { return properties; }
331