ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/lib/cf.pm
Revision: 1.70
Committed: Sun Oct 1 10:55:37 2006 UTC (17 years, 7 months ago) by root
Branch: MAIN
Changes since 1.69: +94 -12 lines
Log Message:
improved docs

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