blob: c372427a2e675a7324da9869f41eefbfa5dfad17 [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
MG Mud User88f12472016-06-24 23:31:02 +020035
Zesstraf971f3a2021-04-13 11:48:37 +020036// Z.Zt. nur Abschalten des Resets noetig.
MG Mud User88f12472016-06-24 23:31:02 +020037protected void create() {
38 // Blueprints in /std benoetigenkeinen Reset ....
39 if (object_name()=="/std/thing/properties")
40 set_next_reset(-1);
41}
42
43protected void create_super() {
44 set_next_reset(-1);
45}
46
47// Welche externen Objekte duerfen zugreifen?
48nomask private int allowed()
49{
50 if ( (previous_object() && IS_ARCH(getuid(previous_object())) &&
51 this_interactive() && IS_ARCH(this_interactive())) ||
52 (previous_object() && getuid(previous_object()) == ROOTID &&
53 geteuid(previous_object()) == ROOTID) )
54 return 1;
55 return 0;
56}
57
58
59// Set() -- provides direct access to a property, no filters
60public varargs mixed Set( string name, mixed Value, int Type, int extern )
61{
62
63 if (!objectp(this_object()))
64 return 0;
65
66 // Properties, die SECURED oder PROTECTED sind, duerfen nur vom Objekt
67 // selber, EM+ oder ROOT veraendert werden
68 if ((prop[F_MODE][name]&(PROTECTED|SECURED))&&
69 (closure_call||extern||extern_call()) &&
70 previous_object() != this_object() && !allowed())
71 return -1;
72
73 // Das SECURED-Flag darf bei Properties nicht mehr geloescht werden
74 if ((prop[F_MODE][name]&SECURED)&&
75 (Type==F_MODE||Type==F_MODE_AD)&&(Value & SECURED))
76 return -2;
77
78 // Setzen duerfen das SECURED-Flag nur das Objekt selber, EM+ oder ROOT
79 if ((Type==F_MODE||Type==F_MODE_AS)&&(Value&SECURED)&&
80 (closure_call ||extern || extern_call()) &&
81 previous_object() != this_object() && !allowed() )
82 return -3;
83
84 switch(Type)
85 {
86 // Je nach Modus Flags veraendern
87 case F_MODE_AS: prop[F_MODE][name]|= Value;
88 return prop[F_MODE][name];
89 case F_MODE_AD: prop[F_MODE][name]&= ~Value;
90 if (!prop[F_MODE][name]) prop[F_MODE]-=([name]);
91 return prop[F_MODE][name];
92 case F_MODE: prop[F_MODE][name]^= Value;
93 if (!prop[F_MODE][name]) prop[F_MODE]-=([name]);
94 return prop[F_MODE][name];
95 case F_SET_METHOD:
96 // -1 als Setz-Methode: Nosetmethod setzen
97 if (Value == -1)
98 {
99 prop[F_SET_METHOD]-=([name]);
100 prop[F_MODE][name] |= NOSETMETHOD;
101 return 0;
102 }
103 // Kein break!
104 case F_QUERY_METHOD:
Zesstra746046c2018-11-04 11:44:44 +0100105 // Ungebundene Lambda_Closure? Heutzutage ein Fehler.
106 if (closurep(Value) && !query_closure_object(Value))
MG Mud User88f12472016-06-24 23:31:02 +0200107 {
Zesstra746046c2018-11-04 11:44:44 +0100108 raise_error("Ungebundene Lambdas sind als Querymethoden "
109 "nicht mehr unterstuetzt.\n");
MG Mud User88f12472016-06-24 23:31:02 +0200110 }
111 // Kein break!
112 default:
113 if (!Value) prop[Type]-=([name]);
114 else prop[Type][name] = Value;
115 }
116
117 // Gesamtwert zurueckgeben
118 return prop[Type][name];
119}
120
121
122// Direktes Auslesen der Property ohne Filter ...
123public varargs mixed Query( string name, int Type )
124{
125 if (pointerp(prop)) return prop[Type][name];
126 return 0;
127}
128
129// Property setzen unter Verwendung evtl. vorhandener Zugriffsfunktionen
130public mixed SetProp( string name, mixed Value )
131{
MG Mud User88f12472016-06-24 23:31:02 +0200132 mixed result;
Zesstra10412ed2019-11-23 15:54:09 +0100133
MG Mud User88f12472016-06-24 23:31:02 +0200134 // nur fuer heute
135 if (!objectp(this_object()))
136 return 0;
137
138 // NOSETMETHOD: Darf nicht gesetzt werden
139 if (prop[F_MODE][name] & NOSETMETHOD ) return -1;
140
141 // Set-Method abfragen, so vorhanden
Zesstra10412ed2019-11-23 15:54:09 +0100142 // TODO: nachdem alle moeglichen Werte als Set-Methode illegal sind, auf
143 // closure aendern.
144 mixed func = prop[F_SET_METHOD][name];
145 if (func)
MG Mud User88f12472016-06-24 23:31:02 +0200146 {
147 int flag;
148
149 // Wert als Set-Method? gleich zurueckgeben
150 if (!closurep(func)) return func;
151
152 // An dieser Stelle muss func eine Closure sein. Da Set() ungebundene
153 // Lambdas bindet, kann es auch nur eine gebundene Closure sein und das
154 // Objekt existiert auch noch (sonst waere func == 0).
155
156 // closure_call setzen, falls noch nicht gesetzt
157 if ((flag=closure_call<time()))
158 closure_call = time()+59;
159
160 // Dann mal die Closure aufrufen. Bei Fehler selbige loeschen
161 if (catch(result=funcall(func, Value, name);publish))
162 {
163 prop[F_SET_METHOD]-=([name]);
164 }
165
166 // Wenn closure_call gesetzt wurde, wieder loeschen
167 if (flag) closure_call = 0;
168
169 // Und zurueckgeben
170 return result;
171 }
172
173 // _set_*-Methode vorhanden? falls ja, aufrufen.i
174 // TODO: Closurecache einfuehren und Funktionaufruf nur noch machen, wenn es
175 // die _set_* auch gibt?
176 if (call_resolved(&result,this_object(),"_set_"+name,Value ))
177 return result;
178
179 // Letzte Moeglichkeit: Muss eine 'normale' Property sein
180 return Set( name, Value, F_VALUE, extern_call() );
181}
182
183
184// Property auslesen unter Verwendung evtl. vorhandener Zugriffsfunktionen
185public mixed QueryProp( string name )
186{
MG Mud User88f12472016-06-24 23:31:02 +0200187 mixed result;
Zesstra10412ed2019-11-23 15:54:09 +0100188
MG Mud User88f12472016-06-24 23:31:02 +0200189 // nur fuer heute
190 if (!objectp(this_object()))
191 return;
192
193 // Query-Methode vorhanden?
Zesstra10412ed2019-11-23 15:54:09 +0100194 mixed func = prop[F_QUERY_METHOD][name];
195 if (func)
MG Mud User88f12472016-06-24 23:31:02 +0200196 {
197 int flag;
198
199 // Wert als Query-Method? Gleich zurueckgeben ...
200 if (!closurep(func)) return func;
201
202 // An dieser Stelle muss func eine Closure sein. Da Set() ungebundene
203 // Lambdas bindet, kann es auch nur eine gebundene Closure sein und das
204 // Objekt existiert auch noch (sonst waere func == 0).
205
206 // closure_call setzen, falls noch nicht gesetzt
207 if ((flag=closure_call<time()))
208 closure_call = time()+59;
209
210 // Dann Mal die Closure aufrufen. Bei Fehler selbige loeschen
211 if (catch(result=funcall(func);publish))
212 {
213 prop[F_QUERY_METHOD]-=([name]);
214 }
215 // Wenn closure_call gesetzt wurde, wieder loeschen
216 if (flag) closure_call = 0;
217
218 // Und zurueckgeben
219 return result;
220 }
221
222 // _query_*-Methode vorhanden? falls ja, aufrufen.
223 // TODO: Closurecache und nur rufen, wenn es _query_* auch gibt?
224 if (call_resolved(&result,this_object(),"_query_"+name))
225 return result;
226
227 // Hilft alles nichts. Es ist eine 'normale' Property ...
228 return prop[F_VALUE][name];
229}
230
231
232// Das gesamte Property-Mapping auf einen Schlag setzen
233public void SetProperties( mapping props )
234{
235 string *names;
236 int i, j, same_object;
237
238 // Kein Mapping? Schlecht ...
239 if(!mappingp(props)) return;
240
241 // Setzen wir selber?
242 same_object = (!closure_call &&
243 (!extern_call()||previous_object()==this_object()||
244 allowed()));
245 names = m_indices(props);
246
247 // Das SECURED-Flag darf nur durch das Objekt selber gesetzt werden:
248 // Alle SECURED-Flags aus props loeschen
249 if (!same_object)
250 {
251 j=sizeof(names);
252 while(j--) props[names[j], F_MODE] &= ~SECURED;
253 }
254
255 j=sizeof(names);
256 while(j--)
257 {
258 // Properties, die schon SECURED oder PROTECTED sind, duerfen
259 // nur vom Objekt selber manipuliert werden
260 if (same_object||!(prop[F_MODE][names[j]] & (PROTECTED|SECURED)) )
261 {
262 i=4;
263 while(i--)
264 {
265 if(props[names[j],i])
266 prop[i][names[j]] = props[names[j], i];
267 else
268 prop[i]-=([names[j]]);
269 }
270 }
271 }
272 return;
273}
274
275
276// Ein Mapping mit allen Properties zurueckgeben
277public mapping QueryProperties()
278{
279 mapping props;
280 int i, j;
281 string *names;
282
283 props = m_allocate( 0, 4 );
284
285 if (pointerp(prop))
286 {
287 i=4;
288 while(i--)
289 {
290 names = m_indices(prop[i]);
291 j=sizeof(names);
292 while(j--) props[names[j], i] = prop[i][names[j]];
293 }
294 }
295 return props;
296}
297
298// Die Properties als urspruengliches Array zurueckgeben
299public mixed *__query_properties()
300{
301 if ( pointerp(prop) )
302 return(deep_copy(prop));
303 else
304 return ({ ([]),([]),([]),([]) });
305}
306
307
308// mapping Properties setzen zum Speichern (per save_object())
309// Aufruf nur aus simul_efun heraus
310public void _set_save_data(mixed data) { properties = data; }
311
312// mapping Properties zum Restoren zurueckgeben
313public mixed _get_save_data() { return properties; }
314