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