ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/lib/cf.pm
Revision: 1.100
Committed: Mon Dec 25 11:25:49 2006 UTC (17 years, 5 months ago) by root
Branch: MAIN
Changes since 1.99: +55 -48 lines
Log Message:
- small, but subtle, rewrite of object management
- perl will now keep attachable objects alive
- objects are now refcounted
- refcouts need to be tested explicitly (refcnt_chk)
- explicit destroy is required current
- explicit destroy asks "nicely" for the object to self destruct, if possible
- refcounts will be used during mortal killing
- minor bugfixes, optimisations etc.
- some former hacks removed.

File Contents

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