blob: 0ce1de7b7ddd64dbe7bd9a3829df6cec5e5708fd [file] [log] [blame]
MG Mud User88f12472016-06-24 23:31:02 +02001#pragma strong_types,save_types
2#pragma no_clone,no_shadow
3
4#include <thing/properties.h>
5
6#define SAVEFILE "/p/daemon/save/tmp_prop_master"
7#define PROPMASTER "/p/daemon/tmp_prop_master"
8#define INDEX(a,b) (object_name(a)+"##"+b)
9
10
11#ifdef DEBUG
12# undef DEBUG
13#endif
14
15#ifdef DEBUG
16# define DBG(x) if ( find_player("rikus") ) \
17 tell_object( find_player("rikus"), x );
18#else
19# define DBG(x)
20#endif
21
22
23mixed *reset_times;
24mapping in_progress;
25
26
27varargs public int remove( int silent );
28public void reset();
29public void print_debug_info();
30static void call_next_update();
31static void do_update();
32public int IsTmpProp( object ob, string prop );
33public void RemoveTmpProp( string prop );
34varargs public void SetTmpProp( object ob, string prop, mixed newval,
35 int tm, int sp );
36
37
38public void create()
39{
40
41 seteuid(getuid(this_object()));
42
43 if ( !restore_object(SAVEFILE) ){
44 in_progress = ([]);
45 reset_times = ({});
46 }
47
48 call_next_update();
49}
50
51
52varargs public int remove( int silent )
53{
54 save_object(SAVEFILE);
55 destruct(this_object());
56
57 return 1;
58}
59
60
61public void reset()
62{
63 save_object(SAVEFILE);
64}
65
66
67public void print_debug_info()
68{
69 printf( "in_progress: %O\nreset_times: %O\n", in_progress, reset_times );
70}
71
72
73static void call_next_update()
74{
75 int dt;
76
77 while ( remove_call_out("do_update") != -1 )
78 ;
79
80 if ( sizeof(reset_times) ){
81 dt = reset_times[0][0] - time();
82
83 if ( dt <= 0 )
84 dt = 5;
85
86 call_out( "do_update", dt );
87 }
88}
89
90
91static void do_update()
92{
93 int i, max;
94 string index;
95 mixed *val;
96
97 DBG( "do_update() aufgerufen!\n" );
98
99 while ( remove_call_out("do_update") != -1 )
100 ;
101
102 call_out( "do_update", 30 ); // Zur Sicherheit...
103
104 if ( !(max = sizeof(reset_times)) )
105 return;
106
107 for ( i = 0; i < max && reset_times[i][0] <= time(); i++ ){
108 index = reset_times[i][1];
109
110 if ( !pointerp(val = in_progress[index]) || !objectp(val[0]) )
111 {
112 m_delete( in_progress ,index );
113 continue;
114 }
115
116 DBG( sprintf("Entferne Eintrag %O!\n", index) );
117
118 if ( val[4] ){
119 if ( val[0]->Query(val[1], F_VALUE) == val[3] ){
120 DBG( "Alte Property per SetProp() restauriert!\n" );
121 val[0]->SetProp( val[1], val[2] );
122 }
123 }
124 else {
125 if ( val[0]->Query( val[1], F_QUERY_METHOD ) == val[2] ){
126 val[0]->Set( val[1], 0, F_QUERY_METHOD );
127 DBG( "F_QUERY_METHOD entfernt!\n" );
128 }
129
130 if ( val[0]->Query( val[1], F_SET_METHOD ) == val[3] ){
131 val[0]->Set( val[1], 0, F_SET_METHOD );
132 DBG( "F_SET_METHOD entfernt!\n" );
133 }
134 }
135
136 m_delete( in_progress ,index );
137 }
138
139 reset_times = reset_times[i..];
140 call_next_update();
141}
142
143
144// Zur Abfrage, ob eine temporaere Property schon gesetzt ist
145public int IsTmpProp( object ob, string prop )
146{
147 mixed oldval;
148
149 if ( !objectp(ob) || !prop )
150 return 0;
151
152 if ( (oldval = in_progress[INDEX(ob, prop)])
153 && ob == oldval[0] && prop == oldval[1] )
154 return 1;
155
156 return 0;
157}
158
159
160// Entfernen einer temporaeren Property.
161// Ist nicht zum Entfernen per Hand gedacht, sondern kann nur vom Objekt selber
162// aufgerufen werden. Geschieht, wenn bei gesetzter temporaerer F_SET_METHOD
163// ein fremdes SetProp() auf die Property kommt.
164public void RemoveTmpProp( string prop )
165{
166 string index;
167 mixed *val;
168 int i;
169
170 DBG( "RemoveTmpProp!\n");
171 if ( !previous_object() || !stringp(prop) || !sizeof(prop) )
172 return;
173
174 index = INDEX(previous_object(), prop);
175 DBG( sprintf("RemoveTmpProp(%O)!\n", index) );
176
177 if ( !(val = in_progress[index]) ){
178 DBG( "Kein Eintrag vorhanden!\n" );
179 return;
180 }
181
182 if ( objectp(val[0]) ){
183 DBG( "Restauriere alten Zustand ...\n" );
184
185 if ( val[4] ){
186 if ( val[0]->Query(val[1], F_VALUE) == val[3] ){
187 DBG( "Alte Property per SetProp() restauriert!\n" );
188 val[0]->SetProp( val[1], val[2] );
189 }
190 }
191 else {
192 if ( val[0]->Query( val[1], F_QUERY_METHOD ) == val[2] ){
193 val[0]->Set( val[1], 0, F_QUERY_METHOD );
194 DBG( "F_QUERY_METHOD entfernt!\n" );
195 }
196
197 if ( val[0]->Query( val[1], F_SET_METHOD ) == val[3] ){
198 val[0]->Set( val[1], 0, F_SET_METHOD );
199 DBG( "F_SET_METHOD entfernt!\n" );
200 }
201 }
202 }
203
204 for ( i = sizeof(reset_times); i--; )
205 if ( reset_times[i][1] == index ){
206 reset_times[i..i] = ({});
207 break;
208 }
209
210 DBG( "Eintrag entfernt!\n" );
211 m_delete( in_progress, index );
212}
213
214
215// Property 'prop' im Objekt 'ob' fuer 'tm' Sekunden auf Wert 'newval' setzen.
216// Wenn der Schalter 'sp' gesetzt ist, wird dafuer SetProp() verwendet,
217// anstatt eine F_QUERY_METHOD zu benutzen.
218//
219// ACHTUNG:
220//
221// Das Setzen von 'sp' ist hoechst fehleranfaellig und sollte nur in wenigen
222// Spezialfaellen geschehen, in denen eine SET-Methode aufgerufen werden muss
223// (wie bei P_LIGHT z.B.). Ansonsten bitte den Default-Aufruf ohne 'sp'
224// verwenden!
225//
226// Es besteht sonst die Gefahr, dass die Property nicht korrekt zurueckgesetzt
227// wird (wenn dieser Master oder 'ob' zerstoert wird - oder beides wie bei einem
228// Crash) oder dass durch Wechselwirkungen mit anderen Query- oder Set-Methoden
229// ein falscher Wert "restauriert" wird.
230
231varargs public void SetTmpProp( object ob, string prop, mixed newval,
232 int tm, int sp )
233{
234 string index;
235 mixed oldval, tmp;
236 int max, pos, l, r;
237 closure a, b;
238
239 if ( !objectp(ob) || !stringp(prop) || !sizeof(prop) || tm <= 0 )
240 return;
241
242 index = INDEX(ob, prop);
243 DBG( sprintf("SetTmpProp( %O, %O, %O, %O, %O )!\n", ob, prop, newval,
244 tm, sp) );
245
246 // wenn bereits ein temporaerer Prozess laeuft, diesen nun beenden!
247 if ( (oldval = in_progress[index])
248 && ob == oldval[0] && prop == oldval[1] ){
249 DBG( "Es laeuft bereits ein Vorgang fuer diese Property!\n" );
250
251 // Wurde die alte temporaere Property per SetProp() gesetzt, muss der
252 // urspruengliche Wert erst restauriert werden.
253 if ( oldval[4] ){
254 if ( oldval[0]->Query(oldval[1], F_VALUE) == oldval[3] ){
255 DBG( "Alte Property per SetProp() restauriert!\n" );
256 oldval[0]->SetProp( oldval[1], oldval[2] );
257 }
258 }
259 // Ansonsten einfach die F_QUERY- und F_SET_METHOD loeschen.
260 else {
261 if ( oldval[0]->Query( oldval[1], F_QUERY_METHOD ) == oldval[2] ){
262 oldval[0]->Set( oldval[1], 0, F_QUERY_METHOD );
263 DBG( "F_QUERY_METHOD entfernt!\n" );
264 }
265
266 if ( oldval[0]->Query( oldval[1], F_SET_METHOD ) == oldval[3] ){
267 oldval[0]->Set( oldval[1], 0, F_SET_METHOD );
268 DBG( "F_SET_METHOD entfernt!\n" );
269 }
270 }
271
272 for ( l = sizeof(reset_times); l--; )
273 if ( reset_times[l][1] == index ){
274 reset_times[l..l] = ({});
275 DBG( "Timer-Eintrag entfernt!\n" );
276 break;
277 }
278 }
279
280 if ( tm < 1000000 )
281 tm += time();
282
283 if ( tm < time() )
284 return;
285
286 if ( !sp ){
287 // Default: F_QUERY_METHOD setzen
288 oldval = ob->Set( prop, newval, F_QUERY_METHOD );
289
290 // F_SET_METHOD, damit die temporaere Property keinen zwischenzeitlich
291 // gesetzten anderen Wert wieder "restauriert".
292
293 a=symbol_function("RemoveTmpProp",this_object());
294 b=symbol_function("SetProp",ob);
295 tmp=ob->Set(prop,lambda(({'set_value,'prop_name}),({#',,({a,'prop_name}),({#'return,({b,'prop_name,'set_value})})})),F_SET_METHOD);
296 }
297 else{
298 // Fuer Spezialfaelle (P_LIGHT z.B.) wird die Property direkt mit
299 // SetProp() gesetzt und spaeter mit dem alten Wert restauriert.
300 // Achtung - extrem fehleranfaellig und wirklich nur fuer Spezialfaelle!
301
302 // Alten Wert mit Query() sichern anstatt mit QueryProp(), um nicht
303 // irgendwelchen F_QUERY_METHODs auf den Leim zu gehen.
304 oldval = ob->Query( prop, F_VALUE );
305
306 // Rueckgabewert des SetProp() speichern, um spaeter erkennen zu
307 // koennen, ob die Property zwischenzeitlich veraendert wurde.
308 tmp = ob->SetProp( prop, newval );
309 }
310
311 in_progress[index] = ({ ob, prop, oldval, tmp, sp });
312
313 if ( !(max = sizeof(reset_times)) )
314 pos = 0;
315 else{
316 l = 0;
317 r = max - 1;
318
319 while ( l < r ){
320 pos = (l + r) / 2;
321
322 if ( tm < reset_times[pos][0] )
323 r = --pos;
324 else
325 l = ++pos;
326 }
327
328 while ( pos >= 0 && pos < max && tm < reset_times[pos][0] )
329 pos--;
330 }
331
332 reset_times = reset_times[0..pos] + ({ ({tm, index}) })
333 + reset_times[pos+1..];
334
335 DBG( sprintf("Property an Stelle %O eingefuegt!\n", pos+1) );
336
337 call_next_update();
338}