MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame^] | 1 | #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 | |
| 23 | mixed *reset_times; |
| 24 | mapping in_progress; |
| 25 | |
| 26 | |
| 27 | varargs public int remove( int silent ); |
| 28 | public void reset(); |
| 29 | public void print_debug_info(); |
| 30 | static void call_next_update(); |
| 31 | static void do_update(); |
| 32 | public int IsTmpProp( object ob, string prop ); |
| 33 | public void RemoveTmpProp( string prop ); |
| 34 | varargs public void SetTmpProp( object ob, string prop, mixed newval, |
| 35 | int tm, int sp ); |
| 36 | |
| 37 | |
| 38 | public 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 | |
| 52 | varargs public int remove( int silent ) |
| 53 | { |
| 54 | save_object(SAVEFILE); |
| 55 | destruct(this_object()); |
| 56 | |
| 57 | return 1; |
| 58 | } |
| 59 | |
| 60 | |
| 61 | public void reset() |
| 62 | { |
| 63 | save_object(SAVEFILE); |
| 64 | } |
| 65 | |
| 66 | |
| 67 | public void print_debug_info() |
| 68 | { |
| 69 | printf( "in_progress: %O\nreset_times: %O\n", in_progress, reset_times ); |
| 70 | } |
| 71 | |
| 72 | |
| 73 | static 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 | |
| 91 | static 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 |
| 145 | public 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. |
| 164 | public 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 | |
| 231 | varargs 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 | } |