ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/lib/cf.pm
Revision: 1.79
Committed: Tue Nov 7 14:58:35 2006 UTC (17 years, 6 months ago) by root
Branch: MAIN
Changes since 1.78: +17 -3 lines
Log Message:
- likely fix patch/create variable setters
- abstract away access rights with $ob->may ("xxx") and use it

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