ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/lib/cf.pm
Revision: 1.84
Committed: Mon Dec 11 02:54:57 2006 UTC (17 years, 5 months ago) by root
Branch: MAIN
Changes since 1.83: +1 -4 lines
Log Message:
- rename $uptime to $UPTIME
- hopefully force alchemy to use one second delay

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