blob: 04dfd6663aa5a706e23c0bcf7a3cfe7283cf384e [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
19#pragma pedantic
20
21#define NEED_PROTOTYPES
22
23#include "/sys/thing/properties.h"
24#include "/secure/wizlevels.h"
25
26
27// the mapping where the actual properties are stored. Direct initialization.
28private nosave mapping *prop = ({ ([]), ([]), ([]), ([]) });
29
30// the mapping that is used for saving
31private mapping properties;
32
33// security-flag
34private nosave int closure_call;
35
36// Initialisierung der Props. Kann leider momentan nicht private sein, weil
37// Padreic son komisches Objekt hat, was die Funktion hier ruft.
38// TODO: irgendwann mal private machen.
39// TODO: Da props jetzt einfach bei der Deklaration initlisiert wird,
40// eruebrigt sich diese Funktion eigentlich. Bis auf Padreics Objekt...
41protected void InitializeProperties() {
42 prop = ({ ([]), ([]), ([]), ([]) });
43 return;
44}
45
46// Props nur dann initialisieren, wenn sie es noch nicht sind
47protected void create() {
48 // Blueprints in /std benoetigenkeinen Reset ....
49 if (object_name()=="/std/thing/properties")
50 set_next_reset(-1);
51}
52
53protected void create_super() {
54 set_next_reset(-1);
55}
56
57// Welche externen Objekte duerfen zugreifen?
58nomask private int allowed()
59{
60 if ( (previous_object() && IS_ARCH(getuid(previous_object())) &&
61 this_interactive() && IS_ARCH(this_interactive())) ||
62 (previous_object() && getuid(previous_object()) == ROOTID &&
63 geteuid(previous_object()) == ROOTID) )
64 return 1;
65 return 0;
66}
67
68
69// Set() -- provides direct access to a property, no filters
70public varargs mixed Set( string name, mixed Value, int Type, int extern )
71{
72
73 if (!objectp(this_object()))
74 return 0;
75
76 // Properties, die SECURED oder PROTECTED sind, duerfen nur vom Objekt
77 // selber, EM+ oder ROOT veraendert werden
78 if ((prop[F_MODE][name]&(PROTECTED|SECURED))&&
79 (closure_call||extern||extern_call()) &&
80 previous_object() != this_object() && !allowed())
81 return -1;
82
83 // Das SECURED-Flag darf bei Properties nicht mehr geloescht werden
84 if ((prop[F_MODE][name]&SECURED)&&
85 (Type==F_MODE||Type==F_MODE_AD)&&(Value & SECURED))
86 return -2;
87
88 // Setzen duerfen das SECURED-Flag nur das Objekt selber, EM+ oder ROOT
89 if ((Type==F_MODE||Type==F_MODE_AS)&&(Value&SECURED)&&
90 (closure_call ||extern || extern_call()) &&
91 previous_object() != this_object() && !allowed() )
92 return -3;
93
94 switch(Type)
95 {
96 // Je nach Modus Flags veraendern
97 case F_MODE_AS: prop[F_MODE][name]|= Value;
98 return prop[F_MODE][name];
99 case F_MODE_AD: prop[F_MODE][name]&= ~Value;
100 if (!prop[F_MODE][name]) prop[F_MODE]-=([name]);
101 return prop[F_MODE][name];
102 case F_MODE: prop[F_MODE][name]^= Value;
103 if (!prop[F_MODE][name]) prop[F_MODE]-=([name]);
104 return prop[F_MODE][name];
105 case F_SET_METHOD:
106 // -1 als Setz-Methode: Nosetmethod setzen
107 if (Value == -1)
108 {
109 prop[F_SET_METHOD]-=([name]);
110 prop[F_MODE][name] |= NOSETMETHOD;
111 return 0;
112 }
113 // Kein break!
114 case F_QUERY_METHOD:
Zesstra746046c2018-11-04 11:44:44 +0100115 // Ungebundene Lambda_Closure? Heutzutage ein Fehler.
116 if (closurep(Value) && !query_closure_object(Value))
MG Mud User88f12472016-06-24 23:31:02 +0200117 {
Zesstra746046c2018-11-04 11:44:44 +0100118 raise_error("Ungebundene Lambdas sind als Querymethoden "
119 "nicht mehr unterstuetzt.\n");
MG Mud User88f12472016-06-24 23:31:02 +0200120 }
121 // Kein break!
122 default:
123 if (!Value) prop[Type]-=([name]);
124 else prop[Type][name] = Value;
125 }
126
127 // Gesamtwert zurueckgeben
128 return prop[Type][name];
129}
130
131
132// Direktes Auslesen der Property ohne Filter ...
133public varargs mixed Query( string name, int Type )
134{
135 if (pointerp(prop)) return prop[Type][name];
136 return 0;
137}
138
139// Property setzen unter Verwendung evtl. vorhandener Zugriffsfunktionen
140public mixed SetProp( string name, mixed Value )
141{
MG Mud User88f12472016-06-24 23:31:02 +0200142 mixed result;
Zesstra3cd0b122019-11-23 15:54:09 +0100143
MG Mud User88f12472016-06-24 23:31:02 +0200144 // nur fuer heute
145 if (!objectp(this_object()))
146 return 0;
147
148 // NOSETMETHOD: Darf nicht gesetzt werden
149 if (prop[F_MODE][name] & NOSETMETHOD ) return -1;
150
151 // Set-Method abfragen, so vorhanden
Zesstra3cd0b122019-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 }
175
176 // Wenn closure_call gesetzt wurde, wieder loeschen
177 if (flag) closure_call = 0;
178
179 // Und zurueckgeben
180 return result;
181 }
182
183 // _set_*-Methode vorhanden? falls ja, aufrufen.i
184 // TODO: Closurecache einfuehren und Funktionaufruf nur noch machen, wenn es
185 // die _set_* auch gibt?
186 if (call_resolved(&result,this_object(),"_set_"+name,Value ))
187 return result;
188
189 // Letzte Moeglichkeit: Muss eine 'normale' Property sein
190 return Set( name, Value, F_VALUE, extern_call() );
191}
192
193
194// Property auslesen unter Verwendung evtl. vorhandener Zugriffsfunktionen
195public mixed QueryProp( string name )
196{
MG Mud User88f12472016-06-24 23:31:02 +0200197 mixed result;
Zesstra3cd0b122019-11-23 15:54:09 +0100198
MG Mud User88f12472016-06-24 23:31:02 +0200199 // nur fuer heute
200 if (!objectp(this_object()))
201 return;
202
203 // Query-Methode vorhanden?
Zesstra3cd0b122019-11-23 15:54:09 +0100204 mixed func = prop[F_QUERY_METHOD][name];
205 if (func)
MG Mud User88f12472016-06-24 23:31:02 +0200206 {
207 int flag;
208
209 // Wert als Query-Method? Gleich zurueckgeben ...
210 if (!closurep(func)) return func;
211
212 // An dieser Stelle muss func eine Closure sein. Da Set() ungebundene
213 // Lambdas bindet, kann es auch nur eine gebundene Closure sein und das
214 // Objekt existiert auch noch (sonst waere func == 0).
215
216 // closure_call setzen, falls noch nicht gesetzt
217 if ((flag=closure_call<time()))
218 closure_call = time()+59;
219
220 // Dann Mal die Closure aufrufen. Bei Fehler selbige loeschen
221 if (catch(result=funcall(func);publish))
222 {
223 prop[F_QUERY_METHOD]-=([name]);
224 }
225 // Wenn closure_call gesetzt wurde, wieder loeschen
226 if (flag) closure_call = 0;
227
228 // Und zurueckgeben
229 return result;
230 }
231
232 // _query_*-Methode vorhanden? falls ja, aufrufen.
233 // TODO: Closurecache und nur rufen, wenn es _query_* auch gibt?
234 if (call_resolved(&result,this_object(),"_query_"+name))
235 return result;
236
237 // Hilft alles nichts. Es ist eine 'normale' Property ...
238 return prop[F_VALUE][name];
239}
240
241
242// Das gesamte Property-Mapping auf einen Schlag setzen
243public void SetProperties( mapping props )
244{
245 string *names;
246 int i, j, same_object;
247
248 // Kein Mapping? Schlecht ...
249 if(!mappingp(props)) return;
250
251 // Setzen wir selber?
252 same_object = (!closure_call &&
253 (!extern_call()||previous_object()==this_object()||
254 allowed()));
255 names = m_indices(props);
256
257 // Das SECURED-Flag darf nur durch das Objekt selber gesetzt werden:
258 // Alle SECURED-Flags aus props loeschen
259 if (!same_object)
260 {
261 j=sizeof(names);
262 while(j--) props[names[j], F_MODE] &= ~SECURED;
263 }
264
265 j=sizeof(names);
266 while(j--)
267 {
268 // Properties, die schon SECURED oder PROTECTED sind, duerfen
269 // nur vom Objekt selber manipuliert werden
270 if (same_object||!(prop[F_MODE][names[j]] & (PROTECTED|SECURED)) )
271 {
272 i=4;
273 while(i--)
274 {
275 if(props[names[j],i])
276 prop[i][names[j]] = props[names[j], i];
277 else
278 prop[i]-=([names[j]]);
279 }
280 }
281 }
282 return;
283}
284
285
286// Ein Mapping mit allen Properties zurueckgeben
287public 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())
319// Aufruf nur aus simul_efun heraus
320public void _set_save_data(mixed data) { properties = data; }
321
322// mapping Properties zum Restoren zurueckgeben
323public mixed _get_save_data() { return properties; }
324