ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/lib/cf.pm
Revision: 1.134
Committed: Thu Jan 4 17:28:49 2007 UTC (17 years, 4 months ago) by root
Branch: MAIN
Changes since 1.133: +8 -0 lines
Log Message:
add some cede's strategically, tune

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