blob: b9653587e3615c411728719dbca15ec00bb52155 [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.
27private nosave mapping *prop = ({ ([]), ([]), ([]), ([]) });
28
29// the mapping that is used for saving
30private mapping properties;
31
32// security-flag
33private nosave int closure_call;
34
35// Initialisierung der Props. Kann leider momentan nicht private sein, weil
36// Padreic son komisches Objekt hat, was die Funktion hier ruft.
37// TODO: irgendwann mal private machen.
38// TODO: Da props jetzt einfach bei der Deklaration initlisiert wird,
39// eruebrigt sich diese Funktion eigentlich. Bis auf Padreics Objekt...
40protected void InitializeProperties() {
41 prop = ({ ([]), ([]), ([]), ([]) });
42 return;
43}
44
45// Props nur dann initialisieren, wenn sie es noch nicht sind
46protected void create() {
47 // Blueprints in /std benoetigenkeinen Reset ....
48 if (object_name()=="/std/thing/properties")
49 set_next_reset(-1);
50}
51
52protected void create_super() {
53 set_next_reset(-1);
54}
55
56// Welche externen Objekte duerfen zugreifen?
57nomask private int allowed()
58{
59 if ( (previous_object() && IS_ARCH(getuid(previous_object())) &&
60 this_interactive() && IS_ARCH(this_interactive())) ||
61 (previous_object() && getuid(previous_object()) == ROOTID &&
62 geteuid(previous_object()) == ROOTID) )
63 return 1;
64 return 0;
65}
66
67
68// Set() -- provides direct access to a property, no filters
69public varargs mixed Set( string name, mixed Value, int Type, int extern )
70{
71
72 if (!objectp(this_object()))
73 return 0;
74
75 // Properties, die SECURED oder PROTECTED sind, duerfen nur vom Objekt
76 // selber, EM+ oder ROOT veraendert werden
77 if ((prop[F_MODE][name]&(PROTECTED|SECURED))&&
78 (closure_call||extern||extern_call()) &&
79 previous_object() != this_object() && !allowed())
80 return -1;
81
82 // Das SECURED-Flag darf bei Properties nicht mehr geloescht werden
83 if ((prop[F_MODE][name]&SECURED)&&
84 (Type==F_MODE||Type==F_MODE_AD)&&(Value & SECURED))
85 return -2;
86
87 // Setzen duerfen das SECURED-Flag nur das Objekt selber, EM+ oder ROOT
88 if ((Type==F_MODE||Type==F_MODE_AS)&&(Value&SECURED)&&
89 (closure_call ||extern || extern_call()) &&
90 previous_object() != this_object() && !allowed() )
91 return -3;
92
93 switch(Type)
94 {
95 // Je nach Modus Flags veraendern
96 case F_MODE_AS: prop[F_MODE][name]|= Value;
97 return prop[F_MODE][name];
98 case F_MODE_AD: prop[F_MODE][name]&= ~Value;
99 if (!prop[F_MODE][name]) prop[F_MODE]-=([name]);
100 return prop[F_MODE][name];
101 case F_MODE: prop[F_MODE][name]^= Value;
102 if (!prop[F_MODE][name]) prop[F_MODE]-=([name]);
103 return prop[F_MODE][name];
104 case F_SET_METHOD:
105 // -1 als Setz-Methode: Nosetmethod setzen
106 if (Value == -1)
107 {
108 prop[F_SET_METHOD]-=([name]);
109 prop[F_MODE][name] |= NOSETMETHOD;
110 return 0;
111 }
112 // Kein break!
113 case F_QUERY_METHOD:
Zesstra746046c2018-11-04 11:44:44 +0100114 // Ungebundene Lambda_Closure? Heutzutage ein Fehler.
115 if (closurep(Value) && !query_closure_object(Value))
MG Mud User88f12472016-06-24 23:31:02 +0200116 {
Zesstra746046c2018-11-04 11:44:44 +0100117 raise_error("Ungebundene Lambdas sind als Querymethoden "
118 "nicht mehr unterstuetzt.\n");
MG Mud User88f12472016-06-24 23:31:02 +0200119 }
120 // Kein break!
121 default:
122 if (!Value) prop[Type]-=([name]);
123 else prop[Type][name] = Value;
124 }
125
126 // Gesamtwert zurueckgeben
127 return prop[Type][name];
128}
129
130
131// Direktes Auslesen der Property ohne Filter ...
132public varargs mixed Query( string name, int Type )
133{
134 if (pointerp(prop)) return prop[Type][name];
135 return 0;
136}
137
138// Property setzen unter Verwendung evtl. vorhandener Zugriffsfunktionen
139public mixed SetProp( string name, mixed Value )
140{
MG Mud User88f12472016-06-24 23:31:02 +0200141 mixed result;
Zesstra10412ed2019-11-23 15:54:09 +0100142
MG Mud User88f12472016-06-24 23:31:02 +0200143 // nur fuer heute
144 if (!objectp(this_object()))
145 return 0;
146
147 // NOSETMETHOD: Darf nicht gesetzt werden
148 if (prop[F_MODE][name] & NOSETMETHOD ) return -1;
149
150 // Set-Method abfragen, so vorhanden
Zesstra10412ed2019-11-23 15:54:09 +0100151 // TODO: nachdem alle moeglichen Werte als Set-Methode illegal sind, auf
152 // closure aendern.
153 mixed func = prop[F_SET_METHOD][name];
154 if (func)
MG Mud User88f12472016-06-24 23:31:02 +0200155 {
156 int flag;
157
158 // Wert als Set-Method? gleich zurueckgeben
159 if (!closurep(func)) return func;
160
161 // An dieser Stelle muss func eine Closure sein. Da Set() ungebundene
162 // Lambdas bindet, kann es auch nur eine gebundene Closure sein und das
163 // Objekt existiert auch noch (sonst waere func == 0).
164
165 // closure_call setzen, falls noch nicht gesetzt
166 if ((flag=closure_call<time()))
167 closure_call = time()+59;
168
169 // Dann mal die Closure aufrufen. Bei Fehler selbige loeschen
170 if (catch(result=funcall(func, Value, name);publish))
171 {
172 prop[F_SET_METHOD]-=([name]);
173 }
174
175 // Wenn closure_call gesetzt wurde, wieder loeschen
176 if (flag) closure_call = 0;
177
178 // Und zurueckgeben
179 return result;
180 }
181
182 // _set_*-Methode vorhanden? falls ja, aufrufen.i
183 // TODO: Closurecache einfuehren und Funktionaufruf nur noch machen, wenn es
184 // die _set_* auch gibt?
185 if (call_resolved(&result,this_object(),"_set_"+name,Value ))
186 return result;
187
188 // Letzte Moeglichkeit: Muss eine 'normale' Property sein
189 return Set( name, Value, F_VALUE, extern_call() );
190}
191
192
193// Property auslesen unter Verwendung evtl. vorhandener Zugriffsfunktionen
194public mixed QueryProp( string name )
195{
MG Mud User88f12472016-06-24 23:31:02 +0200196 mixed result;
Zesstra10412ed2019-11-23 15:54:09 +0100197
MG Mud User88f12472016-06-24 23:31:02 +0200198 // nur fuer heute
199 if (!objectp(this_object()))
200 return;
201
202 // 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.
232 // TODO: Closurecache und nur rufen, wenn es _query_* auch gibt?
233 if (call_resolved(&result,this_object(),"_query_"+name))
234 return result;
235
236 // Hilft alles nichts. Es ist eine 'normale' Property ...
237 return prop[F_VALUE][name];
238}
239
240
241// Das gesamte Property-Mapping auf einen Schlag setzen
242public void SetProperties( mapping props )
243{
244 string *names;
245 int i, j, same_object;
246
247 // Kein Mapping? Schlecht ...
248 if(!mappingp(props)) return;
249
250 // Setzen wir selber?
251 same_object = (!closure_call &&
252 (!extern_call()||previous_object()==this_object()||
253 allowed()));
254 names = m_indices(props);
255
256 // Das SECURED-Flag darf nur durch das Objekt selber gesetzt werden:
257 // Alle SECURED-Flags aus props loeschen
258 if (!same_object)
259 {
260 j=sizeof(names);
261 while(j--) props[names[j], F_MODE] &= ~SECURED;
262 }
263
264 j=sizeof(names);
265 while(j--)
266 {
267 // Properties, die schon SECURED oder PROTECTED sind, duerfen
268 // nur vom Objekt selber manipuliert werden
269 if (same_object||!(prop[F_MODE][names[j]] & (PROTECTED|SECURED)) )
270 {
271 i=4;
272 while(i--)
273 {
274 if(props[names[j],i])
275 prop[i][names[j]] = props[names[j], i];
276 else
277 prop[i]-=([names[j]]);
278 }
279 }
280 }
281 return;
282}
283
284
285// Ein Mapping mit allen Properties zurueckgeben
286public mapping QueryProperties()
287{
288 mapping props;
289 int i, j;
290 string *names;
291
292 props = m_allocate( 0, 4 );
293
294 if (pointerp(prop))
295 {
296 i=4;
297 while(i--)
298 {
299 names = m_indices(prop[i]);
300 j=sizeof(names);
301 while(j--) props[names[j], i] = prop[i][names[j]];
302 }
303 }
304 return props;
305}
306
307// Die Properties als urspruengliches Array zurueckgeben
308public mixed *__query_properties()
309{
310 if ( pointerp(prop) )
311 return(deep_copy(prop));
312 else
313 return ({ ([]),([]),([]),([]) });
314}
315
316
317// mapping Properties setzen zum Speichern (per save_object())
318// Aufruf nur aus simul_efun heraus
319public void _set_save_data(mixed data) { properties = data; }
320
321// mapping Properties zum Restoren zurueckgeben
322public mixed _get_save_data() { return properties; }
323