ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/lib/cf.pm
(Generate patch)

Comparing deliantra/server/lib/cf.pm (file contents):
Revision 1.46 by root, Sun Aug 27 16:15:12 2006 UTC vs.
Revision 1.69 by root, Mon Sep 18 01:10:35 2006 UTC

11use Event; 11use Event;
12$Event::Eval = 1; # no idea why this is required, but it is 12$Event::Eval = 1; # no idea why this is required, but it is
13 13
14use strict; 14use strict;
15 15
16_init_vars;
17
16our %COMMAND = (); 18our %COMMAND = ();
17our @EVENT; 19our @EVENT;
18our %PROP_TYPE;
19our %PROP_IDX;
20our $LIBDIR = maps_directory "perl"; 20our $LIBDIR = maps_directory "perl";
21 21
22our $TICK = MAX_TIME * 1e-6; 22our $TICK = MAX_TIME * 1e-6;
23our $TICK_WATCHER; 23our $TICK_WATCHER;
24our $NEXT_TICK; 24our $NEXT_TICK;
32 print STDERR "cfperl: $msg"; 32 print STDERR "cfperl: $msg";
33 LOG llevError, "cfperl: $msg"; 33 LOG llevError, "cfperl: $msg";
34 }; 34 };
35} 35}
36 36
37my %ignore_set = (MAP_PROP_PATH => 1); # I hate the plug-in api. Deeply!
38
39# generate property mutators
40sub prop_gen {
41 my ($prefix, $class) = @_;
42
43 no strict 'refs';
44
45 for my $prop (keys %PROP_TYPE) {
46 $prop =~ /^\Q$prefix\E_(.*$)/ or next;
47 my $sub = lc $1;
48
49 my $type = $PROP_TYPE{$prop};
50 my $idx = $PROP_IDX {$prop};
51
52 *{"$class\::get_$sub"} = *{"$class\::$sub"} = sub {
53 $_[0]->get_property ($type, $idx)
54 };
55
56 *{"$class\::set_$sub"} = sub {
57 $_[0]->set_property ($type, $idx, $_[1]);
58 } unless $ignore_set{$prop};
59 }
60}
61
62# auto-generate most of the API
63
64prop_gen OBJECT_PROP => "cf::object";
65# CFAPI_OBJECT_ANIMATION?
66prop_gen PLAYER_PROP => "cf::object::player";
67
68prop_gen MAP_PROP => "cf::map";
69prop_gen ARCH_PROP => "cf::arch";
70
71@safe::cf::object::player::ISA = @cf::object::player::ISA = 'cf::object'; 37@safe::cf::object::player::ISA = @cf::object::player::ISA = 'cf::object';
72 38
73# we bless all objects into (empty) derived classes to force a method lookup 39# we bless all objects into (empty) derived classes to force a method lookup
74# within the Safe compartment. 40# within the Safe compartment.
75for my $pkg (qw(cf::object cf::object::player cf::player cf::map cf::party cf::region cf::arch)) { 41for my $pkg (qw(cf::object cf::object::player cf::player cf::map cf::party cf::region cf::arch cf::living)) {
76 no strict 'refs'; 42 no strict 'refs';
77 @{"safe::$pkg\::wrap::ISA"} = @{"$pkg\::wrap::ISA"} = $pkg; 43 @{"safe::$pkg\::wrap::ISA"} = @{"$pkg\::wrap::ISA"} = $pkg;
78} 44}
79 45
80$Event::DIED = sub { 46$Event::DIED = sub {
103} 69}
104 70
105############################################################################# 71#############################################################################
106# "new" plug-in system 72# "new" plug-in system
107 73
74=head3 EVENTS AND OBJECT ATTACHMENTS
75
76=over 4
77
78=item $object->attach ($attachment, key => $value...)
79
108=item $object->attach ($attachment, ...) 80=item $object->detach ($attachment)
109 81
110Attach a pre-registered attachment to an object. 82Attach/detach a pre-registered attachment to an object.
111 83
84=item $player->attach ($attachment, key => $value...)
85
112=item $player->attach ($attachment, ...) 86=item $player->detach ($attachment)
113 87
114Attach a pre-registered attachment to a player. 88Attach/detach a pre-registered attachment to a player.
115 89
116=item $map->attach ($attachment, ...) # not yet persistent 90=item $map->attach ($attachment, key => $value...)
117 91
92=item $map->detach ($attachment)
93
118Attach a pre-registered attachment to a map. 94Attach/detach a pre-registered attachment to a map.
95
96=item $bool = $object->attached ($name)
97
98=item $bool = $player->attached ($name)
99
100=item $bool = $map->attached ($name)
101
102Checks wether the named attachment is currently attached to the object.
119 103
120=item cf::attach_global ... 104=item cf::attach_global ...
121 105
122Attach handlers for global events. 106Attach handlers for global events.
123 107
150package and register them. Only handlers for eevents supported by the 134package and register them. Only handlers for eevents supported by the
151object/class are recognised. 135object/class are recognised.
152 136
153=back 137=back
154 138
155=item cf::attach_to_type $object_type, ... 139=item cf::attach_to_type $object_type, $subtype, ...
156 140
157Attach handlers for a specific object type (e.g. TRANSPORT). 141Attach handlers for a specific object type (e.g. TRANSPORT) and
142subtype. If C<$subtype> is zero or undef, matches all objects of the given
143type.
158 144
159=item cf::attach_to_objects ... 145=item cf::attach_to_objects ...
160 146
161Attach handlers to all objects. Do not use this except for debugging or 147Attach handlers to all objects. Do not use this except for debugging or
162very rare events, as handlers are (obviously) called for I<all> objects in 148very rare events, as handlers are (obviously) called for I<all> objects in
169=item cf::attach_to_maps ... 155=item cf::attach_to_maps ...
170 156
171Attach handlers to all maps. 157Attach handlers to all maps.
172 158
173=item cf:register_attachment $name, ... 159=item cf:register_attachment $name, ...
160
161Register an attachment by name through which objects can refer to this
162attachment.
163
164=item cf:register_player_attachment $name, ...
165
166Register an attachment by name through which players can refer to this
167attachment.
168
169=item cf:register_map_attachment $name, ...
170
171Register an attachment by name through which maps can refer to this
172attachment.
174 173
175=cut 174=cut
176 175
177# the following variables are defined in .xs and must not be re-created 176# the following variables are defined in .xs and must not be re-created
178our @CB_GLOBAL = (); # registry for all global events 177our @CB_GLOBAL = (); # registry for all global events
241 240
242 \%undo 241 \%undo
243} 242}
244 243
245sub _attach_attachment { 244sub _attach_attachment {
246 my ($klass, $obj, $name, @args) = q_; 245 my ($obj, $name, %arg) = @_;
246
247 return if exists $obj->{_attachment}{$name};
247 248
248 my $res; 249 my $res;
249 250
250 if (my $attach = $attachment{$name}) { 251 if (my $attach = $attachment{$name}) {
251 my $registry = $obj->registry; 252 my $registry = $obj->registry;
252 253
254 for (@$attach) {
255 my ($klass, @attach) = @$_;
253 $res = _attach @$registry, $klass, @$attach; 256 $res = _attach @$registry, $klass, @attach;
254
255 if (my $cb = delete $registry->[EVENT_OBJECT_INSTANTIATE]) {
256 for (@$cb) {
257 eval { $_->[1]->($obj, @args); };
258 if ($@) {
259 warn "$@";
260 warn "... while processing '$name' instantiate with args <@args>.\n";
261 }
262 } 257 }
263 } 258
259 $obj->{$name} = \%arg;
264 } else { 260 } else {
265 warn "object uses attachment '$name' that is not available, postponing.\n"; 261 warn "object uses attachment '$name' that is not available, postponing.\n";
266 } 262 }
267 263
268 push @{$obj->{_attachment}}, $name; 264 $obj->{_attachment}{$name} = undef;
269 265
270 $res->{attachment} = $name; 266 $res->{attachment} = $name;
271 $res 267 $res
272} 268}
273 269
274sub cf::object::attach { 270*cf::object::attach =
271*cf::player::attach =
272*cf::map::attach = sub {
275 my ($obj, $name, @args) = @_; 273 my ($obj, $name, %arg) = @_;
276 274
277 _attach_attachment KLASS_OBJECT, $obj, $name, @args; 275 _attach_attachment $obj, $name, %arg;
278} 276};
279 277
278# all those should be optimised
279*cf::object::detach =
280sub cf::player::attach { 280*cf::player::detach =
281*cf::map::detach = sub {
281 my ($obj, $name, @args) = @_; 282 my ($obj, $name) = @_;
282 283
283 _attach_attachment KLASS_PLAYER, $obj, $name, @args; 284 delete $obj->{_attachment}{$name};
284} 285 reattach ($obj);
286};
285 287
286sub cf::map::attach { 288*cf::object::attached =
289*cf::player::attached =
290*cf::map::attached = sub {
287 my ($obj, $name, @args) = @_; 291 my ($obj, $name) = @_;
288 292
289 _attach_attachment KLASS_MAP, $obj, $name, @args; 293 exists $obj->{_attachment}{$name}
290} 294};
291 295
292sub attach_global { 296sub attach_global {
293 _attach @CB_GLOBAL, KLASS_GLOBAL, @_ 297 _attach @CB_GLOBAL, KLASS_GLOBAL, @_
294} 298}
295 299
296sub attach_to_type { 300sub attach_to_type {
297 my $type = shift; 301 my $type = shift;
302 my $subtype = shift;
298 303
299 _attach @{$CB_TYPE[$type]}, KLASS_OBJECT, @_ 304 _attach @{$CB_TYPE[$type + $subtype * NUM_SUBTYPES]}, KLASS_OBJECT, @_
300} 305}
301 306
302sub attach_to_objects { 307sub attach_to_objects {
303 _attach @CB_OBJECT, KLASS_OBJECT, @_ 308 _attach @CB_OBJECT, KLASS_OBJECT, @_
304} 309}
312} 317}
313 318
314sub register_attachment { 319sub register_attachment {
315 my $name = shift; 320 my $name = shift;
316 321
322 $attachment{$name} = [[KLASS_OBJECT, @_]];
323}
324
325sub register_player_attachment {
326 my $name = shift;
327
328 $attachment{$name} = [[KLASS_PLAYER, @_]];
329}
330
331sub register_map_attachment {
332 my $name = shift;
333
317 $attachment{$name} = [@_]; 334 $attachment{$name} = [[KLASS_MAP, @_]];
318} 335}
319 336
320our $override; 337our $override;
321our @invoke_results = (); # referenced from .xs code. TODO: play tricks with reify and mortals? 338our @invoke_results = (); # referenced from .xs code. TODO: play tricks with reify and mortals?
322 339
336 for (@$callbacks) { 353 for (@$callbacks) {
337 eval { &{$_->[1]} }; 354 eval { &{$_->[1]} };
338 355
339 if ($@) { 356 if ($@) {
340 warn "$@"; 357 warn "$@";
341 warn "... while processing $EVENT[$event][0] event, skipping processing altogether.\n"; 358 warn "... while processing $EVENT[$event][0](@_) event, skipping processing altogether.\n";
342 override; 359 override;
343 } 360 }
344 361
345 return 1 if $override; 362 return 1 if $override;
346 } 363 }
347 364
348 0 365 0
349} 366}
367
368=item $bool = cf::invoke EVENT_GLOBAL_XXX, ...
369
370=item $bool = $object->invoke (EVENT_OBJECT_XXX, ...)
371
372=item $bool = $player->invoke (EVENT_PLAYER_XXX, ...)
373
374=item $bool = $map->invoke (EVENT_MAP_XXX, ...)
375
376Generate a global/object/player/map-specific event with the given arguments.
377
378This API is preliminary (most likely, the EVENT_KLASS_xxx prefix will be
379removed in future versions), and there is no public API to access override
380results (if you must, access C<@cf::invoke_results> directly).
381
382=back
383
384=head2 methods valid for all pointers
385
386=over 4
387
388=item $object->valid
389
390=item $player->valid
391
392=item $map->valid
393
394Just because you have a perl object does not mean that the corresponding
395C-level object still exists. If you try to access an object that has no
396valid C counterpart anymore you get an exception at runtime. This method
397can be used to test for existence of the C object part without causing an
398exception.
399
400=back
401
402=cut
403
404*cf::object::valid =
405*cf::player::valid =
406*cf::map::valid = \&cf::_valid;
350 407
351############################################################################# 408#############################################################################
352# object support 409# object support
353 410
354sub instantiate { 411sub instantiate {
356 413
357 $data = from_json $data; 414 $data = from_json $data;
358 415
359 for (@$data) { 416 for (@$data) {
360 my ($name, $args) = @$_; 417 my ($name, $args) = @$_;
361 attach $obj, $name, @{$args || [] }; 418
419 $obj->attach ($name, %{$args || {} });
362 } 420 }
363} 421}
364 422
365# basically do the same as instantiate, without calling instantiate 423# basically do the same as instantiate, without calling instantiate
366sub reattach { 424sub reattach {
367 warn "reattach<@_>\n";#d#
368 my ($obj) = @_; 425 my ($obj) = @_;
369 my $registry = $obj->registry; 426 my $registry = $obj->registry;
370 427
428 @$registry = ();
429
430 delete $obj->{_attachment} unless scalar keys %{ $obj->{_attachment} || {} };
431
371 for my $name (@{ $obj->{_attachment} }) { 432 for my $name (keys %{ $obj->{_attachment} || {} }) {
372 if (my $attach = $attachment{$name}) { 433 if (my $attach = $attachment{$name}) {
434 for (@$attach) {
435 my ($klass, @attach) = @$_;
373 _attach @$registry, KLASS_OBJECT, @$attach; 436 _attach @$registry, $klass, @attach;
437 }
374 } else { 438 } else {
375 warn "object uses attachment '$name' that is not available, postponing.\n"; 439 warn "object uses attachment '$name' that is not available, postponing.\n";
376 } 440 }
377 } 441 }
378
379 warn "reattach<@_, $_>\n";
380} 442}
381 443
382sub object_freezer_save { 444sub object_freezer_save {
383 my ($filename, $objs) = @_; 445 my ($filename, $rdata, $objs) = @_;
384 warn "freeze $filename\n";#d#
385 use Data::Dumper; print Dumper $objs;
386 446
387 $filename .= ".pst"; 447 if (length $$rdata) {
448 warn sprintf "saving %s (%d,%d)\n",
449 $filename, length $$rdata, scalar @$objs;
388 450
389 if (@$objs) {
390 open my $fh, ">:raw", "$filename~"; 451 if (open my $fh, ">:raw", "$filename~") {
391 chmod $fh, SAVE_MODE; 452 chmod SAVE_MODE, $fh;
453 syswrite $fh, $$rdata;
454 close $fh;
455
456 if (@$objs && open my $fh, ">:raw", "$filename.pst~") {
457 chmod SAVE_MODE, $fh;
392 syswrite $fh, Storable::nfreeze { version => 1, objs => $objs }; 458 syswrite $fh, Storable::nfreeze { version => 1, objs => $objs };
393 close $fh; 459 close $fh;
460 rename "$filename.pst~", "$filename.pst";
461 } else {
462 unlink "$filename.pst";
463 }
464
394 rename "$filename~", $filename; 465 rename "$filename~", $filename;
466 } else {
467 warn "FATAL: $filename~: $!\n";
468 }
395 } else { 469 } else {
396 unlink $filename; 470 unlink $filename;
471 unlink "$filename.pst";
397 } 472 }
398} 473}
399 474
400sub object_thawer_load { 475sub object_thawer_load {
401 my ($filename) = @_; 476 my ($filename) = @_;
402 477
403 warn "thaw $filename\n";#d# 478 local $/;
404 479
480 my $av;
481
482 #TODO: use sysread etc.
483 if (open my $data, "<:raw:perlio", $filename) {
484 $data = <$data>;
405 open my $fh, "<:raw:perlio", "$filename.pst" 485 if (open my $pst, "<:raw:perlio", "$filename.pst") {
406 or return; 486 $av = eval { (Storable::thaw <$pst>)->{objs} };
487 }
488 return ($data, $av);
489 }
407 490
408 eval { local $/; (Storable::thaw <$fh>)->{objs} } 491 ()
409} 492}
410 493
411attach_to_objects 494attach_to_objects
412 prio => -1000000, 495 prio => -1000000,
413 on_clone => sub { 496 on_clone => sub {
414 my ($src, $dst) = @_; 497 my ($src, $dst) = @_;
415 498
416 @{$dst->registry} = @{$src->registry}; 499 @{$dst->registry} = @{$src->registry};
417 warn "registry clone ", join ":", @{$src->registry};#d#
418 500
419 %$dst = %$src; 501 %$dst = %$src;
420 502
421 $dst->{_attachment} = [@{ $src->{_attachment} }] 503 %{$dst->{_attachment}} = %{$src->{_attachment}}
422 if exists $src->{_attachment}; 504 if exists $src->{_attachment};
423
424 warn "clone<@_>\n";#d#
425 }, 505 },
426; 506;
427 507
428############################################################################# 508#############################################################################
429# old plug-in events 509# old plug-in events
562 load_extension $ext; 642 load_extension $ext;
563 1 643 1
564 } or warn "$ext not loaded: $@"; 644 } or warn "$ext not loaded: $@";
565 } 645 }
566} 646}
567
568sub _perl_reload(&) {
569 my ($msg) = @_;
570
571 $msg->("reloading...");
572
573 eval {
574 # 1. cancel all watchers
575 $_->cancel for Event::all_watchers;
576
577 # 2. unload all extensions
578 for (@exts) {
579 $msg->("unloading <$_>");
580 unload_extension $_;
581 }
582
583 # 3. unload all modules loaded from $LIBDIR
584 while (my ($k, $v) = each %INC) {
585 next unless $v =~ /^\Q$LIBDIR\E\/.*\.pm$/;
586
587 $msg->("removing <$k>");
588 delete $INC{$k};
589
590 $k =~ s/\.pm$//;
591 $k =~ s/\//::/g;
592
593 if (my $cb = $k->can ("unload_module")) {
594 $cb->();
595 }
596
597 Symbol::delete_package $k;
598 }
599
600 # 4. get rid of safe::, as good as possible
601 Symbol::delete_package "safe::$_"
602 for qw(cf::object cf::object::player cf::player cf::map cf::party cf::region);
603
604 # 5. remove register_script_function callbacks
605 # TODO
606
607 # 6. unload cf.pm "a bit"
608 delete $INC{"cf.pm"};
609
610 # don't, removes xs symbols, too,
611 # and global variables created in xs
612 #Symbol::delete_package __PACKAGE__;
613
614 # 7. reload cf.pm
615 $msg->("reloading cf.pm");
616 require cf;
617 };
618 $msg->($@) if $@;
619
620 $msg->("reloaded");
621};
622
623sub perl_reload() {
624 _perl_reload {
625 warn $_[0];
626 print "$_[0]\n";
627 };
628}
629
630register_command "perl-reload", 0, sub {
631 my ($who, $arg) = @_;
632
633 if ($who->flag (FLAG_WIZ)) {
634 _perl_reload {
635 warn $_[0];
636 $who->message ($_[0]);
637 };
638 }
639};
640 647
641############################################################################# 648#############################################################################
642# extcmd framework, basically convert ext <msg> 649# extcmd framework, basically convert ext <msg>
643# into pkg::->on_extcmd_arg1 (...) while shortcutting a few 650# into pkg::->on_extcmd_arg1 (...) while shortcutting a few
644 651
669 my ($map) = @_; 676 my ($map) = @_;
670 677
671 my $path = $map->tmpname; 678 my $path = $map->tmpname;
672 defined $path or return; 679 defined $path or return;
673 680
674 unlink "$path.cfperl";
675 unlink "$path.pst"; 681 unlink "$path.pst";
676}; 682};
677 683
678*cf::mapsupport::on_swapin =
679*cf::mapsupport::on_load = sub {
680 my ($map) = @_;
681
682 my $path = $map->tmpname;
683 $path = $map->path unless defined $path;
684
685 open my $fh, "<:raw", "$path.cfperl"
686 or return; # no perl data
687
688 my $data = Storable::thaw do { local $/; <$fh> };
689
690 $data->{version} <= 1
691 or return; # too new
692
693 $map->_set_obs ($data->{obs});
694};
695
696attach_to_maps prio => -10000, package => cf::mapsupport::; 684attach_to_maps prio => -10000, package => cf::mapsupport::;
697 685
698############################################################################# 686#############################################################################
699# load/save perl data associated with player->ob objects 687# load/save perl data associated with player->ob objects
700 688
701sub all_objects(@) { 689sub all_objects(@) {
702 @_, map all_objects ($_->inv), @_ 690 @_, map all_objects ($_->inv), @_
703} 691}
704 692
693# TODO: compatibility cruft, remove when no longer needed
705attach_to_players 694attach_to_players
706 on_load => sub { 695 on_load => sub {
707 my ($pl, $path) = @_; 696 my ($pl, $path) = @_;
708 697
709 for my $o (all_objects $pl->ob) { 698 for my $o (all_objects $pl->ob) {
819 } 808 }
820 809
821 wantarray ? @res : $res[0] 810 wantarray ? @res : $res[0]
822} 811}
823 812
813=item cf::register_script_function $function => $cb
814
815Register a function that can be called from within map/npc scripts. The
816function should be reasonably secure and should be put into a package name
817like the extension.
818
819Example: register a function that gets called whenever a map script calls
820C<rent::overview>, as used by the C<rent> extension.
821
822 cf::register_script_function "rent::overview" => sub {
823 ...
824 };
825
826=cut
827
824sub register_script_function { 828sub register_script_function {
825 my ($fun, $cb) = @_; 829 my ($fun, $cb) = @_;
826 830
827 no strict 'refs'; 831 no strict 'refs';
828 *{"safe::$fun"} = $safe_hole->wrap ($cb); 832 *{"safe::$fun"} = $safe_hole->wrap ($cb);
829} 833}
830 834
831############################################################################# 835#############################################################################
836
837=head2 EXTENSION DATABASE SUPPORT
838
839Crossfire maintains a very simple database for extension use. It can
840currently store anything that can be serialised using Storable, which
841excludes objects.
842
843The parameter C<$family> should best start with the name of the extension
844using it, it should be unique.
845
846=over 4
847
848=item $hashref = cf::db_get $family
849
850Return a hashref for use by the extension C<$family>, which can be
851modified. After modifications, you have to call C<cf::db_dirty> or
852C<cf::db_sync>.
853
854=item $value = cf::db_get $family => $key
855
856Returns a single value from the database
857
858=item cf::db_put $family => $hashref
859
860Stores the given family hashref into the database. Updates are delayed, if
861you want the data to be synced to disk immediately, use C<cf::db_sync>.
862
863=item cf::db_put $family => $key => $value
864
865Stores the given C<$value> in the family hash. Updates are delayed, if you
866want the data to be synced to disk immediately, use C<cf::db_sync>.
867
868=item cf::db_dirty
869
870Marks the database as dirty, to be updated at a later time.
871
872=item cf::db_sync
873
874Immediately write the database to disk I<if it is dirty>.
875
876=cut
877
878{
879 my $db;
880 my $path = cf::localdir . "/database.pst";
881
882 sub db_load() {
883 warn "loading database $path\n";#d# remove later
884 $db = stat $path ? Storable::retrieve $path : { };
885 }
886
887 my $pid;
888
889 sub db_save() {
890 warn "saving database $path\n";#d# remove later
891 waitpid $pid, 0 if $pid;
892 if (0 == ($pid = fork)) {
893 $db->{_meta}{version} = 1;
894 Storable::nstore $db, "$path~";
895 rename "$path~", $path;
896 cf::_exit 0 if defined $pid;
897 }
898 }
899
900 my $dirty;
901
902 sub db_sync() {
903 db_save if $dirty;
904 undef $dirty;
905 }
906
907 my $idle = Event->idle (min => $TICK * 2.8, max => 10, repeat => 0, cb => sub {
908 db_sync;
909 });
910
911 sub db_dirty() {
912 $dirty = 1;
913 $idle->start;
914 }
915
916 sub db_get($;$) {
917 @_ >= 2
918 ? $db->{$_[0]}{$_[1]}
919 : ($db->{$_[0]} ||= { })
920 }
921
922 sub db_put($$;$) {
923 if (@_ >= 3) {
924 $db->{$_[0]}{$_[1]} = $_[2];
925 } else {
926 $db->{$_[0]} = $_[1];
927 }
928 db_dirty;
929 }
930
931 attach_global
932 prio => 10000,
933 on_cleanup => sub {
934 db_sync;
935 },
936 ;
937}
938
939#############################################################################
832# the server's main() 940# the server's main()
833 941
834sub main { 942sub main {
943 db_load;
944 load_extensions;
835 Event::loop; 945 Event::loop;
836} 946}
837 947
838############################################################################# 948#############################################################################
839# initialisation 949# initialisation
840 950
951sub _perl_reload(&) {
952 my ($msg) = @_;
953
954 $msg->("reloading...");
955
956 eval {
957 # cancel all watchers
958 $_->cancel for Event::all_watchers;
959
960 # unload all extensions
961 for (@exts) {
962 $msg->("unloading <$_>");
963 unload_extension $_;
964 }
965
966 # unload all modules loaded from $LIBDIR
967 while (my ($k, $v) = each %INC) {
968 next unless $v =~ /^\Q$LIBDIR\E\/.*\.pm$/;
969
970 $msg->("removing <$k>");
971 delete $INC{$k};
972
973 $k =~ s/\.pm$//;
974 $k =~ s/\//::/g;
975
976 if (my $cb = $k->can ("unload_module")) {
977 $cb->();
978 }
979
980 Symbol::delete_package $k;
981 }
982
983 # sync database to disk
984 cf::db_sync;
985
986 # get rid of safe::, as good as possible
987 Symbol::delete_package "safe::$_"
988 for qw(cf::object cf::object::player cf::player cf::map cf::party cf::region);
989
990 # remove register_script_function callbacks
991 # TODO
992
993 # unload cf.pm "a bit"
994 delete $INC{"cf.pm"};
995
996 # don't, removes xs symbols, too,
997 # and global variables created in xs
998 #Symbol::delete_package __PACKAGE__;
999
1000 # reload cf.pm
1001 $msg->("reloading cf.pm");
1002 require cf;
1003
1004 # load database again
1005 cf::db_load;
1006
1007 # load extensions
1008 $msg->("load extensions");
1009 cf::load_extensions;
1010
1011 # reattach attachments to objects
1012 $msg->("reattach");
1013 _global_reattach;
1014 };
1015 $msg->($@) if $@;
1016
1017 $msg->("reloaded");
1018};
1019
1020sub perl_reload() {
1021 _perl_reload {
1022 warn $_[0];
1023 print "$_[0]\n";
1024 };
1025}
1026
1027register_command "perl-reload", 0, sub {
1028 my ($who, $arg) = @_;
1029
1030 if ($who->flag (FLAG_WIZ)) {
1031 _perl_reload {
1032 warn $_[0];
1033 $who->message ($_[0]);
1034 };
1035 }
1036};
1037
841register "<global>", __PACKAGE__; 1038register "<global>", __PACKAGE__;
842 1039
843unshift @INC, $LIBDIR; 1040unshift @INC, $LIBDIR;
844
845load_extensions;
846 1041
847$TICK_WATCHER = Event->timer ( 1042$TICK_WATCHER = Event->timer (
848 prio => 1, 1043 prio => 1,
849 at => $NEXT_TICK || 1, 1044 at => $NEXT_TICK || 1,
850 cb => sub { 1045 cb => sub {

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines