blob: f48d73c63ace16cb775b506150ca529f78d4a7b9 [file] [log] [blame]
MG Mud User88f12472016-06-24 23:31:02 +02001// MorgenGrauen MUDlib
2//
3// upd.c
4//
5// $Id: upd.c 8850 2014-06-13 21:34:44Z Zesstra $
6#pragma strict_types
7#pragma save_types
8#pragma range_check
9#pragma no_clone
MG Mud User88f12472016-06-24 23:31:02 +020010
11#define NEED_PROTOTYPES
12#include <magier.h>
13#include <player.h>
14#undef NEED_PROTOTYPES
15#include <debug_info.h>
16#include <wizlevels.h>
17#include <moving.h>
18#include <properties.h>
19#include <logging.h>
20#include <thing/properties.h>
21
22varargs static int _make(string file, int flags, int recursive);
23
24static mixed _query_localcmds()
25{
26 return ({({"upd","_upd",0,LEARNER_LVL}),
27 ({"load","_load",0,LEARNER_LVL})});
28}
29
30//
31// _save(): Spieler in Rettungsraum retten
32// obj: Spielerobjekt(?)
33// inv_save: Rettungsraumname
34// Rueckgabe: 0 wenn kein Spielerobjekt
35// Spielerobjekt, falls doch
36//
37
38static mixed _save( object obj, object inv_saver )
39{
40 if ( query_once_interactive(obj) )
41 {
42 obj->move( inv_saver, NO_CHECK );
43 return obj;
44 }
45 return 0;
46}
47
48
49//
50// _reload(): Objekt laden
51// file: Filename. Muss in der Form /xx/xx/xx.c vorliegen
52// clone: > 0 -> Es soll geclont werden, enthaelt Objektnummer des
53// Vorgaengerobjektes
54// flags: Kommandozeilenoptionen
55// err: Leerstring als Referenz uebergeben. Enthaelt nach dem
56// Aufruf vom _reload() die Fehlermeldungen als String.
57// Rueckgabe: Das neu erzeugte Objekt bzw. das schon vorhandene Objekt
58// bzw. 0, wenn Fehler auftrat.
59//
60
61private object _reload(string file, int clone, int flags, string err)
62{
63 object obj;
64
65 if (!obj=find_object(file[0..<3]+(clone?("#"+clone):"")))
66 {
67 int pos,pos2;
68 string bt;
69
70 if(file_size(file)<0)
71 {
72 if (file_size(file)==-1)
73 err = sprintf("upd: %s: Datei existiert nicht.\n", file);
74 else // directory
75 err = sprintf("upd: %s: Verzeichnisse koennen nicht geladen "
76 "werden.\n",file);
77 return obj; // 0
78 }
79 pos = max(file_size(__DEBUG_LOG__),0);
80
81 if ((err = (clone?catch(obj = clone_object(file)):
82 catch(load_object(file)) )) && (flags & UPD_B))
83 {
84 if (( pos2=file_size(__DEBUG_LOG__)) > pos )
85 err+=sprintf("\nBacktrace:\n%s",
86 read_bytes(__DEBUG_LOG__,pos, pos2-pos ));
87 else
88 err+=sprintf("\nKEIN BACKTRACE VERFUEGBAR!\n");
89 }
90 if (!err&&!obj&&(!obj = find_object(file[0..<3])))
91 err += sprintf( "upd: %s: Blueprint nach dem Laden zerstoert.\n",file );
92 }
93 else
94 err=sprintf("upd: Objekt existiert schon: %O\n",obj);
95 return obj;
96}
97
98
99//
100// _update(): File updaten -> Blueprint destructen
101// file: Filename
102// dummy: simulieren? (1->wird nicht aktualisiert)
103// flags: Kommandozeilenoptionen
104// Rueckgabe: -1: Keine Vollzugriff
105// 0: Objekt ist nicht geladen
106// 1: Operation wird durchgefuehrt
107//
108
109private varargs int _update(string file, int dummy, int flags)
110{
111 object obj;
112 string err;
113 if (!dummy && !objectp(obj = find_object(file))) return 0;
114 if (!IS_ARCH(this_object()))
115 {
116 // Schreibrechte nur pruefen, wenn echt aktualisiert werden soll.
117 if(!dummy && !MAY_WRITE(file))
Zesstra9ad254c2019-09-27 00:30:41 +0200118 return (printf("upd: %s: Keine Schreibrechte!\n",file), -1);
119 if(!MAY_READ(file))
MG Mud User88f12472016-06-24 23:31:02 +0200120 return (printf("upd: %s: Keine Leserechte!\n", file), -1);
121 }
122 if (dummy) return 1;
123
124 if ( flags & UPD_D )
125 {
126 object *inv;
127 if (sizeof(inv = deep_inventory(obj)))
128 {
129 printf("upd: %s: Entferne Objekte im Inventar\n", file );
130 if (!(flags&UPD_H))
131 {
132 if(err=catch(filter_objects( inv, "remove", 1 )))
133 printf("upd: %s: Fehlgeschlagen. Grund:\n%s\n",
134 file,err);
135 }
136 if (sizeof(inv = deep_inventory(obj)))
137 filter(inv, function void (object ob)
138 {destruct(ob);});
139 }
140 }
141 if (!(flags&UPD_H))
142 {
143 if(err = catch(obj->remove()))
144 printf("upd: %s: remove() fehlgeschlagen. Aufruf von " +
145 "destruct().\n",file);
146 }
147 if(objectp(obj)) destruct(obj);
148 return 1;
149}
150
151
152//
153// _instance_upd(): Alle Objekte nach Clones des Objekts durchsuchen
154// file: Filename des Objektes
155// flags: Kommandozeilenargumente
156// obj: Aktuelles Objekt
157// instances: Zahl der gefundenen Instanzen
158//
159
160private void _instance_upd(string file, int flags, mixed obj, int instances,
161 int firstcall)
162{
163 int i;
164 if (firstcall)
165 printf("upd: %s: %s Instanzen.\n",file,flags&UPD_A?"Aktualisiere":"Suche");
166
167 while (get_eval_cost()>220000 && i < sizeof(obj))
168 {
169 if (!objectp(obj[i]))
170 instances--;
171 else
172 {
173 if (flags&UPD_F&&!(flags&UPD_S))
174 printf( "upd: %O gefunden in %s\n", obj[i],
175 environment(obj[i])?object_name(environment(obj[i]))
176 : "keiner Umgebung" );
177 if (flags&UPD_A) _make(object_name(obj[i]), flags & ~(UPD_A|UPD_F),1 );
178 }
179 i++;
180 }
181 if (i < sizeof(obj))
182 call_out( #'_instance_upd/*'*/,2,file,flags,obj[i..],instances,0);
183 else
184 printf( "upd: %s: %d Instanzen %s\n", file, instances,
185 (flags & UPD_A) ? "aktualisiert" : "gefunden" );
186 return;
187}
188
189
190//
191// _do_make(): Alle geerbten Objekte bearbeiten (fuer -m/-v)
192// file: Name des Files
193// clone: 0, wenn blueprint, ansonsten Clonenummer
194// flags: Kommandozeilenparameter
195// dep: geschachteltes Array mit Meldungen (wg. Rekursion)
196// ready: Array der schon bearbeiteten Objekte (wg. Rekursion)
197// Rueckgabe: Array der Objektnamen, die bearbeitet wurden
198// (Array in Array in ...)
199//
200
201varargs private int _do_make( string file,int clone,int flags,mixed dep,
202 string *ready )
203{
204 object obj;
205 string err;
206 string *ilist;
207 mixed downdeps;
208 int ret;
209
210 if (!pointerp(ready)) ready = ({});
211 ready += ({ file });
212
213 if ( !(obj = _reload(file,clone,flags,&err)))
214 {
215 dep += ({ err });
216 return 0;
217 }
218
219 ilist = inherit_list(obj)-ready;
220
221 downdeps = ({});
222
223 while (sizeof(ilist))
224 {
225 ret = _do_make( ilist[0],0,flags, &downdeps, &ready )||ret;
226 ilist[0..0] = ({});
227 ilist -= ready;
228 }
229
230 if ( ret||file_time(file)>program_time(obj)||(flags &UPD_I))
231 if ( _make( file, flags & ~(UPD_M|UPD_I) ,1) < 0 )
232 dep = ({ "{" + explode(file,"/")[<1] + "}", downdeps });
233 else{
234 dep = ({ "[" + explode(file,"/")[<1] + "]", downdeps });
235 ret = 1;
236 }
237 else if (flags&UPD_V) dep += ({ explode(file,"/")[<1], downdeps });
238 return ret;
239}
240
241
242//
243// _make_dep(): Ausgabe des Ererbungsbaumes
244// Objekte im Array dep
245// prefix enthaelt Zeilenanfang (fuer Rekursion)
246// Rueckgabe: String mit dem Vererbungsbaum des Objektes
247//
248
249private string _make_dep( mixed dep, string prefix )
250{
251 string ret;
252 int i, size;
253
254 ret="";
255 size=sizeof(dep);
256 for (i=0; i<size;i++)
257 if (pointerp(dep[i]))
258 ret += _make_dep(dep[i],prefix + (i < (size-1) ? "| ":" "));
259 else
260 ret += prefix + "+-" + dep[i] + "\n";
261 return ret;
262}
263
264
265//
266// _illegal_closure(): ist closure in arg an objekt gebunden?
267// arg: closure(-array/mapping)
268// Rueckgabe: 0 wenn alles okay
269// 1 wenn closure geloescht werden muss
270//
271
272private int _illegal_closure( mixed arg )
273{
274 int i, j;
275 string *indices;
276
277 if ( closurep(arg) && !objectp(query_closure_object(arg)) )
278 return 1;
279
280 if ( pointerp(arg) ){
281 for ( i = sizeof(arg); i--; )
282 if ( _illegal_closure(arg[i]) )
283 return 1;
284 }
285 else if ( mappingp(arg) ){
286 indices = m_indices(arg);
287 for ( i = sizeof(indices); i--; )
288 for ( j = get_type_info( arg, 1 ); j--; )
289 if ( _illegal_closure(arg[indices[i], j]) )
290 return 1;
291 }
292 return 0;
293}
294
295//
296// _make(): Update file
297// file: Filename
298// flags: Kommandozeilenargumente
299//
300
301varargs static int _make(string file, int flags,int recursive)
302{
303 string msg, err, blue;
304 int inst;
305 object obj, inv_saver;
306 mixed tmp;
307
308 msg = "";
309
310 if (!file) return printf( "upd: Kein Filename uebergeben!\n" ), RET_FAIL;
311
312// Filename in Blue, Objektname in blue, Instanznummer in inst
313
314 if (sscanf(file,"%s#%d",blue,inst)==2) blue += ".c";
315 else blue = file + (file[<2..]==".c" ? "" : ".c");
316
317// Alle Instanzen durchsuchen im Falle von -a oder -f
318
319 if ((flags & UPD_LOAD)&&find_object(file))
320 return printf("load: %s: Objekt ist schon geladen.\n",file),RET_OK;
321
322 if ( flags & (UPD_F|UPD_A))
323 {
324 if (inst) return printf( "upd: %s: Eine Instanz kann keine " +
325 "Clones haben.\n",file ), RET_FAIL;
326 if ((tmp=_update(file, 1,flags))==-1)
327 return printf( "upd: %s: Kein Vollzugriff auf die " +
328 "Datei erlaubt.\n",file), RET_FAIL;
329 if (tmp==0) return RET_FAIL;
330
331 tmp=clones(blue[0..<3],2);
332 if (sizeof(tmp))
333 call_out( #'_instance_upd/*'*/, 0, file,flags,tmp,sizeof(tmp),1);
334 else
335 printf( "upd: %s: Keine Clones vorhanden!\n", blue[0..<3]);
336
337 if ( (flags & UPD_F) && !(flags &(UPD_R|UPD_L|UPD_LOAD))) return RET_OK;
338 // Nichts laden -> Auch kein Backup
339 }
340
341// Backupraum festlegen
342
343 if( blue==INV_SAVE ) {
344 printf("upd: Achtung: Raum zum Zwischenspeichern soll geladen werden?!\n");
345 }
346 if ( !(inv_saver=load_object(INV_SAVE)) )
347 {
348 printf("upd: %s: Raum zum Zwischenspeichern des " +
349 "Rauminhalts ist nicht ladbar.\n" +
350 " %s\n",file,INV_SAVE);
351 return RET_FAIL;
352 }
353
354// Wenn das Objekt existiert bzw. Deep aktualisiert werden soll
355
356 if ( (!(flags&UPD_LOAD))&&
357 ((obj = find_object(file)) || (flags & (UPD_M|UPD_I))))
358 {
359 object *inv, env, *pl_inv;
360 mapping pro;
361 int i;
362 mixed configdata;
363 int restore_config;
364
365 // Wenn Objekt existiert, dann Inhalt und ggf. Daten aus Configure() oder
366 // Props sichern:
367 if (obj)
368 {
369 // im Fall UPD_C erfolgt _kein_ Auslesen und _keine_ Restauration
370 // mittels Configure()
371 if ( ! (flags & UPD_C ) )
372 {
Vanion50652322020-03-10 21:13:25 +0100373 catch(restore_config=call_resolved(&configdata,obj,
MG Mud User88f12472016-06-24 23:31:02 +0200374 "Configure",0);
375 publish);
376 // Wenn UPD_CONF gesetzt wird, _muss_ das Objekt ein oeffentliches
377 // Configure() definieren, sonst erfolgt Abbruch.
378 if ((flags & UPD_CONF) && !restore_config)
379 {
380 printf("upd: %s: hat kein Configure(), Zerstoerung abgebrochen.\n",file);
381 return RET_FAIL;
382 }
383 }
384 if (!(flags&UPD_D)&&(flags&(UPD_L|UPD_R)))
385 {
386 if (i=sizeof(inv=(all_inventory(obj)-({0}))))
387 {
388 mixed items;
389 // Herausbekommen, ob hier Items existieren, die per AddItem
390 // erzeugt werden. Die duerfen nicht gesichert werden.
Vanion50652322020-03-10 21:13:25 +0100391 items=({mixed})obj->QueryProp(P_ITEMS); // mixed, da array of arrays
MG Mud User88f12472016-06-24 23:31:02 +0200392 if (pointerp(items)&&sizeof(items))
393 {
394 items=transpose_array(items)[0];
395 while (i--)
396 if (member(items, inv[i])==-1)
397 inv[i]->move(inv_saver,NO_CHECK);
398 }
399 else // In diesem Objekt sind keine Items gesetzt.
400 while (i--) inv[i]->move(inv_saver,NO_CHECK);
401 }
402 }
403 else
404 {
405 inv=map( deep_inventory(obj), #'_save/*'*/, inv_saver )-({0});
406 }
407 env = environment(obj);
408 if ( flags & UPD_C )
409 {
Vanion50652322020-03-10 21:13:25 +0100410 pro = ({mapping})(obj->QueryProperties());
MG Mud User88f12472016-06-24 23:31:02 +0200411 }
412 }
413 else inv = ({});
414
415// Ererbte Objekte durchsuchen.
416 if ( flags & (UPD_M|UPD_I) )
417 {
418 mixed dep;
419 dep = ({});
420 _do_make( blue, inst, flags & ~(UPD_M|UPD_L|UPD_R|UPD_F|UPD_A), &dep );
421 printf( _make_dep( dep, "" ) + "\n" );
422 }
423
424// Tatsaechlichen Update durchfuehren
425
426 if ( _update(file, 0, flags)< 0) return RET_FAIL;
427 msg += (inst ? "zerstoert" : "aktualisiert");
428
429// Neu laden ??
430 if ( flags & (UPD_R|UPD_L) )
431 {
432 if ( obj = _reload( blue,inst,flags, &err ) )
433 msg += ", " + (inst ? "neu geclont" : "neu geladen");
434
435// Neu geladen: Properties wiederherstellen, Closures filtern
436 if (!err)
437 {
438 if (!obj) obj = find_object(file);
439 // Wenn gewuenscht, Props zurueckschreiben (hat Prioritaet vor
440 // Configure(), weil explizit vom Magier angefordert).
441 if ( pro && (flags & UPD_C) )
442 {
443 string *names;
444
445 names = m_indices(pro);
446
447 // Closures in (mittlerweile) zerstoerten Objekten
448 // rausfiltern, damit die (hoffentlich korrekten) Closures
449 // im neu geclonten Objekt erhalten bleiben
450 for ( i = sizeof(names); i--; )
451 if ( _illegal_closure(pro[names[i], F_VALUE]) ||
452 _illegal_closure(pro[names[i], F_QUERY_METHOD]) ||
453 _illegal_closure(pro[names[i], F_SET_METHOD]) )
454 m_delete( pro, names[i] );
455
456 obj->SetProperties(pro);
457 msg += ", Properties gesetzt";
458 }
459 // Wenn kein UPD_C, wird ggf. das Ergebnis von Configure() wieder
460 // uebergeben.
461 else if (restore_config)
462 {
463 int conf_res;
Vanion50652322020-03-10 21:13:25 +0100464 if (!catch(conf_res=({int})obj->Configure(configdata); publish)
MG Mud User88f12472016-06-24 23:31:02 +0200465 && conf_res == 1)
466 {
467 msg += ", (re-)konfiguriert";
468 }
469 else
470 {
471 msg += ", (Re-)Konfiguration fehlgeschlagen";
472 if (flags & UPD_CONF)
473 printf("upd: Daten von %s konnten nicht rekonfiguriert werden: "
474 "%O\n", file, configdata);
475 }
476 }
477 if (env)
478 {
479 if ( obj->move( env, NO_CHECK ) <= 0 )
480 printf( "upd: /%O konnte nicht in /%O zurueckbewegt werden\n",
481 obj, env );
482 else
483 msg += ", bewegt";
484 }
485 if (i=sizeof(inv))
486 {
487 while(i--) if (inv[i]) inv[i]->move(obj, NO_CHECK );
488 msg += ", Inhalt zurueckbewegt";
489 }
490 }
491 else
492 return printf( "upd: %s: %s", file, err ), RET_FAIL;
493 }
494 }
495 else
496 if ( !_update(file, 0, flags) && (flags & (UPD_L|UPD_LOAD)) )
497 if ( !_reload( blue, inst, flags, &err ) )
498 return printf( "%s: %s: %s", (flags&UPD_LOAD?"load":"upd"),file, err ),
499 RET_FAIL;
500 else
501 msg += "geladen";
502
503 if ( sizeof(msg)&&!(flags&UPD_S&&recursive) )
504 printf("%s: %s: %s.\n",(flags&UPD_LOAD?"load":"upd"),file,msg);
505 return RET_OK;
506}
507
508//
509// _upd: Objekte laden, zerstoeren und aktualisieren
510//
511
512static int _upd(string cmdline)
513{
514 int flags;
515 mixed *args;
516
517 cmdline=_unparsed_args();
518 args=parseargs(cmdline,&flags,UPD_OPTS,1);
519 if(flags==-1||!sizeof(args))
520 return USAGE("upd [-"+UPD_OPTS+"] <datei> [<datei> ..]");
521 if ((flags & UPD_C) && (flags & UPD_CONF))
522 {
523 printf("upd: -c und -C gleichzeitig werden nicht unterstuetzt.\n");
524 return 1;
525 }
526 args=file_list(args,MODE_UPD,0,"/");
527 if(!sizeof(args)) return printf("upd: Keine passende Datei gefunden!\n"),1;
528
529 args=map(args,(: $1[FULLNAME] :))-({0});
530
531 if(!sizeof(args))
532 {
533 printf("upd: Verzeichnisse koennen nicht aktualisiert werden!\n");
534 return 1;
535 }
536 asynchron(args,#'_make,flags,0,0);
537 return 1;
538}
539
540//
541// _load: Objekte laden
542//
543
544static int _load(string cmdline)
545{
546 int flags;
547 mixed *args;
548
549 cmdline=_unparsed_args();
550 args=parseargs(cmdline,&flags,"",1);
551 if(flags==-1||!sizeof(args))
552 return USAGE("load <datei> [<datei> ..]");
553 args=file_list(args,MODE_UPD,0,"/");
554 if(!sizeof(args)) return printf("load: Keine passende Datei gefunden!\n"),1;
555 args=map(args,(: (($1[FILESIZE]!=-2||find_object($1[FULLNAME]))?
556 $1[FULLNAME]:0) :))-({0});
557
558 if(!sizeof(args))
559 return printf("load: Verzeichnisse koennen nicht geladen werden!\n"),1;
560 asynchron(args,#'_make,UPD_LOAD,0,0);
561 return 1;
562}