ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/lib/cf.pm
Revision: 1.69
Committed: Mon Sep 18 01:10:35 2006 UTC (17 years, 8 months ago) by root
Branch: MAIN
Changes since 1.68: +15 -0 lines
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 root 1.1 package cf;
2    
3     use Symbol;
4     use List::Util;
5 root 1.6 use Storable;
6 root 1.23 use Opcode;
7     use Safe;
8     use Safe::Hole;
9 root 1.19
10 root 1.32 use Time::HiRes;
11 root 1.18 use Event;
12 root 1.19 $Event::Eval = 1; # no idea why this is required, but it is
13 root 1.1
14     use strict;
15    
16 root 1.63 _init_vars;
17 root 1.47
18 root 1.39 our %COMMAND = ();
19 root 1.1 our @EVENT;
20 root 1.27 our $LIBDIR = maps_directory "perl";
21 root 1.1
22 root 1.35 our $TICK = MAX_TIME * 1e-6;
23     our $TICK_WATCHER;
24     our $NEXT_TICK;
25    
26 root 1.1 BEGIN {
27     *CORE::GLOBAL::warn = sub {
28     my $msg = join "", @_;
29     $msg .= "\n"
30     unless $msg =~ /\n$/;
31    
32     print STDERR "cfperl: $msg";
33     LOG llevError, "cfperl: $msg";
34     };
35     }
36    
37 root 1.41 @safe::cf::object::player::ISA = @cf::object::player::ISA = 'cf::object';
38 root 1.25
39 root 1.41 # we bless all objects into (empty) derived classes to force a method lookup
40 root 1.25 # within the Safe compartment.
41 root 1.50 for my $pkg (qw(cf::object cf::object::player cf::player cf::map cf::party cf::region cf::arch cf::living)) {
42 root 1.25 no strict 'refs';
43 root 1.41 @{"safe::$pkg\::wrap::ISA"} = @{"$pkg\::wrap::ISA"} = $pkg;
44 root 1.25 }
45 root 1.1
46 root 1.18 $Event::DIED = sub {
47     warn "error in event callback: @_";
48     };
49    
50 root 1.5 my %ext_pkg;
51 root 1.1 my @exts;
52     my @hook;
53     my %command;
54 root 1.15 my %extcmd;
55 root 1.1
56 root 1.39 #############################################################################
57 root 1.45 # utility functions
58 root 1.44
59 root 1.45 use JSON::Syck (); # TODO# replace by JSON::PC once working
60 root 1.44
61 root 1.45 sub from_json($) {
62     $JSON::Syck::ImplicitUnicode = 1; # work around JSON::Syck bugs
63     JSON::Syck::Load $_[0]
64 root 1.44 }
65    
66 root 1.45 sub to_json($) {
67     $JSON::Syck::ImplicitUnicode = 0; # work around JSON::Syck bugs
68     JSON::Syck::Dump $_[0]
69 root 1.44 }
70    
71     #############################################################################
72 root 1.39 # "new" plug-in system
73    
74 root 1.55 =head3 EVENTS AND OBJECT ATTACHMENTS
75    
76     =over 4
77    
78 root 1.48 =item $object->attach ($attachment, key => $value...)
79 root 1.46
80 root 1.53 =item $object->detach ($attachment)
81    
82     Attach/detach a pre-registered attachment to an object.
83 root 1.46
84 root 1.48 =item $player->attach ($attachment, key => $value...)
85 root 1.46
86 root 1.53 =item $player->detach ($attachment)
87    
88     Attach/detach a pre-registered attachment to a player.
89    
90     =item $map->attach ($attachment, key => $value...)
91 root 1.46
92 root 1.53 =item $map->detach ($attachment)
93 root 1.46
94 root 1.53 Attach/detach a pre-registered attachment to a map.
95 root 1.39
96 root 1.55 =item $bool = $object->attached ($name)
97    
98     =item $bool = $player->attached ($name)
99    
100     =item $bool = $map->attached ($name)
101    
102     Checks wether the named attachment is currently attached to the object.
103    
104 root 1.40 =item cf::attach_global ...
105 root 1.39
106 root 1.46 Attach handlers for global events.
107    
108     This and all following C<attach_*>-functions expect any number of the
109     following handler/hook descriptions:
110    
111     =over 4
112    
113     =item prio => $number
114    
115     Set the priority for all following handlers/hooks (unless overwritten
116     by another C<prio> setting). Lower priority handlers get executed
117     earlier. The default priority is C<0>, and many built-in handlers are
118     registered at priority C<-1000>, so lower priorities should not be used
119     unless you know what you are doing.
120    
121     =item on_I<event> => \&cb
122    
123     Call the given code reference whenever the named event happens (event is
124     something like C<instantiate>, C<apply>, C<use_skill> and so on, and which
125     handlers are recognised generally depends on the type of object these
126     handlers attach to).
127    
128     See F<include/eventinc.h> for the full list of events supported, and their
129     class.
130    
131     =item package => package::
132    
133     Look for sub functions of the name C<< on_I<event> >> in the given
134     package and register them. Only handlers for eevents supported by the
135     object/class are recognised.
136    
137     =back
138    
139 root 1.47 =item cf::attach_to_type $object_type, $subtype, ...
140 root 1.39
141 root 1.47 Attach handlers for a specific object type (e.g. TRANSPORT) and
142     subtype. If C<$subtype> is zero or undef, matches all objects of the given
143     type.
144 root 1.46
145 root 1.40 =item cf::attach_to_objects ...
146 root 1.39
147 root 1.46 Attach handlers to all objects. Do not use this except for debugging or
148     very rare events, as handlers are (obviously) called for I<all> objects in
149     the game.
150    
151 root 1.40 =item cf::attach_to_players ...
152 root 1.39
153 root 1.46 Attach handlers to all players.
154    
155 root 1.40 =item cf::attach_to_maps ...
156 root 1.39
157 root 1.46 Attach handlers to all maps.
158    
159 root 1.45 =item cf:register_attachment $name, ...
160    
161 root 1.52 Register an attachment by name through which objects can refer to this
162     attachment.
163    
164 root 1.55 =item cf:register_player_attachment $name, ...
165    
166     Register an attachment by name through which players can refer to this
167     attachment.
168    
169 root 1.52 =item cf:register_map_attachment $name, ...
170    
171     Register an attachment by name through which maps can refer to this
172     attachment.
173    
174 root 1.39 =cut
175    
176 root 1.40 # the following variables are defined in .xs and must not be re-created
177 root 1.39 our @CB_GLOBAL = (); # registry for all global events
178 root 1.45 our @CB_OBJECT = (); # all objects (should not be used except in emergency)
179 root 1.40 our @CB_PLAYER = ();
180 root 1.39 our @CB_TYPE = (); # registry for type (cf-object class) based events
181 root 1.40 our @CB_MAP = ();
182 root 1.39
183 root 1.45 my %attachment;
184    
185 root 1.39 sub _attach_cb($\%$$$) {
186     my ($registry, $undo, $event, $prio, $cb) = @_;
187    
188     use sort 'stable';
189    
190     $cb = [$prio, $cb];
191    
192     @{$registry->[$event]} = sort
193     { $a->[0] cmp $b->[0] }
194     @{$registry->[$event] || []}, $cb;
195    
196     push @{$undo->{cb}}, [$event, $cb];
197     }
198    
199     # attach handles attaching event callbacks
200     # the only thing the caller has to do is pass the correct
201     # registry (== where the callback attaches to).
202 root 1.45 sub _attach(\@$@) {
203     my ($registry, $klass, @arg) = @_;
204 root 1.39
205     my $prio = 0;
206    
207     my %undo = (
208     registry => $registry,
209     cb => [],
210     );
211    
212     my %cb_id = map +("on_" . lc $EVENT[$_][0], $_) , grep $EVENT[$_][1] == $klass, 0 .. $#EVENT;
213    
214 root 1.45 while (@arg) {
215     my $type = shift @arg;
216 root 1.39
217     if ($type eq "prio") {
218 root 1.45 $prio = shift @arg;
219 root 1.39
220     } elsif ($type eq "package") {
221 root 1.45 my $pkg = shift @arg;
222 root 1.39
223     while (my ($name, $id) = each %cb_id) {
224     if (my $cb = $pkg->can ($name)) {
225     _attach_cb $registry, %undo, $id, $prio, $cb;
226     }
227     }
228    
229     } elsif (exists $cb_id{$type}) {
230 root 1.45 _attach_cb $registry, %undo, $cb_id{$type}, $prio, shift @arg;
231 root 1.39
232     } elsif (ref $type) {
233     warn "attaching objects not supported, ignoring.\n";
234    
235     } else {
236 root 1.45 shift @arg;
237 root 1.39 warn "attach argument '$type' not supported, ignoring.\n";
238     }
239     }
240    
241     \%undo
242     }
243    
244 root 1.46 sub _attach_attachment {
245 root 1.48 my ($obj, $name, %arg) = @_;
246 root 1.46
247 root 1.55 return if exists $obj->{_attachment}{$name};
248    
249 root 1.46 my $res;
250    
251     if (my $attach = $attachment{$name}) {
252     my $registry = $obj->registry;
253    
254 root 1.47 for (@$attach) {
255     my ($klass, @attach) = @$_;
256     $res = _attach @$registry, $klass, @attach;
257     }
258 root 1.46
259 root 1.48 $obj->{$name} = \%arg;
260 root 1.46 } else {
261     warn "object uses attachment '$name' that is not available, postponing.\n";
262     }
263    
264 root 1.50 $obj->{_attachment}{$name} = undef;
265 root 1.46
266     $res->{attachment} = $name;
267     $res
268     }
269    
270 root 1.54 *cf::object::attach =
271     *cf::player::attach =
272     *cf::map::attach = sub {
273 root 1.48 my ($obj, $name, %arg) = @_;
274 root 1.46
275 root 1.48 _attach_attachment $obj, $name, %arg;
276 root 1.55 };
277 root 1.46
278 root 1.54 # all those should be optimised
279     *cf::object::detach =
280     *cf::player::detach =
281     *cf::map::detach = sub {
282     my ($obj, $name) = @_;
283 root 1.46
284 root 1.54 delete $obj->{_attachment}{$name};
285 root 1.55 reattach ($obj);
286     };
287    
288     *cf::object::attached =
289     *cf::player::attached =
290     *cf::map::attached = sub {
291     my ($obj, $name) = @_;
292    
293     exists $obj->{_attachment}{$name}
294 root 1.54 };
295 root 1.53
296 root 1.39 sub attach_global {
297     _attach @CB_GLOBAL, KLASS_GLOBAL, @_
298     }
299    
300 root 1.40 sub attach_to_type {
301 root 1.39 my $type = shift;
302 root 1.47 my $subtype = shift;
303 root 1.45
304 root 1.47 _attach @{$CB_TYPE[$type + $subtype * NUM_SUBTYPES]}, KLASS_OBJECT, @_
305 root 1.39 }
306    
307     sub attach_to_objects {
308 root 1.40 _attach @CB_OBJECT, KLASS_OBJECT, @_
309 root 1.39 }
310    
311     sub attach_to_players {
312 root 1.40 _attach @CB_PLAYER, KLASS_PLAYER, @_
313 root 1.39 }
314    
315     sub attach_to_maps {
316 root 1.40 _attach @CB_MAP, KLASS_MAP, @_
317 root 1.39 }
318    
319 root 1.45 sub register_attachment {
320     my $name = shift;
321    
322 root 1.47 $attachment{$name} = [[KLASS_OBJECT, @_]];
323 root 1.45 }
324    
325 root 1.55 sub register_player_attachment {
326     my $name = shift;
327    
328     $attachment{$name} = [[KLASS_PLAYER, @_]];
329     }
330    
331 root 1.52 sub register_map_attachment {
332     my $name = shift;
333    
334     $attachment{$name} = [[KLASS_MAP, @_]];
335     }
336    
337 root 1.39 our $override;
338 root 1.45 our @invoke_results = (); # referenced from .xs code. TODO: play tricks with reify and mortals?
339 root 1.39
340 root 1.45 sub override {
341     $override = 1;
342     @invoke_results = ();
343 root 1.39 }
344    
345 root 1.45 sub do_invoke {
346 root 1.39 my $event = shift;
347 root 1.40 my $callbacks = shift;
348 root 1.39
349 root 1.45 @invoke_results = ();
350    
351 root 1.39 local $override;
352    
353 root 1.40 for (@$callbacks) {
354 root 1.39 eval { &{$_->[1]} };
355    
356     if ($@) {
357     warn "$@";
358 root 1.64 warn "... while processing $EVENT[$event][0](@_) event, skipping processing altogether.\n";
359 root 1.39 override;
360     }
361    
362     return 1 if $override;
363     }
364    
365     0
366     }
367    
368 root 1.55 =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    
376     Generate a global/object/player/map-specific event with the given arguments.
377    
378     This API is preliminary (most likely, the EVENT_KLASS_xxx prefix will be
379     removed in future versions), and there is no public API to access override
380     results (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    
394     Just because you have a perl object does not mean that the corresponding
395     C-level object still exists. If you try to access an object that has no
396     valid C counterpart anymore you get an exception at runtime. This method
397     can be used to test for existence of the C object part without causing an
398     exception.
399    
400     =back
401    
402     =cut
403    
404     *cf::object::valid =
405     *cf::player::valid =
406     *cf::map::valid = \&cf::_valid;
407    
408 root 1.39 #############################################################################
409 root 1.45 # object support
410    
411     sub instantiate {
412     my ($obj, $data) = @_;
413    
414     $data = from_json $data;
415    
416     for (@$data) {
417 root 1.46 my ($name, $args) = @$_;
418 root 1.49
419     $obj->attach ($name, %{$args || {} });
420 root 1.46 }
421     }
422    
423     # basically do the same as instantiate, without calling instantiate
424     sub reattach {
425     my ($obj) = @_;
426     my $registry = $obj->registry;
427 root 1.45
428 root 1.47 @$registry = ();
429    
430 root 1.50 delete $obj->{_attachment} unless scalar keys %{ $obj->{_attachment} || {} };
431 root 1.49
432 root 1.50 for my $name (keys %{ $obj->{_attachment} || {} }) {
433 root 1.45 if (my $attach = $attachment{$name}) {
434 root 1.47 for (@$attach) {
435     my ($klass, @attach) = @$_;
436     _attach @$registry, $klass, @attach;
437     }
438 root 1.45 } else {
439 root 1.46 warn "object uses attachment '$name' that is not available, postponing.\n";
440 root 1.45 }
441 root 1.46 }
442     }
443 root 1.45
444 root 1.46 sub object_freezer_save {
445 root 1.59 my ($filename, $rdata, $objs) = @_;
446 root 1.46
447 root 1.60 if (length $$rdata) {
448     warn sprintf "saving %s (%d,%d)\n",
449     $filename, length $$rdata, scalar @$objs;
450 root 1.59
451 root 1.60 if (open my $fh, ">:raw", "$filename~") {
452 root 1.59 chmod SAVE_MODE, $fh;
453 root 1.60 syswrite $fh, $$rdata;
454 root 1.59 close $fh;
455 root 1.60
456     if (@$objs && open my $fh, ">:raw", "$filename.pst~") {
457     chmod SAVE_MODE, $fh;
458     syswrite $fh, Storable::nfreeze { version => 1, objs => $objs };
459     close $fh;
460     rename "$filename.pst~", "$filename.pst";
461     } else {
462     unlink "$filename.pst";
463     }
464    
465     rename "$filename~", $filename;
466 root 1.59 } else {
467 root 1.60 warn "FATAL: $filename~: $!\n";
468 root 1.59 }
469 root 1.46 } else {
470 root 1.60 unlink $filename;
471     unlink "$filename.pst";
472 root 1.45 }
473     }
474    
475 root 1.46 sub object_thawer_load {
476     my ($filename) = @_;
477    
478 root 1.61 local $/;
479    
480     my $av;
481    
482     #TODO: use sysread etc.
483     if (open my $data, "<:raw:perlio", $filename) {
484     $data = <$data>;
485     if (open my $pst, "<:raw:perlio", "$filename.pst") {
486     $av = eval { (Storable::thaw <$pst>)->{objs} };
487     }
488     return ($data, $av);
489     }
490 root 1.45
491 root 1.61 ()
492 root 1.45 }
493    
494     attach_to_objects
495     prio => -1000000,
496     on_clone => sub {
497     my ($src, $dst) = @_;
498    
499     @{$dst->registry} = @{$src->registry};
500    
501     %$dst = %$src;
502    
503 root 1.50 %{$dst->{_attachment}} = %{$src->{_attachment}}
504 root 1.45 if exists $src->{_attachment};
505     },
506     ;
507    
508     #############################################################################
509 root 1.39 # old plug-in events
510    
511 root 1.1 sub inject_event {
512 root 1.14 my $extension = shift;
513     my $event_code = shift;
514 root 1.1
515 root 1.14 my $cb = $hook[$event_code]{$extension}
516 root 1.5 or return;
517    
518 root 1.14 &$cb
519 root 1.5 }
520    
521     sub inject_global_event {
522 root 1.12 my $event = shift;
523 root 1.5
524 root 1.12 my $cb = $hook[$event]
525 root 1.1 or return;
526    
527 root 1.12 List::Util::max map &$_, values %$cb
528 root 1.1 }
529    
530     sub inject_command {
531     my ($name, $obj, $params) = @_;
532    
533     for my $cmd (@{ $command{$name} }) {
534     $cmd->[1]->($obj, $params);
535     }
536    
537     -1
538     }
539    
540     sub register_command {
541     my ($name, $time, $cb) = @_;
542    
543     my $caller = caller;
544 root 1.16 #warn "registering command '$name/$time' to '$caller'";
545 root 1.4
546 root 1.1 push @{ $command{$name} }, [$time, $cb, $caller];
547     $COMMAND{"$name\000"} = List::Util::max map $_->[0], @{ $command{$name} };
548     }
549    
550 root 1.16 sub register_extcmd {
551     my ($name, $cb) = @_;
552    
553     my $caller = caller;
554     #warn "registering extcmd '$name' to '$caller'";
555    
556     $extcmd{$name} = [$cb, $caller];
557     }
558    
559 root 1.6 sub register {
560     my ($base, $pkg) = @_;
561    
562 root 1.45 #TODO
563 root 1.6 }
564    
565 root 1.1 sub load_extension {
566     my ($path) = @_;
567    
568     $path =~ /([^\/\\]+)\.ext$/ or die "$path";
569 root 1.5 my $base = $1;
570 root 1.1 my $pkg = $1;
571     $pkg =~ s/[^[:word:]]/_/g;
572 root 1.41 $pkg = "ext::$pkg";
573 root 1.1
574     warn "loading '$path' into '$pkg'\n";
575    
576     open my $fh, "<:utf8", $path
577     or die "$path: $!";
578    
579     my $source =
580     "package $pkg; use strict; use utf8;\n"
581     . "#line 1 \"$path\"\n{\n"
582     . (do { local $/; <$fh> })
583     . "\n};\n1";
584    
585     eval $source
586     or die "$path: $@";
587    
588     push @exts, $pkg;
589 root 1.5 $ext_pkg{$base} = $pkg;
590 root 1.1
591 root 1.6 # no strict 'refs';
592 root 1.23 # @{"$pkg\::ISA"} = ext::;
593 root 1.1
594 root 1.6 register $base, $pkg;
595 root 1.1 }
596    
597     sub unload_extension {
598     my ($pkg) = @_;
599    
600     warn "removing extension $pkg\n";
601    
602     # remove hooks
603 root 1.45 #TODO
604     # for my $idx (0 .. $#PLUGIN_EVENT) {
605     # delete $hook[$idx]{$pkg};
606     # }
607 root 1.1
608     # remove commands
609     for my $name (keys %command) {
610     my @cb = grep $_->[2] ne $pkg, @{ $command{$name} };
611    
612     if (@cb) {
613     $command{$name} = \@cb;
614     $COMMAND{"$name\000"} = List::Util::max map $_->[0], @cb;
615     } else {
616     delete $command{$name};
617     delete $COMMAND{"$name\000"};
618     }
619     }
620    
621 root 1.15 # remove extcmds
622 root 1.16 for my $name (grep $extcmd{$_}[1] eq $pkg, keys %extcmd) {
623     delete $extcmd{$name};
624 root 1.15 }
625    
626 root 1.43 if (my $cb = $pkg->can ("unload")) {
627 elmex 1.31 eval {
628     $cb->($pkg);
629     1
630     } or warn "$pkg unloaded, but with errors: $@";
631     }
632    
633 root 1.1 Symbol::delete_package $pkg;
634     }
635    
636     sub load_extensions {
637     my $LIBDIR = maps_directory "perl";
638    
639     for my $ext (<$LIBDIR/*.ext>) {
640 root 1.3 next unless -r $ext;
641 root 1.2 eval {
642     load_extension $ext;
643     1
644     } or warn "$ext not loaded: $@";
645 root 1.1 }
646     }
647    
648 root 1.8 #############################################################################
649 root 1.28 # extcmd framework, basically convert ext <msg>
650 root 1.15 # into pkg::->on_extcmd_arg1 (...) while shortcutting a few
651    
652 root 1.44 attach_to_players
653 root 1.43 on_extcmd => sub {
654     my ($pl, $buf) = @_;
655    
656     my $msg = eval { from_json $buf };
657    
658     if (ref $msg) {
659     if (my $cb = $extcmd{$msg->{msgtype}}) {
660     if (my %reply = $cb->[0]->($pl, $msg)) {
661     $pl->ext_reply ($msg->{msgid}, %reply);
662     }
663 root 1.28 }
664 root 1.43 } else {
665     warn "player " . ($pl->ob->name) . " sent unparseable ext message: <$buf>\n";
666 root 1.28 }
667 root 1.15
668 root 1.43 cf::override;
669     },
670     ;
671 root 1.15
672     #############################################################################
673 root 1.8 # load/save/clean perl data associated with a map
674    
675 root 1.39 *cf::mapsupport::on_clean = sub {
676 root 1.13 my ($map) = @_;
677 root 1.7
678     my $path = $map->tmpname;
679     defined $path or return;
680    
681 root 1.46 unlink "$path.pst";
682 root 1.7 };
683    
684 root 1.39 attach_to_maps prio => -10000, package => cf::mapsupport::;
685    
686 root 1.8 #############################################################################
687     # load/save perl data associated with player->ob objects
688    
689 root 1.33 sub all_objects(@) {
690     @_, map all_objects ($_->inv), @_
691     }
692    
693 root 1.60 # TODO: compatibility cruft, remove when no longer needed
694 root 1.39 attach_to_players
695     on_load => sub {
696     my ($pl, $path) = @_;
697    
698     for my $o (all_objects $pl->ob) {
699     if (my $value = $o->get_ob_key_value ("_perl_data")) {
700     $o->set_ob_key_value ("_perl_data");
701 root 1.8
702 root 1.39 %$o = %{ Storable::thaw pack "H*", $value };
703     }
704 root 1.11 }
705 root 1.39 },
706     ;
707 root 1.6
708 root 1.22 #############################################################################
709     # core extensions - in perl
710    
711 root 1.23 =item cf::player::exists $login
712    
713     Returns true when the given account exists.
714    
715     =cut
716    
717     sub cf::player::exists($) {
718     cf::player::find $_[0]
719     or -f sprintf "%s/%s/%s/%s.pl", cf::localdir, cf::playerdir, ($_[0]) x 2;
720     }
721    
722 root 1.28 =item $player->reply ($npc, $msg[, $flags])
723    
724     Sends a message to the player, as if the npc C<$npc> replied. C<$npc>
725     can be C<undef>. Does the right thing when the player is currently in a
726     dialogue with the given NPC character.
727    
728     =cut
729    
730 root 1.22 # rough implementation of a future "reply" method that works
731     # with dialog boxes.
732 root 1.23 sub cf::object::player::reply($$$;$) {
733     my ($self, $npc, $msg, $flags) = @_;
734    
735     $flags = cf::NDI_BROWN | cf::NDI_UNIQUE unless @_ >= 4;
736 root 1.22
737 root 1.24 if ($self->{record_replies}) {
738     push @{ $self->{record_replies} }, [$npc, $msg, $flags];
739     } else {
740     $msg = $npc->name . " says: $msg" if $npc;
741     $self->message ($msg, $flags);
742     }
743 root 1.22 }
744    
745 root 1.28 =item $player->ext_reply ($msgid, $msgtype, %msg)
746    
747     Sends an ext reply to the player.
748    
749     =cut
750    
751     sub cf::player::ext_reply($$$%) {
752     my ($self, $id, %msg) = @_;
753    
754     $msg{msgid} = $id;
755    
756     $self->send ("ext " . to_json \%msg);
757     }
758    
759 root 1.22 #############################################################################
760 root 1.23 # map scripting support
761    
762 root 1.42 our $safe = new Safe "safe";
763 root 1.23 our $safe_hole = new Safe::Hole;
764    
765     $SIG{FPE} = 'IGNORE';
766    
767     $safe->permit_only (Opcode::opset qw(:base_core :base_mem :base_orig :base_math sort time));
768    
769 root 1.25 # here we export the classes and methods available to script code
770    
771     for (
772 root 1.27 ["cf::object" => qw(contr pay_amount pay_player)],
773 root 1.25 ["cf::object::player" => qw(player)],
774     ["cf::player" => qw(peaceful)],
775     ) {
776     no strict 'refs';
777     my ($pkg, @funs) = @$_;
778 root 1.41 *{"safe::$pkg\::$_"} = $safe_hole->wrap (\&{"$pkg\::$_"})
779 root 1.25 for @funs;
780     }
781 root 1.23
782     sub safe_eval($;@) {
783     my ($code, %vars) = @_;
784    
785     my $qcode = $code;
786     $qcode =~ s/"/‟/g; # not allowed in #line filenames
787     $qcode =~ s/\n/\\n/g;
788    
789     local $_;
790 root 1.41 local @safe::cf::_safe_eval_args = values %vars;
791 root 1.23
792 root 1.42 my $eval =
793 root 1.23 "do {\n"
794     . "my (" . (join ",", map "\$$_", keys %vars) . ") = \@cf::_safe_eval_args;\n"
795     . "#line 0 \"{$qcode}\"\n"
796     . $code
797     . "\n}"
798 root 1.25 ;
799    
800     sub_generation_inc;
801 root 1.42 my @res = wantarray ? $safe->reval ($eval) : scalar $safe->reval ($eval);
802 root 1.25 sub_generation_inc;
803    
804 root 1.42 if ($@) {
805     warn "$@";
806     warn "while executing safe code '$code'\n";
807     warn "with arguments " . (join " ", %vars) . "\n";
808     }
809    
810 root 1.25 wantarray ? @res : $res[0]
811 root 1.23 }
812    
813 root 1.69 =item cf::register_script_function $function => $cb
814    
815     Register a function that can be called from within map/npc scripts. The
816     function should be reasonably secure and should be put into a package name
817     like the extension.
818    
819     Example: register a function that gets called whenever a map script calls
820     C<rent::overview>, as used by the C<rent> extension.
821    
822     cf::register_script_function "rent::overview" => sub {
823     ...
824     };
825    
826     =cut
827    
828 root 1.23 sub register_script_function {
829     my ($fun, $cb) = @_;
830    
831     no strict 'refs';
832 root 1.41 *{"safe::$fun"} = $safe_hole->wrap ($cb);
833 root 1.23 }
834    
835     #############################################################################
836 root 1.65
837     =head2 EXTENSION DATABASE SUPPORT
838    
839     Crossfire maintains a very simple database for extension use. It can
840     currently store anything that can be serialised using Storable, which
841     excludes objects.
842    
843     The parameter C<$family> should best start with the name of the extension
844     using it, it should be unique.
845    
846     =over 4
847    
848     =item $hashref = cf::db_get $family
849    
850     Return a hashref for use by the extension C<$family>, which can be
851     modified. After modifications, you have to call C<cf::db_dirty> or
852     C<cf::db_sync>.
853    
854     =item $value = cf::db_get $family => $key
855    
856     Returns a single value from the database
857    
858     =item cf::db_put $family => $hashref
859    
860     Stores the given family hashref into the database. Updates are delayed, if
861     you want the data to be synced to disk immediately, use C<cf::db_sync>.
862    
863     =item cf::db_put $family => $key => $value
864    
865     Stores the given C<$value> in the family hash. Updates are delayed, if you
866     want the data to be synced to disk immediately, use C<cf::db_sync>.
867    
868     =item cf::db_dirty
869    
870     Marks the database as dirty, to be updated at a later time.
871    
872     =item cf::db_sync
873    
874     Immediately write the database to disk I<if it is dirty>.
875    
876     =cut
877    
878     {
879     my $db;
880 root 1.66 my $path = cf::localdir . "/database.pst";
881 root 1.65
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 root 1.67 if (0 == ($pid = fork)) {
893 root 1.65 $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 root 1.67
931     attach_global
932     prio => 10000,
933     on_cleanup => sub {
934     db_sync;
935     },
936     ;
937 root 1.65 }
938    
939     #############################################################################
940 root 1.34 # the server's main()
941    
942 root 1.39 sub main {
943 root 1.65 db_load;
944 root 1.61 load_extensions;
945 root 1.34 Event::loop;
946     }
947    
948     #############################################################################
949 root 1.22 # initialisation
950    
951 root 1.65 sub _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    
1020     sub perl_reload() {
1021     _perl_reload {
1022     warn $_[0];
1023     print "$_[0]\n";
1024     };
1025     }
1026    
1027     register_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    
1038 root 1.6 register "<global>", __PACKAGE__;
1039    
1040 root 1.27 unshift @INC, $LIBDIR;
1041 root 1.17
1042 root 1.35 $TICK_WATCHER = Event->timer (
1043     prio => 1,
1044     at => $NEXT_TICK || 1,
1045     cb => sub {
1046     cf::server_tick; # one server iteration
1047    
1048     my $NOW = Event::time;
1049     $NEXT_TICK += $TICK;
1050    
1051 root 1.37 # if we are delayed by four ticks, skip them all
1052     $NEXT_TICK = $NOW if $NOW >= $NEXT_TICK + $TICK * 4;
1053 root 1.35
1054     $TICK_WATCHER->at ($NEXT_TICK);
1055     $TICK_WATCHER->start;
1056     },
1057     );
1058    
1059 root 1.1 1
1060