blob: 0f6bbba90b44153f46591aeccecfa5ed9edeabc7 [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;
MG Mud User88f12472016-06-24 23:31:02 +0200237
238 if ( !objectp(ob) || !stringp(prop) || !sizeof(prop) || tm <= 0 )
239 return;
240
241 index = INDEX(ob, prop);
242 DBG( sprintf("SetTmpProp( %O, %O, %O, %O, %O )!\n", ob, prop, newval,
243 tm, sp) );
244
245 // wenn bereits ein temporaerer Prozess laeuft, diesen nun beenden!
246 if ( (oldval = in_progress[index])
247 && ob == oldval[0] && prop == oldval[1] ){
248 DBG( "Es laeuft bereits ein Vorgang fuer diese Property!\n" );
249
250 // Wurde die alte temporaere Property per SetProp() gesetzt, muss der
251 // urspruengliche Wert erst restauriert werden.
252 if ( oldval[4] ){
253 if ( oldval[0]->Query(oldval[1], F_VALUE) == oldval[3] ){
254 DBG( "Alte Property per SetProp() restauriert!\n" );
255 oldval[0]->SetProp( oldval[1], oldval[2] );
256 }
257 }
258 // Ansonsten einfach die F_QUERY- und F_SET_METHOD loeschen.
259 else {
260 if ( oldval[0]->Query( oldval[1], F_QUERY_METHOD ) == oldval[2] ){
261 oldval[0]->Set( oldval[1], 0, F_QUERY_METHOD );
262 DBG( "F_QUERY_METHOD entfernt!\n" );
263 }
264
265 if ( oldval[0]->Query( oldval[1], F_SET_METHOD ) == oldval[3] ){
266 oldval[0]->Set( oldval[1], 0, F_SET_METHOD );
267 DBG( "F_SET_METHOD entfernt!\n" );
268 }
269 }
270
271 for ( l = sizeof(reset_times); l--; )
272 if ( reset_times[l][1] == index ){
273 reset_times[l..l] = ({});
274 DBG( "Timer-Eintrag entfernt!\n" );
275 break;
276 }
277 }
278
279 if ( tm < 1000000 )
280 tm += time();
281
282 if ( tm < time() )
283 return;
284
285 if ( !sp ){
286 // Default: F_QUERY_METHOD setzen
287 oldval = ob->Set( prop, newval, F_QUERY_METHOD );
288
289 // F_SET_METHOD, damit die temporaere Property keinen zwischenzeitlich
290 // gesetzten anderen Wert wieder "restauriert".
291
Arathorn7c451322018-11-15 21:32:01 +0100292 tmp = ob->Set(prop, function mixed (mixed value, string propname) {
293 RemoveTmpProp(propname);
294 return ob->SetProp(propname, value);
295 }, F_SET_METHOD);
MG Mud User88f12472016-06-24 23:31:02 +0200296 }
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}