ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/lib/cf.pm
Revision: 1.83
Committed: Mon Dec 11 01:30:41 2006 UTC (17 years, 5 months ago) by root
Branch: MAIN
Changes since 1.82: +8 -3 lines
Log Message:
*** empty log message ***

File Contents

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