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.71 by root, Sun Oct 1 10:59:30 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;
25
26our %CFG;
27
28#############################################################################
29
30=head2 GLOBAL VARIABLES
31
32=over 4
33
34=item $cf::LIBDIR
35
36The perl library directory, where extensions and cf-specific modules can
37be found. It will be added to C<@INC> automatically.
38
39=item $cf::TICK
40
41The interval between server ticks, in seconds.
42
43=item %cf::CFG
44
45Configuration for the server, loaded from C</etc/crossfire/config>, or
46from wherever your confdir points to.
47
48=back
49
50=cut
25 51
26BEGIN { 52BEGIN {
27 *CORE::GLOBAL::warn = sub { 53 *CORE::GLOBAL::warn = sub {
28 my $msg = join "", @_; 54 my $msg = join "", @_;
29 $msg .= "\n" 55 $msg .= "\n"
32 print STDERR "cfperl: $msg"; 58 print STDERR "cfperl: $msg";
33 LOG llevError, "cfperl: $msg"; 59 LOG llevError, "cfperl: $msg";
34 }; 60 };
35} 61}
36 62
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'; 63@safe::cf::object::player::ISA = @cf::object::player::ISA = 'cf::object';
72 64
73# we bless all objects into (empty) derived classes to force a method lookup 65# we bless all objects into (empty) derived classes to force a method lookup
74# within the Safe compartment. 66# within the Safe compartment.
75for my $pkg (qw(cf::object cf::object::player cf::player cf::map cf::party cf::region cf::arch)) { 67for my $pkg (qw(cf::object cf::object::player cf::player cf::map cf::party cf::region cf::arch cf::living)) {
76 no strict 'refs'; 68 no strict 'refs';
77 @{"safe::$pkg\::wrap::ISA"} = @{"$pkg\::wrap::ISA"} = $pkg; 69 @{"safe::$pkg\::wrap::ISA"} = @{"$pkg\::wrap::ISA"} = $pkg;
78} 70}
79 71
80$Event::DIED = sub { 72$Event::DIED = sub {
85my @exts; 77my @exts;
86my @hook; 78my @hook;
87my %command; 79my %command;
88my %extcmd; 80my %extcmd;
89 81
90############################################################################# 82=head2 UTILITY FUNCTIONS
91# utility functions 83
84=over 4
85
86=cut
92 87
93use JSON::Syck (); # TODO# replace by JSON::PC once working 88use JSON::Syck (); # TODO# replace by JSON::PC once working
89
90=item $ref = cf::from_json $json
91
92Converts a JSON string into the corresponding perl data structure.
93
94=cut
94 95
95sub from_json($) { 96sub from_json($) {
96 $JSON::Syck::ImplicitUnicode = 1; # work around JSON::Syck bugs 97 $JSON::Syck::ImplicitUnicode = 1; # work around JSON::Syck bugs
97 JSON::Syck::Load $_[0] 98 JSON::Syck::Load $_[0]
98} 99}
99 100
101=item $json = cf::to_json $ref
102
103Converts a perl data structure into its JSON representation.
104
105=cut
106
100sub to_json($) { 107sub to_json($) {
101 $JSON::Syck::ImplicitUnicode = 0; # work around JSON::Syck bugs 108 $JSON::Syck::ImplicitUnicode = 0; # work around JSON::Syck bugs
102 JSON::Syck::Dump $_[0] 109 JSON::Syck::Dump $_[0]
103} 110}
104 111
105############################################################################# 112=back
106# "new" plug-in system
107 113
114=cut
115
116#############################################################################
117
118=head2 EVENTS AND OBJECT ATTACHMENTS
119
120=over 4
121
122=item $object->attach ($attachment, key => $value...)
123
108=item $object->attach ($attachment, ...) 124=item $object->detach ($attachment)
109 125
110Attach a pre-registered attachment to an object. 126Attach/detach a pre-registered attachment to an object.
111 127
128=item $player->attach ($attachment, key => $value...)
129
112=item $player->attach ($attachment, ...) 130=item $player->detach ($attachment)
113 131
114Attach a pre-registered attachment to a player. 132Attach/detach a pre-registered attachment to a player.
115 133
116=item $map->attach ($attachment, ...) # not yet persistent 134=item $map->attach ($attachment, key => $value...)
117 135
136=item $map->detach ($attachment)
137
118Attach a pre-registered attachment to a map. 138Attach/detach a pre-registered attachment to a map.
139
140=item $bool = $object->attached ($name)
141
142=item $bool = $player->attached ($name)
143
144=item $bool = $map->attached ($name)
145
146Checks wether the named attachment is currently attached to the object.
119 147
120=item cf::attach_global ... 148=item cf::attach_global ...
121 149
122Attach handlers for global events. 150Attach handlers for global events.
123 151
150package and register them. Only handlers for eevents supported by the 178package and register them. Only handlers for eevents supported by the
151object/class are recognised. 179object/class are recognised.
152 180
153=back 181=back
154 182
155=item cf::attach_to_type $object_type, ... 183=item cf::attach_to_type $object_type, $subtype, ...
156 184
157Attach handlers for a specific object type (e.g. TRANSPORT). 185Attach handlers for a specific object type (e.g. TRANSPORT) and
186subtype. If C<$subtype> is zero or undef, matches all objects of the given
187type.
158 188
159=item cf::attach_to_objects ... 189=item cf::attach_to_objects ...
160 190
161Attach handlers to all objects. Do not use this except for debugging or 191Attach 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 192very rare events, as handlers are (obviously) called for I<all> objects in
169=item cf::attach_to_maps ... 199=item cf::attach_to_maps ...
170 200
171Attach handlers to all maps. 201Attach handlers to all maps.
172 202
173=item cf:register_attachment $name, ... 203=item cf:register_attachment $name, ...
204
205Register an attachment by name through which objects can refer to this
206attachment.
207
208=item cf:register_player_attachment $name, ...
209
210Register an attachment by name through which players can refer to this
211attachment.
212
213=item cf:register_map_attachment $name, ...
214
215Register an attachment by name through which maps can refer to this
216attachment.
174 217
175=cut 218=cut
176 219
177# the following variables are defined in .xs and must not be re-created 220# the following variables are defined in .xs and must not be re-created
178our @CB_GLOBAL = (); # registry for all global events 221our @CB_GLOBAL = (); # registry for all global events
241 284
242 \%undo 285 \%undo
243} 286}
244 287
245sub _attach_attachment { 288sub _attach_attachment {
246 my ($klass, $obj, $name, @args) = q_; 289 my ($obj, $name, %arg) = @_;
290
291 return if exists $obj->{_attachment}{$name};
247 292
248 my $res; 293 my $res;
249 294
250 if (my $attach = $attachment{$name}) { 295 if (my $attach = $attachment{$name}) {
251 my $registry = $obj->registry; 296 my $registry = $obj->registry;
252 297
298 for (@$attach) {
299 my ($klass, @attach) = @$_;
253 $res = _attach @$registry, $klass, @$attach; 300 $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 } 301 }
263 } 302
303 $obj->{$name} = \%arg;
264 } else { 304 } else {
265 warn "object uses attachment '$name' that is not available, postponing.\n"; 305 warn "object uses attachment '$name' that is not available, postponing.\n";
266 } 306 }
267 307
268 push @{$obj->{_attachment}}, $name; 308 $obj->{_attachment}{$name} = undef;
269 309
270 $res->{attachment} = $name; 310 $res->{attachment} = $name;
271 $res 311 $res
272} 312}
273 313
274sub cf::object::attach { 314*cf::object::attach =
315*cf::player::attach =
316*cf::map::attach = sub {
275 my ($obj, $name, @args) = @_; 317 my ($obj, $name, %arg) = @_;
276 318
277 _attach_attachment KLASS_OBJECT, $obj, $name, @args; 319 _attach_attachment $obj, $name, %arg;
278} 320};
279 321
322# all those should be optimised
323*cf::object::detach =
280sub cf::player::attach { 324*cf::player::detach =
325*cf::map::detach = sub {
281 my ($obj, $name, @args) = @_; 326 my ($obj, $name) = @_;
282 327
283 _attach_attachment KLASS_PLAYER, $obj, $name, @args; 328 delete $obj->{_attachment}{$name};
284} 329 reattach ($obj);
330};
285 331
286sub cf::map::attach { 332*cf::object::attached =
333*cf::player::attached =
334*cf::map::attached = sub {
287 my ($obj, $name, @args) = @_; 335 my ($obj, $name) = @_;
288 336
289 _attach_attachment KLASS_MAP, $obj, $name, @args; 337 exists $obj->{_attachment}{$name}
290} 338};
291 339
292sub attach_global { 340sub attach_global {
293 _attach @CB_GLOBAL, KLASS_GLOBAL, @_ 341 _attach @CB_GLOBAL, KLASS_GLOBAL, @_
294} 342}
295 343
296sub attach_to_type { 344sub attach_to_type {
297 my $type = shift; 345 my $type = shift;
346 my $subtype = shift;
298 347
299 _attach @{$CB_TYPE[$type]}, KLASS_OBJECT, @_ 348 _attach @{$CB_TYPE[$type + $subtype * NUM_SUBTYPES]}, KLASS_OBJECT, @_
300} 349}
301 350
302sub attach_to_objects { 351sub attach_to_objects {
303 _attach @CB_OBJECT, KLASS_OBJECT, @_ 352 _attach @CB_OBJECT, KLASS_OBJECT, @_
304} 353}
312} 361}
313 362
314sub register_attachment { 363sub register_attachment {
315 my $name = shift; 364 my $name = shift;
316 365
366 $attachment{$name} = [[KLASS_OBJECT, @_]];
367}
368
369sub register_player_attachment {
370 my $name = shift;
371
372 $attachment{$name} = [[KLASS_PLAYER, @_]];
373}
374
375sub register_map_attachment {
376 my $name = shift;
377
317 $attachment{$name} = [@_]; 378 $attachment{$name} = [[KLASS_MAP, @_]];
318} 379}
319 380
320our $override; 381our $override;
321our @invoke_results = (); # referenced from .xs code. TODO: play tricks with reify and mortals? 382our @invoke_results = (); # referenced from .xs code. TODO: play tricks with reify and mortals?
322 383
336 for (@$callbacks) { 397 for (@$callbacks) {
337 eval { &{$_->[1]} }; 398 eval { &{$_->[1]} };
338 399
339 if ($@) { 400 if ($@) {
340 warn "$@"; 401 warn "$@";
341 warn "... while processing $EVENT[$event][0] event, skipping processing altogether.\n"; 402 warn "... while processing $EVENT[$event][0](@_) event, skipping processing altogether.\n";
342 override; 403 override;
343 } 404 }
344 405
345 return 1 if $override; 406 return 1 if $override;
346 } 407 }
347 408
348 0 409 0
349} 410}
411
412=item $bool = cf::invoke EVENT_GLOBAL_XXX, ...
413
414=item $bool = $object->invoke (EVENT_OBJECT_XXX, ...)
415
416=item $bool = $player->invoke (EVENT_PLAYER_XXX, ...)
417
418=item $bool = $map->invoke (EVENT_MAP_XXX, ...)
419
420Generate a global/object/player/map-specific event with the given arguments.
421
422This API is preliminary (most likely, the EVENT_KLASS_xxx prefix will be
423removed in future versions), and there is no public API to access override
424results (if you must, access C<@cf::invoke_results> directly).
425
426=back
427
428=cut
429
430#############################################################################
431
432=head2 METHODS VALID FOR ALL CORE OBJECTS
433
434=over 4
435
436=item $object->valid, $player->valid, $map->valid
437
438Just because you have a perl object does not mean that the corresponding
439C-level object still exists. If you try to access an object that has no
440valid C counterpart anymore you get an exception at runtime. This method
441can be used to test for existence of the C object part without causing an
442exception.
443
444=back
445
446=cut
447
448*cf::object::valid =
449*cf::player::valid =
450*cf::map::valid = \&cf::_valid;
350 451
351############################################################################# 452#############################################################################
352# object support 453# object support
353 454
354sub instantiate { 455sub instantiate {
356 457
357 $data = from_json $data; 458 $data = from_json $data;
358 459
359 for (@$data) { 460 for (@$data) {
360 my ($name, $args) = @$_; 461 my ($name, $args) = @$_;
361 attach $obj, $name, @{$args || [] }; 462
463 $obj->attach ($name, %{$args || {} });
362 } 464 }
363} 465}
364 466
365# basically do the same as instantiate, without calling instantiate 467# basically do the same as instantiate, without calling instantiate
366sub reattach { 468sub reattach {
367 warn "reattach<@_>\n";#d#
368 my ($obj) = @_; 469 my ($obj) = @_;
369 my $registry = $obj->registry; 470 my $registry = $obj->registry;
370 471
472 @$registry = ();
473
474 delete $obj->{_attachment} unless scalar keys %{ $obj->{_attachment} || {} };
475
371 for my $name (@{ $obj->{_attachment} }) { 476 for my $name (keys %{ $obj->{_attachment} || {} }) {
372 if (my $attach = $attachment{$name}) { 477 if (my $attach = $attachment{$name}) {
478 for (@$attach) {
479 my ($klass, @attach) = @$_;
373 _attach @$registry, KLASS_OBJECT, @$attach; 480 _attach @$registry, $klass, @attach;
481 }
374 } else { 482 } else {
375 warn "object uses attachment '$name' that is not available, postponing.\n"; 483 warn "object uses attachment '$name' that is not available, postponing.\n";
376 } 484 }
377 } 485 }
378
379 warn "reattach<@_, $_>\n";
380} 486}
381 487
382sub object_freezer_save { 488sub object_freezer_save {
383 my ($filename, $objs) = @_; 489 my ($filename, $rdata, $objs) = @_;
384 warn "freeze $filename\n";#d#
385 use Data::Dumper; print Dumper $objs;
386 490
387 $filename .= ".pst"; 491 if (length $$rdata) {
492 warn sprintf "saving %s (%d,%d)\n",
493 $filename, length $$rdata, scalar @$objs;
388 494
389 if (@$objs) {
390 open my $fh, ">:raw", "$filename~"; 495 if (open my $fh, ">:raw", "$filename~") {
391 chmod $fh, SAVE_MODE; 496 chmod SAVE_MODE, $fh;
497 syswrite $fh, $$rdata;
498 close $fh;
499
500 if (@$objs && open my $fh, ">:raw", "$filename.pst~") {
501 chmod SAVE_MODE, $fh;
392 syswrite $fh, Storable::nfreeze { version => 1, objs => $objs }; 502 syswrite $fh, Storable::nfreeze { version => 1, objs => $objs };
393 close $fh; 503 close $fh;
504 rename "$filename.pst~", "$filename.pst";
505 } else {
506 unlink "$filename.pst";
507 }
508
394 rename "$filename~", $filename; 509 rename "$filename~", $filename;
510 } else {
511 warn "FATAL: $filename~: $!\n";
512 }
395 } else { 513 } else {
396 unlink $filename; 514 unlink $filename;
515 unlink "$filename.pst";
397 } 516 }
398} 517}
399 518
400sub object_thawer_load { 519sub object_thawer_load {
401 my ($filename) = @_; 520 my ($filename) = @_;
402 521
403 warn "thaw $filename\n";#d# 522 local $/;
404 523
524 my $av;
525
526 #TODO: use sysread etc.
527 if (open my $data, "<:raw:perlio", $filename) {
528 $data = <$data>;
405 open my $fh, "<:raw:perlio", "$filename.pst" 529 if (open my $pst, "<:raw:perlio", "$filename.pst") {
406 or return; 530 $av = eval { (Storable::thaw <$pst>)->{objs} };
531 }
532 return ($data, $av);
533 }
407 534
408 eval { local $/; (Storable::thaw <$fh>)->{objs} } 535 ()
409} 536}
410 537
411attach_to_objects 538attach_to_objects
412 prio => -1000000, 539 prio => -1000000,
413 on_clone => sub { 540 on_clone => sub {
414 my ($src, $dst) = @_; 541 my ($src, $dst) = @_;
415 542
416 @{$dst->registry} = @{$src->registry}; 543 @{$dst->registry} = @{$src->registry};
417 warn "registry clone ", join ":", @{$src->registry};#d#
418 544
419 %$dst = %$src; 545 %$dst = %$src;
420 546
421 $dst->{_attachment} = [@{ $src->{_attachment} }] 547 %{$dst->{_attachment}} = %{$src->{_attachment}}
422 if exists $src->{_attachment}; 548 if exists $src->{_attachment};
423
424 warn "clone<@_>\n";#d#
425 }, 549 },
426; 550;
427 551
428############################################################################# 552#############################################################################
429# old plug-in events 553# old plug-in events
562 load_extension $ext; 686 load_extension $ext;
563 1 687 1
564 } or warn "$ext not loaded: $@"; 688 } or warn "$ext not loaded: $@";
565 } 689 }
566} 690}
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 691
641############################################################################# 692#############################################################################
642# extcmd framework, basically convert ext <msg> 693# extcmd framework, basically convert ext <msg>
643# into pkg::->on_extcmd_arg1 (...) while shortcutting a few 694# into pkg::->on_extcmd_arg1 (...) while shortcutting a few
644 695
669 my ($map) = @_; 720 my ($map) = @_;
670 721
671 my $path = $map->tmpname; 722 my $path = $map->tmpname;
672 defined $path or return; 723 defined $path or return;
673 724
674 unlink "$path.cfperl";
675 unlink "$path.pst"; 725 unlink "$path.pst";
676}; 726};
677 727
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::; 728attach_to_maps prio => -10000, package => cf::mapsupport::;
697 729
698############################################################################# 730#############################################################################
699# load/save perl data associated with player->ob objects 731# load/save perl data associated with player->ob objects
700 732
701sub all_objects(@) { 733sub all_objects(@) {
702 @_, map all_objects ($_->inv), @_ 734 @_, map all_objects ($_->inv), @_
703} 735}
704 736
737# TODO: compatibility cruft, remove when no longer needed
705attach_to_players 738attach_to_players
706 on_load => sub { 739 on_load => sub {
707 my ($pl, $path) = @_; 740 my ($pl, $path) = @_;
708 741
709 for my $o (all_objects $pl->ob) { 742 for my $o (all_objects $pl->ob) {
715 } 748 }
716 }, 749 },
717; 750;
718 751
719############################################################################# 752#############################################################################
720# core extensions - in perl 753
754=head2 CORE EXTENSIONS
755
756Functions and methods that extend core crossfire objects.
757
758=over 4
721 759
722=item cf::player::exists $login 760=item cf::player::exists $login
723 761
724Returns true when the given account exists. 762Returns true when the given account exists.
725 763
765 $msg{msgid} = $id; 803 $msg{msgid} = $id;
766 804
767 $self->send ("ext " . to_json \%msg); 805 $self->send ("ext " . to_json \%msg);
768} 806}
769 807
808=back
809
810=cut
811
770############################################################################# 812#############################################################################
771# map scripting support 813
814=head2 SAFE SCRIPTING
815
816Functions that provide a safe environment to compile and execute
817snippets of perl code without them endangering the safety of the server
818itself. Looping constructs, I/O operators and other built-in functionality
819is not available in the safe scripting environment, and the number of
820functions and methods that cna be called is greatly reduced.
821
822=cut
772 823
773our $safe = new Safe "safe"; 824our $safe = new Safe "safe";
774our $safe_hole = new Safe::Hole; 825our $safe_hole = new Safe::Hole;
775 826
776$SIG{FPE} = 'IGNORE'; 827$SIG{FPE} = 'IGNORE';
777 828
778$safe->permit_only (Opcode::opset qw(:base_core :base_mem :base_orig :base_math sort time)); 829$safe->permit_only (Opcode::opset qw(:base_core :base_mem :base_orig :base_math sort time));
779 830
780# here we export the classes and methods available to script code 831# here we export the classes and methods available to script code
832
833=pod
834
835The following fucntions and emthods are available within a safe environment:
836
837 cf::object contr pay_amount pay_player
838 cf::object::player player
839 cf::player peaceful
840
841=cut
781 842
782for ( 843for (
783 ["cf::object" => qw(contr pay_amount pay_player)], 844 ["cf::object" => qw(contr pay_amount pay_player)],
784 ["cf::object::player" => qw(player)], 845 ["cf::object::player" => qw(player)],
785 ["cf::player" => qw(peaceful)], 846 ["cf::player" => qw(peaceful)],
788 my ($pkg, @funs) = @$_; 849 my ($pkg, @funs) = @$_;
789 *{"safe::$pkg\::$_"} = $safe_hole->wrap (\&{"$pkg\::$_"}) 850 *{"safe::$pkg\::$_"} = $safe_hole->wrap (\&{"$pkg\::$_"})
790 for @funs; 851 for @funs;
791} 852}
792 853
854=over 4
855
856=item @retval = safe_eval $code, [var => value, ...]
857
858Compiled and executes the given perl code snippet. additional var/value
859pairs result in temporary local (my) scalar variables of the given name
860that are available in the code snippet. Example:
861
862 my $five = safe_eval '$first + $second', first => 1, second => 4;
863
864=cut
865
793sub safe_eval($;@) { 866sub safe_eval($;@) {
794 my ($code, %vars) = @_; 867 my ($code, %vars) = @_;
795 868
796 my $qcode = $code; 869 my $qcode = $code;
797 $qcode =~ s/"/‟/g; # not allowed in #line filenames 870 $qcode =~ s/"/‟/g; # not allowed in #line filenames
819 } 892 }
820 893
821 wantarray ? @res : $res[0] 894 wantarray ? @res : $res[0]
822} 895}
823 896
897=item cf::register_script_function $function => $cb
898
899Register a function that can be called from within map/npc scripts. The
900function should be reasonably secure and should be put into a package name
901like the extension.
902
903Example: register a function that gets called whenever a map script calls
904C<rent::overview>, as used by the C<rent> extension.
905
906 cf::register_script_function "rent::overview" => sub {
907 ...
908 };
909
910=cut
911
824sub register_script_function { 912sub register_script_function {
825 my ($fun, $cb) = @_; 913 my ($fun, $cb) = @_;
826 914
827 no strict 'refs'; 915 no strict 'refs';
828 *{"safe::$fun"} = $safe_hole->wrap ($cb); 916 *{"safe::$fun"} = $safe_hole->wrap ($cb);
829} 917}
830 918
919=back
920
921=cut
922
923#############################################################################
924
925=head2 EXTENSION DATABASE SUPPORT
926
927Crossfire maintains a very simple database for extension use. It can
928currently store anything that can be serialised using Storable, which
929excludes objects.
930
931The parameter C<$family> should best start with the name of the extension
932using it, it should be unique.
933
934=over 4
935
936=item $hashref = cf::db_get $family
937
938Return a hashref for use by the extension C<$family>, which can be
939modified. After modifications, you have to call C<cf::db_dirty> or
940C<cf::db_sync>.
941
942=item $value = cf::db_get $family => $key
943
944Returns a single value from the database
945
946=item cf::db_put $family => $hashref
947
948Stores the given family hashref into the database. Updates are delayed, if
949you want the data to be synced to disk immediately, use C<cf::db_sync>.
950
951=item cf::db_put $family => $key => $value
952
953Stores the given C<$value> in the family hash. Updates are delayed, if you
954want the data to be synced to disk immediately, use C<cf::db_sync>.
955
956=item cf::db_dirty
957
958Marks the database as dirty, to be updated at a later time.
959
960=item cf::db_sync
961
962Immediately write the database to disk I<if it is dirty>.
963
964=cut
965
966{
967 my $db;
968 my $path = cf::localdir . "/database.pst";
969
970 sub db_load() {
971 warn "loading database $path\n";#d# remove later
972 $db = stat $path ? Storable::retrieve $path : { };
973 }
974
975 my $pid;
976
977 sub db_save() {
978 warn "saving database $path\n";#d# remove later
979 waitpid $pid, 0 if $pid;
980 if (0 == ($pid = fork)) {
981 $db->{_meta}{version} = 1;
982 Storable::nstore $db, "$path~";
983 rename "$path~", $path;
984 cf::_exit 0 if defined $pid;
985 }
986 }
987
988 my $dirty;
989
990 sub db_sync() {
991 db_save if $dirty;
992 undef $dirty;
993 }
994
995 my $idle = Event->idle (min => $TICK * 2.8, max => 10, repeat => 0, cb => sub {
996 db_sync;
997 });
998
999 sub db_dirty() {
1000 $dirty = 1;
1001 $idle->start;
1002 }
1003
1004 sub db_get($;$) {
1005 @_ >= 2
1006 ? $db->{$_[0]}{$_[1]}
1007 : ($db->{$_[0]} ||= { })
1008 }
1009
1010 sub db_put($$;$) {
1011 if (@_ >= 3) {
1012 $db->{$_[0]}{$_[1]} = $_[2];
1013 } else {
1014 $db->{$_[0]} = $_[1];
1015 }
1016 db_dirty;
1017 }
1018
1019 attach_global
1020 prio => 10000,
1021 on_cleanup => sub {
1022 db_sync;
1023 },
1024 ;
1025}
1026
831############################################################################# 1027#############################################################################
832# the server's main() 1028# the server's main()
833 1029
834sub main { 1030sub main {
1031 db_load;
1032 load_extensions;
835 Event::loop; 1033 Event::loop;
836} 1034}
837 1035
838############################################################################# 1036#############################################################################
839# initialisation 1037# initialisation
840 1038
1039sub _perl_reload(&) {
1040 my ($msg) = @_;
1041
1042 $msg->("reloading...");
1043
1044 eval {
1045 # cancel all watchers
1046 $_->cancel for Event::all_watchers;
1047
1048 # unload all extensions
1049 for (@exts) {
1050 $msg->("unloading <$_>");
1051 unload_extension $_;
1052 }
1053
1054 # unload all modules loaded from $LIBDIR
1055 while (my ($k, $v) = each %INC) {
1056 next unless $v =~ /^\Q$LIBDIR\E\/.*\.pm$/;
1057
1058 $msg->("removing <$k>");
1059 delete $INC{$k};
1060
1061 $k =~ s/\.pm$//;
1062 $k =~ s/\//::/g;
1063
1064 if (my $cb = $k->can ("unload_module")) {
1065 $cb->();
1066 }
1067
1068 Symbol::delete_package $k;
1069 }
1070
1071 # sync database to disk
1072 cf::db_sync;
1073
1074 # get rid of safe::, as good as possible
1075 Symbol::delete_package "safe::$_"
1076 for qw(cf::object cf::object::player cf::player cf::map cf::party cf::region);
1077
1078 # remove register_script_function callbacks
1079 # TODO
1080
1081 # unload cf.pm "a bit"
1082 delete $INC{"cf.pm"};
1083
1084 # don't, removes xs symbols, too,
1085 # and global variables created in xs
1086 #Symbol::delete_package __PACKAGE__;
1087
1088 # reload cf.pm
1089 $msg->("reloading cf.pm");
1090 require cf;
1091
1092 # load database again
1093 cf::db_load;
1094
1095 # load extensions
1096 $msg->("load extensions");
1097 cf::load_extensions;
1098
1099 # reattach attachments to objects
1100 $msg->("reattach");
1101 _global_reattach;
1102 };
1103 $msg->($@) if $@;
1104
1105 $msg->("reloaded");
1106};
1107
1108sub perl_reload() {
1109 _perl_reload {
1110 warn $_[0];
1111 print "$_[0]\n";
1112 };
1113}
1114
1115register_command "perl-reload", 0, sub {
1116 my ($who, $arg) = @_;
1117
1118 if ($who->flag (FLAG_WIZ)) {
1119 _perl_reload {
1120 warn $_[0];
1121 $who->message ($_[0]);
1122 };
1123 }
1124};
1125
841register "<global>", __PACKAGE__; 1126register "<global>", __PACKAGE__;
842 1127
843unshift @INC, $LIBDIR; 1128unshift @INC, $LIBDIR;
844
845load_extensions;
846 1129
847$TICK_WATCHER = Event->timer ( 1130$TICK_WATCHER = Event->timer (
848 prio => 1, 1131 prio => 1,
849 at => $NEXT_TICK || 1, 1132 at => $NEXT_TICK || 1,
850 cb => sub { 1133 cb => sub {

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines