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