ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/lib/cf.pm
Revision: 1.126
Committed: Tue Jan 2 23:12:47 2007 UTC (17 years, 4 months ago) by root
Branch: MAIN
Changes since 1.125: +2 -1 lines
Log Message:
different fix

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.103 use Coro 3.3;
14 root 1.96 use Coro::Event;
15     use Coro::Timer;
16     use Coro::Signal;
17     use Coro::Semaphore;
18 root 1.105 use Coro::AIO;
19 root 1.96
20 root 1.108 use Digest::MD5;
21 root 1.105 use Fcntl;
22     use IO::AIO 2.31 ();
23 root 1.72 use YAML::Syck ();
24 root 1.32 use Time::HiRes;
25 root 1.96
26     use Event; $Event::Eval = 1; # no idea why this is required, but it is
27 root 1.1
28 root 1.72 # work around bug in YAML::Syck - bad news for perl6, will it be as broken wrt. unicode?
29     $YAML::Syck::ImplicitUnicode = 1;
30    
31 root 1.103 $Coro::main->prio (2); # run main coroutine ("the server") with very high priority
32 root 1.1
33 root 1.87 sub WF_AUTOCANCEL () { 1 } # automatically cancel this watcher on reload
34    
35 root 1.85 our %COMMAND = ();
36     our %COMMAND_TIME = ();
37     our %EXTCMD = ();
38    
39 root 1.1 our @EVENT;
40 root 1.88 our $LIBDIR = datadir . "/ext";
41 root 1.1
42 root 1.35 our $TICK = MAX_TIME * 1e-6;
43     our $TICK_WATCHER;
44     our $NEXT_TICK;
45 root 1.103 our $NOW;
46 root 1.35
47 root 1.70 our %CFG;
48    
49 root 1.84 our $UPTIME; $UPTIME ||= time;
50 root 1.103 our $RUNTIME;
51    
52     our %MAP; # all maps
53     our $LINK_MAP; # the special {link} map
54     our $FREEZE;
55 root 1.108 our $RANDOM_MAPS = cf::localdir . "/random";
56     our %EXT_CORO;
57 root 1.103
58     binmode STDOUT;
59     binmode STDERR;
60    
61     # read virtual server time, if available
62     unless ($RUNTIME || !-e cf::localdir . "/runtime") {
63     open my $fh, "<", cf::localdir . "/runtime"
64     or die "unable to read runtime file: $!";
65     $RUNTIME = <$fh> + 0.;
66     }
67    
68     mkdir cf::localdir;
69     mkdir cf::localdir . "/" . cf::playerdir;
70     mkdir cf::localdir . "/" . cf::tmpdir;
71     mkdir cf::localdir . "/" . cf::uniquedir;
72 root 1.108 mkdir $RANDOM_MAPS;
73 root 1.103
74 root 1.108 # a special map that is always available
75     our $LINK_MAP;
76 root 1.76
77 root 1.110 our $EMERGENCY_POSITION = $cf::CFG{emergency_position} || ["/world/world_105_115", 5, 37];
78    
79 root 1.70 #############################################################################
80    
81     =head2 GLOBAL VARIABLES
82    
83     =over 4
84    
85 root 1.83 =item $cf::UPTIME
86    
87     The timestamp of the server start (so not actually an uptime).
88    
89 root 1.103 =item $cf::RUNTIME
90    
91     The time this server has run, starts at 0 and is increased by $cf::TICK on
92     every server tick.
93    
94 root 1.70 =item $cf::LIBDIR
95    
96     The perl library directory, where extensions and cf-specific modules can
97     be found. It will be added to C<@INC> automatically.
98    
99 root 1.103 =item $cf::NOW
100    
101     The time of the last (current) server tick.
102    
103 root 1.70 =item $cf::TICK
104    
105     The interval between server ticks, in seconds.
106    
107     =item %cf::CFG
108    
109     Configuration for the server, loaded from C</etc/crossfire/config>, or
110     from wherever your confdir points to.
111    
112     =back
113    
114     =cut
115    
116 root 1.1 BEGIN {
117     *CORE::GLOBAL::warn = sub {
118     my $msg = join "", @_;
119 root 1.103 utf8::encode $msg;
120    
121 root 1.1 $msg .= "\n"
122     unless $msg =~ /\n$/;
123    
124     LOG llevError, "cfperl: $msg";
125     };
126     }
127    
128 root 1.93 @safe::cf::global::ISA = @cf::global::ISA = 'cf::attachable';
129     @safe::cf::object::ISA = @cf::object::ISA = 'cf::attachable';
130     @safe::cf::player::ISA = @cf::player::ISA = 'cf::attachable';
131     @safe::cf::client::ISA = @cf::client::ISA = 'cf::attachable';
132     @safe::cf::map::ISA = @cf::map::ISA = 'cf::attachable';
133 root 1.41 @safe::cf::object::player::ISA = @cf::object::player::ISA = 'cf::object';
134 root 1.25
135 root 1.41 # we bless all objects into (empty) derived classes to force a method lookup
136 root 1.25 # within the Safe compartment.
137 root 1.86 for my $pkg (qw(
138 root 1.100 cf::global cf::attachable
139 root 1.86 cf::object cf::object::player
140 root 1.89 cf::client cf::player
141 root 1.86 cf::arch cf::living
142     cf::map cf::party cf::region
143     )) {
144 root 1.25 no strict 'refs';
145 root 1.41 @{"safe::$pkg\::wrap::ISA"} = @{"$pkg\::wrap::ISA"} = $pkg;
146 root 1.25 }
147 root 1.1
148 root 1.18 $Event::DIED = sub {
149     warn "error in event callback: @_";
150     };
151    
152 root 1.5 my %ext_pkg;
153 root 1.1 my @exts;
154     my @hook;
155    
156 root 1.70 =head2 UTILITY FUNCTIONS
157    
158     =over 4
159    
160     =cut
161 root 1.44
162 root 1.45 use JSON::Syck (); # TODO# replace by JSON::PC once working
163 root 1.44
164 root 1.70 =item $ref = cf::from_json $json
165    
166     Converts a JSON string into the corresponding perl data structure.
167    
168     =cut
169    
170 root 1.45 sub from_json($) {
171     $JSON::Syck::ImplicitUnicode = 1; # work around JSON::Syck bugs
172     JSON::Syck::Load $_[0]
173 root 1.44 }
174    
175 root 1.70 =item $json = cf::to_json $ref
176    
177     Converts a perl data structure into its JSON representation.
178    
179     =cut
180    
181 root 1.45 sub to_json($) {
182     $JSON::Syck::ImplicitUnicode = 0; # work around JSON::Syck bugs
183     JSON::Syck::Dump $_[0]
184 root 1.44 }
185    
186 root 1.120 =item my $guard = cf::guard { BLOCK }
187    
188     Run the given callback when the guard object gets destroyed (useful for
189     coroutine cancellations).
190    
191     You can call C<< ->cancel >> on the guard object to stop the block from
192     being executed.
193    
194     =cut
195    
196     sub guard(&) {
197     bless \(my $cb = $_[0]), cf::guard::;
198     }
199    
200     sub cf::guard::cancel {
201     ${$_[0]} = sub { };
202     }
203    
204     sub cf::guard::DESTROY {
205     ${$_[0]}->();
206     }
207    
208     =item cf::lock_wait $string
209    
210     Wait until the given lock is available. See cf::lock_acquire.
211    
212     =item my $lock = cf::lock_acquire $string
213    
214     Wait until the given lock is available and then acquires it and returns
215     a guard object. If the guard object gets destroyed (goes out of scope,
216     for example when the coroutine gets canceled), the lock is automatically
217     returned.
218    
219     Lock names should begin with a unique identifier (for example, find_map
220     uses map_find and load_map uses map_load).
221    
222     =cut
223    
224     our %LOCK;
225    
226     sub lock_wait($) {
227     my ($key) = @_;
228    
229     # wait for lock, if any
230     while ($LOCK{$key}) {
231     push @{ $LOCK{$key} }, $Coro::current;
232     Coro::schedule;
233     }
234     }
235    
236     sub lock_acquire($) {
237     my ($key) = @_;
238    
239     # wait, to be sure we are not locked
240     lock_wait $key;
241    
242     $LOCK{$key} = [];
243    
244     cf::guard {
245     # wake up all waiters, to be on the safe side
246     $_->ready for @{ delete $LOCK{$key} };
247     }
248     }
249    
250 root 1.106 =item cf::sync_job { BLOCK }
251    
252     The design of crossfire+ requires that the main coro ($Coro::main) is
253     always able to handle events or runnable, as crossfire+ is only partly
254     reentrant. Thus "blocking" it by e.g. waiting for I/O is not acceptable.
255    
256     If it must be done, put the blocking parts into C<sync_job>. This will run
257     the given BLOCK in another coroutine while waiting for the result. The
258     server will be frozen during this time, so the block should either finish
259     fast or be very important.
260    
261     =cut
262    
263 root 1.105 sub sync_job(&) {
264     my ($job) = @_;
265    
266     if ($Coro::current == $Coro::main) {
267 root 1.112 # this is the main coro, too bad, we have to block
268     # till the operation succeeds, freezing the server :/
269    
270 root 1.110 # TODO: use suspend/resume instead
271 root 1.112 # (but this is cancel-safe)
272 root 1.110 local $FREEZE = 1;
273 root 1.112
274     my $busy = 1;
275     my @res;
276    
277     (Coro::async {
278     @res = eval { $job->() };
279     warn $@ if $@;
280     undef $busy;
281     })->prio (Coro::PRIO_MAX);
282    
283 root 1.105 while ($busy) {
284     Coro::cede_notself;
285     Event::one_event unless Coro::nready;
286     }
287 root 1.112
288     wantarray ? @res : $res[0]
289 root 1.105 } else {
290 root 1.112 # we are in another coroutine, how wonderful, everything just works
291    
292     $job->()
293 root 1.105 }
294     }
295    
296 root 1.103 =item $coro = cf::coro { BLOCK }
297    
298     Creates and returns a new coro. This coro is automcatially being canceled
299     when the extension calling this is being unloaded.
300    
301     =cut
302    
303     sub coro(&) {
304     my $cb = shift;
305    
306     my $coro; $coro = async {
307     eval {
308     $cb->();
309     };
310     warn $@ if $@;
311     };
312    
313     $coro->on_destroy (sub {
314     delete $EXT_CORO{$coro+0};
315     });
316     $EXT_CORO{$coro+0} = $coro;
317    
318     $coro
319     }
320    
321 root 1.108 sub write_runtime {
322     my $runtime = cf::localdir . "/runtime";
323    
324     my $fh = aio_open "$runtime~", O_WRONLY | O_CREAT, 0644
325     or return;
326    
327 root 1.112 my $value = $cf::RUNTIME + 1 + 10; # 10 is the runtime save interval, for a monotonic clock
328 root 1.108 (aio_write $fh, 0, (length $value), $value, 0) <= 0
329     and return;
330    
331     aio_fsync $fh
332     and return;
333    
334     close $fh
335     or return;
336    
337     aio_rename "$runtime~", $runtime
338     and return;
339    
340     1
341     }
342    
343 root 1.70 =back
344    
345 root 1.71 =cut
346    
347 root 1.44 #############################################################################
348 root 1.39
349 root 1.108 package cf::path;
350    
351     sub new {
352     my ($class, $path, $base) = @_;
353    
354 root 1.110 $path = $path->as_string if ref $path;
355    
356 root 1.108 my $self = bless { }, $class;
357    
358 root 1.114 # {... are special paths that are not touched
359     # ?xxx/... are special absolute paths
360     # ?random/... random maps
361     # /! non-realised random map exit
362     # /... normal maps
363     # ~/... per-player maps without a specific player (DO NOT USE)
364     # ~user/... per-player map of a specific user
365    
366     if ($path =~ /^{/) {
367     # fine as it is
368     } elsif ($path =~ s{^\?random/}{}) {
369 root 1.109 Coro::AIO::aio_load "$cf::RANDOM_MAPS/$path.meta", my $data;
370     $self->{random} = cf::from_json $data;
371 root 1.108 } else {
372     if ($path =~ s{^~([^/]+)?}{}) {
373     $self->{user_rel} = 1;
374    
375     if (defined $1) {
376     $self->{user} = $1;
377     } elsif ($base =~ m{^~([^/]+)/}) {
378     $self->{user} = $1;
379     } else {
380     warn "cannot resolve user-relative path without user <$path,$base>\n";
381     }
382     } elsif ($path =~ /^\//) {
383     # already absolute
384     } else {
385     $base =~ s{[^/]+/?$}{};
386     return $class->new ("$base/$path");
387     }
388    
389     for ($path) {
390     redo if s{/\.?/}{/};
391     redo if s{/[^/]+/\.\./}{/};
392     }
393     }
394    
395     $self->{path} = $path;
396    
397     $self
398     }
399    
400     # the name / primary key / in-game path
401     sub as_string {
402     my ($self) = @_;
403    
404     $self->{user_rel} ? "~$self->{user}$self->{path}"
405     : $self->{random} ? "?random/$self->{path}"
406     : $self->{path}
407     }
408    
409     # the displayed name, this is a one way mapping
410     sub visible_name {
411     my ($self) = @_;
412    
413 root 1.109 # if (my $rmp = $self->{random}) {
414     # # todo: be more intelligent about this
415     # "?random/$rmp->{origin_map}+$rmp->{origin_x}+$rmp->{origin_y}/$rmp->{dungeon_level}"
416     # } else {
417     $self->as_string
418     # }
419 root 1.108 }
420    
421     # escape the /'s in the path
422     sub _escaped_path {
423     # ∕ is U+2215
424     (my $path = $_[0]{path}) =~ s/\//∕/g;
425     $path
426     }
427    
428     # the original (read-only) location
429     sub load_path {
430     my ($self) = @_;
431    
432     sprintf "%s/%s/%s", cf::datadir, cf::mapdir, $self->{path}
433     }
434    
435     # the temporary/swap location
436     sub save_path {
437     my ($self) = @_;
438    
439     $self->{user_rel} ? sprintf "%s/%s/%s/%s", cf::localdir, cf::playerdir, $self->{user}, $self->_escaped_path
440 root 1.109 : $self->{random} ? sprintf "%s/%s", $RANDOM_MAPS, $self->{path}
441 root 1.108 : sprintf "%s/%s/%s", cf::localdir, cf::tmpdir, $self->_escaped_path
442     }
443    
444     # the unique path, might be eq to save_path
445     sub uniq_path {
446     my ($self) = @_;
447    
448     $self->{user_rel} || $self->{random}
449     ? undef
450     : sprintf "%s/%s/%s", cf::localdir, cf::uniquedir, $self->_escaped_path
451     }
452    
453     # return random map parameters, or undef
454     sub random_map_params {
455     my ($self) = @_;
456    
457     $self->{random}
458     }
459    
460     # this is somewhat ugly, but style maps do need special treatment
461     sub is_style_map {
462     $_[0]{path} =~ m{^/styles/}
463     }
464    
465     package cf;
466    
467     #############################################################################
468    
469 root 1.93 =head2 ATTACHABLE OBJECTS
470    
471 root 1.94 Many objects in crossfire are so-called attachable objects. That means you can
472     attach callbacks/event handlers (a collection of which is called an "attachment")
473     to it. All such attachable objects support the following methods.
474    
475     In the following description, CLASS can be any of C<global>, C<object>
476     C<player>, C<client> or C<map> (i.e. the attachable objects in
477     crossfire+).
478 root 1.55
479     =over 4
480    
481 root 1.94 =item $attachable->attach ($attachment, key => $value...)
482    
483     =item $attachable->detach ($attachment)
484    
485     Attach/detach a pre-registered attachment to a specific object and give it
486     the specified key/value pairs as arguments.
487    
488     Example, attach a minesweeper attachment to the given object, making it a
489     10x10 minesweeper game:
490 root 1.46
491 root 1.94 $obj->attach (minesweeper => width => 10, height => 10);
492 root 1.53
493 root 1.93 =item $bool = $attachable->attached ($name)
494 root 1.46
495 root 1.93 Checks wether the named attachment is currently attached to the object.
496 root 1.46
497 root 1.94 =item cf::CLASS->attach ...
498 root 1.46
499 root 1.94 =item cf::CLASS->detach ...
500 root 1.92
501 root 1.94 Define an anonymous attachment and attach it to all objects of the given
502     CLASS. See the next function for an explanation of its arguments.
503 root 1.92
504 root 1.93 You can attach to global events by using the C<cf::global> class.
505 root 1.92
506 root 1.94 Example, log all player logins:
507    
508     cf::player->attach (
509     on_login => sub {
510     my ($pl) = @_;
511     ...
512     },
513     );
514    
515     Example, attach to the jeweler skill:
516    
517     cf::object->attach (
518     type => cf::SKILL,
519     subtype => cf::SK_JEWELER,
520     on_use_skill => sub {
521     my ($sk, $ob, $part, $dir, $msg) = @_;
522     ...
523     },
524     );
525    
526     =item cf::CLASS::attachment $name, ...
527    
528     Register an attachment by C<$name> through which attachable objects of the
529     given CLASS can refer to this attachment.
530    
531     Some classes such as crossfire maps and objects can specify attachments
532     that are attached at load/instantiate time, thus the need for a name.
533    
534     These calls expect any number of the following handler/hook descriptions:
535 root 1.46
536     =over 4
537    
538     =item prio => $number
539    
540     Set the priority for all following handlers/hooks (unless overwritten
541     by another C<prio> setting). Lower priority handlers get executed
542     earlier. The default priority is C<0>, and many built-in handlers are
543     registered at priority C<-1000>, so lower priorities should not be used
544     unless you know what you are doing.
545    
546 root 1.93 =item type => $type
547    
548     (Only for C<< cf::object->attach >> calls), limits the attachment to the
549     given type of objects only (the additional parameter C<subtype> can be
550     used to further limit to the given subtype).
551    
552 root 1.46 =item on_I<event> => \&cb
553    
554     Call the given code reference whenever the named event happens (event is
555     something like C<instantiate>, C<apply>, C<use_skill> and so on, and which
556     handlers are recognised generally depends on the type of object these
557     handlers attach to).
558    
559     See F<include/eventinc.h> for the full list of events supported, and their
560     class.
561    
562     =item package => package::
563    
564     Look for sub functions of the name C<< on_I<event> >> in the given
565     package and register them. Only handlers for eevents supported by the
566     object/class are recognised.
567    
568     =back
569    
570 root 1.94 Example, define an attachment called "sockpuppet" that calls the given
571     event handler when a monster attacks:
572    
573     cf::object::attachment sockpuppet =>
574     on_skill_attack => sub {
575     my ($self, $victim) = @_;
576     ...
577     }
578     }
579    
580 root 1.96 =item $attachable->valid
581    
582     Just because you have a perl object does not mean that the corresponding
583     C-level object still exists. If you try to access an object that has no
584     valid C counterpart anymore you get an exception at runtime. This method
585     can be used to test for existence of the C object part without causing an
586     exception.
587    
588 root 1.39 =cut
589    
590 root 1.40 # the following variables are defined in .xs and must not be re-created
591 root 1.100 our @CB_GLOBAL = (); # registry for all global events
592     our @CB_ATTACHABLE = (); # registry for all attachables
593     our @CB_OBJECT = (); # all objects (should not be used except in emergency)
594     our @CB_PLAYER = ();
595     our @CB_CLIENT = ();
596     our @CB_TYPE = (); # registry for type (cf-object class) based events
597     our @CB_MAP = ();
598 root 1.39
599 root 1.45 my %attachment;
600    
601 root 1.93 sub _attach_cb($$$$) {
602     my ($registry, $event, $prio, $cb) = @_;
603 root 1.39
604     use sort 'stable';
605    
606     $cb = [$prio, $cb];
607    
608     @{$registry->[$event]} = sort
609     { $a->[0] cmp $b->[0] }
610     @{$registry->[$event] || []}, $cb;
611     }
612    
613 root 1.100 # hack
614     my %attachable_klass = map +($_ => 1), KLASS_OBJECT, KLASS_CLIENT, KLASS_PLAYER, KLASS_MAP;
615    
616 root 1.39 # attach handles attaching event callbacks
617     # the only thing the caller has to do is pass the correct
618     # registry (== where the callback attaches to).
619 root 1.93 sub _attach {
620 root 1.45 my ($registry, $klass, @arg) = @_;
621 root 1.39
622 root 1.93 my $object_type;
623 root 1.39 my $prio = 0;
624     my %cb_id = map +("on_" . lc $EVENT[$_][0], $_) , grep $EVENT[$_][1] == $klass, 0 .. $#EVENT;
625    
626 root 1.100 #TODO: get rid of this hack
627     if ($attachable_klass{$klass}) {
628     %cb_id = (%cb_id, map +("on_" . lc $EVENT[$_][0], $_) , grep $EVENT[$_][1] == KLASS_ATTACHABLE, 0 .. $#EVENT);
629     }
630    
631 root 1.45 while (@arg) {
632     my $type = shift @arg;
633 root 1.39
634     if ($type eq "prio") {
635 root 1.45 $prio = shift @arg;
636 root 1.39
637 root 1.93 } elsif ($type eq "type") {
638     $object_type = shift @arg;
639     $registry = $CB_TYPE[$object_type] ||= [];
640    
641     } elsif ($type eq "subtype") {
642     defined $object_type or Carp::croak "subtype specified without type";
643     my $object_subtype = shift @arg;
644     $registry = $CB_TYPE[$object_type + $object_subtype * NUM_SUBTYPES] ||= [];
645    
646 root 1.39 } elsif ($type eq "package") {
647 root 1.45 my $pkg = shift @arg;
648 root 1.39
649     while (my ($name, $id) = each %cb_id) {
650     if (my $cb = $pkg->can ($name)) {
651 root 1.93 _attach_cb $registry, $id, $prio, $cb;
652 root 1.39 }
653     }
654    
655     } elsif (exists $cb_id{$type}) {
656 root 1.93 _attach_cb $registry, $cb_id{$type}, $prio, shift @arg;
657 root 1.39
658     } elsif (ref $type) {
659     warn "attaching objects not supported, ignoring.\n";
660    
661     } else {
662 root 1.45 shift @arg;
663 root 1.39 warn "attach argument '$type' not supported, ignoring.\n";
664     }
665     }
666     }
667    
668 root 1.93 sub _object_attach {
669 root 1.48 my ($obj, $name, %arg) = @_;
670 root 1.46
671 root 1.55 return if exists $obj->{_attachment}{$name};
672    
673 root 1.46 if (my $attach = $attachment{$name}) {
674     my $registry = $obj->registry;
675    
676 root 1.47 for (@$attach) {
677     my ($klass, @attach) = @$_;
678 root 1.93 _attach $registry, $klass, @attach;
679 root 1.47 }
680 root 1.46
681 root 1.48 $obj->{$name} = \%arg;
682 root 1.46 } else {
683     warn "object uses attachment '$name' that is not available, postponing.\n";
684     }
685    
686 root 1.50 $obj->{_attachment}{$name} = undef;
687 root 1.46 }
688    
689 root 1.93 sub cf::attachable::attach {
690     if (ref $_[0]) {
691     _object_attach @_;
692     } else {
693     _attach shift->_attach_registry, @_;
694     }
695 root 1.55 };
696 root 1.46
697 root 1.54 # all those should be optimised
698 root 1.93 sub cf::attachable::detach {
699 root 1.54 my ($obj, $name) = @_;
700 root 1.46
701 root 1.93 if (ref $obj) {
702     delete $obj->{_attachment}{$name};
703     reattach ($obj);
704     } else {
705     Carp::croak "cannot, currently, detach class attachments";
706     }
707 root 1.55 };
708    
709 root 1.93 sub cf::attachable::attached {
710 root 1.55 my ($obj, $name) = @_;
711    
712     exists $obj->{_attachment}{$name}
713 root 1.39 }
714    
715 root 1.100 for my $klass (qw(ATTACHABLE GLOBAL OBJECT PLAYER CLIENT MAP)) {
716 root 1.93 eval "#line " . __LINE__ . " 'cf.pm'
717     sub cf::\L$klass\E::_attach_registry {
718     (\\\@CB_$klass, KLASS_$klass)
719     }
720 root 1.45
721 root 1.93 sub cf::\L$klass\E::attachment {
722     my \$name = shift;
723 root 1.39
724 root 1.93 \$attachment{\$name} = [[KLASS_$klass, \@_]];
725     }
726     ";
727     die if $@;
728 root 1.52 }
729    
730 root 1.39 our $override;
731 root 1.45 our @invoke_results = (); # referenced from .xs code. TODO: play tricks with reify and mortals?
732 root 1.39
733 root 1.45 sub override {
734     $override = 1;
735     @invoke_results = ();
736 root 1.39 }
737    
738 root 1.45 sub do_invoke {
739 root 1.39 my $event = shift;
740 root 1.40 my $callbacks = shift;
741 root 1.39
742 root 1.45 @invoke_results = ();
743    
744 root 1.39 local $override;
745    
746 root 1.40 for (@$callbacks) {
747 root 1.39 eval { &{$_->[1]} };
748    
749     if ($@) {
750     warn "$@";
751 root 1.64 warn "... while processing $EVENT[$event][0](@_) event, skipping processing altogether.\n";
752 root 1.39 override;
753     }
754    
755     return 1 if $override;
756     }
757    
758     0
759     }
760    
761 root 1.96 =item $bool = cf::global::invoke (EVENT_CLASS_XXX, ...)
762 root 1.55
763 root 1.96 =item $bool = $attachable->invoke (EVENT_CLASS_XXX, ...)
764 root 1.55
765 root 1.96 Generate an object-specific event with the given arguments.
766 root 1.55
767 root 1.96 This API is preliminary (most likely, the EVENT_CLASS_xxx prefix will be
768 root 1.55 removed in future versions), and there is no public API to access override
769     results (if you must, access C<@cf::invoke_results> directly).
770    
771     =back
772    
773 root 1.71 =cut
774    
775 root 1.70 #############################################################################
776 root 1.45 # object support
777    
778 root 1.102 sub reattach {
779     # basically do the same as instantiate, without calling instantiate
780     my ($obj) = @_;
781    
782     my $registry = $obj->registry;
783    
784     @$registry = ();
785    
786     delete $obj->{_attachment} unless scalar keys %{ $obj->{_attachment} || {} };
787    
788     for my $name (keys %{ $obj->{_attachment} || {} }) {
789     if (my $attach = $attachment{$name}) {
790     for (@$attach) {
791     my ($klass, @attach) = @$_;
792     _attach $registry, $klass, @attach;
793     }
794     } else {
795     warn "object uses attachment '$name' that is not available, postponing.\n";
796     }
797     }
798     }
799    
800 root 1.100 cf::attachable->attach (
801     prio => -1000000,
802     on_instantiate => sub {
803     my ($obj, $data) = @_;
804 root 1.45
805 root 1.100 $data = from_json $data;
806 root 1.45
807 root 1.100 for (@$data) {
808     my ($name, $args) = @$_;
809 root 1.49
810 root 1.100 $obj->attach ($name, %{$args || {} });
811     }
812     },
813 root 1.102 on_reattach => \&reattach,
814 root 1.100 on_clone => sub {
815     my ($src, $dst) = @_;
816    
817     @{$dst->registry} = @{$src->registry};
818    
819     %$dst = %$src;
820    
821     %{$dst->{_attachment}} = %{$src->{_attachment}}
822     if exists $src->{_attachment};
823     },
824     );
825 root 1.45
826 root 1.46 sub object_freezer_save {
827 root 1.59 my ($filename, $rdata, $objs) = @_;
828 root 1.46
829 root 1.105 sync_job {
830     if (length $$rdata) {
831     warn sprintf "saving %s (%d,%d)\n",
832     $filename, length $$rdata, scalar @$objs;
833 root 1.60
834 root 1.105 if (my $fh = aio_open "$filename~", O_WRONLY | O_CREAT, 0600) {
835 root 1.60 chmod SAVE_MODE, $fh;
836 root 1.105 aio_write $fh, 0, (length $$rdata), $$rdata, 0;
837     aio_fsync $fh;
838 root 1.60 close $fh;
839 root 1.105
840     if (@$objs) {
841     if (my $fh = aio_open "$filename.pst~", O_WRONLY | O_CREAT, 0600) {
842     chmod SAVE_MODE, $fh;
843     my $data = Storable::nfreeze { version => 1, objs => $objs };
844     aio_write $fh, 0, (length $data), $data, 0;
845     aio_fsync $fh;
846     close $fh;
847     aio_rename "$filename.pst~", "$filename.pst";
848     }
849     } else {
850     aio_unlink "$filename.pst";
851     }
852    
853     aio_rename "$filename~", $filename;
854 root 1.60 } else {
855 root 1.105 warn "FATAL: $filename~: $!\n";
856 root 1.60 }
857 root 1.59 } else {
858 root 1.105 aio_unlink $filename;
859     aio_unlink "$filename.pst";
860 root 1.59 }
861 root 1.45 }
862     }
863    
864 root 1.80 sub object_freezer_as_string {
865     my ($rdata, $objs) = @_;
866    
867     use Data::Dumper;
868    
869 root 1.81 $$rdata . Dumper $objs
870 root 1.80 }
871    
872 root 1.46 sub object_thawer_load {
873     my ($filename) = @_;
874    
875 root 1.105 my ($data, $av);
876 root 1.61
877 root 1.105 (aio_load $filename, $data) >= 0
878     or return;
879 root 1.61
880 root 1.105 unless (aio_stat "$filename.pst") {
881     (aio_load "$filename.pst", $av) >= 0
882     or return;
883 root 1.113 $av = eval { (Storable::thaw $av)->{objs} };
884 root 1.61 }
885 root 1.45
886 root 1.118 warn sprintf "loading %s (%d)\n",
887     $filename, length $data, scalar @{$av || []};#d#
888 root 1.105 return ($data, $av);
889 root 1.45 }
890    
891     #############################################################################
892 root 1.85 # command handling &c
893 root 1.39
894 root 1.85 =item cf::register_command $name => \&callback($ob,$args);
895 root 1.1
896 root 1.85 Register a callback for execution when the client sends the user command
897     $name.
898 root 1.5
899 root 1.85 =cut
900 root 1.5
901 root 1.85 sub register_command {
902     my ($name, $cb) = @_;
903 root 1.5
904 root 1.85 my $caller = caller;
905     #warn "registering command '$name/$time' to '$caller'";
906 root 1.1
907 root 1.85 push @{ $COMMAND{$name} }, [$caller, $cb];
908 root 1.1 }
909    
910 root 1.85 =item cf::register_extcmd $name => \&callback($pl,$packet);
911 root 1.1
912 root 1.85 Register a callbackf ro execution when the client sends an extcmd packet.
913 root 1.1
914 root 1.85 If the callback returns something, it is sent back as if reply was being
915     called.
916 root 1.1
917 root 1.85 =cut
918 root 1.1
919 root 1.16 sub register_extcmd {
920     my ($name, $cb) = @_;
921    
922     my $caller = caller;
923     #warn "registering extcmd '$name' to '$caller'";
924    
925 root 1.85 $EXTCMD{$name} = [$cb, $caller];
926 root 1.16 }
927    
928 root 1.93 cf::player->attach (
929 root 1.85 on_command => sub {
930     my ($pl, $name, $params) = @_;
931    
932     my $cb = $COMMAND{$name}
933     or return;
934    
935     for my $cmd (@$cb) {
936     $cmd->[1]->($pl->ob, $params);
937     }
938    
939     cf::override;
940     },
941     on_extcmd => sub {
942     my ($pl, $buf) = @_;
943    
944     my $msg = eval { from_json $buf };
945    
946     if (ref $msg) {
947     if (my $cb = $EXTCMD{$msg->{msgtype}}) {
948     if (my %reply = $cb->[0]->($pl, $msg)) {
949     $pl->ext_reply ($msg->{msgid}, %reply);
950     }
951     }
952     } else {
953     warn "player " . ($pl->ob->name) . " sent unparseable ext message: <$buf>\n";
954     }
955    
956     cf::override;
957     },
958 root 1.93 );
959 root 1.85
960 root 1.6 sub register {
961     my ($base, $pkg) = @_;
962    
963 root 1.45 #TODO
964 root 1.6 }
965    
966 root 1.1 sub load_extension {
967     my ($path) = @_;
968    
969     $path =~ /([^\/\\]+)\.ext$/ or die "$path";
970 root 1.5 my $base = $1;
971 root 1.1 my $pkg = $1;
972     $pkg =~ s/[^[:word:]]/_/g;
973 root 1.41 $pkg = "ext::$pkg";
974 root 1.1
975     warn "loading '$path' into '$pkg'\n";
976    
977     open my $fh, "<:utf8", $path
978     or die "$path: $!";
979    
980     my $source =
981     "package $pkg; use strict; use utf8;\n"
982     . "#line 1 \"$path\"\n{\n"
983     . (do { local $/; <$fh> })
984     . "\n};\n1";
985    
986     eval $source
987 root 1.82 or die $@ ? "$path: $@\n"
988     : "extension disabled.\n";
989 root 1.1
990     push @exts, $pkg;
991 root 1.5 $ext_pkg{$base} = $pkg;
992 root 1.1
993 root 1.6 # no strict 'refs';
994 root 1.23 # @{"$pkg\::ISA"} = ext::;
995 root 1.1
996 root 1.6 register $base, $pkg;
997 root 1.1 }
998    
999     sub unload_extension {
1000     my ($pkg) = @_;
1001    
1002     warn "removing extension $pkg\n";
1003    
1004     # remove hooks
1005 root 1.45 #TODO
1006     # for my $idx (0 .. $#PLUGIN_EVENT) {
1007     # delete $hook[$idx]{$pkg};
1008     # }
1009 root 1.1
1010     # remove commands
1011 root 1.85 for my $name (keys %COMMAND) {
1012     my @cb = grep $_->[0] ne $pkg, @{ $COMMAND{$name} };
1013 root 1.1
1014     if (@cb) {
1015 root 1.85 $COMMAND{$name} = \@cb;
1016 root 1.1 } else {
1017 root 1.85 delete $COMMAND{$name};
1018 root 1.1 }
1019     }
1020    
1021 root 1.15 # remove extcmds
1022 root 1.85 for my $name (grep $EXTCMD{$_}[1] eq $pkg, keys %EXTCMD) {
1023     delete $EXTCMD{$name};
1024 root 1.15 }
1025    
1026 root 1.43 if (my $cb = $pkg->can ("unload")) {
1027 elmex 1.31 eval {
1028     $cb->($pkg);
1029     1
1030     } or warn "$pkg unloaded, but with errors: $@";
1031     }
1032    
1033 root 1.1 Symbol::delete_package $pkg;
1034     }
1035    
1036     sub load_extensions {
1037     for my $ext (<$LIBDIR/*.ext>) {
1038 root 1.3 next unless -r $ext;
1039 root 1.2 eval {
1040     load_extension $ext;
1041     1
1042     } or warn "$ext not loaded: $@";
1043 root 1.1 }
1044     }
1045    
1046 root 1.8 #############################################################################
1047     # load/save/clean perl data associated with a map
1048    
1049 root 1.39 *cf::mapsupport::on_clean = sub {
1050 root 1.13 my ($map) = @_;
1051 root 1.7
1052     my $path = $map->tmpname;
1053     defined $path or return;
1054    
1055 root 1.46 unlink "$path.pst";
1056 root 1.7 };
1057    
1058 root 1.93 cf::map->attach (prio => -10000, package => cf::mapsupport::);
1059 root 1.39
1060 root 1.8 #############################################################################
1061     # load/save perl data associated with player->ob objects
1062    
1063 root 1.33 sub all_objects(@) {
1064     @_, map all_objects ($_->inv), @_
1065     }
1066    
1067 root 1.60 # TODO: compatibility cruft, remove when no longer needed
1068 root 1.93 cf::player->attach (
1069 root 1.39 on_load => sub {
1070     my ($pl, $path) = @_;
1071    
1072     for my $o (all_objects $pl->ob) {
1073     if (my $value = $o->get_ob_key_value ("_perl_data")) {
1074     $o->set_ob_key_value ("_perl_data");
1075 root 1.8
1076 root 1.39 %$o = %{ Storable::thaw pack "H*", $value };
1077     }
1078 root 1.11 }
1079 root 1.39 },
1080 root 1.93 );
1081 root 1.6
1082 root 1.22 #############################################################################
1083 root 1.70
1084     =head2 CORE EXTENSIONS
1085    
1086     Functions and methods that extend core crossfire objects.
1087    
1088 root 1.95 =head3 cf::player
1089    
1090 root 1.70 =over 4
1091 root 1.22
1092 root 1.23 =item cf::player::exists $login
1093    
1094     Returns true when the given account exists.
1095    
1096     =cut
1097    
1098     sub cf::player::exists($) {
1099     cf::player::find $_[0]
1100     or -f sprintf "%s/%s/%s/%s.pl", cf::localdir, cf::playerdir, ($_[0]) x 2;
1101     }
1102    
1103 root 1.95 =item $player->ext_reply ($msgid, $msgtype, %msg)
1104    
1105     Sends an ext reply to the player.
1106    
1107     =cut
1108    
1109     sub cf::player::ext_reply($$$%) {
1110     my ($self, $id, %msg) = @_;
1111    
1112     $msg{msgid} = $id;
1113    
1114     $self->send ("ext " . to_json \%msg);
1115     }
1116    
1117     =back
1118    
1119 root 1.110
1120     =head3 cf::map
1121    
1122     =over 4
1123    
1124     =cut
1125    
1126     package cf::map;
1127    
1128     use Fcntl;
1129     use Coro::AIO;
1130    
1131     our $MAX_RESET = 7200;
1132     our $DEFAULT_RESET = 3600;
1133    
1134     sub generate_random_map {
1135     my ($path, $rmp) = @_;
1136    
1137     # mit "rum" bekleckern, nicht
1138     cf::map::_create_random_map
1139     $path,
1140     $rmp->{wallstyle}, $rmp->{wall_name}, $rmp->{floorstyle}, $rmp->{monsterstyle},
1141     $rmp->{treasurestyle}, $rmp->{layoutstyle}, $rmp->{doorstyle}, $rmp->{decorstyle},
1142     $rmp->{origin_map}, $rmp->{final_map}, $rmp->{exitstyle}, $rmp->{this_map},
1143     $rmp->{exit_on_final_map},
1144     $rmp->{xsize}, $rmp->{ysize},
1145     $rmp->{expand2x}, $rmp->{layoutoptions1}, $rmp->{layoutoptions2}, $rmp->{layoutoptions3},
1146     $rmp->{symmetry}, $rmp->{difficulty}, $rmp->{difficulty_given}, $rmp->{difficulty_increase},
1147     $rmp->{dungeon_level}, $rmp->{dungeon_depth}, $rmp->{decoroptions}, $rmp->{orientation},
1148     $rmp->{origin_y}, $rmp->{origin_x}, $rmp->{random_seed}, $rmp->{total_map_hp},
1149     $rmp->{map_layout_style}, $rmp->{treasureoptions}, $rmp->{symmetry_used},
1150     (cf::region::find $rmp->{region})
1151     }
1152    
1153     # and all this just because we cannot iterate over
1154     # all maps in C++...
1155     sub change_all_map_light {
1156     my ($change) = @_;
1157    
1158 root 1.122 $_->change_map_light ($change)
1159     for grep $_->outdoor, values %cf::MAP;
1160 root 1.110 }
1161    
1162     sub try_load_header($) {
1163     my ($path) = @_;
1164    
1165     utf8::encode $path;
1166     aio_open $path, O_RDONLY, 0
1167     or return;
1168    
1169     my $map = cf::map::new
1170     or return;
1171    
1172     $map->load_header ($path)
1173     or return;
1174    
1175     $map->{load_path} = $path;
1176    
1177     $map
1178     }
1179    
1180 root 1.126 sub find_map;
1181 root 1.110 sub find_map {
1182     my ($path, $origin) = @_;
1183    
1184     #warn "find_map<$path,$origin>\n";#d#
1185    
1186 root 1.112 $path = new cf::path $path, $origin && $origin->path;
1187 root 1.110 my $key = $path->as_string;
1188    
1189 root 1.120 cf::lock_wait "map_find:$key";
1190    
1191 root 1.110 $cf::MAP{$key} || do {
1192 root 1.120 my $guard = cf::lock_acquire "map_find:$key";
1193    
1194 root 1.110 # do it the slow way
1195     my $map = try_load_header $path->save_path;
1196    
1197     if ($map) {
1198     # safety
1199     $map->{instantiate_time} = $cf::RUNTIME
1200     if $map->{instantiate_time} > $cf::RUNTIME;
1201     } else {
1202     if (my $rmp = $path->random_map_params) {
1203     $map = generate_random_map $key, $rmp;
1204     } else {
1205     $map = try_load_header $path->load_path;
1206     }
1207    
1208     $map or return;
1209    
1210 root 1.111 $map->{load_original} = 1;
1211 root 1.110 $map->{instantiate_time} = $cf::RUNTIME;
1212     $map->instantiate;
1213    
1214     # per-player maps become, after loading, normal maps
1215     $map->per_player (0) if $path->{user_rel};
1216     }
1217    
1218     $map->path ($key);
1219     $map->{path} = $path;
1220 root 1.116 $map->{last_save} = $cf::RUNTIME;
1221 root 1.110 $map->last_access ($cf::RUNTIME);
1222    
1223 root 1.112 if ($map->should_reset) {
1224     $map->reset;
1225 root 1.123 undef $guard;
1226 root 1.126 $map = find_map $path
1227 root 1.124 or return;
1228 root 1.112 }
1229 root 1.110
1230     $cf::MAP{$key} = $map
1231     }
1232     }
1233    
1234     sub load {
1235     my ($self) = @_;
1236    
1237 root 1.120 my $path = $self->{path};
1238     my $guard = cf::lock_acquire "map_load:" . $path->as_string;
1239    
1240 root 1.110 return if $self->in_memory != cf::MAP_SWAPPED;
1241    
1242     $self->in_memory (cf::MAP_LOADING);
1243    
1244     $self->alloc;
1245     $self->load_objects ($self->{load_path}, 1)
1246     or return;
1247    
1248 root 1.112 $self->set_object_flag (cf::FLAG_OBJ_ORIGINAL, 1)
1249     if delete $self->{load_original};
1250 root 1.111
1251 root 1.110 if (my $uniq = $path->uniq_path) {
1252     utf8::encode $uniq;
1253     if (aio_open $uniq, O_RDONLY, 0) {
1254     $self->clear_unique_items;
1255     $self->load_objects ($uniq, 0);
1256     }
1257     }
1258    
1259     # now do the right thing for maps
1260     $self->link_multipart_objects;
1261    
1262     if ($self->{path}->is_style_map) {
1263     $self->{deny_save} = 1;
1264     $self->{deny_reset} = 1;
1265     } else {
1266     $self->fix_auto_apply;
1267     $self->decay_objects;
1268     $self->update_buttons;
1269     $self->set_darkness_map;
1270     $self->difficulty ($self->estimate_difficulty)
1271     unless $self->difficulty;
1272     $self->activate;
1273     }
1274    
1275     $self->in_memory (cf::MAP_IN_MEMORY);
1276     }
1277    
1278     sub load_map_sync {
1279     my ($path, $origin) = @_;
1280    
1281     #warn "load_map_sync<$path, $origin>\n";#d#
1282    
1283     cf::sync_job {
1284     my $map = cf::map::find_map $path, $origin
1285     or return;
1286     $map->load;
1287     $map
1288     }
1289     }
1290    
1291     sub save {
1292     my ($self) = @_;
1293    
1294     $self->{last_save} = $cf::RUNTIME;
1295    
1296     return unless $self->dirty;
1297    
1298 root 1.117 my $save = $self->{path}->save_path; utf8::encode $save;
1299     my $uniq = $self->{path}->uniq_path; utf8::encode $uniq;
1300    
1301 root 1.110 $self->{load_path} = $save;
1302    
1303     return if $self->{deny_save};
1304    
1305     if ($uniq) {
1306     $self->save_objects ($save, cf::IO_HEADER | cf::IO_OBJECTS);
1307     $self->save_objects ($uniq, cf::IO_UNIQUES);
1308     } else {
1309     $self->save_objects ($save, cf::IO_HEADER | cf::IO_OBJECTS | cf::IO_UNIQUES);
1310     }
1311     }
1312    
1313     sub swap_out {
1314     my ($self) = @_;
1315    
1316     return if $self->players;
1317     return if $self->in_memory != cf::MAP_IN_MEMORY;
1318     return if $self->{deny_save};
1319    
1320     $self->save;
1321     $self->clear;
1322     $self->in_memory (cf::MAP_SWAPPED);
1323     }
1324    
1325 root 1.112 sub reset_at {
1326     my ($self) = @_;
1327 root 1.110
1328     # TODO: safety, remove and allow resettable per-player maps
1329 root 1.114 return 1e99 if $self->{path}{user_rel};
1330     return 1e99 if $self->{deny_reset};
1331 root 1.110
1332 root 1.112 my $time = $self->fixed_resettime ? $self->{instantiate_time} : $self->last_access;
1333 root 1.114 my $to = List::Util::min $MAX_RESET, $self->reset_timeout || $DEFAULT_RESET;
1334 root 1.110
1335 root 1.112 $time + $to
1336     }
1337    
1338     sub should_reset {
1339     my ($self) = @_;
1340    
1341     $self->reset_at <= $cf::RUNTIME
1342 root 1.111 }
1343    
1344     sub unlink_save {
1345     my ($self) = @_;
1346    
1347     utf8::encode (my $save = $self->{path}->save_path);
1348     aioreq_pri 3; IO::AIO::aio_unlink $save;
1349     aioreq_pri 3; IO::AIO::aio_unlink "$save.pst";
1350 root 1.110 }
1351    
1352 root 1.113 sub rename {
1353     my ($self, $new_path) = @_;
1354    
1355     $self->unlink_save;
1356    
1357     delete $cf::MAP{$self->path};
1358     $self->{path} = new cf::path $new_path;
1359 root 1.114 $self->path ($self->{path}->as_string);
1360 root 1.113 $cf::MAP{$self->path} = $self;
1361    
1362     $self->save;
1363     }
1364    
1365 root 1.110 sub reset {
1366     my ($self) = @_;
1367    
1368     return if $self->players;
1369     return if $self->{path}{user_rel};#d#
1370    
1371     warn "resetting map ", $self->path;#d#
1372    
1373 root 1.111 delete $cf::MAP{$self->path};
1374 root 1.110
1375     $_->clear_links_to ($self) for values %cf::MAP;
1376    
1377 root 1.111 $self->unlink_save;
1378     $self->destroy;
1379 root 1.110 }
1380    
1381 root 1.114 my $nuke_counter = "aaaa";
1382    
1383     sub nuke {
1384     my ($self) = @_;
1385    
1386     $self->{deny_save} = 1;
1387     $self->reset_timeout (1);
1388     $self->rename ("{nuke}/" . ($nuke_counter++));
1389     $self->reset; # polite request, might not happen
1390     }
1391    
1392 root 1.110 sub customise_for {
1393     my ($map, $ob) = @_;
1394    
1395     if ($map->per_player) {
1396     return cf::map::find_map "~" . $ob->name . "/" . $map->{path}{path};
1397     }
1398    
1399     $map
1400     }
1401    
1402     sub emergency_save {
1403     local $cf::FREEZE = 1;
1404    
1405     warn "enter emergency map save\n";
1406    
1407     cf::sync_job {
1408     warn "begin emergency map save\n";
1409     $_->save for values %cf::MAP;
1410     };
1411    
1412     warn "end emergency map save\n";
1413     }
1414    
1415     package cf;
1416    
1417     =back
1418    
1419    
1420 root 1.95 =head3 cf::object::player
1421    
1422     =over 4
1423    
1424 root 1.79 =item $player_object->reply ($npc, $msg[, $flags])
1425 root 1.28
1426     Sends a message to the player, as if the npc C<$npc> replied. C<$npc>
1427     can be C<undef>. Does the right thing when the player is currently in a
1428     dialogue with the given NPC character.
1429    
1430     =cut
1431    
1432 root 1.22 # rough implementation of a future "reply" method that works
1433     # with dialog boxes.
1434 root 1.95 #TODO: the first argument must go, split into a $npc->reply_to ( method
1435 root 1.23 sub cf::object::player::reply($$$;$) {
1436     my ($self, $npc, $msg, $flags) = @_;
1437    
1438     $flags = cf::NDI_BROWN | cf::NDI_UNIQUE unless @_ >= 4;
1439 root 1.22
1440 root 1.24 if ($self->{record_replies}) {
1441     push @{ $self->{record_replies} }, [$npc, $msg, $flags];
1442     } else {
1443     $msg = $npc->name . " says: $msg" if $npc;
1444     $self->message ($msg, $flags);
1445     }
1446 root 1.22 }
1447    
1448 root 1.79 =item $player_object->may ("access")
1449    
1450     Returns wether the given player is authorized to access resource "access"
1451     (e.g. "command_wizcast").
1452    
1453     =cut
1454    
1455     sub cf::object::player::may {
1456     my ($self, $access) = @_;
1457    
1458     $self->flag (cf::FLAG_WIZ) ||
1459     (ref $cf::CFG{"may_$access"}
1460     ? scalar grep $self->name eq $_, @{$cf::CFG{"may_$access"}}
1461     : $cf::CFG{"may_$access"})
1462     }
1463 root 1.70
1464 root 1.115 =item $player_object->enter_link
1465    
1466     Freezes the player and moves him/her to a special map (C<{link}>).
1467    
1468     The player should be reaosnably safe there for short amounts of time. You
1469     I<MUST> call C<leave_link> as soon as possible, though.
1470    
1471     =item $player_object->leave_link ($map, $x, $y)
1472    
1473     Moves the player out of the specila link map onto the given map. If the
1474     map is not valid (or omitted), the player will be moved back to the
1475     location he/she was before the call to C<enter_link>, or, if that fails,
1476     to the emergency map position.
1477    
1478     Might block.
1479    
1480     =cut
1481    
1482 root 1.110 sub cf::object::player::enter_link {
1483     my ($self) = @_;
1484    
1485 root 1.120 $self->deactivate_recursive;
1486    
1487 root 1.110 return if $self->map == $LINK_MAP;
1488    
1489 root 1.120 $self->{_link_pos} ||= [$self->map->{path}, $self->x, $self->y]
1490 root 1.110 if $self->map;
1491    
1492     $self->enter_map ($LINK_MAP, 20, 20);
1493     }
1494    
1495     sub cf::object::player::leave_link {
1496     my ($self, $map, $x, $y) = @_;
1497    
1498     my $link_pos = delete $self->{_link_pos};
1499    
1500     unless ($map) {
1501     # restore original map position
1502     ($map, $x, $y) = @{ $link_pos || [] };
1503     $map = cf::map::find_map $map;
1504    
1505     unless ($map) {
1506     ($map, $x, $y) = @$EMERGENCY_POSITION;
1507     $map = cf::map::find_map $map
1508     or die "FATAL: cannot load emergency map\n";
1509     }
1510     }
1511    
1512     ($x, $y) = (-1, -1)
1513     unless (defined $x) && (defined $y);
1514    
1515     # use -1 or undef as default coordinates, not 0, 0
1516     ($x, $y) = ($map->enter_x, $map->enter_y)
1517     if $x <=0 && $y <= 0;
1518    
1519     $map->load;
1520    
1521     $self->activate_recursive;
1522     $self->enter_map ($map, $x, $y);
1523     }
1524    
1525 root 1.120 cf::player->attach (
1526     on_logout => sub {
1527     my ($pl) = @_;
1528    
1529     # abort map switching before logout
1530     if ($pl->ob->{_link_pos}) {
1531     cf::sync_job {
1532     $pl->ob->leave_link
1533     };
1534     }
1535     },
1536     on_login => sub {
1537     my ($pl) = @_;
1538    
1539     # try to abort aborted map switching on player login :)
1540     # should happen only on crashes
1541     if ($pl->ob->{_link_pos}) {
1542     $pl->ob->enter_link;
1543     Coro::async {
1544     # we need this sleep as the login has a concurrent enter_exit running
1545     # and this sleep increases chances of the player not ending up in scorn
1546     Coro::Timer::sleep 1;
1547     $pl->ob->leave_link;
1548     };
1549     }
1550     },
1551     );
1552    
1553 root 1.118 =item $player_object->goto_map ($path, $x, $y)
1554 root 1.110
1555     =cut
1556    
1557     sub cf::object::player::goto_map {
1558     my ($self, $path, $x, $y) = @_;
1559    
1560     $self->enter_link;
1561    
1562     (Coro::async {
1563     $path = new cf::path $path;
1564    
1565     my $map = cf::map::find_map $path->as_string;
1566     $map = $map->customise_for ($self) if $map;
1567    
1568 root 1.119 # warn "entering ", $map->path, " at ($x, $y)\n"
1569     # if $map;
1570 root 1.110
1571 root 1.115 $map or $self->message ("The exit is closed", cf::NDI_UNIQUE | cf::NDI_RED);
1572    
1573 root 1.110 $self->leave_link ($map, $x, $y);
1574     })->prio (1);
1575     }
1576    
1577     =item $player_object->enter_exit ($exit_object)
1578    
1579     =cut
1580    
1581     sub parse_random_map_params {
1582     my ($spec) = @_;
1583    
1584     my $rmp = { # defaults
1585     xsize => 10,
1586     ysize => 10,
1587     };
1588    
1589     for (split /\n/, $spec) {
1590     my ($k, $v) = split /\s+/, $_, 2;
1591    
1592     $rmp->{lc $k} = $v if (length $k) && (length $v);
1593     }
1594    
1595     $rmp
1596     }
1597    
1598     sub prepare_random_map {
1599     my ($exit) = @_;
1600    
1601     # all this does is basically replace the /! path by
1602     # a new random map path (?random/...) with a seed
1603     # that depends on the exit object
1604    
1605     my $rmp = parse_random_map_params $exit->msg;
1606    
1607     if ($exit->map) {
1608     $rmp->{region} = $exit->map->region_name;
1609     $rmp->{origin_map} = $exit->map->path;
1610     $rmp->{origin_x} = $exit->x;
1611     $rmp->{origin_y} = $exit->y;
1612     }
1613    
1614     $rmp->{random_seed} ||= $exit->random_seed;
1615    
1616     my $data = cf::to_json $rmp;
1617     my $md5 = Digest::MD5::md5_hex $data;
1618    
1619     if (my $fh = aio_open "$cf::RANDOM_MAPS/$md5.meta", O_WRONLY | O_CREAT, 0666) {
1620     aio_write $fh, 0, (length $data), $data, 0;
1621    
1622     $exit->slaying ("?random/$md5");
1623     $exit->msg (undef);
1624     }
1625     }
1626    
1627     sub cf::object::player::enter_exit {
1628     my ($self, $exit) = @_;
1629    
1630     return unless $self->type == cf::PLAYER;
1631    
1632     $self->enter_link;
1633    
1634     (Coro::async {
1635     unless (eval {
1636    
1637     prepare_random_map $exit
1638     if $exit->slaying eq "/!";
1639    
1640     my $path = new cf::path $exit->slaying, $exit->map && $exit->map->path;
1641     $self->goto_map ($path, $exit->stats->hp, $exit->stats->sp);
1642    
1643     1;
1644     }) {
1645     $self->message ("Something went wrong deep within the crossfire server. "
1646     . "I'll try to bring you back to the map you were before. "
1647     . "Please report this to the dungeon master",
1648     cf::NDI_UNIQUE | cf::NDI_RED);
1649    
1650     warn "ERROR in enter_exit: $@";
1651     $self->leave_link;
1652     }
1653     })->prio (1);
1654     }
1655    
1656 root 1.95 =head3 cf::client
1657    
1658     =over 4
1659    
1660     =item $client->send_drawinfo ($text, $flags)
1661    
1662     Sends a drawinfo packet to the client. Circumvents output buffering so
1663     should not be used under normal circumstances.
1664    
1665 root 1.70 =cut
1666    
1667 root 1.95 sub cf::client::send_drawinfo {
1668     my ($self, $text, $flags) = @_;
1669    
1670     utf8::encode $text;
1671     $self->send_packet (sprintf "drawinfo %d %s", $flags, $text);
1672     }
1673    
1674    
1675     =item $success = $client->query ($flags, "text", \&cb)
1676    
1677     Queues a query to the client, calling the given callback with
1678     the reply text on a reply. flags can be C<cf::CS_QUERY_YESNO>,
1679     C<cf::CS_QUERY_SINGLECHAR> or C<cf::CS_QUERY_HIDEINPUT> or C<0>.
1680    
1681     Queries can fail, so check the return code. Or don't, as queries will become
1682     reliable at some point in the future.
1683    
1684     =cut
1685    
1686     sub cf::client::query {
1687     my ($self, $flags, $text, $cb) = @_;
1688    
1689     return unless $self->state == ST_PLAYING
1690     || $self->state == ST_SETUP
1691     || $self->state == ST_CUSTOM;
1692    
1693     $self->state (ST_CUSTOM);
1694    
1695     utf8::encode $text;
1696     push @{ $self->{query_queue} }, [(sprintf "query %d %s", $flags, $text), $cb];
1697    
1698     $self->send_packet ($self->{query_queue}[0][0])
1699     if @{ $self->{query_queue} } == 1;
1700     }
1701    
1702     cf::client->attach (
1703     on_reply => sub {
1704     my ($ns, $msg) = @_;
1705    
1706     # this weird shuffling is so that direct followup queries
1707     # get handled first
1708     my $queue = delete $ns->{query_queue};
1709    
1710     (shift @$queue)->[1]->($msg);
1711    
1712     push @{ $ns->{query_queue} }, @$queue;
1713    
1714     if (@{ $ns->{query_queue} } == @$queue) {
1715     if (@$queue) {
1716     $ns->send_packet ($ns->{query_queue}[0][0]);
1717     } else {
1718 root 1.98 $ns->state (ST_PLAYING) if $ns->state == ST_CUSTOM;
1719 root 1.95 }
1720     }
1721     },
1722     );
1723    
1724 root 1.96 =item $client->coro (\&cb)
1725    
1726     Create a new coroutine, running the specified callback. The coroutine will
1727     be automatically cancelled when the client gets destroyed (e.g. on logout,
1728     or loss of connection).
1729    
1730     =cut
1731    
1732     sub cf::client::coro {
1733     my ($self, $cb) = @_;
1734    
1735     my $coro; $coro = async {
1736     eval {
1737     $cb->();
1738     };
1739     warn $@ if $@;
1740 root 1.103 };
1741    
1742     $coro->on_destroy (sub {
1743 root 1.96 delete $self->{_coro}{$coro+0};
1744 root 1.103 });
1745 root 1.96
1746     $self->{_coro}{$coro+0} = $coro;
1747 root 1.103
1748     $coro
1749 root 1.96 }
1750    
1751     cf::client->attach (
1752     on_destroy => sub {
1753     my ($ns) = @_;
1754    
1755 root 1.97 $_->cancel for values %{ (delete $ns->{_coro}) || {} };
1756 root 1.96 },
1757     );
1758    
1759 root 1.95 =back
1760    
1761 root 1.70
1762     =head2 SAFE SCRIPTING
1763    
1764     Functions that provide a safe environment to compile and execute
1765     snippets of perl code without them endangering the safety of the server
1766     itself. Looping constructs, I/O operators and other built-in functionality
1767     is not available in the safe scripting environment, and the number of
1768 root 1.79 functions and methods that can be called is greatly reduced.
1769 root 1.70
1770     =cut
1771 root 1.23
1772 root 1.42 our $safe = new Safe "safe";
1773 root 1.23 our $safe_hole = new Safe::Hole;
1774    
1775     $SIG{FPE} = 'IGNORE';
1776    
1777     $safe->permit_only (Opcode::opset qw(:base_core :base_mem :base_orig :base_math sort time));
1778    
1779 root 1.25 # here we export the classes and methods available to script code
1780    
1781 root 1.70 =pod
1782    
1783     The following fucntions and emthods are available within a safe environment:
1784    
1785 elmex 1.91 cf::object contr pay_amount pay_player map
1786 root 1.70 cf::object::player player
1787     cf::player peaceful
1788 elmex 1.91 cf::map trigger
1789 root 1.70
1790     =cut
1791    
1792 root 1.25 for (
1793 elmex 1.91 ["cf::object" => qw(contr pay_amount pay_player map)],
1794 root 1.25 ["cf::object::player" => qw(player)],
1795     ["cf::player" => qw(peaceful)],
1796 elmex 1.91 ["cf::map" => qw(trigger)],
1797 root 1.25 ) {
1798     no strict 'refs';
1799     my ($pkg, @funs) = @$_;
1800 root 1.41 *{"safe::$pkg\::$_"} = $safe_hole->wrap (\&{"$pkg\::$_"})
1801 root 1.25 for @funs;
1802     }
1803 root 1.23
1804 root 1.70 =over 4
1805    
1806     =item @retval = safe_eval $code, [var => value, ...]
1807    
1808     Compiled and executes the given perl code snippet. additional var/value
1809     pairs result in temporary local (my) scalar variables of the given name
1810     that are available in the code snippet. Example:
1811    
1812     my $five = safe_eval '$first + $second', first => 1, second => 4;
1813    
1814     =cut
1815    
1816 root 1.23 sub safe_eval($;@) {
1817     my ($code, %vars) = @_;
1818    
1819     my $qcode = $code;
1820     $qcode =~ s/"/‟/g; # not allowed in #line filenames
1821     $qcode =~ s/\n/\\n/g;
1822    
1823     local $_;
1824 root 1.41 local @safe::cf::_safe_eval_args = values %vars;
1825 root 1.23
1826 root 1.42 my $eval =
1827 root 1.23 "do {\n"
1828     . "my (" . (join ",", map "\$$_", keys %vars) . ") = \@cf::_safe_eval_args;\n"
1829     . "#line 0 \"{$qcode}\"\n"
1830     . $code
1831     . "\n}"
1832 root 1.25 ;
1833    
1834     sub_generation_inc;
1835 root 1.42 my @res = wantarray ? $safe->reval ($eval) : scalar $safe->reval ($eval);
1836 root 1.25 sub_generation_inc;
1837    
1838 root 1.42 if ($@) {
1839     warn "$@";
1840     warn "while executing safe code '$code'\n";
1841     warn "with arguments " . (join " ", %vars) . "\n";
1842     }
1843    
1844 root 1.25 wantarray ? @res : $res[0]
1845 root 1.23 }
1846    
1847 root 1.69 =item cf::register_script_function $function => $cb
1848    
1849     Register a function that can be called from within map/npc scripts. The
1850     function should be reasonably secure and should be put into a package name
1851     like the extension.
1852    
1853     Example: register a function that gets called whenever a map script calls
1854     C<rent::overview>, as used by the C<rent> extension.
1855    
1856     cf::register_script_function "rent::overview" => sub {
1857     ...
1858     };
1859    
1860     =cut
1861    
1862 root 1.23 sub register_script_function {
1863     my ($fun, $cb) = @_;
1864    
1865     no strict 'refs';
1866 root 1.41 *{"safe::$fun"} = $safe_hole->wrap ($cb);
1867 root 1.23 }
1868    
1869 root 1.70 =back
1870    
1871 root 1.71 =cut
1872    
1873 root 1.23 #############################################################################
1874 root 1.65
1875     =head2 EXTENSION DATABASE SUPPORT
1876    
1877     Crossfire maintains a very simple database for extension use. It can
1878     currently store anything that can be serialised using Storable, which
1879     excludes objects.
1880    
1881     The parameter C<$family> should best start with the name of the extension
1882     using it, it should be unique.
1883    
1884     =over 4
1885    
1886     =item $hashref = cf::db_get $family
1887    
1888     Return a hashref for use by the extension C<$family>, which can be
1889     modified. After modifications, you have to call C<cf::db_dirty> or
1890     C<cf::db_sync>.
1891    
1892     =item $value = cf::db_get $family => $key
1893    
1894     Returns a single value from the database
1895    
1896     =item cf::db_put $family => $hashref
1897    
1898     Stores the given family hashref into the database. Updates are delayed, if
1899     you want the data to be synced to disk immediately, use C<cf::db_sync>.
1900    
1901     =item cf::db_put $family => $key => $value
1902    
1903     Stores the given C<$value> in the family hash. Updates are delayed, if you
1904     want the data to be synced to disk immediately, use C<cf::db_sync>.
1905    
1906     =item cf::db_dirty
1907    
1908     Marks the database as dirty, to be updated at a later time.
1909    
1910     =item cf::db_sync
1911    
1912     Immediately write the database to disk I<if it is dirty>.
1913    
1914     =cut
1915    
1916 root 1.78 our $DB;
1917    
1918 root 1.65 {
1919 root 1.66 my $path = cf::localdir . "/database.pst";
1920 root 1.65
1921     sub db_load() {
1922 root 1.78 $DB = stat $path ? Storable::retrieve $path : { };
1923 root 1.65 }
1924    
1925     my $pid;
1926    
1927     sub db_save() {
1928     waitpid $pid, 0 if $pid;
1929 root 1.67 if (0 == ($pid = fork)) {
1930 root 1.78 $DB->{_meta}{version} = 1;
1931     Storable::nstore $DB, "$path~";
1932 root 1.65 rename "$path~", $path;
1933     cf::_exit 0 if defined $pid;
1934     }
1935     }
1936    
1937     my $dirty;
1938    
1939     sub db_sync() {
1940     db_save if $dirty;
1941     undef $dirty;
1942     }
1943    
1944 root 1.87 my $idle = Event->idle (min => $TICK * 2.8, max => 10, repeat => 0, data => WF_AUTOCANCEL, cb => sub {
1945 root 1.65 db_sync;
1946     });
1947    
1948     sub db_dirty() {
1949     $dirty = 1;
1950     $idle->start;
1951     }
1952    
1953     sub db_get($;$) {
1954     @_ >= 2
1955 root 1.78 ? $DB->{$_[0]}{$_[1]}
1956     : ($DB->{$_[0]} ||= { })
1957 root 1.65 }
1958    
1959     sub db_put($$;$) {
1960     if (@_ >= 3) {
1961 root 1.78 $DB->{$_[0]}{$_[1]} = $_[2];
1962 root 1.65 } else {
1963 root 1.78 $DB->{$_[0]} = $_[1];
1964 root 1.65 }
1965     db_dirty;
1966     }
1967 root 1.67
1968 root 1.93 cf::global->attach (
1969     prio => 10000,
1970 root 1.67 on_cleanup => sub {
1971     db_sync;
1972     },
1973 root 1.93 );
1974 root 1.65 }
1975    
1976     #############################################################################
1977 root 1.34 # the server's main()
1978    
1979 root 1.73 sub cfg_load {
1980 root 1.72 open my $fh, "<:utf8", cf::confdir . "/config"
1981     or return;
1982    
1983     local $/;
1984     *CFG = YAML::Syck::Load <$fh>;
1985     }
1986    
1987 root 1.39 sub main {
1988 root 1.108 # we must not ever block the main coroutine
1989     local $Coro::idle = sub {
1990 root 1.115 Carp::cluck "FATAL: Coro::idle was called, major BUG, use cf::sync_job!\n";#d#
1991 root 1.108 (Coro::unblock_sub {
1992     Event::one_event;
1993     })->();
1994     };
1995    
1996 root 1.73 cfg_load;
1997 root 1.65 db_load;
1998 root 1.61 load_extensions;
1999 root 1.34 Event::loop;
2000     }
2001    
2002     #############################################################################
2003 root 1.22 # initialisation
2004    
2005 root 1.111 sub reload() {
2006 root 1.106 # can/must only be called in main
2007     if ($Coro::current != $Coro::main) {
2008     warn "can only reload from main coroutine\n";
2009     return;
2010     }
2011    
2012 root 1.103 warn "reloading...";
2013    
2014 root 1.106 local $FREEZE = 1;
2015     cf::emergency_save;
2016    
2017 root 1.103 eval {
2018 root 1.106 # if anything goes wrong in here, we should simply crash as we already saved
2019 root 1.65
2020     # cancel all watchers
2021 root 1.87 for (Event::all_watchers) {
2022     $_->cancel if $_->data & WF_AUTOCANCEL;
2023     }
2024 root 1.65
2025 root 1.103 # cancel all extension coros
2026     $_->cancel for values %EXT_CORO;
2027     %EXT_CORO = ();
2028    
2029 root 1.65 # unload all extensions
2030     for (@exts) {
2031 root 1.103 warn "unloading <$_>";
2032 root 1.65 unload_extension $_;
2033     }
2034    
2035     # unload all modules loaded from $LIBDIR
2036     while (my ($k, $v) = each %INC) {
2037     next unless $v =~ /^\Q$LIBDIR\E\/.*\.pm$/;
2038    
2039 root 1.103 warn "removing <$k>";
2040 root 1.65 delete $INC{$k};
2041    
2042     $k =~ s/\.pm$//;
2043     $k =~ s/\//::/g;
2044    
2045     if (my $cb = $k->can ("unload_module")) {
2046     $cb->();
2047     }
2048    
2049     Symbol::delete_package $k;
2050     }
2051    
2052     # sync database to disk
2053     cf::db_sync;
2054 root 1.103 IO::AIO::flush;
2055 root 1.65
2056     # get rid of safe::, as good as possible
2057     Symbol::delete_package "safe::$_"
2058 root 1.103 for qw(cf::attachable cf::object cf::object::player cf::client cf::player cf::map cf::party cf::region);
2059 root 1.65
2060     # remove register_script_function callbacks
2061     # TODO
2062    
2063     # unload cf.pm "a bit"
2064     delete $INC{"cf.pm"};
2065    
2066     # don't, removes xs symbols, too,
2067     # and global variables created in xs
2068     #Symbol::delete_package __PACKAGE__;
2069    
2070     # reload cf.pm
2071 root 1.103 warn "reloading cf.pm";
2072 root 1.65 require cf;
2073 root 1.100 cf::_connect_to_perl; # nominally unnecessary, but cannot hurt
2074    
2075 root 1.73 # load config and database again
2076     cf::cfg_load;
2077 root 1.65 cf::db_load;
2078    
2079     # load extensions
2080 root 1.103 warn "load extensions";
2081 root 1.65 cf::load_extensions;
2082    
2083     # reattach attachments to objects
2084 root 1.103 warn "reattach";
2085 root 1.65 _global_reattach;
2086     };
2087    
2088 root 1.106 if ($@) {
2089     warn $@;
2090     warn "error while reloading, exiting.";
2091     exit 1;
2092     }
2093    
2094     warn "reloaded successfully";
2095 root 1.65 };
2096    
2097 root 1.108 #############################################################################
2098    
2099     unless ($LINK_MAP) {
2100     $LINK_MAP = cf::map::new;
2101    
2102     $LINK_MAP->width (41);
2103     $LINK_MAP->height (41);
2104     $LINK_MAP->alloc;
2105     $LINK_MAP->path ("{link}");
2106     $LINK_MAP->{path} = bless { path => "{link}" }, "cf::path";
2107     $LINK_MAP->in_memory (MAP_IN_MEMORY);
2108 root 1.110
2109     # dirty hack because... archetypes are not yet loaded
2110     Event->timer (
2111     after => 2,
2112     cb => sub {
2113     $_[0]->w->cancel;
2114    
2115     # provide some exits "home"
2116     my $exit = cf::object::new "exit";
2117    
2118     $exit->slaying ($EMERGENCY_POSITION->[0]);
2119     $exit->stats->hp ($EMERGENCY_POSITION->[1]);
2120     $exit->stats->sp ($EMERGENCY_POSITION->[2]);
2121    
2122     $LINK_MAP->insert ($exit->clone, 19, 19);
2123     $LINK_MAP->insert ($exit->clone, 19, 20);
2124     $LINK_MAP->insert ($exit->clone, 19, 21);
2125     $LINK_MAP->insert ($exit->clone, 20, 19);
2126     $LINK_MAP->insert ($exit->clone, 20, 21);
2127     $LINK_MAP->insert ($exit->clone, 21, 19);
2128     $LINK_MAP->insert ($exit->clone, 21, 20);
2129     $LINK_MAP->insert ($exit->clone, 21, 21);
2130    
2131     $exit->destroy;
2132     });
2133    
2134     $LINK_MAP->{deny_save} = 1;
2135     $LINK_MAP->{deny_reset} = 1;
2136    
2137     $cf::MAP{$LINK_MAP->path} = $LINK_MAP;
2138 root 1.108 }
2139    
2140 root 1.85 register "<global>", __PACKAGE__;
2141    
2142 root 1.111 register_command "reload" => sub {
2143 root 1.65 my ($who, $arg) = @_;
2144    
2145     if ($who->flag (FLAG_WIZ)) {
2146 root 1.107 $who->message ("start of reload.");
2147 root 1.111 reload;
2148 root 1.107 $who->message ("end of reload.");
2149 root 1.65 }
2150     };
2151    
2152 root 1.27 unshift @INC, $LIBDIR;
2153 root 1.17
2154 root 1.35 $TICK_WATCHER = Event->timer (
2155 root 1.104 reentrant => 0,
2156     prio => 0,
2157     at => $NEXT_TICK || $TICK,
2158     data => WF_AUTOCANCEL,
2159     cb => sub {
2160 root 1.103 unless ($FREEZE) {
2161     cf::server_tick; # one server iteration
2162     $RUNTIME += $TICK;
2163     }
2164 root 1.35
2165     $NEXT_TICK += $TICK;
2166    
2167 root 1.78 # if we are delayed by four ticks or more, skip them all
2168 root 1.103 $NEXT_TICK = Event::time if Event::time >= $NEXT_TICK + $TICK * 4;
2169 root 1.35
2170     $TICK_WATCHER->at ($NEXT_TICK);
2171     $TICK_WATCHER->start;
2172     },
2173     );
2174    
2175 root 1.80 IO::AIO::max_poll_time $TICK * 0.2;
2176 root 1.77
2177 root 1.108 Event->io (
2178     fd => IO::AIO::poll_fileno,
2179     poll => 'r',
2180     prio => 5,
2181     data => WF_AUTOCANCEL,
2182     cb => \&IO::AIO::poll_cb,
2183     );
2184    
2185     Event->timer (
2186     data => WF_AUTOCANCEL,
2187     after => 0,
2188     interval => 10,
2189     cb => sub {
2190     (Coro::unblock_sub {
2191     write_runtime
2192     or warn "ERROR: unable to write runtime file: $!";
2193     })->();
2194     },
2195     );
2196 root 1.103
2197 root 1.125 END { cf::emergency_save }
2198    
2199 root 1.1 1
2200