ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/lib/cf.pm
Revision: 1.95
Committed: Fri Dec 22 02:04:20 2006 UTC (17 years, 5 months ago) by root
Branch: MAIN
Changes since 1.94: +91 -15 lines
Log Message:
- misc stuff
- implement $client->query

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 root 1.95 =head3 cf::player
764    
765 root 1.70 =over 4
766 root 1.22
767 root 1.23 =item cf::player::exists $login
768    
769     Returns true when the given account exists.
770    
771     =cut
772    
773     sub cf::player::exists($) {
774     cf::player::find $_[0]
775     or -f sprintf "%s/%s/%s/%s.pl", cf::localdir, cf::playerdir, ($_[0]) x 2;
776     }
777    
778 root 1.95 =item $player->ext_reply ($msgid, $msgtype, %msg)
779    
780     Sends an ext reply to the player.
781    
782     =cut
783    
784     sub cf::player::ext_reply($$$%) {
785     my ($self, $id, %msg) = @_;
786    
787     $msg{msgid} = $id;
788    
789     $self->send ("ext " . to_json \%msg);
790     }
791    
792     =back
793    
794     =head3 cf::object::player
795    
796     =over 4
797    
798 root 1.79 =item $player_object->reply ($npc, $msg[, $flags])
799 root 1.28
800     Sends a message to the player, as if the npc C<$npc> replied. C<$npc>
801     can be C<undef>. Does the right thing when the player is currently in a
802     dialogue with the given NPC character.
803    
804     =cut
805    
806 root 1.22 # rough implementation of a future "reply" method that works
807     # with dialog boxes.
808 root 1.95 #TODO: the first argument must go, split into a $npc->reply_to ( method
809 root 1.23 sub cf::object::player::reply($$$;$) {
810     my ($self, $npc, $msg, $flags) = @_;
811    
812     $flags = cf::NDI_BROWN | cf::NDI_UNIQUE unless @_ >= 4;
813 root 1.22
814 root 1.24 if ($self->{record_replies}) {
815     push @{ $self->{record_replies} }, [$npc, $msg, $flags];
816     } else {
817     $msg = $npc->name . " says: $msg" if $npc;
818     $self->message ($msg, $flags);
819     }
820 root 1.22 }
821    
822 root 1.79 =item $player_object->may ("access")
823    
824     Returns wether the given player is authorized to access resource "access"
825     (e.g. "command_wizcast").
826    
827     =cut
828    
829     sub cf::object::player::may {
830     my ($self, $access) = @_;
831    
832     $self->flag (cf::FLAG_WIZ) ||
833     (ref $cf::CFG{"may_$access"}
834     ? scalar grep $self->name eq $_, @{$cf::CFG{"may_$access"}}
835     : $cf::CFG{"may_$access"})
836     }
837 root 1.70
838 root 1.95 =head3 cf::client
839    
840     =over 4
841    
842     =item $client->send_drawinfo ($text, $flags)
843    
844     Sends a drawinfo packet to the client. Circumvents output buffering so
845     should not be used under normal circumstances.
846    
847 root 1.70 =cut
848    
849 root 1.95 sub cf::client::send_drawinfo {
850     my ($self, $text, $flags) = @_;
851    
852     utf8::encode $text;
853     $self->send_packet (sprintf "drawinfo %d %s", $flags, $text);
854     }
855    
856    
857     =item $success = $client->query ($flags, "text", \&cb)
858    
859     Queues a query to the client, calling the given callback with
860     the reply text on a reply. flags can be C<cf::CS_QUERY_YESNO>,
861     C<cf::CS_QUERY_SINGLECHAR> or C<cf::CS_QUERY_HIDEINPUT> or C<0>.
862    
863     Queries can fail, so check the return code. Or don't, as queries will become
864     reliable at some point in the future.
865    
866     =cut
867    
868     sub cf::client::query {
869     my ($self, $flags, $text, $cb) = @_;
870    
871     return unless $self->state == ST_PLAYING
872     || $self->state == ST_SETUP
873     || $self->state == ST_CUSTOM;
874    
875     $self->state (ST_CUSTOM);
876    
877     utf8::encode $text;
878     push @{ $self->{query_queue} }, [(sprintf "query %d %s", $flags, $text), $cb];
879    
880     $self->send_packet ($self->{query_queue}[0][0])
881     if @{ $self->{query_queue} } == 1;
882     }
883    
884     cf::client->attach (
885     on_reply => sub {
886     my ($ns, $msg) = @_;
887    
888     # this weird shuffling is so that direct followup queries
889     # get handled first
890     my $queue = delete $ns->{query_queue};
891    
892     (shift @$queue)->[1]->($msg);
893    
894     push @{ $ns->{query_queue} }, @$queue;
895    
896     if (@{ $ns->{query_queue} } == @$queue) {
897     if (@$queue) {
898     $ns->send_packet ($ns->{query_queue}[0][0]);
899     } else {
900     $ns->state (ST_PLAYING);
901     }
902     }
903     },
904     );
905    
906     =back
907    
908 root 1.70
909     =head2 SAFE SCRIPTING
910    
911     Functions that provide a safe environment to compile and execute
912     snippets of perl code without them endangering the safety of the server
913     itself. Looping constructs, I/O operators and other built-in functionality
914     is not available in the safe scripting environment, and the number of
915 root 1.79 functions and methods that can be called is greatly reduced.
916 root 1.70
917     =cut
918 root 1.23
919 root 1.42 our $safe = new Safe "safe";
920 root 1.23 our $safe_hole = new Safe::Hole;
921    
922     $SIG{FPE} = 'IGNORE';
923    
924     $safe->permit_only (Opcode::opset qw(:base_core :base_mem :base_orig :base_math sort time));
925    
926 root 1.25 # here we export the classes and methods available to script code
927    
928 root 1.70 =pod
929    
930     The following fucntions and emthods are available within a safe environment:
931    
932 elmex 1.91 cf::object contr pay_amount pay_player map
933 root 1.70 cf::object::player player
934     cf::player peaceful
935 elmex 1.91 cf::map trigger
936 root 1.70
937     =cut
938    
939 root 1.25 for (
940 elmex 1.91 ["cf::object" => qw(contr pay_amount pay_player map)],
941 root 1.25 ["cf::object::player" => qw(player)],
942     ["cf::player" => qw(peaceful)],
943 elmex 1.91 ["cf::map" => qw(trigger)],
944 root 1.25 ) {
945     no strict 'refs';
946     my ($pkg, @funs) = @$_;
947 root 1.41 *{"safe::$pkg\::$_"} = $safe_hole->wrap (\&{"$pkg\::$_"})
948 root 1.25 for @funs;
949     }
950 root 1.23
951 root 1.70 =over 4
952    
953     =item @retval = safe_eval $code, [var => value, ...]
954    
955     Compiled and executes the given perl code snippet. additional var/value
956     pairs result in temporary local (my) scalar variables of the given name
957     that are available in the code snippet. Example:
958    
959     my $five = safe_eval '$first + $second', first => 1, second => 4;
960    
961     =cut
962    
963 root 1.23 sub safe_eval($;@) {
964     my ($code, %vars) = @_;
965    
966     my $qcode = $code;
967     $qcode =~ s/"/‟/g; # not allowed in #line filenames
968     $qcode =~ s/\n/\\n/g;
969    
970     local $_;
971 root 1.41 local @safe::cf::_safe_eval_args = values %vars;
972 root 1.23
973 root 1.42 my $eval =
974 root 1.23 "do {\n"
975     . "my (" . (join ",", map "\$$_", keys %vars) . ") = \@cf::_safe_eval_args;\n"
976     . "#line 0 \"{$qcode}\"\n"
977     . $code
978     . "\n}"
979 root 1.25 ;
980    
981     sub_generation_inc;
982 root 1.42 my @res = wantarray ? $safe->reval ($eval) : scalar $safe->reval ($eval);
983 root 1.25 sub_generation_inc;
984    
985 root 1.42 if ($@) {
986     warn "$@";
987     warn "while executing safe code '$code'\n";
988     warn "with arguments " . (join " ", %vars) . "\n";
989     }
990    
991 root 1.25 wantarray ? @res : $res[0]
992 root 1.23 }
993    
994 root 1.69 =item cf::register_script_function $function => $cb
995    
996     Register a function that can be called from within map/npc scripts. The
997     function should be reasonably secure and should be put into a package name
998     like the extension.
999    
1000     Example: register a function that gets called whenever a map script calls
1001     C<rent::overview>, as used by the C<rent> extension.
1002    
1003     cf::register_script_function "rent::overview" => sub {
1004     ...
1005     };
1006    
1007     =cut
1008    
1009 root 1.23 sub register_script_function {
1010     my ($fun, $cb) = @_;
1011    
1012     no strict 'refs';
1013 root 1.41 *{"safe::$fun"} = $safe_hole->wrap ($cb);
1014 root 1.23 }
1015    
1016 root 1.70 =back
1017    
1018 root 1.71 =cut
1019    
1020 root 1.23 #############################################################################
1021 root 1.65
1022     =head2 EXTENSION DATABASE SUPPORT
1023    
1024     Crossfire maintains a very simple database for extension use. It can
1025     currently store anything that can be serialised using Storable, which
1026     excludes objects.
1027    
1028     The parameter C<$family> should best start with the name of the extension
1029     using it, it should be unique.
1030    
1031     =over 4
1032    
1033     =item $hashref = cf::db_get $family
1034    
1035     Return a hashref for use by the extension C<$family>, which can be
1036     modified. After modifications, you have to call C<cf::db_dirty> or
1037     C<cf::db_sync>.
1038    
1039     =item $value = cf::db_get $family => $key
1040    
1041     Returns a single value from the database
1042    
1043     =item cf::db_put $family => $hashref
1044    
1045     Stores the given family hashref into the database. Updates are delayed, if
1046     you want the data to be synced to disk immediately, use C<cf::db_sync>.
1047    
1048     =item cf::db_put $family => $key => $value
1049    
1050     Stores the given C<$value> in the family hash. Updates are delayed, if you
1051     want the data to be synced to disk immediately, use C<cf::db_sync>.
1052    
1053     =item cf::db_dirty
1054    
1055     Marks the database as dirty, to be updated at a later time.
1056    
1057     =item cf::db_sync
1058    
1059     Immediately write the database to disk I<if it is dirty>.
1060    
1061     =cut
1062    
1063 root 1.78 our $DB;
1064    
1065 root 1.65 {
1066 root 1.66 my $path = cf::localdir . "/database.pst";
1067 root 1.65
1068     sub db_load() {
1069     warn "loading database $path\n";#d# remove later
1070 root 1.78 $DB = stat $path ? Storable::retrieve $path : { };
1071 root 1.65 }
1072    
1073     my $pid;
1074    
1075     sub db_save() {
1076     warn "saving database $path\n";#d# remove later
1077     waitpid $pid, 0 if $pid;
1078 root 1.67 if (0 == ($pid = fork)) {
1079 root 1.78 $DB->{_meta}{version} = 1;
1080     Storable::nstore $DB, "$path~";
1081 root 1.65 rename "$path~", $path;
1082     cf::_exit 0 if defined $pid;
1083     }
1084     }
1085    
1086     my $dirty;
1087    
1088     sub db_sync() {
1089     db_save if $dirty;
1090     undef $dirty;
1091     }
1092    
1093 root 1.87 my $idle = Event->idle (min => $TICK * 2.8, max => 10, repeat => 0, data => WF_AUTOCANCEL, cb => sub {
1094 root 1.65 db_sync;
1095     });
1096    
1097     sub db_dirty() {
1098     $dirty = 1;
1099     $idle->start;
1100     }
1101    
1102     sub db_get($;$) {
1103     @_ >= 2
1104 root 1.78 ? $DB->{$_[0]}{$_[1]}
1105     : ($DB->{$_[0]} ||= { })
1106 root 1.65 }
1107    
1108     sub db_put($$;$) {
1109     if (@_ >= 3) {
1110 root 1.78 $DB->{$_[0]}{$_[1]} = $_[2];
1111 root 1.65 } else {
1112 root 1.78 $DB->{$_[0]} = $_[1];
1113 root 1.65 }
1114     db_dirty;
1115     }
1116 root 1.67
1117 root 1.93 cf::global->attach (
1118     prio => 10000,
1119 root 1.67 on_cleanup => sub {
1120     db_sync;
1121     },
1122 root 1.93 );
1123 root 1.65 }
1124    
1125     #############################################################################
1126 root 1.34 # the server's main()
1127    
1128 root 1.73 sub cfg_load {
1129 root 1.72 open my $fh, "<:utf8", cf::confdir . "/config"
1130     or return;
1131    
1132     local $/;
1133     *CFG = YAML::Syck::Load <$fh>;
1134     }
1135    
1136 root 1.39 sub main {
1137 root 1.73 cfg_load;
1138 root 1.65 db_load;
1139 root 1.61 load_extensions;
1140 root 1.34 Event::loop;
1141     }
1142    
1143     #############################################################################
1144 root 1.22 # initialisation
1145    
1146 root 1.65 sub _perl_reload(&) {
1147     my ($msg) = @_;
1148    
1149     $msg->("reloading...");
1150    
1151     eval {
1152     # cancel all watchers
1153 root 1.87 for (Event::all_watchers) {
1154     $_->cancel if $_->data & WF_AUTOCANCEL;
1155     }
1156 root 1.65
1157     # unload all extensions
1158     for (@exts) {
1159     $msg->("unloading <$_>");
1160     unload_extension $_;
1161     }
1162    
1163     # unload all modules loaded from $LIBDIR
1164     while (my ($k, $v) = each %INC) {
1165     next unless $v =~ /^\Q$LIBDIR\E\/.*\.pm$/;
1166    
1167     $msg->("removing <$k>");
1168     delete $INC{$k};
1169    
1170     $k =~ s/\.pm$//;
1171     $k =~ s/\//::/g;
1172    
1173     if (my $cb = $k->can ("unload_module")) {
1174     $cb->();
1175     }
1176    
1177     Symbol::delete_package $k;
1178     }
1179    
1180     # sync database to disk
1181     cf::db_sync;
1182    
1183     # get rid of safe::, as good as possible
1184     Symbol::delete_package "safe::$_"
1185     for qw(cf::object cf::object::player cf::player cf::map cf::party cf::region);
1186    
1187     # remove register_script_function callbacks
1188     # TODO
1189    
1190     # unload cf.pm "a bit"
1191     delete $INC{"cf.pm"};
1192    
1193     # don't, removes xs symbols, too,
1194     # and global variables created in xs
1195     #Symbol::delete_package __PACKAGE__;
1196    
1197     # reload cf.pm
1198     $msg->("reloading cf.pm");
1199     require cf;
1200    
1201 root 1.73 # load config and database again
1202     cf::cfg_load;
1203 root 1.65 cf::db_load;
1204    
1205     # load extensions
1206     $msg->("load extensions");
1207     cf::load_extensions;
1208    
1209     # reattach attachments to objects
1210     $msg->("reattach");
1211     _global_reattach;
1212     };
1213     $msg->($@) if $@;
1214    
1215     $msg->("reloaded");
1216     };
1217    
1218     sub perl_reload() {
1219     _perl_reload {
1220     warn $_[0];
1221     print "$_[0]\n";
1222     };
1223     }
1224    
1225 root 1.85 register "<global>", __PACKAGE__;
1226    
1227     register_command "perl-reload" => sub {
1228 root 1.65 my ($who, $arg) = @_;
1229    
1230     if ($who->flag (FLAG_WIZ)) {
1231     _perl_reload {
1232     warn $_[0];
1233     $who->message ($_[0]);
1234     };
1235     }
1236     };
1237    
1238 root 1.27 unshift @INC, $LIBDIR;
1239 root 1.17
1240 root 1.35 $TICK_WATCHER = Event->timer (
1241 root 1.90 prio => 0,
1242 root 1.77 at => $NEXT_TICK || 1,
1243 root 1.87 data => WF_AUTOCANCEL,
1244 root 1.77 cb => sub {
1245 root 1.35 cf::server_tick; # one server iteration
1246    
1247     my $NOW = Event::time;
1248     $NEXT_TICK += $TICK;
1249    
1250 root 1.78 # if we are delayed by four ticks or more, skip them all
1251 root 1.37 $NEXT_TICK = $NOW if $NOW >= $NEXT_TICK + $TICK * 4;
1252 root 1.35
1253     $TICK_WATCHER->at ($NEXT_TICK);
1254     $TICK_WATCHER->start;
1255     },
1256     );
1257    
1258 root 1.80 IO::AIO::max_poll_time $TICK * 0.2;
1259 root 1.77
1260     Event->io (fd => IO::AIO::poll_fileno,
1261     poll => 'r',
1262     prio => 5,
1263 root 1.87 data => WF_AUTOCANCEL,
1264 root 1.77 cb => \&IO::AIO::poll_cb);
1265    
1266 root 1.1 1
1267