ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/lib/cf.pm
Revision: 1.68
Committed: Tue Sep 12 23:45:16 2006 UTC (17 years, 8 months ago) by root
Branch: MAIN
Changes since 1.67: +0 -1 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     sub register_script_function {
814     my ($fun, $cb) = @_;
815    
816     no strict 'refs';
817 root 1.41 *{"safe::$fun"} = $safe_hole->wrap ($cb);
818 root 1.23 }
819    
820     #############################################################################
821 root 1.65
822     =head2 EXTENSION DATABASE SUPPORT
823    
824     Crossfire maintains a very simple database for extension use. It can
825     currently store anything that can be serialised using Storable, which
826     excludes objects.
827    
828     The parameter C<$family> should best start with the name of the extension
829     using it, it should be unique.
830    
831     =over 4
832    
833     =item $hashref = cf::db_get $family
834    
835     Return a hashref for use by the extension C<$family>, which can be
836     modified. After modifications, you have to call C<cf::db_dirty> or
837     C<cf::db_sync>.
838    
839     =item $value = cf::db_get $family => $key
840    
841     Returns a single value from the database
842    
843     =item cf::db_put $family => $hashref
844    
845     Stores the given family hashref into the database. Updates are delayed, if
846     you want the data to be synced to disk immediately, use C<cf::db_sync>.
847    
848     =item cf::db_put $family => $key => $value
849    
850     Stores the given C<$value> in the family hash. Updates are delayed, if you
851     want the data to be synced to disk immediately, use C<cf::db_sync>.
852    
853     =item cf::db_dirty
854    
855     Marks the database as dirty, to be updated at a later time.
856    
857     =item cf::db_sync
858    
859     Immediately write the database to disk I<if it is dirty>.
860    
861     =cut
862    
863     {
864     my $db;
865 root 1.66 my $path = cf::localdir . "/database.pst";
866 root 1.65
867     sub db_load() {
868     warn "loading database $path\n";#d# remove later
869     $db = stat $path ? Storable::retrieve $path : { };
870     }
871    
872     my $pid;
873    
874     sub db_save() {
875     warn "saving database $path\n";#d# remove later
876     waitpid $pid, 0 if $pid;
877 root 1.67 if (0 == ($pid = fork)) {
878 root 1.65 $db->{_meta}{version} = 1;
879     Storable::nstore $db, "$path~";
880     rename "$path~", $path;
881     cf::_exit 0 if defined $pid;
882     }
883     }
884    
885     my $dirty;
886    
887     sub db_sync() {
888     db_save if $dirty;
889     undef $dirty;
890     }
891    
892     my $idle = Event->idle (min => $TICK * 2.8, max => 10, repeat => 0, cb => sub {
893     db_sync;
894     });
895    
896     sub db_dirty() {
897     $dirty = 1;
898     $idle->start;
899     }
900    
901     sub db_get($;$) {
902     @_ >= 2
903     ? $db->{$_[0]}{$_[1]}
904     : ($db->{$_[0]} ||= { })
905     }
906    
907     sub db_put($$;$) {
908     if (@_ >= 3) {
909     $db->{$_[0]}{$_[1]} = $_[2];
910     } else {
911     $db->{$_[0]} = $_[1];
912     }
913     db_dirty;
914     }
915 root 1.67
916     attach_global
917     prio => 10000,
918     on_cleanup => sub {
919     db_sync;
920     },
921     ;
922 root 1.65 }
923    
924     #############################################################################
925 root 1.34 # the server's main()
926    
927 root 1.39 sub main {
928 root 1.65 db_load;
929 root 1.61 load_extensions;
930 root 1.34 Event::loop;
931     }
932    
933     #############################################################################
934 root 1.22 # initialisation
935    
936 root 1.65 sub _perl_reload(&) {
937     my ($msg) = @_;
938    
939     $msg->("reloading...");
940    
941     eval {
942     # cancel all watchers
943     $_->cancel for Event::all_watchers;
944    
945     # unload all extensions
946     for (@exts) {
947     $msg->("unloading <$_>");
948     unload_extension $_;
949     }
950    
951     # unload all modules loaded from $LIBDIR
952     while (my ($k, $v) = each %INC) {
953     next unless $v =~ /^\Q$LIBDIR\E\/.*\.pm$/;
954    
955     $msg->("removing <$k>");
956     delete $INC{$k};
957    
958     $k =~ s/\.pm$//;
959     $k =~ s/\//::/g;
960    
961     if (my $cb = $k->can ("unload_module")) {
962     $cb->();
963     }
964    
965     Symbol::delete_package $k;
966     }
967    
968     # sync database to disk
969     cf::db_sync;
970    
971     # get rid of safe::, as good as possible
972     Symbol::delete_package "safe::$_"
973     for qw(cf::object cf::object::player cf::player cf::map cf::party cf::region);
974    
975     # remove register_script_function callbacks
976     # TODO
977    
978     # unload cf.pm "a bit"
979     delete $INC{"cf.pm"};
980    
981     # don't, removes xs symbols, too,
982     # and global variables created in xs
983     #Symbol::delete_package __PACKAGE__;
984    
985     # reload cf.pm
986     $msg->("reloading cf.pm");
987     require cf;
988    
989     # load database again
990     cf::db_load;
991    
992     # load extensions
993     $msg->("load extensions");
994     cf::load_extensions;
995    
996     # reattach attachments to objects
997     $msg->("reattach");
998     _global_reattach;
999     };
1000     $msg->($@) if $@;
1001    
1002     $msg->("reloaded");
1003     };
1004    
1005     sub perl_reload() {
1006     _perl_reload {
1007     warn $_[0];
1008     print "$_[0]\n";
1009     };
1010     }
1011    
1012     register_command "perl-reload", 0, sub {
1013     my ($who, $arg) = @_;
1014    
1015     if ($who->flag (FLAG_WIZ)) {
1016     _perl_reload {
1017     warn $_[0];
1018     $who->message ($_[0]);
1019     };
1020     }
1021     };
1022    
1023 root 1.6 register "<global>", __PACKAGE__;
1024    
1025 root 1.27 unshift @INC, $LIBDIR;
1026 root 1.17
1027 root 1.35 $TICK_WATCHER = Event->timer (
1028     prio => 1,
1029     at => $NEXT_TICK || 1,
1030     cb => sub {
1031     cf::server_tick; # one server iteration
1032    
1033     my $NOW = Event::time;
1034     $NEXT_TICK += $TICK;
1035    
1036 root 1.37 # if we are delayed by four ticks, skip them all
1037     $NEXT_TICK = $NOW if $NOW >= $NEXT_TICK + $TICK * 4;
1038 root 1.35
1039     $TICK_WATCHER->at ($NEXT_TICK);
1040     $TICK_WATCHER->start;
1041     },
1042     );
1043    
1044 root 1.1 1
1045