ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/lib/cf.pm
Revision: 1.85
Committed: Mon Dec 11 22:56:57 2006 UTC (17 years, 6 months ago) by root
Branch: MAIN
Changes since 1.84: +61 -68 lines
Log Message:
- use new event mechanism for command handling instead of the old plugin system

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