ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/lib/cf.pm
Revision: 1.94
Committed: Thu Dec 21 23:02:54 2006 UTC (17 years, 5 months ago) by root
Branch: MAIN
Changes since 1.93: +60 -14 lines
Log Message:
document the facts

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