ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/lib/cf.pm
Revision: 1.263
Committed: Sat May 5 05:40:27 2007 UTC (17 years ago) by root
Branch: MAIN
Changes since 1.262: +3 -0 lines
Log Message:
*** empty log message ***

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