ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/lib/cf.pm
Revision: 1.262
Committed: Sat Apr 28 05:55:55 2007 UTC (17 years ago) by root
Branch: MAIN
Changes since 1.261: +31 -20 lines
Log Message:
reset (some) signal handlers to default after fork, limit the number of concurrent async backtraces

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.250 use Socket;
9 root 1.6 use Storable;
10 root 1.224 use Event;
11 root 1.23 use Opcode;
12     use Safe;
13     use Safe::Hole;
14 root 1.19
15 root 1.244 use Coro 3.61 ();
16 root 1.224 use Coro::State;
17 root 1.250 use Coro::Handle;
18 root 1.96 use Coro::Event;
19     use Coro::Timer;
20     use Coro::Signal;
21     use Coro::Semaphore;
22 root 1.105 use Coro::AIO;
23 root 1.237 use Coro::Storable;
24 root 1.96
25 root 1.206 use BDB ();
26 root 1.154 use Data::Dumper;
27 root 1.108 use Digest::MD5;
28 root 1.105 use Fcntl;
29 root 1.227 use YAML::Syck ();
30 root 1.145 use IO::AIO 2.32 ();
31 root 1.32 use Time::HiRes;
32 root 1.208 use Compress::LZF;
33    
34 root 1.227 # configure various modules to our taste
35     #
36 root 1.237 $Storable::canonical = 1; # reduce rsync transfers
37 root 1.224 Coro::State::cctx_stacksize 256000; # 1-2MB stack, for deep recursions in maze generator
38 root 1.208 Compress::LZF::sfreeze_cr { }; # prime Compress::LZF so it does not use require later
39 root 1.227
40 root 1.224 $Event::Eval = 1; # no idea why this is required, but it is
41 root 1.1
42 root 1.72 # work around bug in YAML::Syck - bad news for perl6, will it be as broken wrt. unicode?
43     $YAML::Syck::ImplicitUnicode = 1;
44    
45 root 1.139 $Coro::main->prio (Coro::PRIO_MAX); # run main coroutine ("the server") with very high priority
46 root 1.1
47 root 1.227 sub WF_AUTOCANCEL () { 1 } # automatically cancel this watcher on reload
48    
49 root 1.85 our %COMMAND = ();
50     our %COMMAND_TIME = ();
51 root 1.159
52     our @EXTS = (); # list of extension package names
53 root 1.85 our %EXTCMD = ();
54 root 1.159 our %EXT_CORO = (); # coroutines bound to extensions
55 root 1.161 our %EXT_MAP = (); # pluggable maps
56 root 1.85
57 root 1.223 our $RELOAD; # number of reloads so far
58 root 1.1 our @EVENT;
59 root 1.253
60     our $CONFDIR = confdir;
61     our $DATADIR = datadir;
62     our $LIBDIR = "$DATADIR/ext";
63     our $PODDIR = "$DATADIR/pod";
64     our $MAPDIR = "$DATADIR/" . mapdir;
65     our $LOCALDIR = localdir;
66     our $TMPDIR = "$LOCALDIR/" . tmpdir;
67     our $UNIQUEDIR = "$LOCALDIR/" . uniquedir;
68     our $PLAYERDIR = "$LOCALDIR/" . playerdir;
69     our $RANDOMDIR = "$LOCALDIR/random";
70     our $BDBDIR = "$LOCALDIR/db";
71 root 1.1
72 root 1.245 our $TICK = MAX_TIME * 1e-6; # this is a CONSTANT(!)
73 root 1.35 our $TICK_WATCHER;
74 root 1.168 our $AIO_POLL_WATCHER;
75 root 1.214 our $NEXT_RUNTIME_WRITE; # when should the runtime file be written
76 root 1.35 our $NEXT_TICK;
77 root 1.103 our $NOW;
78 root 1.205 our $USE_FSYNC = 1; # use fsync to write maps - default off
79 root 1.35
80 root 1.206 our $BDB_POLL_WATCHER;
81     our $DB_ENV;
82    
83 root 1.70 our %CFG;
84    
85 root 1.84 our $UPTIME; $UPTIME ||= time;
86 root 1.103 our $RUNTIME;
87    
88 root 1.143 our %PLAYER; # all users
89     our %MAP; # all maps
90 root 1.166 our $LINK_MAP; # the special {link} map, which is always available
91 root 1.103
92 root 1.166 # used to convert map paths into valid unix filenames by replacing / by ∕
93     our $PATH_SEP = "∕"; # U+2215, chosen purely for visual reasons
94    
95 root 1.103 binmode STDOUT;
96     binmode STDERR;
97    
98     # read virtual server time, if available
99 root 1.253 unless ($RUNTIME || !-e "$LOCALDIR/runtime") {
100     open my $fh, "<", "$LOCALDIR/runtime"
101 root 1.103 or die "unable to read runtime file: $!";
102     $RUNTIME = <$fh> + 0.;
103     }
104    
105 root 1.253 mkdir $_
106     for $LOCALDIR, $TMPDIR, $UNIQUEDIR, $PLAYERDIR, $RANDOMDIR, $BDBDIR;
107 root 1.103
108 root 1.131 our $EMERGENCY_POSITION;
109 root 1.110
110 root 1.199 sub cf::map::normalise;
111    
112 root 1.70 #############################################################################
113    
114     =head2 GLOBAL VARIABLES
115    
116     =over 4
117    
118 root 1.83 =item $cf::UPTIME
119    
120     The timestamp of the server start (so not actually an uptime).
121    
122 root 1.103 =item $cf::RUNTIME
123    
124     The time this server has run, starts at 0 and is increased by $cf::TICK on
125     every server tick.
126    
127 root 1.253 =item $cf::CONFDIR $cf::DATADIR $cf::LIBDIR $cf::PODDIR
128     $cf::MAPDIR $cf::LOCALDIR $cf::TMPDIR $cf::UNIQUEDIR
129     $cf::PLAYERDIR $cf::RANDOMDIR $cf::BDBDIR
130    
131     Various directories - "/etc", read-only install directory, perl-library
132     directory, pod-directory, read-only maps directory, "/var", "/var/tmp",
133     unique-items directory, player file directory, random maps directory and
134     database environment.
135 root 1.70
136 root 1.103 =item $cf::NOW
137    
138     The time of the last (current) server tick.
139    
140 root 1.70 =item $cf::TICK
141    
142     The interval between server ticks, in seconds.
143    
144     =item %cf::CFG
145    
146     Configuration for the server, loaded from C</etc/crossfire/config>, or
147     from wherever your confdir points to.
148    
149 root 1.239 =item cf::wait_for_tick, cf::wait_for_tick_begin
150 root 1.155
151 root 1.239 These are functions that inhibit the current coroutine one tick. cf::wait_for_tick_begin only
152     returns directly I<after> the tick processing (and consequently, can only wake one process
153     per tick), while cf::wait_for_tick wakes up all waiters after tick processing.
154 root 1.155
155 root 1.70 =back
156    
157     =cut
158    
159 root 1.1 BEGIN {
160     *CORE::GLOBAL::warn = sub {
161     my $msg = join "", @_;
162 root 1.103
163 root 1.1 $msg .= "\n"
164     unless $msg =~ /\n$/;
165    
166 root 1.255 $msg =~ s/([\x00-\x08\x0b-\x1f])/sprintf "\\x%02x", ord $1/ge;
167 root 1.250
168     utf8::encode $msg;
169 root 1.146 LOG llevError, $msg;
170 root 1.1 };
171     }
172    
173 root 1.93 @safe::cf::global::ISA = @cf::global::ISA = 'cf::attachable';
174     @safe::cf::object::ISA = @cf::object::ISA = 'cf::attachable';
175     @safe::cf::player::ISA = @cf::player::ISA = 'cf::attachable';
176     @safe::cf::client::ISA = @cf::client::ISA = 'cf::attachable';
177     @safe::cf::map::ISA = @cf::map::ISA = 'cf::attachable';
178 root 1.41 @safe::cf::object::player::ISA = @cf::object::player::ISA = 'cf::object';
179 root 1.25
180 root 1.41 # we bless all objects into (empty) derived classes to force a method lookup
181 root 1.25 # within the Safe compartment.
182 root 1.86 for my $pkg (qw(
183 root 1.100 cf::global cf::attachable
184 root 1.86 cf::object cf::object::player
185 root 1.89 cf::client cf::player
186 root 1.86 cf::arch cf::living
187     cf::map cf::party cf::region
188     )) {
189 root 1.25 no strict 'refs';
190 root 1.41 @{"safe::$pkg\::wrap::ISA"} = @{"$pkg\::wrap::ISA"} = $pkg;
191 root 1.25 }
192 root 1.1
193 root 1.18 $Event::DIED = sub {
194     warn "error in event callback: @_";
195     };
196    
197 root 1.70 =head2 UTILITY FUNCTIONS
198    
199     =over 4
200    
201 root 1.154 =item dumpval $ref
202    
203 root 1.70 =cut
204 root 1.44
205 root 1.154 sub dumpval {
206     eval {
207     local $SIG{__DIE__};
208     my $d;
209     if (1) {
210     $d = new Data::Dumper([$_[0]], ["*var"]);
211     $d->Terse(1);
212     $d->Indent(2);
213     $d->Quotekeys(0);
214     $d->Useqq(1);
215     #$d->Bless(...);
216     $d->Seen($_[1]) if @_ > 1;
217     $d = $d->Dump();
218     }
219     $d =~ s/([\x00-\x07\x09\x0b\x0c\x0e-\x1f])/sprintf "\\x%02x", ord($1)/ge;
220     $d
221     } || "[unable to dump $_[0]: '$@']";
222     }
223    
224 root 1.227 use JSON::XS qw(to_json from_json); # TODO# replace by JSON::PC once working
225 root 1.44
226 root 1.70 =item $ref = cf::from_json $json
227    
228     Converts a JSON string into the corresponding perl data structure.
229    
230     =item $json = cf::to_json $ref
231    
232     Converts a perl data structure into its JSON representation.
233    
234 root 1.120 =item cf::lock_wait $string
235    
236     Wait until the given lock is available. See cf::lock_acquire.
237    
238     =item my $lock = cf::lock_acquire $string
239    
240     Wait until the given lock is available and then acquires it and returns
241 root 1.135 a Coro::guard object. If the guard object gets destroyed (goes out of scope,
242 root 1.120 for example when the coroutine gets canceled), the lock is automatically
243     returned.
244    
245 root 1.133 Lock names should begin with a unique identifier (for example, cf::map::find
246     uses map_find and cf::map::load uses map_load).
247 root 1.120
248 root 1.253 =item $locked = cf::lock_active $string
249    
250     Return true if the lock is currently active, i.e. somebody has locked it.
251    
252 root 1.120 =cut
253    
254     our %LOCK;
255    
256     sub lock_wait($) {
257     my ($key) = @_;
258    
259     # wait for lock, if any
260     while ($LOCK{$key}) {
261     push @{ $LOCK{$key} }, $Coro::current;
262     Coro::schedule;
263     }
264     }
265    
266     sub lock_acquire($) {
267     my ($key) = @_;
268    
269     # wait, to be sure we are not locked
270     lock_wait $key;
271    
272     $LOCK{$key} = [];
273    
274 root 1.135 Coro::guard {
275 root 1.120 # wake up all waiters, to be on the safe side
276     $_->ready for @{ delete $LOCK{$key} };
277     }
278     }
279    
280 root 1.253 sub lock_active($) {
281     my ($key) = @_;
282    
283     ! ! $LOCK{$key}
284     }
285    
286 root 1.133 sub freeze_mainloop {
287     return unless $TICK_WATCHER->is_active;
288    
289 root 1.168 my $guard = Coro::guard {
290     $TICK_WATCHER->start;
291     };
292 root 1.133 $TICK_WATCHER->stop;
293     $guard
294     }
295    
296 root 1.140 =item cf::async { BLOCK }
297    
298     Currently the same as Coro::async_pool, meaning you cannot use
299     C<on_destroy>, C<join> or other gimmicks on these coroutines. The only
300     thing you are allowed to do is call C<prio> on it.
301    
302     =cut
303    
304     BEGIN { *async = \&Coro::async_pool }
305    
306 root 1.106 =item cf::sync_job { BLOCK }
307    
308     The design of crossfire+ requires that the main coro ($Coro::main) is
309     always able to handle events or runnable, as crossfire+ is only partly
310     reentrant. Thus "blocking" it by e.g. waiting for I/O is not acceptable.
311    
312     If it must be done, put the blocking parts into C<sync_job>. This will run
313     the given BLOCK in another coroutine while waiting for the result. The
314     server will be frozen during this time, so the block should either finish
315     fast or be very important.
316    
317     =cut
318    
319 root 1.105 sub sync_job(&) {
320     my ($job) = @_;
321    
322     if ($Coro::current == $Coro::main) {
323 root 1.112 # this is the main coro, too bad, we have to block
324     # till the operation succeeds, freezing the server :/
325    
326 root 1.110 # TODO: use suspend/resume instead
327 root 1.112 # (but this is cancel-safe)
328 root 1.133 my $freeze_guard = freeze_mainloop;
329 root 1.112
330     my $busy = 1;
331     my @res;
332    
333 root 1.140 (async {
334 root 1.112 @res = eval { $job->() };
335     warn $@ if $@;
336     undef $busy;
337     })->prio (Coro::PRIO_MAX);
338    
339 root 1.105 while ($busy) {
340 root 1.141 Coro::cede or Event::one_event;
341 root 1.105 }
342 root 1.112
343     wantarray ? @res : $res[0]
344 root 1.105 } else {
345 root 1.112 # we are in another coroutine, how wonderful, everything just works
346    
347     $job->()
348 root 1.105 }
349     }
350    
351 root 1.140 =item $coro = cf::async_ext { BLOCK }
352 root 1.103
353 root 1.159 Like async, but this coro is automatically being canceled when the
354 root 1.140 extension calling this is being unloaded.
355 root 1.103
356     =cut
357    
358 root 1.140 sub async_ext(&) {
359 root 1.103 my $cb = shift;
360    
361 root 1.140 my $coro = &Coro::async ($cb);
362 root 1.103
363     $coro->on_destroy (sub {
364     delete $EXT_CORO{$coro+0};
365     });
366     $EXT_CORO{$coro+0} = $coro;
367    
368     $coro
369     }
370    
371 root 1.108 sub write_runtime {
372 root 1.219 my $guard = cf::lock_acquire "write_runtime";
373    
374 root 1.253 my $runtime = "$LOCALDIR/runtime";
375 root 1.108
376     my $fh = aio_open "$runtime~", O_WRONLY | O_CREAT, 0644
377     or return;
378    
379 root 1.186 my $value = $cf::RUNTIME + 90 + 10;
380     # 10 is the runtime save interval, for a monotonic clock
381     # 60 allows for the watchdog to kill the server.
382    
383 root 1.108 (aio_write $fh, 0, (length $value), $value, 0) <= 0
384     and return;
385    
386 root 1.204 # always fsync - this file is important
387 root 1.108 aio_fsync $fh
388     and return;
389    
390     close $fh
391     or return;
392    
393     aio_rename "$runtime~", $runtime
394     and return;
395    
396     1
397     }
398    
399 root 1.230 =item cf::datalog type => key => value, ...
400    
401     Log a datalog packet of the given type with the given key-value pairs.
402    
403     =cut
404    
405     sub datalog($@) {
406     my ($type, %kv) = @_;
407     warn "DATALOG ", JSON::XS->new->ascii->encode ({ %kv, type => $type });
408     }
409    
410 root 1.70 =back
411    
412 root 1.71 =cut
413    
414 root 1.44 #############################################################################
415 root 1.39
416 root 1.93 =head2 ATTACHABLE OBJECTS
417    
418 root 1.94 Many objects in crossfire are so-called attachable objects. That means you can
419     attach callbacks/event handlers (a collection of which is called an "attachment")
420     to it. All such attachable objects support the following methods.
421    
422     In the following description, CLASS can be any of C<global>, C<object>
423     C<player>, C<client> or C<map> (i.e. the attachable objects in
424     crossfire+).
425 root 1.55
426     =over 4
427    
428 root 1.94 =item $attachable->attach ($attachment, key => $value...)
429    
430     =item $attachable->detach ($attachment)
431    
432     Attach/detach a pre-registered attachment to a specific object and give it
433     the specified key/value pairs as arguments.
434    
435     Example, attach a minesweeper attachment to the given object, making it a
436     10x10 minesweeper game:
437 root 1.46
438 root 1.94 $obj->attach (minesweeper => width => 10, height => 10);
439 root 1.53
440 root 1.93 =item $bool = $attachable->attached ($name)
441 root 1.46
442 root 1.93 Checks wether the named attachment is currently attached to the object.
443 root 1.46
444 root 1.94 =item cf::CLASS->attach ...
445 root 1.46
446 root 1.94 =item cf::CLASS->detach ...
447 root 1.92
448 root 1.94 Define an anonymous attachment and attach it to all objects of the given
449     CLASS. See the next function for an explanation of its arguments.
450 root 1.92
451 root 1.93 You can attach to global events by using the C<cf::global> class.
452 root 1.92
453 root 1.94 Example, log all player logins:
454    
455     cf::player->attach (
456     on_login => sub {
457     my ($pl) = @_;
458     ...
459     },
460     );
461    
462     Example, attach to the jeweler skill:
463    
464     cf::object->attach (
465     type => cf::SKILL,
466     subtype => cf::SK_JEWELER,
467     on_use_skill => sub {
468     my ($sk, $ob, $part, $dir, $msg) = @_;
469     ...
470     },
471     );
472    
473     =item cf::CLASS::attachment $name, ...
474    
475     Register an attachment by C<$name> through which attachable objects of the
476     given CLASS can refer to this attachment.
477    
478     Some classes such as crossfire maps and objects can specify attachments
479     that are attached at load/instantiate time, thus the need for a name.
480    
481     These calls expect any number of the following handler/hook descriptions:
482 root 1.46
483     =over 4
484    
485     =item prio => $number
486    
487     Set the priority for all following handlers/hooks (unless overwritten
488     by another C<prio> setting). Lower priority handlers get executed
489     earlier. The default priority is C<0>, and many built-in handlers are
490     registered at priority C<-1000>, so lower priorities should not be used
491     unless you know what you are doing.
492    
493 root 1.93 =item type => $type
494    
495     (Only for C<< cf::object->attach >> calls), limits the attachment to the
496     given type of objects only (the additional parameter C<subtype> can be
497     used to further limit to the given subtype).
498    
499 root 1.46 =item on_I<event> => \&cb
500    
501     Call the given code reference whenever the named event happens (event is
502     something like C<instantiate>, C<apply>, C<use_skill> and so on, and which
503     handlers are recognised generally depends on the type of object these
504     handlers attach to).
505    
506     See F<include/eventinc.h> for the full list of events supported, and their
507     class.
508    
509     =item package => package::
510    
511     Look for sub functions of the name C<< on_I<event> >> in the given
512     package and register them. Only handlers for eevents supported by the
513     object/class are recognised.
514    
515     =back
516    
517 root 1.94 Example, define an attachment called "sockpuppet" that calls the given
518     event handler when a monster attacks:
519    
520     cf::object::attachment sockpuppet =>
521     on_skill_attack => sub {
522     my ($self, $victim) = @_;
523     ...
524     }
525     }
526    
527 root 1.96 =item $attachable->valid
528    
529     Just because you have a perl object does not mean that the corresponding
530     C-level object still exists. If you try to access an object that has no
531     valid C counterpart anymore you get an exception at runtime. This method
532     can be used to test for existence of the C object part without causing an
533     exception.
534    
535 root 1.39 =cut
536    
537 root 1.40 # the following variables are defined in .xs and must not be re-created
538 root 1.100 our @CB_GLOBAL = (); # registry for all global events
539     our @CB_ATTACHABLE = (); # registry for all attachables
540     our @CB_OBJECT = (); # all objects (should not be used except in emergency)
541     our @CB_PLAYER = ();
542     our @CB_CLIENT = ();
543     our @CB_TYPE = (); # registry for type (cf-object class) based events
544     our @CB_MAP = ();
545 root 1.39
546 root 1.45 my %attachment;
547    
548 root 1.170 sub cf::attachable::thawer_merge {
549     # simply override everything except _meta
550     local $_[0]{_meta};
551     %{$_[0]} = %{$_[1]};
552     }
553    
554 root 1.93 sub _attach_cb($$$$) {
555     my ($registry, $event, $prio, $cb) = @_;
556 root 1.39
557     use sort 'stable';
558    
559     $cb = [$prio, $cb];
560    
561     @{$registry->[$event]} = sort
562     { $a->[0] cmp $b->[0] }
563     @{$registry->[$event] || []}, $cb;
564     }
565    
566 root 1.100 # hack
567     my %attachable_klass = map +($_ => 1), KLASS_OBJECT, KLASS_CLIENT, KLASS_PLAYER, KLASS_MAP;
568    
569 root 1.39 # attach handles attaching event callbacks
570     # the only thing the caller has to do is pass the correct
571     # registry (== where the callback attaches to).
572 root 1.93 sub _attach {
573 root 1.45 my ($registry, $klass, @arg) = @_;
574 root 1.39
575 root 1.93 my $object_type;
576 root 1.39 my $prio = 0;
577     my %cb_id = map +("on_" . lc $EVENT[$_][0], $_) , grep $EVENT[$_][1] == $klass, 0 .. $#EVENT;
578    
579 root 1.100 #TODO: get rid of this hack
580     if ($attachable_klass{$klass}) {
581     %cb_id = (%cb_id, map +("on_" . lc $EVENT[$_][0], $_) , grep $EVENT[$_][1] == KLASS_ATTACHABLE, 0 .. $#EVENT);
582     }
583    
584 root 1.45 while (@arg) {
585     my $type = shift @arg;
586 root 1.39
587     if ($type eq "prio") {
588 root 1.45 $prio = shift @arg;
589 root 1.39
590 root 1.93 } elsif ($type eq "type") {
591     $object_type = shift @arg;
592     $registry = $CB_TYPE[$object_type] ||= [];
593    
594     } elsif ($type eq "subtype") {
595     defined $object_type or Carp::croak "subtype specified without type";
596     my $object_subtype = shift @arg;
597     $registry = $CB_TYPE[$object_type + $object_subtype * NUM_SUBTYPES] ||= [];
598    
599 root 1.39 } elsif ($type eq "package") {
600 root 1.45 my $pkg = shift @arg;
601 root 1.39
602     while (my ($name, $id) = each %cb_id) {
603     if (my $cb = $pkg->can ($name)) {
604 root 1.93 _attach_cb $registry, $id, $prio, $cb;
605 root 1.39 }
606     }
607    
608     } elsif (exists $cb_id{$type}) {
609 root 1.93 _attach_cb $registry, $cb_id{$type}, $prio, shift @arg;
610 root 1.39
611     } elsif (ref $type) {
612     warn "attaching objects not supported, ignoring.\n";
613    
614     } else {
615 root 1.45 shift @arg;
616 root 1.39 warn "attach argument '$type' not supported, ignoring.\n";
617     }
618     }
619     }
620    
621 root 1.93 sub _object_attach {
622 root 1.48 my ($obj, $name, %arg) = @_;
623 root 1.46
624 root 1.55 return if exists $obj->{_attachment}{$name};
625    
626 root 1.46 if (my $attach = $attachment{$name}) {
627     my $registry = $obj->registry;
628    
629 root 1.47 for (@$attach) {
630     my ($klass, @attach) = @$_;
631 root 1.93 _attach $registry, $klass, @attach;
632 root 1.47 }
633 root 1.46
634 root 1.48 $obj->{$name} = \%arg;
635 root 1.46 } else {
636     warn "object uses attachment '$name' that is not available, postponing.\n";
637     }
638    
639 root 1.50 $obj->{_attachment}{$name} = undef;
640 root 1.46 }
641    
642 root 1.93 sub cf::attachable::attach {
643     if (ref $_[0]) {
644     _object_attach @_;
645     } else {
646     _attach shift->_attach_registry, @_;
647     }
648 root 1.55 };
649 root 1.46
650 root 1.54 # all those should be optimised
651 root 1.93 sub cf::attachable::detach {
652 root 1.54 my ($obj, $name) = @_;
653 root 1.46
654 root 1.93 if (ref $obj) {
655     delete $obj->{_attachment}{$name};
656     reattach ($obj);
657     } else {
658     Carp::croak "cannot, currently, detach class attachments";
659     }
660 root 1.55 };
661    
662 root 1.93 sub cf::attachable::attached {
663 root 1.55 my ($obj, $name) = @_;
664    
665     exists $obj->{_attachment}{$name}
666 root 1.39 }
667    
668 root 1.100 for my $klass (qw(ATTACHABLE GLOBAL OBJECT PLAYER CLIENT MAP)) {
669 root 1.93 eval "#line " . __LINE__ . " 'cf.pm'
670     sub cf::\L$klass\E::_attach_registry {
671     (\\\@CB_$klass, KLASS_$klass)
672     }
673 root 1.45
674 root 1.93 sub cf::\L$klass\E::attachment {
675     my \$name = shift;
676 root 1.39
677 root 1.93 \$attachment{\$name} = [[KLASS_$klass, \@_]];
678     }
679     ";
680     die if $@;
681 root 1.52 }
682    
683 root 1.39 our $override;
684 root 1.45 our @invoke_results = (); # referenced from .xs code. TODO: play tricks with reify and mortals?
685 root 1.39
686 root 1.45 sub override {
687     $override = 1;
688     @invoke_results = ();
689 root 1.39 }
690    
691 root 1.45 sub do_invoke {
692 root 1.39 my $event = shift;
693 root 1.40 my $callbacks = shift;
694 root 1.39
695 root 1.45 @invoke_results = ();
696    
697 root 1.39 local $override;
698    
699 root 1.40 for (@$callbacks) {
700 root 1.39 eval { &{$_->[1]} };
701    
702     if ($@) {
703     warn "$@";
704 root 1.64 warn "... while processing $EVENT[$event][0](@_) event, skipping processing altogether.\n";
705 root 1.39 override;
706     }
707    
708     return 1 if $override;
709     }
710    
711     0
712     }
713    
714 root 1.96 =item $bool = cf::global::invoke (EVENT_CLASS_XXX, ...)
715 root 1.55
716 root 1.96 =item $bool = $attachable->invoke (EVENT_CLASS_XXX, ...)
717 root 1.55
718 root 1.96 Generate an object-specific event with the given arguments.
719 root 1.55
720 root 1.96 This API is preliminary (most likely, the EVENT_CLASS_xxx prefix will be
721 root 1.55 removed in future versions), and there is no public API to access override
722     results (if you must, access C<@cf::invoke_results> directly).
723    
724     =back
725    
726 root 1.71 =cut
727    
728 root 1.70 #############################################################################
729 root 1.45 # object support
730    
731 root 1.102 sub reattach {
732     # basically do the same as instantiate, without calling instantiate
733     my ($obj) = @_;
734    
735 root 1.169 bless $obj, ref $obj; # re-bless in case extensions have been reloaded
736    
737 root 1.102 my $registry = $obj->registry;
738    
739     @$registry = ();
740    
741     delete $obj->{_attachment} unless scalar keys %{ $obj->{_attachment} || {} };
742    
743     for my $name (keys %{ $obj->{_attachment} || {} }) {
744     if (my $attach = $attachment{$name}) {
745     for (@$attach) {
746     my ($klass, @attach) = @$_;
747     _attach $registry, $klass, @attach;
748     }
749     } else {
750     warn "object uses attachment '$name' that is not available, postponing.\n";
751     }
752     }
753     }
754    
755 root 1.100 cf::attachable->attach (
756     prio => -1000000,
757     on_instantiate => sub {
758     my ($obj, $data) = @_;
759 root 1.45
760 root 1.100 $data = from_json $data;
761 root 1.45
762 root 1.100 for (@$data) {
763     my ($name, $args) = @$_;
764 root 1.49
765 root 1.100 $obj->attach ($name, %{$args || {} });
766     }
767     },
768 root 1.102 on_reattach => \&reattach,
769 root 1.100 on_clone => sub {
770     my ($src, $dst) = @_;
771    
772     @{$dst->registry} = @{$src->registry};
773    
774     %$dst = %$src;
775    
776     %{$dst->{_attachment}} = %{$src->{_attachment}}
777     if exists $src->{_attachment};
778     },
779     );
780 root 1.45
781 root 1.46 sub object_freezer_save {
782 root 1.59 my ($filename, $rdata, $objs) = @_;
783 root 1.46
784 root 1.105 sync_job {
785     if (length $$rdata) {
786     warn sprintf "saving %s (%d,%d)\n",
787     $filename, length $$rdata, scalar @$objs;
788 root 1.60
789 root 1.105 if (my $fh = aio_open "$filename~", O_WRONLY | O_CREAT, 0600) {
790 root 1.60 chmod SAVE_MODE, $fh;
791 root 1.105 aio_write $fh, 0, (length $$rdata), $$rdata, 0;
792 root 1.204 aio_fsync $fh if $cf::USE_FSYNC;
793 root 1.60 close $fh;
794 root 1.105
795     if (@$objs) {
796     if (my $fh = aio_open "$filename.pst~", O_WRONLY | O_CREAT, 0600) {
797     chmod SAVE_MODE, $fh;
798     my $data = Storable::nfreeze { version => 1, objs => $objs };
799     aio_write $fh, 0, (length $data), $data, 0;
800 root 1.204 aio_fsync $fh if $cf::USE_FSYNC;
801 root 1.105 close $fh;
802     aio_rename "$filename.pst~", "$filename.pst";
803     }
804     } else {
805     aio_unlink "$filename.pst";
806     }
807    
808     aio_rename "$filename~", $filename;
809 root 1.60 } else {
810 root 1.105 warn "FATAL: $filename~: $!\n";
811 root 1.60 }
812 root 1.59 } else {
813 root 1.105 aio_unlink $filename;
814     aio_unlink "$filename.pst";
815 root 1.59 }
816 root 1.45 }
817     }
818    
819 root 1.80 sub object_freezer_as_string {
820     my ($rdata, $objs) = @_;
821    
822     use Data::Dumper;
823    
824 root 1.81 $$rdata . Dumper $objs
825 root 1.80 }
826    
827 root 1.46 sub object_thawer_load {
828     my ($filename) = @_;
829    
830 root 1.105 my ($data, $av);
831 root 1.61
832 root 1.105 (aio_load $filename, $data) >= 0
833     or return;
834 root 1.61
835 root 1.105 unless (aio_stat "$filename.pst") {
836     (aio_load "$filename.pst", $av) >= 0
837     or return;
838 root 1.113 $av = eval { (Storable::thaw $av)->{objs} };
839 root 1.61 }
840 root 1.45
841 root 1.118 warn sprintf "loading %s (%d)\n",
842     $filename, length $data, scalar @{$av || []};#d#
843 root 1.105 return ($data, $av);
844 root 1.45 }
845    
846     #############################################################################
847 root 1.85 # command handling &c
848 root 1.39
849 root 1.85 =item cf::register_command $name => \&callback($ob,$args);
850 root 1.1
851 root 1.85 Register a callback for execution when the client sends the user command
852     $name.
853 root 1.5
854 root 1.85 =cut
855 root 1.5
856 root 1.85 sub register_command {
857     my ($name, $cb) = @_;
858 root 1.5
859 root 1.85 my $caller = caller;
860     #warn "registering command '$name/$time' to '$caller'";
861 root 1.1
862 root 1.85 push @{ $COMMAND{$name} }, [$caller, $cb];
863 root 1.1 }
864    
865 root 1.85 =item cf::register_extcmd $name => \&callback($pl,$packet);
866 root 1.1
867 root 1.85 Register a callbackf ro execution when the client sends an extcmd packet.
868 root 1.1
869 root 1.85 If the callback returns something, it is sent back as if reply was being
870     called.
871 root 1.1
872 root 1.85 =cut
873 root 1.1
874 root 1.16 sub register_extcmd {
875     my ($name, $cb) = @_;
876    
877 root 1.159 $EXTCMD{$name} = $cb;
878 root 1.16 }
879    
880 root 1.93 cf::player->attach (
881 root 1.85 on_command => sub {
882     my ($pl, $name, $params) = @_;
883    
884     my $cb = $COMMAND{$name}
885     or return;
886    
887     for my $cmd (@$cb) {
888     $cmd->[1]->($pl->ob, $params);
889     }
890    
891     cf::override;
892     },
893     on_extcmd => sub {
894     my ($pl, $buf) = @_;
895    
896     my $msg = eval { from_json $buf };
897    
898     if (ref $msg) {
899     if (my $cb = $EXTCMD{$msg->{msgtype}}) {
900 root 1.159 if (my %reply = $cb->($pl, $msg)) {
901 root 1.85 $pl->ext_reply ($msg->{msgid}, %reply);
902     }
903     }
904     } else {
905     warn "player " . ($pl->ob->name) . " sent unparseable ext message: <$buf>\n";
906     }
907    
908     cf::override;
909     },
910 root 1.93 );
911 root 1.85
912 root 1.1 sub load_extension {
913     my ($path) = @_;
914    
915     $path =~ /([^\/\\]+)\.ext$/ or die "$path";
916 root 1.5 my $base = $1;
917 root 1.1 my $pkg = $1;
918     $pkg =~ s/[^[:word:]]/_/g;
919 root 1.41 $pkg = "ext::$pkg";
920 root 1.1
921 root 1.160 warn "... loading '$path' into '$pkg'\n";
922 root 1.1
923     open my $fh, "<:utf8", $path
924     or die "$path: $!";
925    
926     my $source =
927     "package $pkg; use strict; use utf8;\n"
928     . "#line 1 \"$path\"\n{\n"
929     . (do { local $/; <$fh> })
930     . "\n};\n1";
931    
932 root 1.166 unless (eval $source) {
933     my $msg = $@ ? "$path: $@\n"
934     : "extension disabled.\n";
935     if ($source =~ /^#!.*perl.*#.*MANDATORY/m) { # ugly match
936     warn $@;
937     warn "mandatory extension failed to load, exiting.\n";
938     exit 1;
939     }
940     die $@;
941     }
942 root 1.1
943 root 1.159 push @EXTS, $pkg;
944 root 1.1 }
945    
946     sub load_extensions {
947     for my $ext (<$LIBDIR/*.ext>) {
948 root 1.3 next unless -r $ext;
949 root 1.2 eval {
950     load_extension $ext;
951     1
952     } or warn "$ext not loaded: $@";
953 root 1.1 }
954     }
955    
956 root 1.8 #############################################################################
957 root 1.70
958     =head2 CORE EXTENSIONS
959    
960     Functions and methods that extend core crossfire objects.
961    
962 root 1.143 =cut
963    
964     package cf::player;
965    
966 root 1.154 use Coro::AIO;
967    
968 root 1.95 =head3 cf::player
969    
970 root 1.70 =over 4
971 root 1.22
972 root 1.143 =item cf::player::find $login
973 root 1.23
974 root 1.143 Returns the given player object, loading it if necessary (might block).
975 root 1.23
976     =cut
977    
978 root 1.145 sub playerdir($) {
979 root 1.253 "$PLAYERDIR/"
980 root 1.145 . (ref $_[0] ? $_[0]->ob->name : $_[0])
981     }
982    
983 root 1.143 sub path($) {
984 root 1.145 my $login = ref $_[0] ? $_[0]->ob->name : $_[0];
985    
986 root 1.234 (playerdir $login) . "/playerdata"
987 root 1.143 }
988    
989     sub find_active($) {
990     $cf::PLAYER{$_[0]}
991     and $cf::PLAYER{$_[0]}->active
992     and $cf::PLAYER{$_[0]}
993     }
994    
995     sub exists($) {
996     my ($login) = @_;
997    
998     $cf::PLAYER{$login}
999 root 1.180 or cf::sync_job { !aio_stat path $login }
1000 root 1.143 }
1001    
1002     sub find($) {
1003     return $cf::PLAYER{$_[0]} || do {
1004     my $login = $_[0];
1005    
1006     my $guard = cf::lock_acquire "user_find:$login";
1007    
1008 root 1.151 $cf::PLAYER{$_[0]} || do {
1009 root 1.234 # rename old playerfiles to new ones
1010     #TODO: remove when no longer required
1011     aio_link +(playerdir $login) . "/$login.pl.pst", (playerdir $login) . "/playerdata.pst";
1012     aio_link +(playerdir $login) . "/$login.pl" , (playerdir $login) . "/playerdata";
1013     aio_unlink +(playerdir $login) . "/$login.pl.pst";
1014     aio_unlink +(playerdir $login) . "/$login.pl";
1015    
1016 root 1.151 my $pl = load_pl path $login
1017     or return;
1018     $cf::PLAYER{$login} = $pl
1019     }
1020     }
1021 root 1.143 }
1022    
1023     sub save($) {
1024     my ($pl) = @_;
1025    
1026     return if $pl->{deny_save};
1027    
1028     my $path = path $pl;
1029     my $guard = cf::lock_acquire "user_save:$path";
1030    
1031     return if $pl->{deny_save};
1032 root 1.146
1033 root 1.154 aio_mkdir playerdir $pl, 0770;
1034 root 1.143 $pl->{last_save} = $cf::RUNTIME;
1035    
1036     $pl->save_pl ($path);
1037     Coro::cede;
1038     }
1039    
1040     sub new($) {
1041     my ($login) = @_;
1042    
1043     my $self = create;
1044    
1045     $self->ob->name ($login);
1046     $self->{deny_save} = 1;
1047    
1048     $cf::PLAYER{$login} = $self;
1049    
1050     $self
1051 root 1.23 }
1052    
1053 root 1.154 =item $pl->quit_character
1054    
1055     Nukes the player without looking back. If logged in, the connection will
1056     be destroyed. May block for a long time.
1057    
1058     =cut
1059    
1060 root 1.145 sub quit_character {
1061     my ($pl) = @_;
1062    
1063 root 1.220 my $name = $pl->ob->name;
1064    
1065 root 1.145 $pl->{deny_save} = 1;
1066     $pl->password ("*"); # this should lock out the player until we nuked the dir
1067    
1068     $pl->invoke (cf::EVENT_PLAYER_LOGOUT, 1) if $pl->active;
1069     $pl->deactivate;
1070     $pl->invoke (cf::EVENT_PLAYER_QUIT);
1071     $pl->ns->destroy if $pl->ns;
1072    
1073     my $path = playerdir $pl;
1074     my $temp = "$path~$cf::RUNTIME~deleting~";
1075 root 1.154 aio_rename $path, $temp;
1076 root 1.150 delete $cf::PLAYER{$pl->ob->name};
1077     $pl->destroy;
1078 root 1.220
1079     my $prefix = qr<^~\Q$name\E/>;
1080    
1081     # nuke player maps
1082     $cf::MAP{$_}->nuke for grep /$prefix/, keys %cf::MAP;
1083    
1084 root 1.150 IO::AIO::aio_rmtree $temp;
1085 root 1.145 }
1086    
1087 pippijn 1.221 =item $pl->kick
1088    
1089     Kicks a player out of the game. This destroys the connection.
1090    
1091     =cut
1092    
1093     sub kick {
1094     my ($pl, $kicker) = @_;
1095    
1096     $pl->invoke (cf::EVENT_PLAYER_KICK, $kicker);
1097     $pl->killer ("kicked");
1098     $pl->ns->destroy;
1099     }
1100    
1101 root 1.154 =item cf::player::list_logins
1102    
1103     Returns am arrayref of all valid playernames in the system, can take a
1104     while and may block, so not sync_job-capable, ever.
1105    
1106     =cut
1107    
1108     sub list_logins {
1109 root 1.253 my $dirs = aio_readdir $PLAYERDIR
1110 root 1.154 or return [];
1111    
1112     my @logins;
1113    
1114     for my $login (@$dirs) {
1115     my $fh = aio_open path $login, Fcntl::O_RDONLY, 0 or next;
1116     aio_read $fh, 0, 512, my $buf, 0 or next;
1117 root 1.155 $buf !~ /^password -------------$/m or next; # official not-valid tag
1118 root 1.154
1119     utf8::decode $login;
1120     push @logins, $login;
1121     }
1122    
1123     \@logins
1124     }
1125    
1126     =item $player->maps
1127    
1128 root 1.166 Returns an arrayref of map paths that are private for this
1129 root 1.154 player. May block.
1130    
1131     =cut
1132    
1133     sub maps($) {
1134     my ($pl) = @_;
1135    
1136 root 1.201 $pl = ref $pl ? $pl->ob->name : $pl;
1137    
1138 root 1.154 my $files = aio_readdir playerdir $pl
1139     or return;
1140    
1141     my @paths;
1142    
1143     for (@$files) {
1144     utf8::decode $_;
1145     next if /\.(?:pl|pst)$/;
1146 root 1.158 next unless /^$PATH_SEP/o;
1147 root 1.154
1148 root 1.201 push @paths, cf::map::normalise "~$pl/$_";
1149 root 1.154 }
1150    
1151     \@paths
1152     }
1153    
1154 root 1.231 =item $player->ext_reply ($msgid, %msg)
1155 root 1.95
1156     Sends an ext reply to the player.
1157    
1158     =cut
1159    
1160 root 1.231 sub ext_reply($$%) {
1161 root 1.95 my ($self, $id, %msg) = @_;
1162    
1163     $msg{msgid} = $id;
1164    
1165 root 1.143 $self->send ("ext " . cf::to_json \%msg);
1166 root 1.95 }
1167    
1168 root 1.231 =item $player->ext_event ($type, %msg)
1169    
1170     Sends an ext event to the client.
1171    
1172     =cut
1173    
1174     sub ext_event($$%) {
1175     my ($self, $type, %msg) = @_;
1176    
1177 root 1.232 $self->ns->ext_event ($type, %msg);
1178 root 1.231 }
1179    
1180 root 1.238 =head3 cf::region
1181    
1182     =over 4
1183    
1184     =cut
1185    
1186     package cf::region;
1187    
1188     =item cf::region::find_by_path $path
1189    
1190     Tries to decuce the probable region for a map knowing only its path.
1191    
1192     =cut
1193    
1194     sub find_by_path($) {
1195     my ($path) = @_;
1196    
1197     my ($match, $specificity);
1198    
1199     for my $region (list) {
1200     if ($region->match && $path =~ $region->match) {
1201     ($match, $specificity) = ($region, $region->specificity)
1202     if $region->specificity > $specificity;
1203     }
1204     }
1205    
1206     $match
1207     }
1208 root 1.143
1209 root 1.95 =back
1210    
1211 root 1.110 =head3 cf::map
1212    
1213     =over 4
1214    
1215     =cut
1216    
1217     package cf::map;
1218    
1219     use Fcntl;
1220     use Coro::AIO;
1221    
1222 root 1.166 use overload
1223 root 1.173 '""' => \&as_string,
1224     fallback => 1;
1225 root 1.166
1226 root 1.133 our $MAX_RESET = 3600;
1227     our $DEFAULT_RESET = 3000;
1228 root 1.110
1229     sub generate_random_map {
1230 root 1.166 my ($self, $rmp) = @_;
1231 root 1.110 # mit "rum" bekleckern, nicht
1232 root 1.166 $self->_create_random_map (
1233 root 1.110 $rmp->{wallstyle}, $rmp->{wall_name}, $rmp->{floorstyle}, $rmp->{monsterstyle},
1234     $rmp->{treasurestyle}, $rmp->{layoutstyle}, $rmp->{doorstyle}, $rmp->{decorstyle},
1235     $rmp->{origin_map}, $rmp->{final_map}, $rmp->{exitstyle}, $rmp->{this_map},
1236     $rmp->{exit_on_final_map},
1237     $rmp->{xsize}, $rmp->{ysize},
1238     $rmp->{expand2x}, $rmp->{layoutoptions1}, $rmp->{layoutoptions2}, $rmp->{layoutoptions3},
1239     $rmp->{symmetry}, $rmp->{difficulty}, $rmp->{difficulty_given}, $rmp->{difficulty_increase},
1240     $rmp->{dungeon_level}, $rmp->{dungeon_depth}, $rmp->{decoroptions}, $rmp->{orientation},
1241     $rmp->{origin_y}, $rmp->{origin_x}, $rmp->{random_seed}, $rmp->{total_map_hp},
1242     $rmp->{map_layout_style}, $rmp->{treasureoptions}, $rmp->{symmetry_used},
1243 root 1.162 (cf::region::find $rmp->{region}), $rmp->{custom}
1244     )
1245 root 1.110 }
1246    
1247 root 1.187 =item cf::map->register ($regex, $prio)
1248    
1249     Register a handler for the map path matching the given regex at the
1250     givne priority (higher is better, built-in handlers have priority 0, the
1251     default).
1252    
1253     =cut
1254    
1255 root 1.166 sub register {
1256 root 1.187 my (undef, $regex, $prio) = @_;
1257 root 1.166 my $pkg = caller;
1258    
1259     no strict;
1260     push @{"$pkg\::ISA"}, __PACKAGE__;
1261    
1262 root 1.187 $EXT_MAP{$pkg} = [$prio, qr<$regex>];
1263 root 1.166 }
1264    
1265     # also paths starting with '/'
1266 root 1.187 $EXT_MAP{"cf::map"} = [0, qr{^(?=/)}];
1267 root 1.166
1268 root 1.170 sub thawer_merge {
1269 root 1.172 my ($self, $merge) = @_;
1270    
1271 root 1.170 # we have to keep some variables in memory intact
1272 root 1.172 local $self->{path};
1273     local $self->{load_path};
1274     local $self->{deny_save};
1275     local $self->{deny_reset};
1276 root 1.170
1277 root 1.172 $self->SUPER::thawer_merge ($merge);
1278 root 1.170 }
1279    
1280 root 1.166 sub normalise {
1281     my ($path, $base) = @_;
1282    
1283 root 1.192 $path = "$path"; # make sure its a string
1284    
1285 root 1.199 $path =~ s/\.map$//;
1286    
1287 root 1.166 # map plan:
1288     #
1289     # /! non-realised random map exit (special hack!)
1290     # {... are special paths that are not being touched
1291     # ?xxx/... are special absolute paths
1292     # ?random/... random maps
1293     # /... normal maps
1294     # ~user/... per-player map of a specific user
1295    
1296     $path =~ s/$PATH_SEP/\//go;
1297    
1298     # treat it as relative path if it starts with
1299     # something that looks reasonable
1300     if ($path =~ m{^(?:\./|\.\./|\w)}) {
1301     $base or Carp::carp "normalise called with relative path and no base: '$path'";
1302    
1303     $base =~ s{[^/]+/?$}{};
1304     $path = "$base/$path";
1305     }
1306    
1307     for ($path) {
1308     redo if s{//}{/};
1309     redo if s{/\.?/}{/};
1310     redo if s{/[^/]+/\.\./}{/};
1311     }
1312    
1313     $path
1314     }
1315    
1316     sub new_from_path {
1317     my (undef, $path, $base) = @_;
1318    
1319     return $path if UNIVERSAL::isa $path, "cf::map"; # already a map object
1320    
1321     $path = normalise $path, $base;
1322    
1323 root 1.187 for my $pkg (sort { $EXT_MAP{$b}[0] <=> $EXT_MAP{$a}[0] } keys %EXT_MAP) {
1324     if ($path =~ $EXT_MAP{$pkg}[1]) {
1325 root 1.166 my $self = bless cf::map::new, $pkg;
1326     $self->{path} = $path; $self->path ($path);
1327     $self->init; # pass $1 etc.
1328     return $self;
1329     }
1330     }
1331    
1332 root 1.192 Carp::carp "unable to resolve path '$path' (base '$base').";
1333 root 1.166 ()
1334     }
1335    
1336     sub init {
1337     my ($self) = @_;
1338    
1339     $self
1340     }
1341    
1342     sub as_string {
1343     my ($self) = @_;
1344    
1345     "$self->{path}"
1346     }
1347    
1348     # the displayed name, this is a one way mapping
1349     sub visible_name {
1350     &as_string
1351     }
1352    
1353     # the original (read-only) location
1354     sub load_path {
1355     my ($self) = @_;
1356    
1357 root 1.254 "$MAPDIR/$self->{path}.map"
1358 root 1.166 }
1359    
1360     # the temporary/swap location
1361     sub save_path {
1362     my ($self) = @_;
1363    
1364 root 1.167 (my $path = $_[0]{path}) =~ s/\//$PATH_SEP/g;
1365 root 1.254 "$TMPDIR/$path.map"
1366 root 1.166 }
1367    
1368     # the unique path, undef == no special unique path
1369     sub uniq_path {
1370     my ($self) = @_;
1371    
1372 root 1.167 (my $path = $_[0]{path}) =~ s/\//$PATH_SEP/g;
1373 root 1.253 "$UNIQUEDIR/$path"
1374 root 1.166 }
1375    
1376 root 1.110 # and all this just because we cannot iterate over
1377     # all maps in C++...
1378     sub change_all_map_light {
1379     my ($change) = @_;
1380    
1381 root 1.122 $_->change_map_light ($change)
1382     for grep $_->outdoor, values %cf::MAP;
1383 root 1.110 }
1384    
1385 root 1.166 sub unlink_save {
1386     my ($self) = @_;
1387    
1388     utf8::encode (my $save = $self->save_path);
1389 root 1.170 IO::AIO::aioreq_pri 4; Coro::AIO::aio_unlink $save;
1390     IO::AIO::aioreq_pri 4; Coro::AIO::aio_unlink "$save.pst";
1391 root 1.166 }
1392    
1393     sub load_header_from($) {
1394     my ($self, $path) = @_;
1395 root 1.110
1396     utf8::encode $path;
1397 root 1.200 #aio_open $path, O_RDONLY, 0
1398     # or return;
1399 root 1.110
1400 root 1.166 $self->_load_header ($path)
1401 root 1.110 or return;
1402    
1403 root 1.166 $self->{load_path} = $path;
1404 root 1.135
1405 root 1.166 1
1406     }
1407 root 1.110
1408 root 1.188 sub load_header_orig {
1409 root 1.166 my ($self) = @_;
1410 root 1.110
1411 root 1.166 $self->load_header_from ($self->load_path)
1412 root 1.110 }
1413    
1414 root 1.188 sub load_header_temp {
1415 root 1.166 my ($self) = @_;
1416 root 1.110
1417 root 1.166 $self->load_header_from ($self->save_path)
1418     }
1419 root 1.110
1420 root 1.188 sub prepare_temp {
1421     my ($self) = @_;
1422    
1423     $self->last_access ((delete $self->{last_access})
1424     || $cf::RUNTIME); #d#
1425     # safety
1426     $self->{instantiate_time} = $cf::RUNTIME
1427     if $self->{instantiate_time} > $cf::RUNTIME;
1428     }
1429    
1430     sub prepare_orig {
1431     my ($self) = @_;
1432    
1433     $self->{load_original} = 1;
1434     $self->{instantiate_time} = $cf::RUNTIME;
1435     $self->last_access ($cf::RUNTIME);
1436     $self->instantiate;
1437     }
1438    
1439 root 1.166 sub load_header {
1440     my ($self) = @_;
1441 root 1.110
1442 root 1.188 if ($self->load_header_temp) {
1443     $self->prepare_temp;
1444 root 1.166 } else {
1445 root 1.188 $self->load_header_orig
1446 root 1.166 or return;
1447 root 1.188 $self->prepare_orig;
1448 root 1.166 }
1449 root 1.120
1450 root 1.238 $self->default_region (cf::region::find_by_path $self->{path})
1451     unless $self->default_region;
1452    
1453 root 1.166 1
1454     }
1455 root 1.110
1456 root 1.166 sub find;
1457     sub find {
1458     my ($path, $origin) = @_;
1459 root 1.134
1460 root 1.166 $path = normalise $path, $origin && $origin->path;
1461 root 1.110
1462 root 1.166 cf::lock_wait "map_find:$path";
1463 root 1.110
1464 root 1.166 $cf::MAP{$path} || do {
1465     my $guard = cf::lock_acquire "map_find:$path";
1466     my $map = new_from_path cf::map $path
1467     or return;
1468 root 1.110
1469 root 1.116 $map->{last_save} = $cf::RUNTIME;
1470 root 1.110
1471 root 1.166 $map->load_header
1472     or return;
1473 root 1.134
1474 root 1.195 if ($map->should_reset && 0) {#d#TODO# disabled, crashy (locking issue?)
1475 root 1.185 # doing this can freeze the server in a sync job, obviously
1476     #$cf::WAIT_FOR_TICK->wait;
1477 root 1.112 $map->reset;
1478 root 1.123 undef $guard;
1479 root 1.192 return find $path;
1480 root 1.112 }
1481 root 1.110
1482 root 1.166 $cf::MAP{$path} = $map
1483 root 1.110 }
1484     }
1485    
1486 root 1.188 sub pre_load { }
1487     sub post_load { }
1488    
1489 root 1.110 sub load {
1490     my ($self) = @_;
1491    
1492 root 1.196 local $self->{deny_reset} = 1; # loading can take a long time
1493    
1494 root 1.120 my $path = $self->{path};
1495    
1496 root 1.256 {
1497     my $guard = cf::lock_acquire "map_load:$path";
1498    
1499     return if $self->in_memory != cf::MAP_SWAPPED;
1500 root 1.110
1501 root 1.256 $self->in_memory (cf::MAP_LOADING);
1502 root 1.110
1503 root 1.256 $self->alloc;
1504 root 1.188
1505 root 1.256 $self->pre_load;
1506     Coro::cede;
1507 root 1.188
1508 root 1.256 $self->_load_objects ($self->{load_path}, 1)
1509     or return;
1510 root 1.110
1511 root 1.256 $self->set_object_flag (cf::FLAG_OBJ_ORIGINAL, 1)
1512     if delete $self->{load_original};
1513 root 1.111
1514 root 1.256 if (my $uniq = $self->uniq_path) {
1515     utf8::encode $uniq;
1516     if (aio_open $uniq, O_RDONLY, 0) {
1517     $self->clear_unique_items;
1518     $self->_load_objects ($uniq, 0);
1519     }
1520 root 1.110 }
1521    
1522 root 1.166 Coro::cede;
1523 root 1.256 # now do the right thing for maps
1524     $self->link_multipart_objects;
1525 root 1.110 $self->difficulty ($self->estimate_difficulty)
1526     unless $self->difficulty;
1527 root 1.166 Coro::cede;
1528 root 1.256
1529     unless ($self->{deny_activate}) {
1530     $self->decay_objects;
1531     $self->fix_auto_apply;
1532     $self->update_buttons;
1533     Coro::cede;
1534     $self->set_darkness_map;
1535     Coro::cede;
1536     $self->activate;
1537     }
1538    
1539     $self->in_memory (cf::MAP_IN_MEMORY);
1540 root 1.110 }
1541    
1542 root 1.188 $self->post_load;
1543 root 1.166 }
1544    
1545     sub customise_for {
1546     my ($self, $ob) = @_;
1547    
1548     return find "~" . $ob->name . "/" . $self->{path}
1549     if $self->per_player;
1550 root 1.134
1551 root 1.166 $self
1552 root 1.110 }
1553    
1554 root 1.157 # find and load all maps in the 3x3 area around a map
1555     sub load_diag {
1556     my ($map) = @_;
1557    
1558     my @diag; # diagonal neighbours
1559    
1560     for (0 .. 3) {
1561     my $neigh = $map->tile_path ($_)
1562     or next;
1563     $neigh = find $neigh, $map
1564     or next;
1565     $neigh->load;
1566    
1567     push @diag, [$neigh->tile_path (($_ + 3) % 4), $neigh],
1568     [$neigh->tile_path (($_ + 1) % 4), $neigh];
1569     }
1570    
1571     for (@diag) {
1572     my $neigh = find @$_
1573     or next;
1574     $neigh->load;
1575     }
1576     }
1577    
1578 root 1.133 sub find_sync {
1579 root 1.110 my ($path, $origin) = @_;
1580    
1581 root 1.157 cf::sync_job { find $path, $origin }
1582 root 1.133 }
1583    
1584     sub do_load_sync {
1585     my ($map) = @_;
1586 root 1.110
1587 root 1.133 cf::sync_job { $map->load };
1588 root 1.110 }
1589    
1590 root 1.157 our %MAP_PREFETCH;
1591 root 1.183 our $MAP_PREFETCHER = undef;
1592 root 1.157
1593     sub find_async {
1594     my ($path, $origin) = @_;
1595    
1596 root 1.166 $path = normalise $path, $origin && $origin->{path};
1597 root 1.157
1598 root 1.166 if (my $map = $cf::MAP{$path}) {
1599 root 1.157 return $map if $map->in_memory == cf::MAP_IN_MEMORY;
1600     }
1601    
1602 root 1.183 undef $MAP_PREFETCH{$path};
1603     $MAP_PREFETCHER ||= cf::async {
1604     while (%MAP_PREFETCH) {
1605     for my $path (keys %MAP_PREFETCH) {
1606     my $map = find $path
1607     or next;
1608     $map->load;
1609    
1610     delete $MAP_PREFETCH{$path};
1611     }
1612     }
1613     undef $MAP_PREFETCHER;
1614     };
1615 root 1.189 $MAP_PREFETCHER->prio (6);
1616 root 1.157
1617     ()
1618     }
1619    
1620 root 1.110 sub save {
1621     my ($self) = @_;
1622    
1623 root 1.137 my $lock = cf::lock_acquire "map_data:" . $self->path;
1624    
1625 root 1.110 $self->{last_save} = $cf::RUNTIME;
1626    
1627     return unless $self->dirty;
1628    
1629 root 1.166 my $save = $self->save_path; utf8::encode $save;
1630     my $uniq = $self->uniq_path; utf8::encode $uniq;
1631 root 1.117
1632 root 1.110 $self->{load_path} = $save;
1633    
1634     return if $self->{deny_save};
1635    
1636 root 1.132 local $self->{last_access} = $self->last_access;#d#
1637    
1638 root 1.143 cf::async {
1639     $_->contr->save for $self->players;
1640     };
1641    
1642 root 1.110 if ($uniq) {
1643 root 1.166 $self->_save_objects ($save, cf::IO_HEADER | cf::IO_OBJECTS);
1644     $self->_save_objects ($uniq, cf::IO_UNIQUES);
1645 root 1.110 } else {
1646 root 1.166 $self->_save_objects ($save, cf::IO_HEADER | cf::IO_OBJECTS | cf::IO_UNIQUES);
1647 root 1.110 }
1648     }
1649    
1650     sub swap_out {
1651     my ($self) = @_;
1652    
1653 root 1.130 # save first because save cedes
1654     $self->save;
1655    
1656 root 1.137 my $lock = cf::lock_acquire "map_data:" . $self->path;
1657    
1658 root 1.110 return if $self->players;
1659     return if $self->in_memory != cf::MAP_IN_MEMORY;
1660     return if $self->{deny_save};
1661    
1662     $self->clear;
1663     $self->in_memory (cf::MAP_SWAPPED);
1664     }
1665    
1666 root 1.112 sub reset_at {
1667     my ($self) = @_;
1668 root 1.110
1669     # TODO: safety, remove and allow resettable per-player maps
1670 root 1.169 return 1e99 if $self->isa ("ext::map_per_player");#d#
1671 root 1.114 return 1e99 if $self->{deny_reset};
1672 root 1.110
1673 root 1.112 my $time = $self->fixed_resettime ? $self->{instantiate_time} : $self->last_access;
1674 root 1.114 my $to = List::Util::min $MAX_RESET, $self->reset_timeout || $DEFAULT_RESET;
1675 root 1.110
1676 root 1.112 $time + $to
1677     }
1678    
1679     sub should_reset {
1680     my ($self) = @_;
1681    
1682     $self->reset_at <= $cf::RUNTIME
1683 root 1.111 }
1684    
1685 root 1.110 sub reset {
1686     my ($self) = @_;
1687    
1688 root 1.167 my $lock = cf::lock_acquire "map_data:$self->{path}";
1689 root 1.137
1690 root 1.110 return if $self->players;
1691 root 1.166 return if $self->isa ("ext::map_per_player");#d#
1692 root 1.110
1693     warn "resetting map ", $self->path;#d#
1694    
1695 root 1.210 $self->in_memory (cf::MAP_SWAPPED);
1696    
1697     # need to save uniques path
1698     unless ($self->{deny_save}) {
1699     my $uniq = $self->uniq_path; utf8::encode $uniq;
1700    
1701     $self->_save_objects ($uniq, cf::IO_UNIQUES)
1702     if $uniq;
1703     }
1704    
1705 root 1.111 delete $cf::MAP{$self->path};
1706 root 1.110
1707 root 1.167 $self->clear;
1708    
1709 root 1.110 $_->clear_links_to ($self) for values %cf::MAP;
1710    
1711 root 1.166 $self->unlink_save;
1712 root 1.111 $self->destroy;
1713 root 1.110 }
1714    
1715 root 1.114 my $nuke_counter = "aaaa";
1716    
1717     sub nuke {
1718     my ($self) = @_;
1719    
1720 root 1.174 delete $cf::MAP{$self->path};
1721    
1722     $self->unlink_save;
1723    
1724     bless $self, "cf::map";
1725     delete $self->{deny_reset};
1726 root 1.114 $self->{deny_save} = 1;
1727     $self->reset_timeout (1);
1728 root 1.174 $self->path ($self->{path} = "{nuke}/" . ($nuke_counter++));
1729    
1730     $cf::MAP{$self->path} = $self;
1731    
1732 root 1.114 $self->reset; # polite request, might not happen
1733     }
1734    
1735 root 1.158 =item cf::map::unique_maps
1736    
1737 root 1.166 Returns an arrayref of paths of all shared maps that have
1738 root 1.158 instantiated unique items. May block.
1739    
1740     =cut
1741    
1742     sub unique_maps() {
1743 root 1.253 my $files = aio_readdir $UNIQUEDIR
1744 root 1.158 or return;
1745    
1746     my @paths;
1747    
1748     for (@$files) {
1749     utf8::decode $_;
1750     next if /\.pst$/;
1751     next unless /^$PATH_SEP/o;
1752    
1753 root 1.199 push @paths, cf::map::normalise $_;
1754 root 1.158 }
1755    
1756     \@paths
1757     }
1758    
1759 root 1.155 package cf;
1760    
1761     =back
1762    
1763     =head3 cf::object
1764    
1765     =cut
1766    
1767     package cf::object;
1768    
1769     =over 4
1770    
1771     =item $ob->inv_recursive
1772 root 1.110
1773 root 1.155 Returns the inventory of the object _and_ their inventories, recursively.
1774 root 1.110
1775 root 1.155 =cut
1776 root 1.144
1777 root 1.155 sub inv_recursive_;
1778     sub inv_recursive_ {
1779     map { $_, inv_recursive_ $_->inv } @_
1780     }
1781 root 1.110
1782 root 1.155 sub inv_recursive {
1783     inv_recursive_ inv $_[0]
1784 root 1.110 }
1785    
1786     package cf;
1787    
1788     =back
1789    
1790 root 1.95 =head3 cf::object::player
1791    
1792     =over 4
1793    
1794 root 1.79 =item $player_object->reply ($npc, $msg[, $flags])
1795 root 1.28
1796     Sends a message to the player, as if the npc C<$npc> replied. C<$npc>
1797     can be C<undef>. Does the right thing when the player is currently in a
1798     dialogue with the given NPC character.
1799    
1800     =cut
1801    
1802 root 1.22 # rough implementation of a future "reply" method that works
1803     # with dialog boxes.
1804 root 1.95 #TODO: the first argument must go, split into a $npc->reply_to ( method
1805 root 1.23 sub cf::object::player::reply($$$;$) {
1806     my ($self, $npc, $msg, $flags) = @_;
1807    
1808     $flags = cf::NDI_BROWN | cf::NDI_UNIQUE unless @_ >= 4;
1809 root 1.22
1810 root 1.24 if ($self->{record_replies}) {
1811     push @{ $self->{record_replies} }, [$npc, $msg, $flags];
1812     } else {
1813     $msg = $npc->name . " says: $msg" if $npc;
1814     $self->message ($msg, $flags);
1815     }
1816 root 1.22 }
1817    
1818 root 1.79 =item $player_object->may ("access")
1819    
1820     Returns wether the given player is authorized to access resource "access"
1821     (e.g. "command_wizcast").
1822    
1823     =cut
1824    
1825     sub cf::object::player::may {
1826     my ($self, $access) = @_;
1827    
1828     $self->flag (cf::FLAG_WIZ) ||
1829     (ref $cf::CFG{"may_$access"}
1830     ? scalar grep $self->name eq $_, @{$cf::CFG{"may_$access"}}
1831     : $cf::CFG{"may_$access"})
1832     }
1833 root 1.70
1834 root 1.115 =item $player_object->enter_link
1835    
1836     Freezes the player and moves him/her to a special map (C<{link}>).
1837    
1838 root 1.166 The player should be reasonably safe there for short amounts of time. You
1839 root 1.115 I<MUST> call C<leave_link> as soon as possible, though.
1840    
1841 root 1.166 Will never block.
1842    
1843 root 1.115 =item $player_object->leave_link ($map, $x, $y)
1844    
1845 root 1.166 Moves the player out of the special C<{link}> map onto the specified
1846     map. If the map is not valid (or omitted), the player will be moved back
1847     to the location he/she was before the call to C<enter_link>, or, if that
1848     fails, to the emergency map position.
1849 root 1.115
1850     Might block.
1851    
1852     =cut
1853    
1854 root 1.166 sub link_map {
1855     unless ($LINK_MAP) {
1856     $LINK_MAP = cf::map::find "{link}"
1857 root 1.196 or cf::cleanup "FATAL: unable to provide {link} map, exiting.";
1858 root 1.166 $LINK_MAP->load;
1859     }
1860    
1861     $LINK_MAP
1862     }
1863    
1864 root 1.110 sub cf::object::player::enter_link {
1865     my ($self) = @_;
1866    
1867 root 1.259 $self->deactivate_recursive;
1868 root 1.258
1869 root 1.166 return if UNIVERSAL::isa $self->map, "ext::map_link";
1870 root 1.110
1871 root 1.120 $self->{_link_pos} ||= [$self->map->{path}, $self->x, $self->y]
1872 root 1.110 if $self->map;
1873    
1874 root 1.194 $self->enter_map ($LINK_MAP || link_map, 10, 10);
1875 root 1.110 }
1876    
1877     sub cf::object::player::leave_link {
1878     my ($self, $map, $x, $y) = @_;
1879    
1880     my $link_pos = delete $self->{_link_pos};
1881    
1882     unless ($map) {
1883     # restore original map position
1884     ($map, $x, $y) = @{ $link_pos || [] };
1885 root 1.133 $map = cf::map::find $map;
1886 root 1.110
1887     unless ($map) {
1888     ($map, $x, $y) = @$EMERGENCY_POSITION;
1889 root 1.133 $map = cf::map::find $map
1890 root 1.110 or die "FATAL: cannot load emergency map\n";
1891     }
1892     }
1893    
1894     ($x, $y) = (-1, -1)
1895     unless (defined $x) && (defined $y);
1896    
1897     # use -1 or undef as default coordinates, not 0, 0
1898     ($x, $y) = ($map->enter_x, $map->enter_y)
1899     if $x <=0 && $y <= 0;
1900    
1901     $map->load;
1902 root 1.157 $map->load_diag;
1903 root 1.110
1904 root 1.143 return unless $self->contr->active;
1905 root 1.110 $self->activate_recursive;
1906 root 1.215
1907     local $self->{_prev_pos} = $link_pos; # ugly hack for rent.ext
1908 root 1.110 $self->enter_map ($map, $x, $y);
1909     }
1910    
1911 root 1.120 cf::player->attach (
1912     on_logout => sub {
1913     my ($pl) = @_;
1914    
1915     # abort map switching before logout
1916     if ($pl->ob->{_link_pos}) {
1917     cf::sync_job {
1918     $pl->ob->leave_link
1919     };
1920     }
1921     },
1922     on_login => sub {
1923     my ($pl) = @_;
1924    
1925     # try to abort aborted map switching on player login :)
1926     # should happen only on crashes
1927     if ($pl->ob->{_link_pos}) {
1928     $pl->ob->enter_link;
1929 root 1.140 (async {
1930     $pl->ob->reply (undef,
1931     "There was an internal problem at your last logout, "
1932     . "the server will try to bring you to your intended destination in a second.",
1933     cf::NDI_RED);
1934 root 1.215 # we need this sleep as the login has a concurrent enter_exit running
1935     # and this sleep increases chances of the player not ending up in scorn
1936 root 1.120 Coro::Timer::sleep 1;
1937     $pl->ob->leave_link;
1938 root 1.139 })->prio (2);
1939 root 1.120 }
1940     },
1941     );
1942    
1943 root 1.136 =item $player_object->goto ($path, $x, $y)
1944 root 1.110
1945     =cut
1946    
1947 root 1.136 sub cf::object::player::goto {
1948 root 1.110 my ($self, $path, $x, $y) = @_;
1949    
1950     $self->enter_link;
1951    
1952 root 1.140 (async {
1953 root 1.197 my $map = eval {
1954     my $map = cf::map::find $path;
1955     $map = $map->customise_for ($self) if $map;
1956     $map
1957     } or
1958     $self->message ("The exit to '$path' is closed", cf::NDI_UNIQUE | cf::NDI_RED);
1959 root 1.115
1960 root 1.110 $self->leave_link ($map, $x, $y);
1961     })->prio (1);
1962     }
1963    
1964     =item $player_object->enter_exit ($exit_object)
1965    
1966     =cut
1967    
1968     sub parse_random_map_params {
1969     my ($spec) = @_;
1970    
1971     my $rmp = { # defaults
1972 root 1.181 xsize => (cf::rndm 15, 40),
1973     ysize => (cf::rndm 15, 40),
1974     symmetry => (cf::rndm 1, cf::SYMMETRY_XY),
1975 root 1.182 #layout => string,
1976 root 1.110 };
1977    
1978     for (split /\n/, $spec) {
1979     my ($k, $v) = split /\s+/, $_, 2;
1980    
1981     $rmp->{lc $k} = $v if (length $k) && (length $v);
1982     }
1983    
1984     $rmp
1985     }
1986    
1987     sub prepare_random_map {
1988     my ($exit) = @_;
1989    
1990 root 1.179 my $guard = cf::lock_acquire "exit_prepare:$exit";
1991    
1992 root 1.110 # all this does is basically replace the /! path by
1993     # a new random map path (?random/...) with a seed
1994     # that depends on the exit object
1995    
1996     my $rmp = parse_random_map_params $exit->msg;
1997    
1998     if ($exit->map) {
1999 root 1.198 $rmp->{region} = $exit->region->name;
2000 root 1.110 $rmp->{origin_map} = $exit->map->path;
2001     $rmp->{origin_x} = $exit->x;
2002     $rmp->{origin_y} = $exit->y;
2003     }
2004    
2005     $rmp->{random_seed} ||= $exit->random_seed;
2006    
2007     my $data = cf::to_json $rmp;
2008     my $md5 = Digest::MD5::md5_hex $data;
2009 root 1.253 my $meta = "$RANDOMDIR/$md5.meta";
2010 root 1.110
2011 root 1.177 if (my $fh = aio_open "$meta~", O_WRONLY | O_CREAT, 0666) {
2012 root 1.110 aio_write $fh, 0, (length $data), $data, 0;
2013 root 1.177 undef $fh;
2014     aio_rename "$meta~", $meta;
2015 root 1.110
2016     $exit->slaying ("?random/$md5");
2017     $exit->msg (undef);
2018     }
2019     }
2020    
2021     sub cf::object::player::enter_exit {
2022     my ($self, $exit) = @_;
2023    
2024     return unless $self->type == cf::PLAYER;
2025    
2026 root 1.195 if ($exit->slaying eq "/!") {
2027     #TODO: this should de-fi-ni-te-ly not be a sync-job
2028 root 1.233 # the problem is that $exit might not survive long enough
2029     # so it needs to be done right now, right here
2030 root 1.195 cf::sync_job { prepare_random_map $exit };
2031     }
2032    
2033     my $slaying = cf::map::normalise $exit->slaying, $exit->map && $exit->map->path;
2034     my $hp = $exit->stats->hp;
2035     my $sp = $exit->stats->sp;
2036    
2037 root 1.110 $self->enter_link;
2038    
2039 root 1.140 (async {
2040 root 1.133 $self->deactivate_recursive; # just to be sure
2041 root 1.110 unless (eval {
2042 root 1.195 $self->goto ($slaying, $hp, $sp);
2043 root 1.110
2044     1;
2045     }) {
2046     $self->message ("Something went wrong deep within the crossfire server. "
2047 root 1.233 . "I'll try to bring you back to the map you were before. "
2048     . "Please report this to the dungeon master!",
2049     cf::NDI_UNIQUE | cf::NDI_RED);
2050 root 1.110
2051     warn "ERROR in enter_exit: $@";
2052     $self->leave_link;
2053     }
2054     })->prio (1);
2055     }
2056    
2057 root 1.95 =head3 cf::client
2058    
2059     =over 4
2060    
2061     =item $client->send_drawinfo ($text, $flags)
2062    
2063     Sends a drawinfo packet to the client. Circumvents output buffering so
2064     should not be used under normal circumstances.
2065    
2066 root 1.70 =cut
2067    
2068 root 1.95 sub cf::client::send_drawinfo {
2069     my ($self, $text, $flags) = @_;
2070    
2071     utf8::encode $text;
2072 root 1.225 $self->send_packet (sprintf "drawinfo %d %s", $flags || cf::NDI_BLACK, $text);
2073 root 1.95 }
2074    
2075 root 1.232 =item $client->ext_event ($type, %msg)
2076    
2077     Sends an exti event to the client.
2078    
2079     =cut
2080    
2081     sub cf::client::ext_event($$%) {
2082     my ($self, $type, %msg) = @_;
2083    
2084     $msg{msgtype} = "event_$type";
2085     $self->send_packet ("ext " . cf::to_json \%msg);
2086     }
2087 root 1.95
2088     =item $success = $client->query ($flags, "text", \&cb)
2089    
2090     Queues a query to the client, calling the given callback with
2091     the reply text on a reply. flags can be C<cf::CS_QUERY_YESNO>,
2092     C<cf::CS_QUERY_SINGLECHAR> or C<cf::CS_QUERY_HIDEINPUT> or C<0>.
2093    
2094     Queries can fail, so check the return code. Or don't, as queries will become
2095     reliable at some point in the future.
2096    
2097     =cut
2098    
2099     sub cf::client::query {
2100     my ($self, $flags, $text, $cb) = @_;
2101    
2102     return unless $self->state == ST_PLAYING
2103     || $self->state == ST_SETUP
2104     || $self->state == ST_CUSTOM;
2105    
2106     $self->state (ST_CUSTOM);
2107    
2108     utf8::encode $text;
2109     push @{ $self->{query_queue} }, [(sprintf "query %d %s", $flags, $text), $cb];
2110    
2111     $self->send_packet ($self->{query_queue}[0][0])
2112     if @{ $self->{query_queue} } == 1;
2113     }
2114    
2115     cf::client->attach (
2116     on_reply => sub {
2117     my ($ns, $msg) = @_;
2118    
2119     # this weird shuffling is so that direct followup queries
2120     # get handled first
2121 root 1.128 my $queue = delete $ns->{query_queue}
2122 root 1.129 or return; # be conservative, not sure how that can happen, but we saw a crash here
2123 root 1.95
2124     (shift @$queue)->[1]->($msg);
2125 root 1.202 return unless $ns->valid; # temporary(?) workaround for callback destroying socket
2126 root 1.95
2127     push @{ $ns->{query_queue} }, @$queue;
2128    
2129     if (@{ $ns->{query_queue} } == @$queue) {
2130     if (@$queue) {
2131     $ns->send_packet ($ns->{query_queue}[0][0]);
2132     } else {
2133 root 1.98 $ns->state (ST_PLAYING) if $ns->state == ST_CUSTOM;
2134 root 1.95 }
2135     }
2136     },
2137     );
2138    
2139 root 1.140 =item $client->async (\&cb)
2140 root 1.96
2141     Create a new coroutine, running the specified callback. The coroutine will
2142     be automatically cancelled when the client gets destroyed (e.g. on logout,
2143     or loss of connection).
2144    
2145     =cut
2146    
2147 root 1.140 sub cf::client::async {
2148 root 1.96 my ($self, $cb) = @_;
2149    
2150 root 1.140 my $coro = &Coro::async ($cb);
2151 root 1.103
2152     $coro->on_destroy (sub {
2153 root 1.96 delete $self->{_coro}{$coro+0};
2154 root 1.103 });
2155 root 1.96
2156     $self->{_coro}{$coro+0} = $coro;
2157 root 1.103
2158     $coro
2159 root 1.96 }
2160    
2161     cf::client->attach (
2162     on_destroy => sub {
2163     my ($ns) = @_;
2164    
2165 root 1.97 $_->cancel for values %{ (delete $ns->{_coro}) || {} };
2166 root 1.96 },
2167     );
2168    
2169 root 1.95 =back
2170    
2171 root 1.70
2172     =head2 SAFE SCRIPTING
2173    
2174     Functions that provide a safe environment to compile and execute
2175     snippets of perl code without them endangering the safety of the server
2176     itself. Looping constructs, I/O operators and other built-in functionality
2177     is not available in the safe scripting environment, and the number of
2178 root 1.79 functions and methods that can be called is greatly reduced.
2179 root 1.70
2180     =cut
2181 root 1.23
2182 root 1.42 our $safe = new Safe "safe";
2183 root 1.23 our $safe_hole = new Safe::Hole;
2184    
2185     $SIG{FPE} = 'IGNORE';
2186    
2187     $safe->permit_only (Opcode::opset qw(:base_core :base_mem :base_orig :base_math sort time));
2188    
2189 root 1.25 # here we export the classes and methods available to script code
2190    
2191 root 1.70 =pod
2192    
2193 root 1.228 The following functions and methods are available within a safe environment:
2194 root 1.70
2195 elmex 1.91 cf::object contr pay_amount pay_player map
2196 root 1.70 cf::object::player player
2197     cf::player peaceful
2198 elmex 1.91 cf::map trigger
2199 root 1.70
2200     =cut
2201    
2202 root 1.25 for (
2203 elmex 1.91 ["cf::object" => qw(contr pay_amount pay_player map)],
2204 root 1.25 ["cf::object::player" => qw(player)],
2205     ["cf::player" => qw(peaceful)],
2206 elmex 1.91 ["cf::map" => qw(trigger)],
2207 root 1.25 ) {
2208     no strict 'refs';
2209     my ($pkg, @funs) = @$_;
2210 root 1.41 *{"safe::$pkg\::$_"} = $safe_hole->wrap (\&{"$pkg\::$_"})
2211 root 1.25 for @funs;
2212     }
2213 root 1.23
2214 root 1.70 =over 4
2215    
2216     =item @retval = safe_eval $code, [var => value, ...]
2217    
2218     Compiled and executes the given perl code snippet. additional var/value
2219     pairs result in temporary local (my) scalar variables of the given name
2220     that are available in the code snippet. Example:
2221    
2222     my $five = safe_eval '$first + $second', first => 1, second => 4;
2223    
2224     =cut
2225    
2226 root 1.23 sub safe_eval($;@) {
2227     my ($code, %vars) = @_;
2228    
2229     my $qcode = $code;
2230     $qcode =~ s/"/‟/g; # not allowed in #line filenames
2231     $qcode =~ s/\n/\\n/g;
2232    
2233     local $_;
2234 root 1.41 local @safe::cf::_safe_eval_args = values %vars;
2235 root 1.23
2236 root 1.42 my $eval =
2237 root 1.23 "do {\n"
2238     . "my (" . (join ",", map "\$$_", keys %vars) . ") = \@cf::_safe_eval_args;\n"
2239     . "#line 0 \"{$qcode}\"\n"
2240     . $code
2241     . "\n}"
2242 root 1.25 ;
2243    
2244     sub_generation_inc;
2245 root 1.42 my @res = wantarray ? $safe->reval ($eval) : scalar $safe->reval ($eval);
2246 root 1.25 sub_generation_inc;
2247    
2248 root 1.42 if ($@) {
2249     warn "$@";
2250     warn "while executing safe code '$code'\n";
2251     warn "with arguments " . (join " ", %vars) . "\n";
2252     }
2253    
2254 root 1.25 wantarray ? @res : $res[0]
2255 root 1.23 }
2256    
2257 root 1.69 =item cf::register_script_function $function => $cb
2258    
2259     Register a function that can be called from within map/npc scripts. The
2260     function should be reasonably secure and should be put into a package name
2261     like the extension.
2262    
2263     Example: register a function that gets called whenever a map script calls
2264     C<rent::overview>, as used by the C<rent> extension.
2265    
2266     cf::register_script_function "rent::overview" => sub {
2267     ...
2268     };
2269    
2270     =cut
2271    
2272 root 1.23 sub register_script_function {
2273     my ($fun, $cb) = @_;
2274    
2275     no strict 'refs';
2276 root 1.41 *{"safe::$fun"} = $safe_hole->wrap ($cb);
2277 root 1.23 }
2278    
2279 root 1.70 =back
2280    
2281 root 1.71 =cut
2282    
2283 root 1.23 #############################################################################
2284 root 1.65
2285     =head2 EXTENSION DATABASE SUPPORT
2286    
2287     Crossfire maintains a very simple database for extension use. It can
2288 root 1.250 currently store binary data only (use Compress::LZF::sfreeze_cr/sthaw to
2289     convert to/from binary).
2290 root 1.65
2291     The parameter C<$family> should best start with the name of the extension
2292     using it, it should be unique.
2293    
2294     =over 4
2295    
2296     =item $value = cf::db_get $family => $key
2297    
2298 root 1.208 Returns a single value from the database.
2299 root 1.65
2300     =item cf::db_put $family => $key => $value
2301    
2302 root 1.208 Stores the given C<$value> in the family.
2303 root 1.65
2304     =cut
2305    
2306 root 1.78 our $DB;
2307    
2308 root 1.210 sub db_init {
2309     unless ($DB) {
2310     $DB = BDB::db_create $DB_ENV;
2311 root 1.65
2312 root 1.210 cf::sync_job {
2313     eval {
2314     $DB->set_flags (BDB::CHKSUM);
2315 root 1.65
2316 root 1.210 BDB::db_open $DB, undef, "db", undef, BDB::BTREE,
2317     BDB::CREATE | BDB::AUTO_COMMIT, 0666;
2318     cf::cleanup "db_open(db): $!" if $!;
2319     };
2320     cf::cleanup "db_open(db): $@" if $@;
2321 root 1.208 };
2322 root 1.65 }
2323 root 1.208 }
2324 root 1.65
2325 root 1.208 sub db_get($$) {
2326     my $key = "$_[0]/$_[1]";
2327 root 1.65
2328 root 1.208 cf::sync_job {
2329     BDB::db_get $DB, undef, $key, my $data;
2330 root 1.65
2331 root 1.208 $! ? ()
2332 root 1.250 : $data
2333 root 1.65 }
2334 root 1.208 }
2335 root 1.65
2336 root 1.208 sub db_put($$$) {
2337     BDB::dbreq_pri 4;
2338 root 1.250 BDB::db_put $DB, undef, "$_[0]/$_[1]", $_[2], 0, sub { };
2339 root 1.65 }
2340    
2341 root 1.250 =item cf::cache $id => [$paths...], $processversion => $process
2342 root 1.249
2343     Generic caching function that returns the value of the resource $id,
2344     caching and regenerating as required.
2345    
2346     This function can block.
2347    
2348     =cut
2349    
2350     sub cache {
2351 root 1.250 my ($id, $src, $processversion, $process) = @_;
2352 root 1.249
2353 root 1.250 my $meta =
2354     join "\x00",
2355     $processversion,
2356     map {
2357     aio_stat $_
2358     and Carp::croak "$_: $!";
2359    
2360     ($_, (stat _)[7,9])
2361     } @$src;
2362    
2363     my $dbmeta = db_get cache => "$id/meta";
2364     if ($dbmeta ne $meta) {
2365     # changed, we may need to process
2366    
2367     my @data;
2368     my $md5;
2369    
2370     for (0 .. $#$src) {
2371     0 <= aio_load $src->[$_], $data[$_]
2372     or Carp::croak "$src->[$_]: $!";
2373     }
2374    
2375     # if processing is expensive, check
2376     # checksum first
2377     if (1) {
2378     $md5 =
2379     join "\x00",
2380     $processversion,
2381     map {
2382     Coro::cede;
2383     ($src->[$_], Digest::MD5::md5_hex $data[$_])
2384     } 0.. $#$src;
2385    
2386    
2387     my $dbmd5 = db_get cache => "$id/md5";
2388     if ($dbmd5 eq $md5) {
2389     db_put cache => "$id/meta", $meta;
2390    
2391     return db_get cache => "$id/data";
2392     }
2393     }
2394 root 1.249
2395 root 1.253 my $t1 = Time::HiRes::time;
2396 root 1.250 my $data = $process->(\@data);
2397 root 1.253 my $t2 = Time::HiRes::time;
2398    
2399     warn "cache: '$id' processed in ", $t2 - $t1, "s\n";
2400 root 1.249
2401 root 1.250 db_put cache => "$id/data", $data;
2402     db_put cache => "$id/md5" , $md5;
2403     db_put cache => "$id/meta", $meta;
2404 root 1.249
2405 root 1.250 return $data;
2406 root 1.249 }
2407    
2408 root 1.250 db_get cache => "$id/data"
2409     }
2410    
2411     =item fork_call { }, $args
2412    
2413     Executes the given code block with the given arguments in a seperate
2414     process, returning the results. Everything must be serialisable with
2415     Coro::Storable. May, of course, block. Note that the executed sub may
2416     never block itself or use any form of Event handling.
2417    
2418     =cut
2419    
2420     sub fork_call(&@) {
2421     my ($cb, @args) = @_;
2422    
2423     # socketpair my $fh1, my $fh2, Socket::AF_UNIX, Socket::SOCK_STREAM, Socket::PF_UNSPEC
2424     # or die "socketpair: $!";
2425     pipe my $fh1, my $fh2
2426     or die "pipe: $!";
2427    
2428     if (my $pid = fork) {
2429     close $fh2;
2430    
2431     my $res = (Coro::Handle::unblock $fh1)->readline (undef);
2432     $res = Coro::Storable::thaw $res;
2433    
2434     waitpid $pid, 0; # should not block anymore, we expect the child to simply behave
2435    
2436     die $$res unless "ARRAY" eq ref $res;
2437    
2438     return wantarray ? @$res : $res->[-1];
2439 root 1.249 } else {
2440 root 1.262 reset_signals;
2441 root 1.251 local $SIG{__WARN__};
2442 root 1.262 local $SIG{__DIE__};
2443 root 1.250 eval {
2444     close $fh1;
2445    
2446     my @res = eval { $cb->(@args) };
2447     syswrite $fh2, Coro::Storable::freeze +($@ ? \"$@" : \@res);
2448     };
2449    
2450 root 1.251 warn $@ if $@;
2451 root 1.250 _exit 0;
2452 root 1.249 }
2453 root 1.250 }
2454 root 1.249
2455    
2456    
2457 root 1.65 #############################################################################
2458 root 1.203 # the server's init and main functions
2459    
2460 root 1.246 sub load_facedata($) {
2461     my ($path) = @_;
2462 root 1.223
2463 root 1.229 warn "loading facedata from $path\n";
2464 root 1.223
2465 root 1.236 my $facedata;
2466     0 < aio_load $path, $facedata
2467 root 1.223 or die "$path: $!";
2468    
2469 root 1.237 $facedata = Coro::Storable::thaw $facedata;
2470 root 1.223
2471 root 1.236 $facedata->{version} == 2
2472 root 1.226 or cf::cleanup "$path: version mismatch, cannot proceed.";
2473    
2474 root 1.236 {
2475     my $faces = $facedata->{faceinfo};
2476    
2477     while (my ($face, $info) = each %$faces) {
2478     my $idx = (cf::face::find $face) || cf::face::alloc $face;
2479     cf::face::set $idx, $info->{visibility}, $info->{magicmap};
2480     cf::face::set_data $idx, 0, $info->{data32}, $info->{chksum32};
2481     cf::face::set_data $idx, 1, $info->{data64}, $info->{chksum64};
2482     Coro::cede;
2483     }
2484    
2485     while (my ($face, $info) = each %$faces) {
2486     next unless $info->{smooth};
2487     my $idx = cf::face::find $face
2488     or next;
2489     if (my $smooth = cf::face::find $info->{smooth}) {
2490     cf::face::set_smooth $idx, $smooth, $info->{smoothlevel};
2491     } else {
2492     warn "smooth face '$info->{smooth}' not found for face '$face'";
2493     }
2494     Coro::cede;
2495     }
2496 root 1.223 }
2497    
2498 root 1.236 {
2499     my $anims = $facedata->{animinfo};
2500    
2501     while (my ($anim, $info) = each %$anims) {
2502     cf::anim::set $anim, $info->{frames}, $info->{facings};
2503     Coro::cede;
2504 root 1.225 }
2505 root 1.236
2506     cf::anim::invalidate_all; # d'oh
2507 root 1.225 }
2508    
2509 root 1.223 1
2510     }
2511    
2512 root 1.253 sub reload_regions {
2513     load_resource_file "$MAPDIR/regions"
2514     or die "unable to load regions file\n";
2515     }
2516    
2517 root 1.246 sub reload_facedata {
2518 root 1.253 load_facedata "$DATADIR/facedata"
2519 root 1.246 or die "unable to load facedata\n";
2520     }
2521    
2522     sub reload_archetypes {
2523 root 1.253 load_resource_file "$DATADIR/archetypes"
2524 root 1.246 or die "unable to load archetypes\n";
2525 root 1.241 }
2526    
2527 root 1.246 sub reload_treasures {
2528 root 1.253 load_resource_file "$DATADIR/treasures"
2529 root 1.246 or die "unable to load treasurelists\n";
2530 root 1.241 }
2531    
2532 root 1.223 sub reload_resources {
2533 root 1.245 warn "reloading resource files...\n";
2534    
2535 root 1.246 reload_regions;
2536     reload_facedata;
2537     reload_archetypes;
2538     reload_treasures;
2539 root 1.245
2540     warn "finished reloading resource files\n";
2541 root 1.223 }
2542    
2543     sub init {
2544     reload_resources;
2545 root 1.203 }
2546 root 1.34
2547 root 1.73 sub cfg_load {
2548 root 1.253 open my $fh, "<:utf8", "$CONFDIR/config"
2549 root 1.72 or return;
2550    
2551     local $/;
2552     *CFG = YAML::Syck::Load <$fh>;
2553 root 1.131
2554     $EMERGENCY_POSITION = $CFG{emergency_position} || ["/world/world_105_115", 5, 37];
2555    
2556 root 1.139 $cf::map::MAX_RESET = $CFG{map_max_reset} if exists $CFG{map_max_reset};
2557     $cf::map::DEFAULT_RESET = $CFG{map_default_reset} if exists $CFG{map_default_reset};
2558    
2559 root 1.131 if (exists $CFG{mlockall}) {
2560     eval {
2561 root 1.147 $CFG{mlockall} ? eval "mlockall()" : eval "munlockall()"
2562 root 1.131 and die "WARNING: m(un)lockall failed: $!\n";
2563     };
2564     warn $@ if $@;
2565     }
2566 root 1.72 }
2567    
2568 root 1.39 sub main {
2569 root 1.108 # we must not ever block the main coroutine
2570     local $Coro::idle = sub {
2571 root 1.115 Carp::cluck "FATAL: Coro::idle was called, major BUG, use cf::sync_job!\n";#d#
2572 root 1.175 (async {
2573     Event::one_event;
2574     })->prio (Coro::PRIO_MAX);
2575 root 1.108 };
2576    
2577 root 1.73 cfg_load;
2578 root 1.210 db_init;
2579 root 1.61 load_extensions;
2580 root 1.183
2581     $TICK_WATCHER->start;
2582 root 1.34 Event::loop;
2583     }
2584    
2585     #############################################################################
2586 root 1.155 # initialisation and cleanup
2587    
2588     # install some emergency cleanup handlers
2589     BEGIN {
2590     for my $signal (qw(INT HUP TERM)) {
2591     Event->signal (
2592 root 1.189 reentrant => 0,
2593     data => WF_AUTOCANCEL,
2594     signal => $signal,
2595 root 1.191 prio => 0,
2596 root 1.189 cb => sub {
2597 root 1.155 cf::cleanup "SIG$signal";
2598     },
2599     );
2600     }
2601     }
2602    
2603 root 1.156 sub emergency_save() {
2604 root 1.155 my $freeze_guard = cf::freeze_mainloop;
2605    
2606     warn "enter emergency perl save\n";
2607    
2608     cf::sync_job {
2609     # use a peculiar iteration method to avoid tripping on perl
2610     # refcount bugs in for. also avoids problems with players
2611 root 1.167 # and maps saved/destroyed asynchronously.
2612 root 1.155 warn "begin emergency player save\n";
2613     for my $login (keys %cf::PLAYER) {
2614     my $pl = $cf::PLAYER{$login} or next;
2615     $pl->valid or next;
2616     $pl->save;
2617     }
2618     warn "end emergency player save\n";
2619    
2620     warn "begin emergency map save\n";
2621     for my $path (keys %cf::MAP) {
2622     my $map = $cf::MAP{$path} or next;
2623     $map->valid or next;
2624     $map->save;
2625     }
2626     warn "end emergency map save\n";
2627 root 1.208
2628     warn "begin emergency database checkpoint\n";
2629     BDB::db_env_txn_checkpoint $DB_ENV;
2630     warn "end emergency database checkpoint\n";
2631 root 1.155 };
2632    
2633     warn "leave emergency perl save\n";
2634     }
2635 root 1.22
2636 root 1.211 sub post_cleanup {
2637     my ($make_core) = @_;
2638    
2639     warn Carp::longmess "post_cleanup backtrace"
2640     if $make_core;
2641     }
2642    
2643 root 1.246 sub do_reload_perl() {
2644 root 1.106 # can/must only be called in main
2645     if ($Coro::current != $Coro::main) {
2646 root 1.183 warn "can only reload from main coroutine";
2647 root 1.106 return;
2648     }
2649    
2650 root 1.103 warn "reloading...";
2651    
2652 root 1.212 warn "entering sync_job";
2653    
2654 root 1.213 cf::sync_job {
2655 root 1.214 cf::write_runtime; # external watchdog should not bark
2656 root 1.212 cf::emergency_save;
2657 root 1.214 cf::write_runtime; # external watchdog should not bark
2658 root 1.183
2659 root 1.212 warn "syncing database to disk";
2660     BDB::db_env_txn_checkpoint $DB_ENV;
2661 root 1.106
2662     # if anything goes wrong in here, we should simply crash as we already saved
2663 root 1.65
2664 root 1.183 warn "cancelling all WF_AUTOCANCEL watchers";
2665 root 1.87 for (Event::all_watchers) {
2666     $_->cancel if $_->data & WF_AUTOCANCEL;
2667     }
2668 root 1.65
2669 root 1.183 warn "flushing outstanding aio requests";
2670     for (;;) {
2671 root 1.208 BDB::flush;
2672 root 1.183 IO::AIO::flush;
2673     Coro::cede;
2674 root 1.208 last unless IO::AIO::nreqs || BDB::nreqs;
2675 root 1.183 warn "iterate...";
2676     }
2677    
2678 root 1.223 ++$RELOAD;
2679    
2680 root 1.183 warn "cancelling all extension coros";
2681 root 1.103 $_->cancel for values %EXT_CORO;
2682     %EXT_CORO = ();
2683    
2684 root 1.183 warn "removing commands";
2685 root 1.159 %COMMAND = ();
2686    
2687 root 1.183 warn "removing ext commands";
2688 root 1.159 %EXTCMD = ();
2689    
2690 root 1.183 warn "unloading/nuking all extensions";
2691 root 1.159 for my $pkg (@EXTS) {
2692 root 1.160 warn "... unloading $pkg";
2693 root 1.159
2694     if (my $cb = $pkg->can ("unload")) {
2695     eval {
2696     $cb->($pkg);
2697     1
2698     } or warn "$pkg unloaded, but with errors: $@";
2699     }
2700    
2701 root 1.160 warn "... nuking $pkg";
2702 root 1.159 Symbol::delete_package $pkg;
2703 root 1.65 }
2704    
2705 root 1.183 warn "unloading all perl modules loaded from $LIBDIR";
2706 root 1.65 while (my ($k, $v) = each %INC) {
2707     next unless $v =~ /^\Q$LIBDIR\E\/.*\.pm$/;
2708    
2709 root 1.183 warn "... unloading $k";
2710 root 1.65 delete $INC{$k};
2711    
2712     $k =~ s/\.pm$//;
2713     $k =~ s/\//::/g;
2714    
2715     if (my $cb = $k->can ("unload_module")) {
2716     $cb->();
2717     }
2718    
2719     Symbol::delete_package $k;
2720     }
2721    
2722 root 1.183 warn "getting rid of safe::, as good as possible";
2723 root 1.65 Symbol::delete_package "safe::$_"
2724 root 1.103 for qw(cf::attachable cf::object cf::object::player cf::client cf::player cf::map cf::party cf::region);
2725 root 1.65
2726 root 1.183 warn "unloading cf.pm \"a bit\"";
2727 root 1.65 delete $INC{"cf.pm"};
2728 root 1.252 delete $INC{"cf/pod.pm"};
2729 root 1.65
2730     # don't, removes xs symbols, too,
2731     # and global variables created in xs
2732     #Symbol::delete_package __PACKAGE__;
2733    
2734 root 1.183 warn "unload completed, starting to reload now";
2735    
2736 root 1.103 warn "reloading cf.pm";
2737 root 1.65 require cf;
2738 root 1.100 cf::_connect_to_perl; # nominally unnecessary, but cannot hurt
2739    
2740 root 1.183 warn "loading config and database again";
2741 root 1.73 cf::cfg_load;
2742 root 1.65
2743 root 1.183 warn "loading extensions";
2744 root 1.65 cf::load_extensions;
2745    
2746 root 1.183 warn "reattaching attachments to objects/players";
2747 root 1.222 _global_reattach; # objects, sockets
2748 root 1.183 warn "reattaching attachments to maps";
2749 root 1.144 reattach $_ for values %MAP;
2750 root 1.222 warn "reattaching attachments to players";
2751     reattach $_ for values %PLAYER;
2752 root 1.183
2753 root 1.212 warn "leaving sync_job";
2754 root 1.183
2755 root 1.212 1
2756     } or do {
2757 root 1.106 warn $@;
2758     warn "error while reloading, exiting.";
2759     exit 1;
2760 root 1.212 };
2761 root 1.106
2762 root 1.159 warn "reloaded";
2763 root 1.65 };
2764    
2765 root 1.175 our $RELOAD_WATCHER; # used only during reload
2766    
2767 root 1.246 sub reload_perl() {
2768     # doing reload synchronously and two reloads happen back-to-back,
2769     # coro crashes during coro_state_free->destroy here.
2770    
2771     $RELOAD_WATCHER ||= Event->timer (
2772     reentrant => 0,
2773     after => 0,
2774     data => WF_AUTOCANCEL,
2775     cb => sub {
2776     do_reload_perl;
2777     undef $RELOAD_WATCHER;
2778     },
2779     );
2780     }
2781    
2782 root 1.111 register_command "reload" => sub {
2783 root 1.65 my ($who, $arg) = @_;
2784    
2785     if ($who->flag (FLAG_WIZ)) {
2786 root 1.175 $who->message ("reloading server.");
2787 root 1.246 async { reload_perl };
2788 root 1.65 }
2789     };
2790    
2791 root 1.27 unshift @INC, $LIBDIR;
2792 root 1.17
2793 root 1.183 my $bug_warning = 0;
2794    
2795 root 1.239 our @WAIT_FOR_TICK;
2796     our @WAIT_FOR_TICK_BEGIN;
2797    
2798     sub wait_for_tick {
2799 root 1.240 return unless $TICK_WATCHER->is_active;
2800 root 1.241 return if $Coro::current == $Coro::main;
2801    
2802 root 1.239 my $signal = new Coro::Signal;
2803     push @WAIT_FOR_TICK, $signal;
2804     $signal->wait;
2805     }
2806    
2807     sub wait_for_tick_begin {
2808 root 1.240 return unless $TICK_WATCHER->is_active;
2809 root 1.241 return if $Coro::current == $Coro::main;
2810    
2811 root 1.239 my $signal = new Coro::Signal;
2812     push @WAIT_FOR_TICK_BEGIN, $signal;
2813     $signal->wait;
2814     }
2815    
2816 root 1.35 $TICK_WATCHER = Event->timer (
2817 root 1.104 reentrant => 0,
2818 root 1.183 parked => 1,
2819 root 1.191 prio => 0,
2820 root 1.104 at => $NEXT_TICK || $TICK,
2821     data => WF_AUTOCANCEL,
2822     cb => sub {
2823 root 1.183 if ($Coro::current != $Coro::main) {
2824     Carp::cluck "major BUG: server tick called outside of main coro, skipping it"
2825     unless ++$bug_warning > 10;
2826     return;
2827     }
2828    
2829 root 1.163 $NOW = Event::time;
2830    
2831 root 1.133 cf::server_tick; # one server iteration
2832 root 1.245
2833 root 1.133 $RUNTIME += $TICK;
2834 root 1.35 $NEXT_TICK += $TICK;
2835    
2836 root 1.214 if ($NOW >= $NEXT_RUNTIME_WRITE) {
2837     $NEXT_RUNTIME_WRITE = $NOW + 10;
2838     Coro::async_pool {
2839     write_runtime
2840     or warn "ERROR: unable to write runtime file: $!";
2841     };
2842     }
2843    
2844 root 1.191 # my $AFTER = Event::time;
2845     # warn $AFTER - $NOW;#d#
2846 root 1.190
2847 root 1.78 # if we are delayed by four ticks or more, skip them all
2848 root 1.103 $NEXT_TICK = Event::time if Event::time >= $NEXT_TICK + $TICK * 4;
2849 root 1.35
2850     $TICK_WATCHER->at ($NEXT_TICK);
2851     $TICK_WATCHER->start;
2852 root 1.245
2853     if (my $sig = shift @WAIT_FOR_TICK_BEGIN) {
2854     $sig->send;
2855     }
2856     while (my $sig = shift @WAIT_FOR_TICK) {
2857     $sig->send;
2858     }
2859    
2860     _post_tick;
2861 root 1.35 },
2862     );
2863    
2864 root 1.206 {
2865     BDB::max_poll_time $TICK * 0.1;
2866     $BDB_POLL_WATCHER = Event->io (
2867     reentrant => 0,
2868     fd => BDB::poll_fileno,
2869     poll => 'r',
2870     prio => 0,
2871     data => WF_AUTOCANCEL,
2872     cb => \&BDB::poll_cb,
2873     );
2874     BDB::min_parallel 8;
2875    
2876     BDB::set_sync_prepare {
2877     my $status;
2878     my $current = $Coro::current;
2879     (
2880     sub {
2881     $status = $!;
2882     $current->ready; undef $current;
2883     },
2884     sub {
2885     Coro::schedule while defined $current;
2886     $! = $status;
2887     },
2888     )
2889     };
2890 root 1.77
2891 root 1.206 unless ($DB_ENV) {
2892     $DB_ENV = BDB::db_env_create;
2893    
2894     cf::sync_job {
2895 root 1.208 eval {
2896     BDB::db_env_open
2897     $DB_ENV,
2898 root 1.253 $BDBDIR,
2899 root 1.208 BDB::INIT_LOCK | BDB::INIT_LOG | BDB::INIT_MPOOL | BDB::INIT_TXN
2900     | BDB::RECOVER | BDB::REGISTER | BDB::USE_ENVIRON | BDB::CREATE,
2901     0666;
2902    
2903 root 1.253 cf::cleanup "db_env_open($BDBDIR): $!" if $!;
2904 root 1.208
2905     $DB_ENV->set_flags (BDB::AUTO_COMMIT | BDB::REGION_INIT | BDB::TXN_NOSYNC, 1);
2906     $DB_ENV->set_lk_detect;
2907     };
2908    
2909     cf::cleanup "db_env_open(db): $@" if $@;
2910 root 1.206 };
2911     }
2912     }
2913    
2914     {
2915     IO::AIO::min_parallel 8;
2916    
2917     undef $Coro::AIO::WATCHER;
2918     IO::AIO::max_poll_time $TICK * 0.1;
2919     $AIO_POLL_WATCHER = Event->io (
2920     reentrant => 0,
2921 root 1.214 data => WF_AUTOCANCEL,
2922 root 1.206 fd => IO::AIO::poll_fileno,
2923     poll => 'r',
2924     prio => 6,
2925     cb => \&IO::AIO::poll_cb,
2926     );
2927     }
2928 root 1.108
2929 root 1.262 my $_log_backtrace;
2930    
2931 root 1.260 sub _log_backtrace {
2932     my ($msg, @addr) = @_;
2933    
2934 root 1.262 $msg =~ s/\n//;
2935 root 1.260
2936 root 1.262 # limit the # of concurrent backtraces
2937     if ($_log_backtrace < 2) {
2938     ++$_log_backtrace;
2939     async {
2940     my @bt = fork_call {
2941     @addr = map { sprintf "%x", $_ } @addr;
2942     my $self = (-f "/proc/$$/exe") ? "/proc/$$/exe" : $^X;
2943     open my $fh, "exec addr2line -C -f -i -e \Q$self\E @addr 2>&1 |"
2944     or die "addr2line: $!";
2945    
2946     my @funcs;
2947     my @res = <$fh>;
2948     chomp for @res;
2949     while (@res) {
2950     my ($func, $line) = splice @res, 0, 2, ();
2951     push @funcs, "[$func] $line";
2952     }
2953 root 1.260
2954 root 1.262 @funcs
2955     };
2956 root 1.260
2957 root 1.262 LOG llevInfo, "[ABT] $msg\n";
2958     LOG llevInfo, "[ABT] $_\n" for @bt;
2959     --$_log_backtrace;
2960     };
2961     } else {
2962 root 1.260 LOG llevInfo, "[ABT] $msg\n";
2963 root 1.262 LOG llevInfo, "[ABT] [suppressed]\n";
2964     }
2965 root 1.260 }
2966    
2967 root 1.249 # load additional modules
2968     use cf::pod;
2969    
2970 root 1.125 END { cf::emergency_save }
2971    
2972 root 1.1 1
2973