ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/lib/cf.pm
Revision: 1.457
Committed: Wed Oct 1 05:50:19 2008 UTC (15 years, 7 months ago) by root
Branch: MAIN
CVS Tags: rel-2_72
Changes since 1.456: +59 -21 lines
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 root 1.412 #
2     # This file is part of Deliantra, the Roguelike Realtime MMORPG.
3     #
4     # Copyright (©) 2006,2007,2008 Marc Alexander Lehmann / Robin Redeker / the Deliantra team
5     #
6     # Deliantra is free software: you can redistribute it and/or modify
7     # it under the terms of the GNU General Public License as published by
8     # the Free Software Foundation, either version 3 of the License, or
9     # (at your option) any later version.
10     #
11     # This program is distributed in the hope that it will be useful,
12     # but WITHOUT ANY WARRANTY; without even the implied warranty of
13     # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14     # GNU General Public License for more details.
15     #
16     # You should have received a copy of the GNU General Public License
17     # along with this program. If not, see <http://www.gnu.org/licenses/>.
18     #
19     # The authors can be reached via e-mail to <support@deliantra.net>
20     #
21    
22 root 1.1 package cf;
23    
24 root 1.441 use 5.10.0;
25 root 1.96 use utf8;
26 root 1.441 use strict "vars", "subs";
27 root 1.96
28 root 1.1 use Symbol;
29     use List::Util;
30 root 1.250 use Socket;
31 root 1.433 use EV;
32 root 1.23 use Opcode;
33     use Safe;
34     use Safe::Hole;
35 root 1.385 use Storable ();
36 root 1.19
37 root 1.433 use Coro ();
38 root 1.224 use Coro::State;
39 root 1.250 use Coro::Handle;
40 root 1.441 use Coro::EV;
41 root 1.434 use Coro::AnyEvent;
42 root 1.96 use Coro::Timer;
43     use Coro::Signal;
44     use Coro::Semaphore;
45 root 1.433 use Coro::AnyEvent;
46 root 1.105 use Coro::AIO;
47 root 1.437 use Coro::BDB 1.6;
48 root 1.237 use Coro::Storable;
49 root 1.332 use Coro::Util ();
50 root 1.96
51 root 1.398 use JSON::XS 2.01 ();
52 root 1.206 use BDB ();
53 root 1.154 use Data::Dumper;
54 root 1.108 use Digest::MD5;
55 root 1.105 use Fcntl;
56 root 1.408 use YAML ();
57 root 1.433 use IO::AIO ();
58 root 1.32 use Time::HiRes;
59 root 1.208 use Compress::LZF;
60 root 1.302 use Digest::MD5 ();
61 root 1.208
62 root 1.433 AnyEvent::detect;
63    
64 root 1.227 # configure various modules to our taste
65     #
66 root 1.237 $Storable::canonical = 1; # reduce rsync transfers
67 root 1.224 Coro::State::cctx_stacksize 256000; # 1-2MB stack, for deep recursions in maze generator
68 root 1.227
69 root 1.139 $Coro::main->prio (Coro::PRIO_MAX); # run main coroutine ("the server") with very high priority
70 root 1.1
71 root 1.449 # make sure c-lzf reinitialises itself
72     Compress::LZF::set_serializer "Storable", "Storable::net_mstore", "Storable::mretrieve";
73     Compress::LZF::sfreeze_cr { }; # prime Compress::LZF so it does not use require later
74 root 1.448
75 root 1.227 sub WF_AUTOCANCEL () { 1 } # automatically cancel this watcher on reload
76    
77 root 1.85 our %COMMAND = ();
78     our %COMMAND_TIME = ();
79 root 1.159
80     our @EXTS = (); # list of extension package names
81 root 1.85 our %EXTCMD = ();
82 root 1.287 our %EXTICMD = ();
83 root 1.159 our %EXT_CORO = (); # coroutines bound to extensions
84 root 1.161 our %EXT_MAP = (); # pluggable maps
85 root 1.85
86 root 1.451 our $RELOAD; # number of reloads so far, non-zero while in reload
87 root 1.1 our @EVENT;
88 root 1.253
89 root 1.445 our $CONFDIR = confdir;
90     our $DATADIR = datadir;
91     our $LIBDIR = "$DATADIR/ext";
92     our $PODDIR = "$DATADIR/pod";
93     our $MAPDIR = "$DATADIR/" . mapdir;
94     our $LOCALDIR = localdir;
95     our $TMPDIR = "$LOCALDIR/" . tmpdir;
96     our $UNIQUEDIR = "$LOCALDIR/" . uniquedir;
97     our $PLAYERDIR = "$LOCALDIR/" . playerdir;
98     our $RANDOMDIR = "$LOCALDIR/random";
99     our $BDBDIR = "$LOCALDIR/db";
100     our $PIDFILE = "$LOCALDIR/pid";
101     our $RUNTIMEFILE = "$LOCALDIR/runtime";
102    
103 root 1.405 our %RESOURCE;
104 root 1.1
105 root 1.245 our $TICK = MAX_TIME * 1e-6; # this is a CONSTANT(!)
106 root 1.214 our $NEXT_RUNTIME_WRITE; # when should the runtime file be written
107 root 1.35 our $NEXT_TICK;
108 root 1.205 our $USE_FSYNC = 1; # use fsync to write maps - default off
109 root 1.35
110 root 1.371 our $BDB_DEADLOCK_WATCHER;
111 root 1.363 our $BDB_CHECKPOINT_WATCHER;
112     our $BDB_TRICKLE_WATCHER;
113 root 1.206 our $DB_ENV;
114    
115 root 1.70 our %CFG;
116    
117 root 1.84 our $UPTIME; $UPTIME ||= time;
118 root 1.103 our $RUNTIME;
119 root 1.399 our $NOW;
120 root 1.103
121 root 1.356 our (%PLAYER, %PLAYER_LOADING); # all users
122     our (%MAP, %MAP_LOADING ); # all maps
123 root 1.166 our $LINK_MAP; # the special {link} map, which is always available
124 root 1.103
125 root 1.166 # used to convert map paths into valid unix filenames by replacing / by ∕
126     our $PATH_SEP = "∕"; # U+2215, chosen purely for visual reasons
127    
128 root 1.265 our $LOAD; # a number between 0 (idle) and 1 (too many objects)
129     our $LOADAVG; # same thing, but with alpha-smoothing
130 root 1.412 our $JITTER; # average jitter
131     our $TICK_START; # for load detecting purposes
132 root 1.265
133 root 1.453 our @POST_INIT;
134    
135 root 1.457 our $REATTACH_ON_RELOAD; # ste to true to force object reattach on reload (slow)
136    
137 root 1.103 binmode STDOUT;
138     binmode STDERR;
139    
140     # read virtual server time, if available
141 root 1.445 unless ($RUNTIME || !-e $RUNTIMEFILE) {
142     open my $fh, "<", $RUNTIMEFILE
143     or die "unable to read $RUNTIMEFILE file: $!";
144 root 1.103 $RUNTIME = <$fh> + 0.;
145     }
146    
147 root 1.253 mkdir $_
148     for $LOCALDIR, $TMPDIR, $UNIQUEDIR, $PLAYERDIR, $RANDOMDIR, $BDBDIR;
149 root 1.103
150 root 1.131 our $EMERGENCY_POSITION;
151 root 1.110
152 root 1.199 sub cf::map::normalise;
153    
154 root 1.70 #############################################################################
155    
156     =head2 GLOBAL VARIABLES
157    
158     =over 4
159    
160 root 1.83 =item $cf::UPTIME
161    
162     The timestamp of the server start (so not actually an uptime).
163    
164 root 1.103 =item $cf::RUNTIME
165    
166     The time this server has run, starts at 0 and is increased by $cf::TICK on
167     every server tick.
168    
169 root 1.253 =item $cf::CONFDIR $cf::DATADIR $cf::LIBDIR $cf::PODDIR
170     $cf::MAPDIR $cf::LOCALDIR $cf::TMPDIR $cf::UNIQUEDIR
171     $cf::PLAYERDIR $cf::RANDOMDIR $cf::BDBDIR
172    
173     Various directories - "/etc", read-only install directory, perl-library
174     directory, pod-directory, read-only maps directory, "/var", "/var/tmp",
175     unique-items directory, player file directory, random maps directory and
176     database environment.
177 root 1.70
178 root 1.103 =item $cf::NOW
179    
180     The time of the last (current) server tick.
181    
182 root 1.70 =item $cf::TICK
183    
184     The interval between server ticks, in seconds.
185    
186 root 1.265 =item $cf::LOADAVG
187    
188     The current CPU load on the server (alpha-smoothed), as a value between 0
189     (none) and 1 (overloaded), indicating how much time is spent on processing
190     objects per tick. Healthy values are < 0.5.
191    
192     =item $cf::LOAD
193    
194     The raw value load value from the last tick.
195    
196 root 1.70 =item %cf::CFG
197    
198 root 1.395 Configuration for the server, loaded from C</etc/deliantra-server/config>, or
199 root 1.70 from wherever your confdir points to.
200    
201 root 1.239 =item cf::wait_for_tick, cf::wait_for_tick_begin
202 root 1.155
203 root 1.239 These are functions that inhibit the current coroutine one tick. cf::wait_for_tick_begin only
204     returns directly I<after> the tick processing (and consequently, can only wake one process
205     per tick), while cf::wait_for_tick wakes up all waiters after tick processing.
206 root 1.155
207 elmex 1.310 =item @cf::INVOKE_RESULTS
208    
209     This array contains the results of the last C<invoke ()> call. When
210     C<cf::override> is called C<@cf::INVOKE_RESULTS> is set to the parameters of
211     that call.
212    
213 root 1.70 =back
214    
215     =cut
216    
217 root 1.1 BEGIN {
218     *CORE::GLOBAL::warn = sub {
219     my $msg = join "", @_;
220 root 1.103
221 root 1.1 $msg .= "\n"
222     unless $msg =~ /\n$/;
223    
224 root 1.255 $msg =~ s/([\x00-\x08\x0b-\x1f])/sprintf "\\x%02x", ord $1/ge;
225 root 1.250
226 root 1.146 LOG llevError, $msg;
227 root 1.1 };
228     }
229    
230 root 1.407 $Coro::State::DIEHOOK = sub {
231 root 1.410 return unless $^S eq 0; # "eq", not "=="
232    
233     if ($Coro::current == $Coro::main) {#d#
234     warn "DIEHOOK called in main context, Coro bug?\n";#d#
235     return;#d#
236     }#d#
237    
238     # kill coroutine otherwise
239 root 1.407 warn Carp::longmess $_[0];
240 root 1.410 Coro::terminate
241 root 1.407 };
242    
243 root 1.410 $SIG{__DIE__} = sub { }; #d#?
244    
245 root 1.93 @safe::cf::global::ISA = @cf::global::ISA = 'cf::attachable';
246     @safe::cf::object::ISA = @cf::object::ISA = 'cf::attachable';
247     @safe::cf::player::ISA = @cf::player::ISA = 'cf::attachable';
248     @safe::cf::client::ISA = @cf::client::ISA = 'cf::attachable';
249     @safe::cf::map::ISA = @cf::map::ISA = 'cf::attachable';
250 root 1.273 @safe::cf::arch::ISA = @cf::arch::ISA = 'cf::object';
251     @safe::cf::object::player::ISA = @cf::object::player::ISA = 'cf::object'; # not really true (yet)
252 root 1.25
253 root 1.41 # we bless all objects into (empty) derived classes to force a method lookup
254 root 1.25 # within the Safe compartment.
255 root 1.86 for my $pkg (qw(
256 root 1.100 cf::global cf::attachable
257 root 1.86 cf::object cf::object::player
258 root 1.89 cf::client cf::player
259 root 1.86 cf::arch cf::living
260 root 1.440 cf::map cf::mapspace
261     cf::party cf::region
262 root 1.86 )) {
263 root 1.41 @{"safe::$pkg\::wrap::ISA"} = @{"$pkg\::wrap::ISA"} = $pkg;
264 root 1.25 }
265 root 1.1
266 root 1.396 $EV::DIED = sub {
267 root 1.18 warn "error in event callback: @_";
268     };
269    
270 root 1.281 #############################################################################
271    
272 root 1.70 =head2 UTILITY FUNCTIONS
273    
274     =over 4
275    
276 root 1.154 =item dumpval $ref
277    
278 root 1.70 =cut
279 root 1.44
280 root 1.154 sub dumpval {
281     eval {
282     local $SIG{__DIE__};
283     my $d;
284     if (1) {
285     $d = new Data::Dumper([$_[0]], ["*var"]);
286     $d->Terse(1);
287     $d->Indent(2);
288     $d->Quotekeys(0);
289     $d->Useqq(1);
290     #$d->Bless(...);
291     $d->Seen($_[1]) if @_ > 1;
292     $d = $d->Dump();
293     }
294     $d =~ s/([\x00-\x07\x09\x0b\x0c\x0e-\x1f])/sprintf "\\x%02x", ord($1)/ge;
295     $d
296     } || "[unable to dump $_[0]: '$@']";
297     }
298    
299 root 1.398 =item $ref = cf::decode_json $json
300 root 1.70
301     Converts a JSON string into the corresponding perl data structure.
302    
303 root 1.398 =item $json = cf::encode_json $ref
304 root 1.70
305     Converts a perl data structure into its JSON representation.
306    
307 root 1.287 =cut
308    
309 root 1.290 our $json_coder = JSON::XS->new->utf8->max_size (1e6); # accept ~1mb max
310 root 1.287
311 root 1.398 sub encode_json($) { $json_coder->encode ($_[0]) }
312     sub decode_json($) { $json_coder->decode ($_[0]) }
313 root 1.287
314 root 1.453 =item cf::post_init { BLOCK }
315    
316     Execute the given codeblock, I<after> all extensions have been (re-)loaded,
317     but I<before> the server starts ticking again.
318    
319     The cdoeblock will have a single boolean argument to indicate whether this
320     is a reload or not.
321    
322     =cut
323    
324     sub post_init(&) {
325     push @POST_INIT, shift;
326     }
327    
328 root 1.120 =item cf::lock_wait $string
329    
330     Wait until the given lock is available. See cf::lock_acquire.
331    
332     =item my $lock = cf::lock_acquire $string
333    
334     Wait until the given lock is available and then acquires it and returns
335 root 1.135 a Coro::guard object. If the guard object gets destroyed (goes out of scope,
336 root 1.120 for example when the coroutine gets canceled), the lock is automatically
337     returned.
338    
339 root 1.347 Locks are *not* recursive, locking from the same coro twice results in a
340     deadlocked coro.
341    
342 root 1.133 Lock names should begin with a unique identifier (for example, cf::map::find
343     uses map_find and cf::map::load uses map_load).
344 root 1.120
345 root 1.253 =item $locked = cf::lock_active $string
346    
347     Return true if the lock is currently active, i.e. somebody has locked it.
348    
349 root 1.120 =cut
350    
351     our %LOCK;
352 root 1.358 our %LOCKER;#d#
353 root 1.120
354     sub lock_wait($) {
355     my ($key) = @_;
356    
357 root 1.358 if ($LOCKER{$key} == $Coro::current) {#d#
358     Carp::cluck "lock_wait($key) for already-acquired lock";#d#
359     return;#d#
360     }#d#
361    
362 root 1.120 # wait for lock, if any
363     while ($LOCK{$key}) {
364 root 1.451 #local $Coro::current->{desc} = "$Coro::current->{desc} <waiting for lock $key>";
365 root 1.120 push @{ $LOCK{$key} }, $Coro::current;
366     Coro::schedule;
367     }
368     }
369    
370     sub lock_acquire($) {
371     my ($key) = @_;
372    
373     # wait, to be sure we are not locked
374     lock_wait $key;
375    
376     $LOCK{$key} = [];
377 root 1.358 $LOCKER{$key} = $Coro::current;#d#
378 root 1.120
379 root 1.135 Coro::guard {
380 root 1.358 delete $LOCKER{$key};#d#
381 root 1.120 # wake up all waiters, to be on the safe side
382     $_->ready for @{ delete $LOCK{$key} };
383     }
384     }
385    
386 root 1.253 sub lock_active($) {
387     my ($key) = @_;
388    
389     ! ! $LOCK{$key}
390     }
391    
392 root 1.133 sub freeze_mainloop {
393 root 1.412 tick_inhibit_inc;
394 root 1.133
395 root 1.412 Coro::guard \&tick_inhibit_dec;
396 root 1.133 }
397    
398 root 1.396 =item cf::periodic $interval, $cb
399    
400     Like EV::periodic, but randomly selects a starting point so that the actions
401     get spread over timer.
402    
403     =cut
404    
405     sub periodic($$) {
406     my ($interval, $cb) = @_;
407    
408     my $start = rand List::Util::min 180, $interval;
409    
410     EV::periodic $start, $interval, 0, $cb
411     }
412    
413 root 1.315 =item cf::get_slot $time[, $priority[, $name]]
414 root 1.314
415     Allocate $time seconds of blocking CPU time at priority C<$priority>:
416     This call blocks and returns only when you have at least C<$time> seconds
417     of cpu time till the next tick. The slot is only valid till the next cede.
418    
419 root 1.315 The optional C<$name> can be used to identify the job to run. It might be
420     used for statistical purposes and should identify the same time-class.
421    
422 root 1.314 Useful for short background jobs.
423    
424     =cut
425    
426     our @SLOT_QUEUE;
427     our $SLOT_QUEUE;
428    
429     $SLOT_QUEUE->cancel if $SLOT_QUEUE;
430     $SLOT_QUEUE = Coro::async {
431 root 1.374 $Coro::current->desc ("timeslot manager");
432    
433 root 1.314 my $signal = new Coro::Signal;
434    
435     while () {
436     next_job:
437     my $avail = cf::till_tick;
438     if ($avail > 0.01) {
439     for (0 .. $#SLOT_QUEUE) {
440     if ($SLOT_QUEUE[$_][0] < $avail) {
441     my $job = splice @SLOT_QUEUE, $_, 1, ();
442     $job->[2]->send;
443     Coro::cede;
444     goto next_job;
445     }
446     }
447     }
448    
449     if (@SLOT_QUEUE) {
450 root 1.380 # we do not use wait_for_tick() as it returns immediately when tick is inactive
451 root 1.314 push @cf::WAIT_FOR_TICK, $signal;
452     $signal->wait;
453     } else {
454     Coro::schedule;
455     }
456     }
457     };
458    
459 root 1.315 sub get_slot($;$$) {
460 root 1.423 return if tick_inhibit || $Coro::current == $Coro::main;
461 root 1.420
462 root 1.315 my ($time, $pri, $name) = @_;
463    
464     $time = $TICK * .6 if $time > $TICK * .6;
465     my $sig = new Coro::Signal;
466 root 1.314
467 root 1.315 push @SLOT_QUEUE, [$time, $pri, $sig, $name];
468 root 1.314 @SLOT_QUEUE = sort { $b->[1] <=> $a->[1] } @SLOT_QUEUE;
469     $SLOT_QUEUE->ready;
470     $sig->wait;
471     }
472    
473 root 1.140 =item cf::async { BLOCK }
474    
475     Currently the same as Coro::async_pool, meaning you cannot use
476     C<on_destroy>, C<join> or other gimmicks on these coroutines. The only
477     thing you are allowed to do is call C<prio> on it.
478    
479     =cut
480    
481     BEGIN { *async = \&Coro::async_pool }
482    
483 root 1.106 =item cf::sync_job { BLOCK }
484    
485 root 1.394 The design of Deliantra requires that the main coroutine ($Coro::main)
486     is always able to handle events or runnable, as Deliantra is only
487 root 1.281 partly reentrant. Thus "blocking" it by e.g. waiting for I/O is not
488     acceptable.
489 root 1.106
490     If it must be done, put the blocking parts into C<sync_job>. This will run
491     the given BLOCK in another coroutine while waiting for the result. The
492     server will be frozen during this time, so the block should either finish
493     fast or be very important.
494    
495     =cut
496    
497 root 1.105 sub sync_job(&) {
498     my ($job) = @_;
499    
500     if ($Coro::current == $Coro::main) {
501 root 1.396 my $time = EV::time;
502 root 1.265
503 root 1.112 # this is the main coro, too bad, we have to block
504     # till the operation succeeds, freezing the server :/
505    
506 root 1.385 LOG llevError, Carp::longmess "sync job";#d#
507 root 1.379
508 root 1.133 my $freeze_guard = freeze_mainloop;
509 root 1.112
510     my $busy = 1;
511     my @res;
512    
513 root 1.140 (async {
514 root 1.374 $Coro::current->desc ("sync job coro");
515 root 1.112 @res = eval { $job->() };
516     warn $@ if $@;
517     undef $busy;
518     })->prio (Coro::PRIO_MAX);
519    
520 root 1.105 while ($busy) {
521 root 1.387 if (Coro::nready) {
522     Coro::cede_notself;
523     } else {
524 root 1.396 EV::loop EV::LOOP_ONESHOT;
525 root 1.387 }
526 root 1.105 }
527 root 1.112
528 root 1.412 my $time = EV::time - $time;
529 root 1.265
530 root 1.412 $TICK_START += $time; # do not account sync jobs to server load
531 root 1.265
532 root 1.112 wantarray ? @res : $res[0]
533 root 1.105 } else {
534 root 1.112 # we are in another coroutine, how wonderful, everything just works
535    
536     $job->()
537 root 1.105 }
538     }
539    
540 root 1.140 =item $coro = cf::async_ext { BLOCK }
541 root 1.103
542 root 1.159 Like async, but this coro is automatically being canceled when the
543 root 1.140 extension calling this is being unloaded.
544 root 1.103
545     =cut
546    
547 root 1.140 sub async_ext(&) {
548 root 1.103 my $cb = shift;
549    
550 root 1.140 my $coro = &Coro::async ($cb);
551 root 1.103
552     $coro->on_destroy (sub {
553     delete $EXT_CORO{$coro+0};
554     });
555     $EXT_CORO{$coro+0} = $coro;
556    
557     $coro
558     }
559    
560 root 1.281 =item fork_call { }, $args
561    
562     Executes the given code block with the given arguments in a seperate
563     process, returning the results. Everything must be serialisable with
564     Coro::Storable. May, of course, block. Note that the executed sub may
565 root 1.396 never block itself or use any form of event handling.
566 root 1.281
567     =cut
568    
569     sub fork_call(&@) {
570     my ($cb, @args) = @_;
571    
572 root 1.332 # we seemingly have to make a local copy of the whole thing,
573     # otherwise perl prematurely frees the stuff :/
574 root 1.355 # TODO: investigate and fix (likely this will be rather laborious)
575 root 1.281
576 root 1.332 my @res = Coro::Util::fork_eval {
577 root 1.281 reset_signals;
578 root 1.332 &$cb
579     }, @args;
580 root 1.298
581 root 1.332 wantarray ? @res : $res[-1]
582 root 1.281 }
583    
584 root 1.415 =item $coin = coin_from_name $name
585    
586     =cut
587    
588     our %coin_alias = (
589     "silver" => "silvercoin",
590     "silvercoin" => "silvercoin",
591     "silvercoins" => "silvercoin",
592     "gold" => "goldcoin",
593     "goldcoin" => "goldcoin",
594     "goldcoins" => "goldcoin",
595     "platinum" => "platinacoin",
596     "platinumcoin" => "platinacoin",
597     "platinumcoins" => "platinacoin",
598     "platina" => "platinacoin",
599     "platinacoin" => "platinacoin",
600     "platinacoins" => "platinacoin",
601     "royalty" => "royalty",
602     "royalties" => "royalty",
603     );
604    
605     sub coin_from_name($) {
606     $coin_alias{$_[0]}
607     ? cf::arch::find $coin_alias{$_[0]}
608     : undef
609     }
610    
611 root 1.281 =item $value = cf::db_get $family => $key
612    
613     Returns a single value from the environment database.
614    
615     =item cf::db_put $family => $key => $value
616    
617     Stores the given C<$value> in the family. It can currently store binary
618     data only (use Compress::LZF::sfreeze_cr/sthaw to convert to/from binary).
619    
620 root 1.363 =item $db = cf::db_table "name"
621    
622     Create and/or open a new database table. The string must not be "db" and must be unique
623     within each server.
624    
625 root 1.281 =cut
626    
627 root 1.363 sub db_table($) {
628     my ($name) = @_;
629     my $db = BDB::db_create $DB_ENV;
630    
631     eval {
632     $db->set_flags (BDB::CHKSUM);
633    
634     utf8::encode $name;
635     BDB::db_open $db, undef, $name, undef, BDB::BTREE,
636     BDB::CREATE | BDB::AUTO_COMMIT, 0666;
637     cf::cleanup "db_open(db): $!" if $!;
638     };
639     cf::cleanup "db_open(db): $@" if $@;
640    
641     $db
642     }
643    
644 root 1.281 our $DB;
645    
646     sub db_init {
647 root 1.363 cf::sync_job {
648     $DB ||= db_table "db";
649     };
650 root 1.281 }
651    
652     sub db_get($$) {
653     my $key = "$_[0]/$_[1]";
654    
655     cf::sync_job {
656     BDB::db_get $DB, undef, $key, my $data;
657    
658     $! ? ()
659     : $data
660     }
661     }
662    
663     sub db_put($$$) {
664     BDB::dbreq_pri 4;
665     BDB::db_put $DB, undef, "$_[0]/$_[1]", $_[2], 0, sub { };
666     }
667    
668     =item cf::cache $id => [$paths...], $processversion => $process
669    
670     Generic caching function that returns the value of the resource $id,
671     caching and regenerating as required.
672    
673     This function can block.
674    
675     =cut
676    
677     sub cache {
678     my ($id, $src, $processversion, $process) = @_;
679    
680     my $meta =
681     join "\x00",
682     $processversion,
683     map {
684     aio_stat $_
685     and Carp::croak "$_: $!";
686 root 1.264
687 root 1.281 ($_, (stat _)[7,9])
688     } @$src;
689 root 1.264
690 root 1.281 my $dbmeta = db_get cache => "$id/meta";
691     if ($dbmeta ne $meta) {
692     # changed, we may need to process
693 root 1.264
694 root 1.281 my @data;
695     my $md5;
696 root 1.219
697 root 1.281 for (0 .. $#$src) {
698     0 <= aio_load $src->[$_], $data[$_]
699     or Carp::croak "$src->[$_]: $!";
700     }
701 root 1.108
702 root 1.281 # if processing is expensive, check
703     # checksum first
704     if (1) {
705     $md5 =
706     join "\x00",
707     $processversion,
708     map {
709 root 1.346 cf::cede_to_tick;
710 root 1.281 ($src->[$_], Digest::MD5::md5_hex $data[$_])
711     } 0.. $#$src;
712    
713 root 1.186
714 root 1.281 my $dbmd5 = db_get cache => "$id/md5";
715     if ($dbmd5 eq $md5) {
716     db_put cache => "$id/meta", $meta;
717 root 1.108
718 root 1.281 return db_get cache => "$id/data";
719     }
720     }
721 root 1.108
722 root 1.281 my $t1 = Time::HiRes::time;
723     my $data = $process->(\@data);
724     my $t2 = Time::HiRes::time;
725 root 1.264
726 root 1.281 warn "cache: '$id' processed in ", $t2 - $t1, "s\n";
727 root 1.108
728 root 1.281 db_put cache => "$id/data", $data;
729     db_put cache => "$id/md5" , $md5;
730     db_put cache => "$id/meta", $meta;
731 root 1.108
732 root 1.281 return $data;
733     }
734 root 1.263
735 root 1.281 db_get cache => "$id/data"
736 root 1.108 }
737    
738 root 1.230 =item cf::datalog type => key => value, ...
739    
740     Log a datalog packet of the given type with the given key-value pairs.
741    
742     =cut
743    
744     sub datalog($@) {
745     my ($type, %kv) = @_;
746     warn "DATALOG ", JSON::XS->new->ascii->encode ({ %kv, type => $type });
747     }
748    
749 root 1.70 =back
750    
751 root 1.71 =cut
752    
753 root 1.44 #############################################################################
754 root 1.39
755 root 1.93 =head2 ATTACHABLE OBJECTS
756    
757 root 1.447 Many objects in deliantra are so-called attachable objects. That means you can
758 root 1.94 attach callbacks/event handlers (a collection of which is called an "attachment")
759     to it. All such attachable objects support the following methods.
760    
761     In the following description, CLASS can be any of C<global>, C<object>
762     C<player>, C<client> or C<map> (i.e. the attachable objects in
763 root 1.394 Deliantra).
764 root 1.55
765     =over 4
766    
767 root 1.94 =item $attachable->attach ($attachment, key => $value...)
768    
769     =item $attachable->detach ($attachment)
770    
771     Attach/detach a pre-registered attachment to a specific object and give it
772     the specified key/value pairs as arguments.
773    
774     Example, attach a minesweeper attachment to the given object, making it a
775     10x10 minesweeper game:
776 root 1.46
777 root 1.94 $obj->attach (minesweeper => width => 10, height => 10);
778 root 1.53
779 root 1.93 =item $bool = $attachable->attached ($name)
780 root 1.46
781 root 1.93 Checks wether the named attachment is currently attached to the object.
782 root 1.46
783 root 1.94 =item cf::CLASS->attach ...
784 root 1.46
785 root 1.94 =item cf::CLASS->detach ...
786 root 1.92
787 root 1.94 Define an anonymous attachment and attach it to all objects of the given
788     CLASS. See the next function for an explanation of its arguments.
789 root 1.92
790 root 1.93 You can attach to global events by using the C<cf::global> class.
791 root 1.92
792 root 1.94 Example, log all player logins:
793    
794     cf::player->attach (
795     on_login => sub {
796     my ($pl) = @_;
797     ...
798     },
799     );
800    
801     Example, attach to the jeweler skill:
802    
803     cf::object->attach (
804     type => cf::SKILL,
805     subtype => cf::SK_JEWELER,
806     on_use_skill => sub {
807     my ($sk, $ob, $part, $dir, $msg) = @_;
808     ...
809     },
810     );
811    
812     =item cf::CLASS::attachment $name, ...
813    
814     Register an attachment by C<$name> through which attachable objects of the
815     given CLASS can refer to this attachment.
816    
817 root 1.447 Some classes such as deliantra maps and objects can specify attachments
818 root 1.94 that are attached at load/instantiate time, thus the need for a name.
819    
820     These calls expect any number of the following handler/hook descriptions:
821 root 1.46
822     =over 4
823    
824     =item prio => $number
825    
826     Set the priority for all following handlers/hooks (unless overwritten
827     by another C<prio> setting). Lower priority handlers get executed
828     earlier. The default priority is C<0>, and many built-in handlers are
829     registered at priority C<-1000>, so lower priorities should not be used
830     unless you know what you are doing.
831    
832 root 1.93 =item type => $type
833    
834     (Only for C<< cf::object->attach >> calls), limits the attachment to the
835     given type of objects only (the additional parameter C<subtype> can be
836     used to further limit to the given subtype).
837    
838 root 1.46 =item on_I<event> => \&cb
839    
840     Call the given code reference whenever the named event happens (event is
841     something like C<instantiate>, C<apply>, C<use_skill> and so on, and which
842     handlers are recognised generally depends on the type of object these
843     handlers attach to).
844    
845     See F<include/eventinc.h> for the full list of events supported, and their
846     class.
847    
848     =item package => package::
849    
850     Look for sub functions of the name C<< on_I<event> >> in the given
851     package and register them. Only handlers for eevents supported by the
852     object/class are recognised.
853    
854     =back
855    
856 root 1.94 Example, define an attachment called "sockpuppet" that calls the given
857     event handler when a monster attacks:
858    
859     cf::object::attachment sockpuppet =>
860     on_skill_attack => sub {
861     my ($self, $victim) = @_;
862     ...
863     }
864     }
865    
866 root 1.96 =item $attachable->valid
867    
868     Just because you have a perl object does not mean that the corresponding
869     C-level object still exists. If you try to access an object that has no
870     valid C counterpart anymore you get an exception at runtime. This method
871     can be used to test for existence of the C object part without causing an
872     exception.
873    
874 root 1.39 =cut
875    
876 root 1.40 # the following variables are defined in .xs and must not be re-created
877 root 1.100 our @CB_GLOBAL = (); # registry for all global events
878     our @CB_ATTACHABLE = (); # registry for all attachables
879     our @CB_OBJECT = (); # all objects (should not be used except in emergency)
880     our @CB_PLAYER = ();
881     our @CB_CLIENT = ();
882     our @CB_TYPE = (); # registry for type (cf-object class) based events
883     our @CB_MAP = ();
884 root 1.39
885 root 1.45 my %attachment;
886    
887 root 1.170 sub cf::attachable::thawer_merge {
888     # simply override everything except _meta
889     local $_[0]{_meta};
890     %{$_[0]} = %{$_[1]};
891     }
892    
893 root 1.93 sub _attach_cb($$$$) {
894     my ($registry, $event, $prio, $cb) = @_;
895 root 1.39
896     use sort 'stable';
897    
898     $cb = [$prio, $cb];
899    
900     @{$registry->[$event]} = sort
901     { $a->[0] cmp $b->[0] }
902     @{$registry->[$event] || []}, $cb;
903     }
904    
905 root 1.100 # hack
906     my %attachable_klass = map +($_ => 1), KLASS_OBJECT, KLASS_CLIENT, KLASS_PLAYER, KLASS_MAP;
907    
908 root 1.39 # attach handles attaching event callbacks
909     # the only thing the caller has to do is pass the correct
910     # registry (== where the callback attaches to).
911 root 1.93 sub _attach {
912 root 1.45 my ($registry, $klass, @arg) = @_;
913 root 1.39
914 root 1.93 my $object_type;
915 root 1.39 my $prio = 0;
916     my %cb_id = map +("on_" . lc $EVENT[$_][0], $_) , grep $EVENT[$_][1] == $klass, 0 .. $#EVENT;
917    
918 root 1.100 #TODO: get rid of this hack
919     if ($attachable_klass{$klass}) {
920     %cb_id = (%cb_id, map +("on_" . lc $EVENT[$_][0], $_) , grep $EVENT[$_][1] == KLASS_ATTACHABLE, 0 .. $#EVENT);
921     }
922    
923 root 1.45 while (@arg) {
924     my $type = shift @arg;
925 root 1.39
926     if ($type eq "prio") {
927 root 1.45 $prio = shift @arg;
928 root 1.39
929 root 1.93 } elsif ($type eq "type") {
930     $object_type = shift @arg;
931     $registry = $CB_TYPE[$object_type] ||= [];
932    
933     } elsif ($type eq "subtype") {
934     defined $object_type or Carp::croak "subtype specified without type";
935     my $object_subtype = shift @arg;
936 root 1.267 $registry = $CB_TYPE[$object_type + $object_subtype * NUM_TYPES] ||= [];
937 root 1.93
938 root 1.39 } elsif ($type eq "package") {
939 root 1.45 my $pkg = shift @arg;
940 root 1.39
941     while (my ($name, $id) = each %cb_id) {
942     if (my $cb = $pkg->can ($name)) {
943 root 1.93 _attach_cb $registry, $id, $prio, $cb;
944 root 1.39 }
945     }
946    
947     } elsif (exists $cb_id{$type}) {
948 root 1.93 _attach_cb $registry, $cb_id{$type}, $prio, shift @arg;
949 root 1.39
950     } elsif (ref $type) {
951     warn "attaching objects not supported, ignoring.\n";
952    
953     } else {
954 root 1.45 shift @arg;
955 root 1.39 warn "attach argument '$type' not supported, ignoring.\n";
956     }
957     }
958     }
959    
960 root 1.93 sub _object_attach {
961 root 1.48 my ($obj, $name, %arg) = @_;
962 root 1.46
963 root 1.55 return if exists $obj->{_attachment}{$name};
964    
965 root 1.46 if (my $attach = $attachment{$name}) {
966     my $registry = $obj->registry;
967    
968 root 1.47 for (@$attach) {
969     my ($klass, @attach) = @$_;
970 root 1.93 _attach $registry, $klass, @attach;
971 root 1.47 }
972 root 1.46
973 root 1.48 $obj->{$name} = \%arg;
974 root 1.46 } else {
975 root 1.280 warn "object uses attachment '$name' which is not available, postponing.\n";
976 root 1.46 }
977    
978 root 1.50 $obj->{_attachment}{$name} = undef;
979 root 1.46 }
980    
981 root 1.93 sub cf::attachable::attach {
982     if (ref $_[0]) {
983     _object_attach @_;
984     } else {
985     _attach shift->_attach_registry, @_;
986     }
987 root 1.267 _recalc_want;
988 root 1.55 };
989 root 1.46
990 root 1.54 # all those should be optimised
991 root 1.93 sub cf::attachable::detach {
992 root 1.54 my ($obj, $name) = @_;
993 root 1.46
994 root 1.93 if (ref $obj) {
995     delete $obj->{_attachment}{$name};
996     reattach ($obj);
997     } else {
998     Carp::croak "cannot, currently, detach class attachments";
999     }
1000 root 1.267 _recalc_want;
1001 root 1.55 };
1002    
1003 root 1.93 sub cf::attachable::attached {
1004 root 1.55 my ($obj, $name) = @_;
1005    
1006     exists $obj->{_attachment}{$name}
1007 root 1.39 }
1008    
1009 root 1.100 for my $klass (qw(ATTACHABLE GLOBAL OBJECT PLAYER CLIENT MAP)) {
1010 root 1.93 eval "#line " . __LINE__ . " 'cf.pm'
1011     sub cf::\L$klass\E::_attach_registry {
1012     (\\\@CB_$klass, KLASS_$klass)
1013     }
1014 root 1.45
1015 root 1.93 sub cf::\L$klass\E::attachment {
1016     my \$name = shift;
1017 root 1.39
1018 root 1.93 \$attachment{\$name} = [[KLASS_$klass, \@_]];
1019     }
1020     ";
1021     die if $@;
1022 root 1.52 }
1023    
1024 root 1.39 our $override;
1025 elmex 1.310 our @INVOKE_RESULTS = (); # referenced from .xs code. TODO: play tricks with reify and mortals?
1026 root 1.39
1027 root 1.45 sub override {
1028     $override = 1;
1029 elmex 1.310 @INVOKE_RESULTS = (@_);
1030 root 1.39 }
1031    
1032 root 1.45 sub do_invoke {
1033 root 1.39 my $event = shift;
1034 root 1.40 my $callbacks = shift;
1035 root 1.39
1036 elmex 1.310 @INVOKE_RESULTS = ();
1037 root 1.45
1038 root 1.39 local $override;
1039    
1040 root 1.40 for (@$callbacks) {
1041 root 1.39 eval { &{$_->[1]} };
1042    
1043     if ($@) {
1044     warn "$@";
1045 root 1.64 warn "... while processing $EVENT[$event][0](@_) event, skipping processing altogether.\n";
1046 root 1.39 override;
1047     }
1048    
1049     return 1 if $override;
1050     }
1051    
1052     0
1053     }
1054    
1055 root 1.406 =item $bool = cf::global->invoke (EVENT_CLASS_XXX, ...)
1056 root 1.55
1057 root 1.96 =item $bool = $attachable->invoke (EVENT_CLASS_XXX, ...)
1058 root 1.55
1059 root 1.96 Generate an object-specific event with the given arguments.
1060 root 1.55
1061 root 1.96 This API is preliminary (most likely, the EVENT_CLASS_xxx prefix will be
1062 root 1.55 removed in future versions), and there is no public API to access override
1063 elmex 1.310 results (if you must, access C<@cf::INVOKE_RESULTS> directly).
1064 root 1.55
1065     =back
1066    
1067 root 1.71 =cut
1068    
1069 root 1.70 #############################################################################
1070 root 1.45 # object support
1071 root 1.312
1072 root 1.386 sub _object_equal($$);
1073     sub _object_equal($$) {
1074     my ($a, $b) = @_;
1075    
1076     return 0 unless (ref $a) eq (ref $b);
1077    
1078     if ("HASH" eq ref $a) {
1079     my @ka = keys %$a;
1080     my @kb = keys %$b;
1081    
1082     return 0 if @ka != @kb;
1083    
1084     for (0 .. $#ka) {
1085     return 0 unless $ka[$_] eq $kb[$_];
1086     return 0 unless _object_equal $a->{$ka[$_]}, $b->{$kb[$_]};
1087     }
1088    
1089     } elsif ("ARRAY" eq ref $a) {
1090    
1091     return 0 if @$a != @$b;
1092    
1093     for (0 .. $#$a) {
1094     return 0 unless _object_equal $a->[$_], $b->[$_];
1095     }
1096    
1097     } elsif ($a ne $b) {
1098     return 0;
1099     }
1100    
1101     1
1102     }
1103    
1104     our $SLOW_MERGES;#d#
1105 root 1.312 sub _can_merge {
1106     my ($ob1, $ob2) = @_;
1107    
1108 root 1.386 ++$SLOW_MERGES;#d#
1109 root 1.312
1110 root 1.386 # we do the slow way here
1111     return _object_equal $ob1, $ob2
1112 root 1.312 }
1113 root 1.45
1114 root 1.102 sub reattach {
1115     # basically do the same as instantiate, without calling instantiate
1116     my ($obj) = @_;
1117    
1118 root 1.441 # no longer needed after getting rid of delete_package?
1119     #bless $obj, ref $obj; # re-bless in case extensions have been reloaded
1120 root 1.169
1121 root 1.102 my $registry = $obj->registry;
1122    
1123     @$registry = ();
1124    
1125     delete $obj->{_attachment} unless scalar keys %{ $obj->{_attachment} || {} };
1126    
1127     for my $name (keys %{ $obj->{_attachment} || {} }) {
1128     if (my $attach = $attachment{$name}) {
1129     for (@$attach) {
1130     my ($klass, @attach) = @$_;
1131     _attach $registry, $klass, @attach;
1132     }
1133     } else {
1134     warn "object uses attachment '$name' that is not available, postponing.\n";
1135     }
1136     }
1137     }
1138    
1139 root 1.100 cf::attachable->attach (
1140     prio => -1000000,
1141     on_instantiate => sub {
1142     my ($obj, $data) = @_;
1143 root 1.45
1144 root 1.398 $data = decode_json $data;
1145 root 1.45
1146 root 1.100 for (@$data) {
1147     my ($name, $args) = @$_;
1148 root 1.49
1149 root 1.100 $obj->attach ($name, %{$args || {} });
1150     }
1151     },
1152 root 1.102 on_reattach => \&reattach,
1153 root 1.100 on_clone => sub {
1154     my ($src, $dst) = @_;
1155    
1156     @{$dst->registry} = @{$src->registry};
1157    
1158     %$dst = %$src;
1159    
1160     %{$dst->{_attachment}} = %{$src->{_attachment}}
1161     if exists $src->{_attachment};
1162     },
1163     );
1164 root 1.45
1165 root 1.46 sub object_freezer_save {
1166 root 1.59 my ($filename, $rdata, $objs) = @_;
1167 root 1.46
1168 root 1.105 sync_job {
1169     if (length $$rdata) {
1170 root 1.362 utf8::decode (my $decname = $filename);
1171 root 1.105 warn sprintf "saving %s (%d,%d)\n",
1172 root 1.362 $decname, length $$rdata, scalar @$objs;
1173 root 1.60
1174 root 1.105 if (my $fh = aio_open "$filename~", O_WRONLY | O_CREAT, 0600) {
1175 root 1.427 aio_chmod $fh, SAVE_MODE;
1176 root 1.105 aio_write $fh, 0, (length $$rdata), $$rdata, 0;
1177 root 1.204 aio_fsync $fh if $cf::USE_FSYNC;
1178 root 1.427 aio_close $fh;
1179 root 1.105
1180     if (@$objs) {
1181     if (my $fh = aio_open "$filename.pst~", O_WRONLY | O_CREAT, 0600) {
1182 root 1.427 aio_chmod $fh, SAVE_MODE;
1183 root 1.388 my $data = Coro::Storable::nfreeze { version => 1, objs => $objs };
1184 root 1.105 aio_write $fh, 0, (length $data), $data, 0;
1185 root 1.204 aio_fsync $fh if $cf::USE_FSYNC;
1186 root 1.427 aio_close $fh;
1187 root 1.105 aio_rename "$filename.pst~", "$filename.pst";
1188     }
1189     } else {
1190     aio_unlink "$filename.pst";
1191     }
1192    
1193     aio_rename "$filename~", $filename;
1194 root 1.456
1195     $filename =~ s%/[^/]+$%%;
1196 root 1.457 aio_pathsync $filename if $cf::USE_FSYNC;
1197 root 1.60 } else {
1198 root 1.105 warn "FATAL: $filename~: $!\n";
1199 root 1.60 }
1200 root 1.59 } else {
1201 root 1.105 aio_unlink $filename;
1202     aio_unlink "$filename.pst";
1203 root 1.59 }
1204 root 1.356 };
1205 root 1.45 }
1206    
1207 root 1.80 sub object_freezer_as_string {
1208     my ($rdata, $objs) = @_;
1209    
1210     use Data::Dumper;
1211    
1212 root 1.81 $$rdata . Dumper $objs
1213 root 1.80 }
1214    
1215 root 1.46 sub object_thawer_load {
1216     my ($filename) = @_;
1217    
1218 root 1.105 my ($data, $av);
1219 root 1.61
1220 root 1.105 (aio_load $filename, $data) >= 0
1221     or return;
1222 root 1.61
1223 root 1.105 unless (aio_stat "$filename.pst") {
1224     (aio_load "$filename.pst", $av) >= 0
1225     or return;
1226 root 1.356
1227 root 1.388 my $st = eval { Coro::Storable::thaw $av };
1228 root 1.380 $av = $st->{objs};
1229 root 1.61 }
1230 root 1.45
1231 root 1.362 utf8::decode (my $decname = $filename);
1232     warn sprintf "loading %s (%d,%d)\n",
1233     $decname, length $data, scalar @{$av || []};
1234 root 1.356
1235     ($data, $av)
1236 root 1.45 }
1237    
1238 root 1.281 =head2 COMMAND CALLBACKS
1239    
1240     =over 4
1241    
1242     =cut
1243    
1244 root 1.45 #############################################################################
1245 root 1.85 # command handling &c
1246 root 1.39
1247 root 1.85 =item cf::register_command $name => \&callback($ob,$args);
1248 root 1.1
1249 root 1.85 Register a callback for execution when the client sends the user command
1250     $name.
1251 root 1.5
1252 root 1.85 =cut
1253 root 1.5
1254 root 1.85 sub register_command {
1255     my ($name, $cb) = @_;
1256 root 1.5
1257 root 1.85 my $caller = caller;
1258     #warn "registering command '$name/$time' to '$caller'";
1259 root 1.1
1260 root 1.85 push @{ $COMMAND{$name} }, [$caller, $cb];
1261 root 1.1 }
1262    
1263 root 1.85 =item cf::register_extcmd $name => \&callback($pl,$packet);
1264 root 1.1
1265 root 1.287 Register a callback for execution when the client sends an (synchronous)
1266     extcmd packet. Ext commands will be processed in the order they are
1267     received by the server, like other user commands. The first argument is
1268     the logged-in player. Ext commands can only be processed after a player
1269     has logged in successfully.
1270    
1271     If the callback returns something, it is sent back as if reply was being
1272     called.
1273    
1274     =item cf::register_exticmd $name => \&callback($ns,$packet);
1275    
1276     Register a callback for execution when the client sends an (asynchronous)
1277     exticmd packet. Exti commands are processed by the server as soon as they
1278     are received, i.e. out of order w.r.t. other commands. The first argument
1279     is a client socket. Exti commands can be received anytime, even before
1280     log-in.
1281 root 1.1
1282 root 1.85 If the callback returns something, it is sent back as if reply was being
1283     called.
1284 root 1.1
1285 root 1.85 =cut
1286 root 1.1
1287 root 1.16 sub register_extcmd {
1288     my ($name, $cb) = @_;
1289    
1290 root 1.159 $EXTCMD{$name} = $cb;
1291 root 1.16 }
1292    
1293 root 1.287 sub register_exticmd {
1294     my ($name, $cb) = @_;
1295    
1296     $EXTICMD{$name} = $cb;
1297     }
1298    
1299 root 1.457 use File::Glob ();
1300    
1301 root 1.93 cf::player->attach (
1302 root 1.85 on_command => sub {
1303     my ($pl, $name, $params) = @_;
1304    
1305     my $cb = $COMMAND{$name}
1306     or return;
1307    
1308     for my $cmd (@$cb) {
1309     $cmd->[1]->($pl->ob, $params);
1310     }
1311    
1312     cf::override;
1313     },
1314     on_extcmd => sub {
1315     my ($pl, $buf) = @_;
1316    
1317 root 1.290 my $msg = eval { $pl->ns->{json_coder}->decode ($buf) };
1318 root 1.85
1319     if (ref $msg) {
1320 root 1.316 my ($type, $reply, @payload) =
1321     "ARRAY" eq ref $msg
1322     ? @$msg
1323     : ($msg->{msgtype}, $msg->{msgid}, %$msg); # TODO: version 1, remove
1324    
1325 root 1.338 my @reply;
1326    
1327 root 1.316 if (my $cb = $EXTCMD{$type}) {
1328 root 1.338 @reply = $cb->($pl, @payload);
1329     }
1330    
1331     $pl->ext_reply ($reply, @reply)
1332     if $reply;
1333 root 1.316
1334 root 1.85 } else {
1335     warn "player " . ($pl->ob->name) . " sent unparseable ext message: <$buf>\n";
1336     }
1337    
1338     cf::override;
1339     },
1340 root 1.93 );
1341 root 1.85
1342 root 1.457 # "readahead" all extensions
1343     sub cache_extensions {
1344     my $grp = IO::AIO::aio_group;
1345    
1346     add $grp IO::AIO::aio_readdir $LIBDIR, sub {
1347     for (grep /\.ext$/, @{$_[0]}) {
1348     add $grp IO::AIO::aio_load "$LIBDIR/$_", my $data;
1349     }
1350     };
1351    
1352     $grp
1353     }
1354    
1355 root 1.278 sub load_extensions {
1356     cf::sync_job {
1357     my %todo;
1358    
1359     for my $path (<$LIBDIR/*.ext>) {
1360     next unless -r $path;
1361    
1362     $path =~ /([^\/\\]+)\.ext$/ or die "$path";
1363     my $base = $1;
1364     my $pkg = $1;
1365     $pkg =~ s/[^[:word:]]/_/g;
1366     $pkg = "ext::$pkg";
1367    
1368     open my $fh, "<:utf8", $path
1369     or die "$path: $!";
1370    
1371     my $source = do { local $/; <$fh> };
1372 root 1.1
1373 root 1.278 my %ext = (
1374     path => $path,
1375     base => $base,
1376     pkg => $pkg,
1377     );
1378 root 1.1
1379 root 1.279 $ext{meta} = { map { (split /=/, $_, 2)[0, 1] } split /\s+/, $1 }
1380     if $source =~ /\A#!.*?perl.*?#\s*(.*)$/m;
1381 root 1.1
1382 root 1.278 $ext{source} =
1383 root 1.441 "package $pkg; use 5.10.0; use strict 'vars', 'subs'; use utf8;\n"
1384 root 1.278 . "#line 1 \"$path\"\n{\n"
1385     . $source
1386     . "\n};\n1";
1387 root 1.1
1388 root 1.278 $todo{$base} = \%ext;
1389 root 1.166 }
1390 root 1.1
1391 root 1.278 my %done;
1392     while (%todo) {
1393     my $progress;
1394    
1395     while (my ($k, $v) = each %todo) {
1396 root 1.279 for (split /,\s*/, $v->{meta}{depends}) {
1397 root 1.278 goto skip
1398     unless exists $done{$_};
1399     }
1400    
1401     warn "... loading '$k' into '$v->{pkg}'\n";
1402    
1403     unless (eval $v->{source}) {
1404     my $msg = $@ ? "$v->{path}: $@\n"
1405 root 1.279 : "$v->{base}: extension inactive.\n";
1406 root 1.278
1407     if (exists $v->{meta}{mandatory}) {
1408     warn $msg;
1409 root 1.411 cf::cleanup "mandatory extension failed to load, exiting.";
1410 root 1.278 }
1411    
1412 root 1.279 warn $msg;
1413 root 1.278 }
1414    
1415     $done{$k} = delete $todo{$k};
1416     push @EXTS, $v->{pkg};
1417 root 1.279 $progress = 1;
1418 root 1.278 }
1419 root 1.1
1420 root 1.278 skip:
1421     die "cannot load " . (join ", ", keys %todo) . ": unable to resolve dependencies\n"
1422     unless $progress;
1423     }
1424     };
1425 root 1.1 }
1426    
1427 root 1.8 #############################################################################
1428 root 1.70
1429 root 1.281 =back
1430    
1431 root 1.70 =head2 CORE EXTENSIONS
1432    
1433 root 1.447 Functions and methods that extend core deliantra objects.
1434 root 1.70
1435 root 1.143 =cut
1436    
1437     package cf::player;
1438    
1439 root 1.154 use Coro::AIO;
1440    
1441 root 1.95 =head3 cf::player
1442    
1443 root 1.70 =over 4
1444 root 1.22
1445 root 1.361 =item cf::player::num_playing
1446    
1447     Returns the official number of playing players, as per the Crossfire metaserver rules.
1448    
1449     =cut
1450    
1451     sub num_playing {
1452     scalar grep
1453     $_->ob->map
1454     && !$_->hidden
1455     && !$_->ob->flag (cf::FLAG_WIZ),
1456     cf::player::list
1457     }
1458    
1459 root 1.143 =item cf::player::find $login
1460 root 1.23
1461 root 1.143 Returns the given player object, loading it if necessary (might block).
1462 root 1.23
1463     =cut
1464    
1465 root 1.145 sub playerdir($) {
1466 root 1.253 "$PLAYERDIR/"
1467 root 1.145 . (ref $_[0] ? $_[0]->ob->name : $_[0])
1468     }
1469    
1470 root 1.143 sub path($) {
1471 root 1.145 my $login = ref $_[0] ? $_[0]->ob->name : $_[0];
1472    
1473 root 1.234 (playerdir $login) . "/playerdata"
1474 root 1.143 }
1475    
1476     sub find_active($) {
1477     $cf::PLAYER{$_[0]}
1478     and $cf::PLAYER{$_[0]}->active
1479     and $cf::PLAYER{$_[0]}
1480     }
1481    
1482     sub exists($) {
1483     my ($login) = @_;
1484    
1485     $cf::PLAYER{$login}
1486 root 1.452 or !aio_stat path $login
1487 root 1.143 }
1488    
1489     sub find($) {
1490     return $cf::PLAYER{$_[0]} || do {
1491     my $login = $_[0];
1492    
1493     my $guard = cf::lock_acquire "user_find:$login";
1494    
1495 root 1.151 $cf::PLAYER{$_[0]} || do {
1496 root 1.234 # rename old playerfiles to new ones
1497     #TODO: remove when no longer required
1498     aio_link +(playerdir $login) . "/$login.pl.pst", (playerdir $login) . "/playerdata.pst";
1499     aio_link +(playerdir $login) . "/$login.pl" , (playerdir $login) . "/playerdata";
1500     aio_unlink +(playerdir $login) . "/$login.pl.pst";
1501     aio_unlink +(playerdir $login) . "/$login.pl";
1502    
1503 root 1.356 my $f = new_from_file cf::object::thawer path $login
1504 root 1.151 or return;
1505 root 1.356
1506     my $pl = cf::player::load_pl $f
1507     or return;
1508 root 1.427
1509 root 1.356 local $cf::PLAYER_LOADING{$login} = $pl;
1510     $f->resolve_delayed_derefs;
1511 root 1.151 $cf::PLAYER{$login} = $pl
1512     }
1513     }
1514 root 1.143 }
1515    
1516     sub save($) {
1517     my ($pl) = @_;
1518    
1519     return if $pl->{deny_save};
1520    
1521     my $path = path $pl;
1522     my $guard = cf::lock_acquire "user_save:$path";
1523    
1524     return if $pl->{deny_save};
1525 root 1.146
1526 root 1.154 aio_mkdir playerdir $pl, 0770;
1527 root 1.143 $pl->{last_save} = $cf::RUNTIME;
1528    
1529 root 1.420 cf::get_slot 0.01;
1530    
1531 root 1.143 $pl->save_pl ($path);
1532 root 1.346 cf::cede_to_tick;
1533 root 1.143 }
1534    
1535     sub new($) {
1536     my ($login) = @_;
1537    
1538     my $self = create;
1539    
1540     $self->ob->name ($login);
1541     $self->{deny_save} = 1;
1542    
1543     $cf::PLAYER{$login} = $self;
1544    
1545     $self
1546 root 1.23 }
1547    
1548 root 1.329 =item $player->send_msg ($channel, $msg, $color, [extra...])
1549    
1550     =cut
1551    
1552     sub send_msg {
1553     my $ns = shift->ns
1554     or return;
1555     $ns->send_msg (@_);
1556     }
1557    
1558 root 1.154 =item $pl->quit_character
1559    
1560     Nukes the player without looking back. If logged in, the connection will
1561     be destroyed. May block for a long time.
1562    
1563     =cut
1564    
1565 root 1.145 sub quit_character {
1566     my ($pl) = @_;
1567    
1568 root 1.220 my $name = $pl->ob->name;
1569    
1570 root 1.145 $pl->{deny_save} = 1;
1571 root 1.443 $pl->password ("*"); # this should lock out the player until we have nuked the dir
1572 root 1.145
1573     $pl->invoke (cf::EVENT_PLAYER_LOGOUT, 1) if $pl->active;
1574     $pl->deactivate;
1575 root 1.432 my $killer = cf::arch::get "killer_quit"; $pl->killer ($killer); $killer->destroy;
1576     $pl->ob->check_score;
1577 root 1.145 $pl->invoke (cf::EVENT_PLAYER_QUIT);
1578     $pl->ns->destroy if $pl->ns;
1579    
1580     my $path = playerdir $pl;
1581     my $temp = "$path~$cf::RUNTIME~deleting~";
1582 root 1.154 aio_rename $path, $temp;
1583 root 1.150 delete $cf::PLAYER{$pl->ob->name};
1584     $pl->destroy;
1585 root 1.220
1586     my $prefix = qr<^~\Q$name\E/>;
1587    
1588     # nuke player maps
1589     $cf::MAP{$_}->nuke for grep /$prefix/, keys %cf::MAP;
1590    
1591 root 1.150 IO::AIO::aio_rmtree $temp;
1592 root 1.145 }
1593    
1594 pippijn 1.221 =item $pl->kick
1595    
1596     Kicks a player out of the game. This destroys the connection.
1597    
1598     =cut
1599    
1600     sub kick {
1601     my ($pl, $kicker) = @_;
1602    
1603     $pl->invoke (cf::EVENT_PLAYER_KICK, $kicker);
1604     $pl->killer ("kicked");
1605     $pl->ns->destroy;
1606     }
1607    
1608 root 1.154 =item cf::player::list_logins
1609    
1610     Returns am arrayref of all valid playernames in the system, can take a
1611     while and may block, so not sync_job-capable, ever.
1612    
1613     =cut
1614    
1615     sub list_logins {
1616 root 1.253 my $dirs = aio_readdir $PLAYERDIR
1617 root 1.154 or return [];
1618    
1619     my @logins;
1620    
1621     for my $login (@$dirs) {
1622 root 1.354 my $path = path $login;
1623    
1624     # a .pst is a dead give-away for a valid player
1625 root 1.427 # if no pst file found, open and chekc for blocked users
1626     if (aio_stat "$path.pst") {
1627 root 1.354 my $fh = aio_open $path, Fcntl::O_RDONLY, 0 or next;
1628     aio_read $fh, 0, 512, my $buf, 0 or next;
1629     $buf !~ /^password -------------$/m or next; # official not-valid tag
1630     }
1631 root 1.154
1632     utf8::decode $login;
1633     push @logins, $login;
1634     }
1635    
1636     \@logins
1637     }
1638    
1639     =item $player->maps
1640    
1641 root 1.166 Returns an arrayref of map paths that are private for this
1642 root 1.154 player. May block.
1643    
1644     =cut
1645    
1646     sub maps($) {
1647     my ($pl) = @_;
1648    
1649 root 1.201 $pl = ref $pl ? $pl->ob->name : $pl;
1650    
1651 root 1.154 my $files = aio_readdir playerdir $pl
1652     or return;
1653    
1654     my @paths;
1655    
1656     for (@$files) {
1657     utf8::decode $_;
1658     next if /\.(?:pl|pst)$/;
1659 root 1.158 next unless /^$PATH_SEP/o;
1660 root 1.154
1661 root 1.201 push @paths, cf::map::normalise "~$pl/$_";
1662 root 1.154 }
1663    
1664     \@paths
1665     }
1666    
1667 root 1.447 =item $protocol_xml = $player->expand_cfpod ($cfpod)
1668 root 1.283
1669 root 1.447 Expand deliantra pod fragments into protocol xml.
1670 root 1.283
1671 root 1.316 =item $player->ext_reply ($msgid, @msg)
1672 root 1.95
1673     Sends an ext reply to the player.
1674    
1675     =cut
1676    
1677 root 1.316 sub ext_reply($$@) {
1678     my ($self, $id, @msg) = @_;
1679 root 1.95
1680 root 1.336 $self->ns->ext_reply ($id, @msg)
1681 root 1.95 }
1682    
1683 root 1.316 =item $player->ext_msg ($type, @msg)
1684 root 1.231
1685     Sends an ext event to the client.
1686    
1687     =cut
1688    
1689 root 1.316 sub ext_msg($$@) {
1690     my ($self, $type, @msg) = @_;
1691 root 1.231
1692 root 1.316 $self->ns->ext_msg ($type, @msg);
1693 root 1.231 }
1694    
1695 root 1.238 =head3 cf::region
1696    
1697     =over 4
1698    
1699     =cut
1700    
1701     package cf::region;
1702    
1703     =item cf::region::find_by_path $path
1704    
1705 root 1.281 Tries to decuce the likely region for a map knowing only its path.
1706 root 1.238
1707     =cut
1708    
1709     sub find_by_path($) {
1710     my ($path) = @_;
1711    
1712     my ($match, $specificity);
1713    
1714     for my $region (list) {
1715 root 1.304 if ($region->{match} && $path =~ $region->{match}) {
1716 root 1.238 ($match, $specificity) = ($region, $region->specificity)
1717     if $region->specificity > $specificity;
1718     }
1719     }
1720    
1721     $match
1722     }
1723 root 1.143
1724 root 1.95 =back
1725    
1726 root 1.110 =head3 cf::map
1727    
1728     =over 4
1729    
1730     =cut
1731    
1732     package cf::map;
1733    
1734     use Fcntl;
1735     use Coro::AIO;
1736    
1737 root 1.166 use overload
1738 root 1.173 '""' => \&as_string,
1739     fallback => 1;
1740 root 1.166
1741 root 1.133 our $MAX_RESET = 3600;
1742     our $DEFAULT_RESET = 3000;
1743 root 1.110
1744     sub generate_random_map {
1745 root 1.166 my ($self, $rmp) = @_;
1746 root 1.418
1747     my $lock = cf::lock_acquire "generate_random_map"; # the random map generator is NOT reentrant ATM
1748    
1749 root 1.110 # mit "rum" bekleckern, nicht
1750 root 1.166 $self->_create_random_map (
1751 root 1.110 $rmp->{wallstyle}, $rmp->{wall_name}, $rmp->{floorstyle}, $rmp->{monsterstyle},
1752     $rmp->{treasurestyle}, $rmp->{layoutstyle}, $rmp->{doorstyle}, $rmp->{decorstyle},
1753     $rmp->{origin_map}, $rmp->{final_map}, $rmp->{exitstyle}, $rmp->{this_map},
1754     $rmp->{exit_on_final_map},
1755     $rmp->{xsize}, $rmp->{ysize},
1756     $rmp->{expand2x}, $rmp->{layoutoptions1}, $rmp->{layoutoptions2}, $rmp->{layoutoptions3},
1757     $rmp->{symmetry}, $rmp->{difficulty}, $rmp->{difficulty_given}, $rmp->{difficulty_increase},
1758     $rmp->{dungeon_level}, $rmp->{dungeon_depth}, $rmp->{decoroptions}, $rmp->{orientation},
1759     $rmp->{origin_y}, $rmp->{origin_x}, $rmp->{random_seed}, $rmp->{total_map_hp},
1760     $rmp->{map_layout_style}, $rmp->{treasureoptions}, $rmp->{symmetry_used},
1761 root 1.162 (cf::region::find $rmp->{region}), $rmp->{custom}
1762     )
1763 root 1.110 }
1764    
1765 root 1.187 =item cf::map->register ($regex, $prio)
1766    
1767     Register a handler for the map path matching the given regex at the
1768     givne priority (higher is better, built-in handlers have priority 0, the
1769     default).
1770    
1771     =cut
1772    
1773 root 1.166 sub register {
1774 root 1.187 my (undef, $regex, $prio) = @_;
1775 root 1.166 my $pkg = caller;
1776    
1777     no strict;
1778     push @{"$pkg\::ISA"}, __PACKAGE__;
1779    
1780 root 1.187 $EXT_MAP{$pkg} = [$prio, qr<$regex>];
1781 root 1.166 }
1782    
1783     # also paths starting with '/'
1784 root 1.187 $EXT_MAP{"cf::map"} = [0, qr{^(?=/)}];
1785 root 1.166
1786 root 1.170 sub thawer_merge {
1787 root 1.172 my ($self, $merge) = @_;
1788    
1789 root 1.170 # we have to keep some variables in memory intact
1790 root 1.172 local $self->{path};
1791     local $self->{load_path};
1792 root 1.170
1793 root 1.172 $self->SUPER::thawer_merge ($merge);
1794 root 1.170 }
1795    
1796 root 1.166 sub normalise {
1797     my ($path, $base) = @_;
1798    
1799 root 1.192 $path = "$path"; # make sure its a string
1800    
1801 root 1.199 $path =~ s/\.map$//;
1802    
1803 root 1.166 # map plan:
1804     #
1805     # /! non-realised random map exit (special hack!)
1806     # {... are special paths that are not being touched
1807     # ?xxx/... are special absolute paths
1808     # ?random/... random maps
1809     # /... normal maps
1810     # ~user/... per-player map of a specific user
1811    
1812     $path =~ s/$PATH_SEP/\//go;
1813    
1814     # treat it as relative path if it starts with
1815     # something that looks reasonable
1816     if ($path =~ m{^(?:\./|\.\./|\w)}) {
1817     $base or Carp::carp "normalise called with relative path and no base: '$path'";
1818    
1819     $base =~ s{[^/]+/?$}{};
1820     $path = "$base/$path";
1821     }
1822    
1823     for ($path) {
1824     redo if s{//}{/};
1825     redo if s{/\.?/}{/};
1826     redo if s{/[^/]+/\.\./}{/};
1827     }
1828    
1829     $path
1830     }
1831    
1832     sub new_from_path {
1833     my (undef, $path, $base) = @_;
1834    
1835     return $path if UNIVERSAL::isa $path, "cf::map"; # already a map object
1836    
1837     $path = normalise $path, $base;
1838    
1839 root 1.187 for my $pkg (sort { $EXT_MAP{$b}[0] <=> $EXT_MAP{$a}[0] } keys %EXT_MAP) {
1840     if ($path =~ $EXT_MAP{$pkg}[1]) {
1841 root 1.166 my $self = bless cf::map::new, $pkg;
1842     $self->{path} = $path; $self->path ($path);
1843     $self->init; # pass $1 etc.
1844     return $self;
1845     }
1846     }
1847    
1848 root 1.308 Carp::cluck "unable to resolve path '$path' (base '$base').";
1849 root 1.166 ()
1850     }
1851    
1852     sub init {
1853     my ($self) = @_;
1854    
1855     $self
1856     }
1857    
1858     sub as_string {
1859     my ($self) = @_;
1860    
1861     "$self->{path}"
1862     }
1863    
1864     # the displayed name, this is a one way mapping
1865     sub visible_name {
1866     &as_string
1867     }
1868    
1869     # the original (read-only) location
1870     sub load_path {
1871     my ($self) = @_;
1872    
1873 root 1.254 "$MAPDIR/$self->{path}.map"
1874 root 1.166 }
1875    
1876     # the temporary/swap location
1877     sub save_path {
1878     my ($self) = @_;
1879    
1880 root 1.419 (my $path = $_[0]{path}) =~ s/\//$PATH_SEP/go;
1881 root 1.254 "$TMPDIR/$path.map"
1882 root 1.166 }
1883    
1884     # the unique path, undef == no special unique path
1885     sub uniq_path {
1886     my ($self) = @_;
1887    
1888 root 1.419 (my $path = $_[0]{path}) =~ s/\//$PATH_SEP/go;
1889 root 1.253 "$UNIQUEDIR/$path"
1890 root 1.166 }
1891    
1892 root 1.110 # and all this just because we cannot iterate over
1893     # all maps in C++...
1894     sub change_all_map_light {
1895     my ($change) = @_;
1896    
1897 root 1.122 $_->change_map_light ($change)
1898     for grep $_->outdoor, values %cf::MAP;
1899 root 1.110 }
1900    
1901 root 1.275 sub decay_objects {
1902     my ($self) = @_;
1903    
1904     return if $self->{deny_reset};
1905    
1906     $self->do_decay_objects;
1907     }
1908    
1909 root 1.166 sub unlink_save {
1910     my ($self) = @_;
1911    
1912     utf8::encode (my $save = $self->save_path);
1913 root 1.170 IO::AIO::aioreq_pri 4; Coro::AIO::aio_unlink $save;
1914     IO::AIO::aioreq_pri 4; Coro::AIO::aio_unlink "$save.pst";
1915 root 1.166 }
1916    
1917     sub load_header_from($) {
1918     my ($self, $path) = @_;
1919 root 1.110
1920     utf8::encode $path;
1921 root 1.356 my $f = new_from_file cf::object::thawer $path
1922     or return;
1923 root 1.110
1924 root 1.356 $self->_load_header ($f)
1925 root 1.110 or return;
1926    
1927 root 1.356 local $MAP_LOADING{$self->{path}} = $self;
1928     $f->resolve_delayed_derefs;
1929    
1930 root 1.166 $self->{load_path} = $path;
1931 root 1.135
1932 root 1.166 1
1933     }
1934 root 1.110
1935 root 1.188 sub load_header_orig {
1936 root 1.166 my ($self) = @_;
1937 root 1.110
1938 root 1.166 $self->load_header_from ($self->load_path)
1939 root 1.110 }
1940    
1941 root 1.188 sub load_header_temp {
1942 root 1.166 my ($self) = @_;
1943 root 1.110
1944 root 1.166 $self->load_header_from ($self->save_path)
1945     }
1946 root 1.110
1947 root 1.188 sub prepare_temp {
1948     my ($self) = @_;
1949    
1950     $self->last_access ((delete $self->{last_access})
1951     || $cf::RUNTIME); #d#
1952     # safety
1953     $self->{instantiate_time} = $cf::RUNTIME
1954     if $self->{instantiate_time} > $cf::RUNTIME;
1955     }
1956    
1957     sub prepare_orig {
1958     my ($self) = @_;
1959    
1960     $self->{load_original} = 1;
1961     $self->{instantiate_time} = $cf::RUNTIME;
1962     $self->last_access ($cf::RUNTIME);
1963     $self->instantiate;
1964     }
1965    
1966 root 1.166 sub load_header {
1967     my ($self) = @_;
1968 root 1.110
1969 root 1.188 if ($self->load_header_temp) {
1970     $self->prepare_temp;
1971 root 1.166 } else {
1972 root 1.188 $self->load_header_orig
1973 root 1.166 or return;
1974 root 1.188 $self->prepare_orig;
1975 root 1.166 }
1976 root 1.120
1977 root 1.275 $self->{deny_reset} = 1
1978     if $self->no_reset;
1979    
1980 root 1.238 $self->default_region (cf::region::find_by_path $self->{path})
1981     unless $self->default_region;
1982    
1983 root 1.166 1
1984     }
1985 root 1.110
1986 root 1.166 sub find;
1987     sub find {
1988     my ($path, $origin) = @_;
1989 root 1.134
1990 root 1.166 $path = normalise $path, $origin && $origin->path;
1991 root 1.110
1992 root 1.358 cf::lock_wait "map_data:$path";#d#remove
1993 root 1.166 cf::lock_wait "map_find:$path";
1994 root 1.110
1995 root 1.166 $cf::MAP{$path} || do {
1996 root 1.429 my $guard1 = cf::lock_acquire "map_data:$path"; # just for the fun of it
1997     my $guard2 = cf::lock_acquire "map_find:$path";
1998 root 1.358
1999 root 1.166 my $map = new_from_path cf::map $path
2000     or return;
2001 root 1.110
2002 root 1.116 $map->{last_save} = $cf::RUNTIME;
2003 root 1.110
2004 root 1.166 $map->load_header
2005     or return;
2006 root 1.134
2007 root 1.275 if ($map->should_reset) {#d#TODO# disabled, crashy (locking issue?)
2008 root 1.185 # doing this can freeze the server in a sync job, obviously
2009     #$cf::WAIT_FOR_TICK->wait;
2010 root 1.429 undef $guard2;
2011 root 1.358 undef $guard1;
2012 root 1.112 $map->reset;
2013 root 1.192 return find $path;
2014 root 1.112 }
2015 root 1.110
2016 root 1.166 $cf::MAP{$path} = $map
2017 root 1.110 }
2018     }
2019    
2020 root 1.188 sub pre_load { }
2021     sub post_load { }
2022    
2023 root 1.110 sub load {
2024     my ($self) = @_;
2025    
2026 root 1.196 local $self->{deny_reset} = 1; # loading can take a long time
2027    
2028 root 1.120 my $path = $self->{path};
2029    
2030 root 1.256 {
2031 root 1.357 my $guard = cf::lock_acquire "map_data:$path";
2032 root 1.256
2033 root 1.357 return unless $self->valid;
2034 root 1.360 return unless $self->in_memory == cf::MAP_SWAPPED;
2035 root 1.110
2036 root 1.256 $self->in_memory (cf::MAP_LOADING);
2037 root 1.110
2038 root 1.256 $self->alloc;
2039 root 1.188
2040 root 1.256 $self->pre_load;
2041 root 1.346 cf::cede_to_tick;
2042 root 1.188
2043 root 1.356 my $f = new_from_file cf::object::thawer $self->{load_path};
2044     $f->skip_block;
2045     $self->_load_objects ($f)
2046 root 1.256 or return;
2047 root 1.110
2048 root 1.439 $self->post_load_original
2049 root 1.256 if delete $self->{load_original};
2050 root 1.111
2051 root 1.256 if (my $uniq = $self->uniq_path) {
2052     utf8::encode $uniq;
2053 root 1.356 unless (aio_stat $uniq) {
2054     if (my $f = new_from_file cf::object::thawer $uniq) {
2055     $self->clear_unique_items;
2056     $self->_load_objects ($f);
2057     $f->resolve_delayed_derefs;
2058     }
2059 root 1.256 }
2060 root 1.110 }
2061    
2062 root 1.356 $f->resolve_delayed_derefs;
2063    
2064 root 1.346 cf::cede_to_tick;
2065 root 1.256 # now do the right thing for maps
2066     $self->link_multipart_objects;
2067 root 1.110 $self->difficulty ($self->estimate_difficulty)
2068     unless $self->difficulty;
2069 root 1.346 cf::cede_to_tick;
2070 root 1.256
2071     unless ($self->{deny_activate}) {
2072     $self->decay_objects;
2073     $self->fix_auto_apply;
2074     $self->update_buttons;
2075 root 1.346 cf::cede_to_tick;
2076 root 1.256 $self->set_darkness_map;
2077 root 1.346 cf::cede_to_tick;
2078 root 1.256 $self->activate;
2079     }
2080    
2081 root 1.325 $self->{last_save} = $cf::RUNTIME;
2082     $self->last_access ($cf::RUNTIME);
2083 root 1.324
2084 root 1.420 $self->in_memory (cf::MAP_ACTIVE);
2085 root 1.110 }
2086    
2087 root 1.188 $self->post_load;
2088 root 1.166 }
2089    
2090     sub customise_for {
2091     my ($self, $ob) = @_;
2092    
2093     return find "~" . $ob->name . "/" . $self->{path}
2094     if $self->per_player;
2095 root 1.134
2096 root 1.275 # return find "?party/" . $ob->name . "/" . $self->{path}
2097     # if $self->per_party;
2098    
2099 root 1.166 $self
2100 root 1.110 }
2101    
2102 root 1.157 # find and load all maps in the 3x3 area around a map
2103 root 1.333 sub load_neighbours {
2104 root 1.157 my ($map) = @_;
2105    
2106 root 1.333 my @neigh; # diagonal neighbours
2107 root 1.157
2108     for (0 .. 3) {
2109     my $neigh = $map->tile_path ($_)
2110     or next;
2111     $neigh = find $neigh, $map
2112     or next;
2113     $neigh->load;
2114    
2115 root 1.333 push @neigh,
2116     [$neigh->tile_path (($_ + 3) % 4), $neigh],
2117     [$neigh->tile_path (($_ + 1) % 4), $neigh];
2118 root 1.157 }
2119    
2120 root 1.333 for (grep defined $_->[0], @neigh) {
2121     my ($path, $origin) = @$_;
2122     my $neigh = find $path, $origin
2123 root 1.157 or next;
2124     $neigh->load;
2125     }
2126     }
2127    
2128 root 1.133 sub find_sync {
2129 root 1.110 my ($path, $origin) = @_;
2130    
2131 root 1.157 cf::sync_job { find $path, $origin }
2132 root 1.133 }
2133    
2134     sub do_load_sync {
2135     my ($map) = @_;
2136 root 1.110
2137 root 1.339 cf::LOG cf::llevDebug | cf::logBacktrace, "do_load_sync"
2138 root 1.342 if $Coro::current == $Coro::main;
2139 root 1.339
2140 root 1.133 cf::sync_job { $map->load };
2141 root 1.110 }
2142    
2143 root 1.157 our %MAP_PREFETCH;
2144 root 1.183 our $MAP_PREFETCHER = undef;
2145 root 1.157
2146     sub find_async {
2147 root 1.339 my ($path, $origin, $load) = @_;
2148 root 1.157
2149 root 1.166 $path = normalise $path, $origin && $origin->{path};
2150 root 1.157
2151 root 1.166 if (my $map = $cf::MAP{$path}) {
2152 root 1.420 return $map if !$load || $map->in_memory == cf::MAP_ACTIVE;
2153 root 1.157 }
2154    
2155 root 1.339 $MAP_PREFETCH{$path} |= $load;
2156    
2157 root 1.183 $MAP_PREFETCHER ||= cf::async {
2158 root 1.374 $Coro::current->{desc} = "map prefetcher";
2159    
2160 root 1.183 while (%MAP_PREFETCH) {
2161 root 1.339 while (my ($k, $v) = each %MAP_PREFETCH) {
2162     if (my $map = find $k) {
2163     $map->load if $v;
2164 root 1.308 }
2165 root 1.183
2166 root 1.339 delete $MAP_PREFETCH{$k};
2167 root 1.183 }
2168     }
2169     undef $MAP_PREFETCHER;
2170     };
2171 root 1.189 $MAP_PREFETCHER->prio (6);
2172 root 1.157
2173     ()
2174     }
2175    
2176 root 1.110 sub save {
2177     my ($self) = @_;
2178    
2179 root 1.345 my $lock = cf::lock_acquire "map_data:$self->{path}";
2180 root 1.137
2181 root 1.110 $self->{last_save} = $cf::RUNTIME;
2182    
2183     return unless $self->dirty;
2184    
2185 root 1.166 my $save = $self->save_path; utf8::encode $save;
2186     my $uniq = $self->uniq_path; utf8::encode $uniq;
2187 root 1.117
2188 root 1.110 $self->{load_path} = $save;
2189    
2190     return if $self->{deny_save};
2191    
2192 root 1.132 local $self->{last_access} = $self->last_access;#d#
2193    
2194 root 1.143 cf::async {
2195 root 1.374 $Coro::current->{desc} = "map player save";
2196 root 1.143 $_->contr->save for $self->players;
2197     };
2198    
2199 root 1.420 cf::get_slot 0.02;
2200    
2201 root 1.110 if ($uniq) {
2202 root 1.166 $self->_save_objects ($save, cf::IO_HEADER | cf::IO_OBJECTS);
2203     $self->_save_objects ($uniq, cf::IO_UNIQUES);
2204 root 1.110 } else {
2205 root 1.166 $self->_save_objects ($save, cf::IO_HEADER | cf::IO_OBJECTS | cf::IO_UNIQUES);
2206 root 1.110 }
2207     }
2208    
2209     sub swap_out {
2210     my ($self) = @_;
2211    
2212 root 1.130 # save first because save cedes
2213     $self->save;
2214    
2215 root 1.345 my $lock = cf::lock_acquire "map_data:$self->{path}";
2216 root 1.137
2217 root 1.110 return if $self->players;
2218 root 1.420 return if $self->in_memory != cf::MAP_ACTIVE;
2219 root 1.110 return if $self->{deny_save};
2220    
2221 root 1.359 $self->in_memory (cf::MAP_SWAPPED);
2222    
2223 root 1.358 $self->deactivate;
2224 root 1.359 $_->clear_links_to ($self) for values %cf::MAP;
2225 root 1.110 $self->clear;
2226     }
2227    
2228 root 1.112 sub reset_at {
2229     my ($self) = @_;
2230 root 1.110
2231     # TODO: safety, remove and allow resettable per-player maps
2232 root 1.114 return 1e99 if $self->{deny_reset};
2233 root 1.110
2234 root 1.112 my $time = $self->fixed_resettime ? $self->{instantiate_time} : $self->last_access;
2235 root 1.114 my $to = List::Util::min $MAX_RESET, $self->reset_timeout || $DEFAULT_RESET;
2236 root 1.110
2237 root 1.112 $time + $to
2238     }
2239    
2240     sub should_reset {
2241     my ($self) = @_;
2242    
2243     $self->reset_at <= $cf::RUNTIME
2244 root 1.111 }
2245    
2246 root 1.110 sub reset {
2247     my ($self) = @_;
2248    
2249 root 1.167 my $lock = cf::lock_acquire "map_data:$self->{path}";
2250 root 1.137
2251 root 1.110 return if $self->players;
2252    
2253 root 1.274 warn "resetting map ", $self->path;
2254 root 1.110
2255 root 1.210 $self->in_memory (cf::MAP_SWAPPED);
2256    
2257     # need to save uniques path
2258     unless ($self->{deny_save}) {
2259     my $uniq = $self->uniq_path; utf8::encode $uniq;
2260    
2261     $self->_save_objects ($uniq, cf::IO_UNIQUES)
2262     if $uniq;
2263     }
2264    
2265 root 1.111 delete $cf::MAP{$self->path};
2266 root 1.110
2267 root 1.358 $self->deactivate;
2268 root 1.359 $_->clear_links_to ($self) for values %cf::MAP;
2269 root 1.167 $self->clear;
2270    
2271 root 1.166 $self->unlink_save;
2272 root 1.111 $self->destroy;
2273 root 1.110 }
2274    
2275 root 1.114 my $nuke_counter = "aaaa";
2276    
2277     sub nuke {
2278     my ($self) = @_;
2279    
2280 root 1.349 {
2281     my $lock = cf::lock_acquire "map_data:$self->{path}";
2282    
2283     delete $cf::MAP{$self->path};
2284 root 1.174
2285 root 1.351 $self->unlink_save;
2286    
2287 root 1.349 bless $self, "cf::map";
2288     delete $self->{deny_reset};
2289     $self->{deny_save} = 1;
2290     $self->reset_timeout (1);
2291     $self->path ($self->{path} = "{nuke}/" . ($nuke_counter++));
2292 root 1.174
2293 root 1.349 $cf::MAP{$self->path} = $self;
2294     }
2295 root 1.174
2296 root 1.114 $self->reset; # polite request, might not happen
2297     }
2298    
2299 root 1.276 =item $maps = cf::map::tmp_maps
2300    
2301     Returns an arrayref with all map paths of currently instantiated and saved
2302 root 1.277 maps. May block.
2303 root 1.276
2304     =cut
2305    
2306     sub tmp_maps() {
2307     [
2308     map {
2309     utf8::decode $_;
2310 root 1.277 /\.map$/
2311 root 1.276 ? normalise $_
2312     : ()
2313     } @{ aio_readdir $TMPDIR or [] }
2314     ]
2315     }
2316    
2317 root 1.277 =item $maps = cf::map::random_maps
2318    
2319     Returns an arrayref with all map paths of currently instantiated and saved
2320     random maps. May block.
2321    
2322     =cut
2323    
2324     sub random_maps() {
2325     [
2326     map {
2327     utf8::decode $_;
2328     /\.map$/
2329     ? normalise "?random/$_"
2330     : ()
2331     } @{ aio_readdir $RANDOMDIR or [] }
2332     ]
2333     }
2334    
2335 root 1.158 =item cf::map::unique_maps
2336    
2337 root 1.166 Returns an arrayref of paths of all shared maps that have
2338 root 1.158 instantiated unique items. May block.
2339    
2340     =cut
2341    
2342     sub unique_maps() {
2343 root 1.276 [
2344     map {
2345     utf8::decode $_;
2346 root 1.419 s/\.map$//; # TODO future compatibility hack
2347     /\.pst$/ || !/^$PATH_SEP/o # TODO unique maps apparebntly lack the .map suffix :/
2348     ? ()
2349     : normalise $_
2350 root 1.276 } @{ aio_readdir $UNIQUEDIR or [] }
2351     ]
2352 root 1.158 }
2353    
2354 root 1.155 =back
2355    
2356     =head3 cf::object
2357    
2358     =cut
2359    
2360     package cf::object;
2361    
2362     =over 4
2363    
2364     =item $ob->inv_recursive
2365 root 1.110
2366 root 1.419 Returns the inventory of the object I<and> their inventories, recursively,
2367     but I<not> the object itself.
2368 root 1.110
2369 root 1.155 =cut
2370 root 1.144
2371 root 1.155 sub inv_recursive_;
2372     sub inv_recursive_ {
2373     map { $_, inv_recursive_ $_->inv } @_
2374     }
2375 root 1.110
2376 root 1.155 sub inv_recursive {
2377     inv_recursive_ inv $_[0]
2378 root 1.110 }
2379    
2380 root 1.356 =item $ref = $ob->ref
2381    
2382 root 1.419 Creates and returns a persistent reference to an object that can be stored as a string.
2383 root 1.356
2384     =item $ob = cf::object::deref ($refstring)
2385    
2386     returns the objetc referenced by refstring. may return undef when it cnanot find the object,
2387     even if the object actually exists. May block.
2388    
2389     =cut
2390    
2391     sub deref {
2392     my ($ref) = @_;
2393    
2394 root 1.377 if ($ref =~ m{^player\/(<1\.[0-9a-f]+>)/(.*)$}) {
2395 root 1.356 my ($uuid, $name) = ($1, $2);
2396     my $pl = $cf::PLAYER_LOADING{$name} || cf::player::find $name
2397     or return;
2398     $pl->ob->uuid eq $uuid
2399     or return;
2400    
2401     $pl->ob
2402     } else {
2403     warn "$ref: cannot resolve object reference\n";
2404     undef
2405     }
2406     }
2407    
2408 root 1.110 package cf;
2409    
2410     =back
2411    
2412 root 1.95 =head3 cf::object::player
2413    
2414     =over 4
2415    
2416 root 1.79 =item $player_object->reply ($npc, $msg[, $flags])
2417 root 1.28
2418     Sends a message to the player, as if the npc C<$npc> replied. C<$npc>
2419     can be C<undef>. Does the right thing when the player is currently in a
2420     dialogue with the given NPC character.
2421    
2422     =cut
2423    
2424 root 1.428 our $SAY_CHANNEL = {
2425     id => "say",
2426     title => "Map",
2427     reply => "say ",
2428     tooltip => "Things said to and replied from npcs near you and other players on the same map only.",
2429     };
2430    
2431     our $CHAT_CHANNEL = {
2432     id => "chat",
2433     title => "Chat",
2434     reply => "chat ",
2435     tooltip => "Player chat and shouts, global to the server.",
2436     };
2437    
2438 root 1.22 # rough implementation of a future "reply" method that works
2439     # with dialog boxes.
2440 root 1.95 #TODO: the first argument must go, split into a $npc->reply_to ( method
2441 root 1.23 sub cf::object::player::reply($$$;$) {
2442     my ($self, $npc, $msg, $flags) = @_;
2443    
2444     $flags = cf::NDI_BROWN | cf::NDI_UNIQUE unless @_ >= 4;
2445 root 1.22
2446 root 1.24 if ($self->{record_replies}) {
2447     push @{ $self->{record_replies} }, [$npc, $msg, $flags];
2448 elmex 1.282
2449 root 1.24 } else {
2450 elmex 1.282 my $pl = $self->contr;
2451    
2452     if ($pl->{npc_dialog} && $pl->{npc_dialog}->{id}) {
2453 root 1.316 my $dialog = $pl->{npc_dialog};
2454     $dialog->{pl}->ext_msg ($dialog->{id}, update => msg => $dialog->{pl}->expand_cfpod ($msg));
2455 elmex 1.282
2456     } else {
2457     $msg = $npc->name . " says: $msg" if $npc;
2458 root 1.428 $self->send_msg ($SAY_CHANNEL => $msg, $flags);
2459 elmex 1.282 }
2460 root 1.24 }
2461 root 1.22 }
2462    
2463 root 1.329 =item $object->send_msg ($channel, $msg, $color, [extra...])
2464    
2465     =cut
2466    
2467     sub cf::object::send_msg {
2468     my $pl = shift->contr
2469     or return;
2470     $pl->send_msg (@_);
2471     }
2472    
2473 root 1.79 =item $player_object->may ("access")
2474    
2475     Returns wether the given player is authorized to access resource "access"
2476     (e.g. "command_wizcast").
2477    
2478     =cut
2479    
2480     sub cf::object::player::may {
2481     my ($self, $access) = @_;
2482    
2483     $self->flag (cf::FLAG_WIZ) ||
2484     (ref $cf::CFG{"may_$access"}
2485     ? scalar grep $self->name eq $_, @{$cf::CFG{"may_$access"}}
2486     : $cf::CFG{"may_$access"})
2487     }
2488 root 1.70
2489 root 1.115 =item $player_object->enter_link
2490    
2491     Freezes the player and moves him/her to a special map (C<{link}>).
2492    
2493 root 1.446 The player should be reasonably safe there for short amounts of time (e.g.
2494     for loading a map). You I<MUST> call C<leave_link> as soon as possible,
2495     though, as the palyer cannot control the character while it is on the link
2496     map.
2497 root 1.115
2498 root 1.166 Will never block.
2499    
2500 root 1.115 =item $player_object->leave_link ($map, $x, $y)
2501    
2502 root 1.166 Moves the player out of the special C<{link}> map onto the specified
2503     map. If the map is not valid (or omitted), the player will be moved back
2504     to the location he/she was before the call to C<enter_link>, or, if that
2505     fails, to the emergency map position.
2506 root 1.115
2507     Might block.
2508    
2509     =cut
2510    
2511 root 1.166 sub link_map {
2512     unless ($LINK_MAP) {
2513     $LINK_MAP = cf::map::find "{link}"
2514 root 1.196 or cf::cleanup "FATAL: unable to provide {link} map, exiting.";
2515 root 1.166 $LINK_MAP->load;
2516     }
2517    
2518     $LINK_MAP
2519     }
2520    
2521 root 1.110 sub cf::object::player::enter_link {
2522     my ($self) = @_;
2523    
2524 root 1.259 $self->deactivate_recursive;
2525 root 1.258
2526 root 1.166 return if UNIVERSAL::isa $self->map, "ext::map_link";
2527 root 1.110
2528 root 1.120 $self->{_link_pos} ||= [$self->map->{path}, $self->x, $self->y]
2529 root 1.270 if $self->map && $self->map->{path} ne "{link}";
2530 root 1.110
2531 root 1.194 $self->enter_map ($LINK_MAP || link_map, 10, 10);
2532 root 1.110 }
2533    
2534     sub cf::object::player::leave_link {
2535     my ($self, $map, $x, $y) = @_;
2536    
2537 root 1.270 return unless $self->contr->active;
2538    
2539 root 1.110 my $link_pos = delete $self->{_link_pos};
2540    
2541     unless ($map) {
2542     # restore original map position
2543     ($map, $x, $y) = @{ $link_pos || [] };
2544 root 1.133 $map = cf::map::find $map;
2545 root 1.110
2546     unless ($map) {
2547     ($map, $x, $y) = @$EMERGENCY_POSITION;
2548 root 1.133 $map = cf::map::find $map
2549 root 1.110 or die "FATAL: cannot load emergency map\n";
2550     }
2551     }
2552    
2553     ($x, $y) = (-1, -1)
2554     unless (defined $x) && (defined $y);
2555    
2556     # use -1 or undef as default coordinates, not 0, 0
2557     ($x, $y) = ($map->enter_x, $map->enter_y)
2558     if $x <=0 && $y <= 0;
2559    
2560     $map->load;
2561 root 1.333 $map->load_neighbours;
2562 root 1.110
2563 root 1.143 return unless $self->contr->active;
2564 root 1.446 $self->flag (cf::FLAG_DEBUG, 0);#d# temp
2565 root 1.110 $self->activate_recursive;
2566 root 1.215
2567     local $self->{_prev_pos} = $link_pos; # ugly hack for rent.ext
2568 root 1.110 $self->enter_map ($map, $x, $y);
2569     }
2570    
2571 root 1.306 =item $player_object->goto ($path, $x, $y[, $check->($map)[, $done->()]])
2572 root 1.268
2573     Moves the player to the given map-path and coordinates by first freezing
2574     her, loading and preparing them map, calling the provided $check callback
2575     that has to return the map if sucecssful, and then unfreezes the player on
2576 root 1.306 the new (success) or old (failed) map position. In either case, $done will
2577     be called at the end of this process.
2578 root 1.110
2579 root 1.436 Note that $check will be called with a potentially non-loaded map, so if
2580     it needs a loaded map it has to call C<< ->load >>.
2581    
2582 root 1.110 =cut
2583    
2584 root 1.270 our $GOTOGEN;
2585    
2586 root 1.136 sub cf::object::player::goto {
2587 root 1.306 my ($self, $path, $x, $y, $check, $done) = @_;
2588 root 1.268
2589 root 1.270 # do generation counting so two concurrent goto's will be executed in-order
2590     my $gen = $self->{_goto_generation} = ++$GOTOGEN;
2591    
2592 root 1.110 $self->enter_link;
2593    
2594 root 1.140 (async {
2595 root 1.374 $Coro::current->{desc} = "player::goto $path $x $y";
2596    
2597 root 1.365 # *tag paths override both path and x|y
2598     if ($path =~ /^\*(.*)$/) {
2599     if (my @obs = grep $_->map, ext::map_tags::find $1) {
2600     my $ob = $obs[rand @obs];
2601 root 1.366
2602 root 1.367 # see if we actually can go there
2603 root 1.368 if (@obs = grep !$self->blocked ($_->map, $_->x, $_->y), $ob, $ob->tail) {
2604     $ob = $obs[rand @obs];
2605 root 1.369 } else {
2606     $self->message ("Wow, it's pretty crowded in there.", cf::NDI_UNIQUE | cf::NDI_RED);
2607 root 1.368 }
2608 root 1.369 # else put us there anyways for now #d#
2609 root 1.366
2610 root 1.365 ($path, $x, $y) = ($ob->map, $ob->x, $ob->y);
2611 root 1.369 } else {
2612     ($path, $x, $y) = (undef, undef, undef);
2613 root 1.365 }
2614     }
2615    
2616 root 1.197 my $map = eval {
2617 root 1.369 my $map = defined $path ? cf::map::find $path : undef;
2618 root 1.268
2619     if ($map) {
2620     $map = $map->customise_for ($self);
2621     $map = $check->($map) if $check && $map;
2622     } else {
2623 root 1.369 $self->message ("The exit to '$path' is closed.", cf::NDI_UNIQUE | cf::NDI_RED);
2624 root 1.268 }
2625    
2626 root 1.197 $map
2627 root 1.268 };
2628    
2629     if ($@) {
2630     $self->message ("Something went wrong within the server, please report this incident!", cf::NDI_UNIQUE | cf::NDI_RED);
2631     LOG llevError | logBacktrace, Carp::longmess $@;
2632     }
2633 root 1.115
2634 root 1.270 if ($gen == $self->{_goto_generation}) {
2635     delete $self->{_goto_generation};
2636     $self->leave_link ($map, $x, $y);
2637     }
2638 root 1.306
2639     $done->() if $done;
2640 root 1.110 })->prio (1);
2641     }
2642    
2643     =item $player_object->enter_exit ($exit_object)
2644    
2645     =cut
2646    
2647     sub parse_random_map_params {
2648     my ($spec) = @_;
2649    
2650     my $rmp = { # defaults
2651 root 1.181 xsize => (cf::rndm 15, 40),
2652     ysize => (cf::rndm 15, 40),
2653     symmetry => (cf::rndm 1, cf::SYMMETRY_XY),
2654 root 1.182 #layout => string,
2655 root 1.110 };
2656    
2657     for (split /\n/, $spec) {
2658     my ($k, $v) = split /\s+/, $_, 2;
2659    
2660     $rmp->{lc $k} = $v if (length $k) && (length $v);
2661     }
2662    
2663     $rmp
2664     }
2665    
2666     sub prepare_random_map {
2667     my ($exit) = @_;
2668    
2669     # all this does is basically replace the /! path by
2670     # a new random map path (?random/...) with a seed
2671     # that depends on the exit object
2672    
2673     my $rmp = parse_random_map_params $exit->msg;
2674    
2675     if ($exit->map) {
2676 root 1.198 $rmp->{region} = $exit->region->name;
2677 root 1.110 $rmp->{origin_map} = $exit->map->path;
2678     $rmp->{origin_x} = $exit->x;
2679     $rmp->{origin_y} = $exit->y;
2680 root 1.430
2681     $exit->map->touch;
2682 root 1.110 }
2683    
2684     $rmp->{random_seed} ||= $exit->random_seed;
2685    
2686 root 1.422 my $data = JSON::XS->new->utf8->pretty->canonical->encode ($rmp);
2687 root 1.110 my $md5 = Digest::MD5::md5_hex $data;
2688 root 1.253 my $meta = "$RANDOMDIR/$md5.meta";
2689 root 1.110
2690 root 1.177 if (my $fh = aio_open "$meta~", O_WRONLY | O_CREAT, 0666) {
2691 root 1.110 aio_write $fh, 0, (length $data), $data, 0;
2692 root 1.177 undef $fh;
2693     aio_rename "$meta~", $meta;
2694 root 1.110
2695 root 1.430 my $slaying = "?random/$md5";
2696    
2697     if ($exit->valid) {
2698     $exit->slaying ("?random/$md5");
2699     $exit->msg (undef);
2700     }
2701 root 1.110 }
2702     }
2703    
2704     sub cf::object::player::enter_exit {
2705     my ($self, $exit) = @_;
2706    
2707     return unless $self->type == cf::PLAYER;
2708    
2709 root 1.430 $self->enter_link;
2710    
2711     (async {
2712     $Coro::current->{desc} = "enter_exit";
2713    
2714     unless (eval {
2715     $self->deactivate_recursive; # just to be sure
2716 root 1.195
2717 root 1.430 # random map handling
2718     {
2719     my $guard = cf::lock_acquire "exit_prepare:$exit";
2720 root 1.195
2721 root 1.430 prepare_random_map $exit
2722     if $exit->slaying eq "/!";
2723     }
2724 root 1.110
2725 root 1.430 my $map = cf::map::normalise $exit->slaying, $exit->map && $exit->map->path;
2726     my $x = $exit->stats->hp;
2727     my $y = $exit->stats->sp;
2728 root 1.296
2729 root 1.430 $self->goto ($map, $x, $y);
2730 root 1.374
2731 root 1.430 # if exit is damned, update players death & WoR home-position
2732     $self->contr->savebed ($map, $x, $y)
2733     if $exit->flag (cf::FLAG_DAMNED);
2734 root 1.110
2735 root 1.430 1
2736 root 1.110 }) {
2737 root 1.447 $self->message ("Something went wrong deep within the deliantra server. "
2738 root 1.233 . "I'll try to bring you back to the map you were before. "
2739     . "Please report this to the dungeon master!",
2740     cf::NDI_UNIQUE | cf::NDI_RED);
2741 root 1.110
2742     warn "ERROR in enter_exit: $@";
2743     $self->leave_link;
2744     }
2745     })->prio (1);
2746     }
2747    
2748 root 1.95 =head3 cf::client
2749    
2750     =over 4
2751    
2752     =item $client->send_drawinfo ($text, $flags)
2753    
2754     Sends a drawinfo packet to the client. Circumvents output buffering so
2755     should not be used under normal circumstances.
2756    
2757 root 1.70 =cut
2758    
2759 root 1.95 sub cf::client::send_drawinfo {
2760     my ($self, $text, $flags) = @_;
2761    
2762     utf8::encode $text;
2763 root 1.225 $self->send_packet (sprintf "drawinfo %d %s", $flags || cf::NDI_BLACK, $text);
2764 root 1.95 }
2765    
2766 root 1.311 =item $client->send_msg ($channel, $msg, $color, [extra...])
2767 root 1.283
2768     Send a drawinfo or msg packet to the client, formatting the msg for the
2769     client if neccessary. C<$type> should be a string identifying the type of
2770     the message, with C<log> being the default. If C<$color> is negative, suppress
2771     the message unless the client supports the msg packet.
2772    
2773     =cut
2774    
2775 root 1.391 # non-persistent channels (usually the info channel)
2776 root 1.350 our %CHANNEL = (
2777     "c/identify" => {
2778 root 1.375 id => "infobox",
2779 root 1.350 title => "Identify",
2780     reply => undef,
2781     tooltip => "Items recently identified",
2782     },
2783 root 1.352 "c/examine" => {
2784 root 1.375 id => "infobox",
2785 root 1.352 title => "Examine",
2786     reply => undef,
2787     tooltip => "Signs and other items you examined",
2788     },
2789 root 1.389 "c/book" => {
2790     id => "infobox",
2791     title => "Book",
2792     reply => undef,
2793     tooltip => "The contents of a note or book",
2794     },
2795 root 1.375 "c/lookat" => {
2796     id => "infobox",
2797     title => "Look",
2798     reply => undef,
2799     tooltip => "What you saw there",
2800     },
2801 root 1.390 "c/who" => {
2802     id => "infobox",
2803     title => "Players",
2804     reply => undef,
2805     tooltip => "Shows players who are currently online",
2806     },
2807     "c/body" => {
2808     id => "infobox",
2809     title => "Body Parts",
2810     reply => undef,
2811     tooltip => "Shows which body parts you posess and are available",
2812     },
2813 root 1.450 "c/skills" => {
2814     id => "infobox",
2815     title => "Skills",
2816     reply => undef,
2817     tooltip => "Shows your experience per skill and item power",
2818     },
2819 root 1.390 "c/uptime" => {
2820     id => "infobox",
2821     title => "Uptime",
2822     reply => undef,
2823 root 1.391 tooltip => "How long the server has been running since last restart",
2824 root 1.390 },
2825     "c/mapinfo" => {
2826     id => "infobox",
2827     title => "Map Info",
2828     reply => undef,
2829     tooltip => "Information related to the maps",
2830     },
2831 root 1.426 "c/party" => {
2832     id => "party",
2833     title => "Party",
2834     reply => "gsay ",
2835     tooltip => "Messages and chat related to your party",
2836     },
2837 root 1.350 );
2838    
2839 root 1.283 sub cf::client::send_msg {
2840 root 1.311 my ($self, $channel, $msg, $color, @extra) = @_;
2841 root 1.283
2842 root 1.447 $msg = $self->pl->expand_cfpod ($msg)
2843     unless $color & cf::NDI_VERBATIM;
2844 root 1.283
2845 root 1.323 $color &= cf::NDI_CLIENT_MASK; # just in case...
2846 root 1.311
2847 root 1.350 # check predefined channels, for the benefit of C
2848 root 1.375 if ($CHANNEL{$channel}) {
2849     $channel = $CHANNEL{$channel};
2850    
2851     $self->ext_msg (channel_info => $channel)
2852     if $self->can_msg;
2853    
2854     $channel = $channel->{id};
2855 root 1.350
2856 root 1.375 } elsif (ref $channel) {
2857 root 1.311 # send meta info to client, if not yet sent
2858     unless (exists $self->{channel}{$channel->{id}}) {
2859     $self->{channel}{$channel->{id}} = $channel;
2860 root 1.353 $self->ext_msg (channel_info => $channel)
2861     if $self->can_msg;
2862 root 1.311 }
2863    
2864     $channel = $channel->{id};
2865     }
2866    
2867 root 1.313 return unless @extra || length $msg;
2868    
2869 root 1.283 if ($self->can_msg) {
2870 root 1.323 # default colour, mask it out
2871     $color &= ~(cf::NDI_COLOR_MASK | cf::NDI_DEF)
2872     if $color & cf::NDI_DEF;
2873    
2874 root 1.443 my $pkt = "msg "
2875     . $self->{json_coder}->encode (
2876     [$color & cf::NDI_CLIENT_MASK, $channel, $msg, @extra]
2877     );
2878    
2879     # try lzf for large packets
2880     $pkt = "lzf " . Compress::LZF::compress $pkt
2881     if 1024 <= length $pkt and $self->{can_lzf};
2882    
2883     # split very large packets
2884     if (8192 < length $pkt and $self->{can_lzf}) {
2885     $self->send_packet ("frag $_") for unpack "(a8192)*", $pkt;
2886     $pkt = "frag";
2887     }
2888    
2889     $self->send_packet ($pkt);
2890 root 1.283 } else {
2891 root 1.323 if ($color >= 0) {
2892     # replace some tags by gcfclient-compatible ones
2893     for ($msg) {
2894     1 while
2895     s/<b>([^<]*)<\/b>/[b]${1}[\/b]/
2896     || s/<i>([^<]*)<\/i>/[i]${1}[\/i]/
2897     || s/<u>([^<]*)<\/u>/[ul]${1}[\/ul]/
2898     || s/<tt>([^<]*)<\/tt>/[fixed]${1}[\/fixed]/
2899     || s/<fg name=\"([^"]+)\">([^<]*)<\/fg>/[color=$1]${2}[\/color]/;
2900     }
2901    
2902     $color &= cf::NDI_COLOR_MASK;
2903 root 1.283
2904 root 1.327 utf8::encode $msg;
2905    
2906 root 1.284 if (0 && $msg =~ /\[/) {
2907 root 1.331 # COMMAND/INFO
2908     $self->send_packet ("drawextinfo $color 10 8 $msg")
2909 root 1.283 } else {
2910 root 1.286 $msg =~ s/\[\/?(?:b|i|u|fixed|color)[^\]]*\]//g;
2911 root 1.283 $self->send_packet ("drawinfo $color $msg")
2912     }
2913     }
2914     }
2915     }
2916    
2917 root 1.316 =item $client->ext_msg ($type, @msg)
2918 root 1.232
2919 root 1.287 Sends an ext event to the client.
2920 root 1.232
2921     =cut
2922    
2923 root 1.316 sub cf::client::ext_msg($$@) {
2924     my ($self, $type, @msg) = @_;
2925 root 1.232
2926 root 1.343 if ($self->extcmd == 2) {
2927 root 1.316 $self->send_packet ("ext " . $self->{json_coder}->encode ([$type, @msg]));
2928 root 1.343 } elsif ($self->extcmd == 1) { # TODO: remove
2929 root 1.316 push @msg, msgtype => "event_$type";
2930     $self->send_packet ("ext " . $self->{json_coder}->encode ({@msg}));
2931     }
2932 root 1.232 }
2933 root 1.95
2934 root 1.336 =item $client->ext_reply ($msgid, @msg)
2935    
2936     Sends an ext reply to the client.
2937    
2938     =cut
2939    
2940     sub cf::client::ext_reply($$@) {
2941     my ($self, $id, @msg) = @_;
2942    
2943     if ($self->extcmd == 2) {
2944     $self->send_packet ("ext " . $self->{json_coder}->encode (["reply-$id", @msg]));
2945 root 1.343 } elsif ($self->extcmd == 1) {
2946 root 1.336 #TODO: version 1, remove
2947     unshift @msg, msgtype => "reply", msgid => $id;
2948     $self->send_packet ("ext " . $self->{json_coder}->encode ({@msg}));
2949     }
2950     }
2951    
2952 root 1.95 =item $success = $client->query ($flags, "text", \&cb)
2953    
2954     Queues a query to the client, calling the given callback with
2955     the reply text on a reply. flags can be C<cf::CS_QUERY_YESNO>,
2956     C<cf::CS_QUERY_SINGLECHAR> or C<cf::CS_QUERY_HIDEINPUT> or C<0>.
2957    
2958 root 1.287 Queries can fail, so check the return code. Or don't, as queries will
2959     become reliable at some point in the future.
2960 root 1.95
2961     =cut
2962    
2963     sub cf::client::query {
2964     my ($self, $flags, $text, $cb) = @_;
2965    
2966     return unless $self->state == ST_PLAYING
2967     || $self->state == ST_SETUP
2968     || $self->state == ST_CUSTOM;
2969    
2970     $self->state (ST_CUSTOM);
2971    
2972     utf8::encode $text;
2973     push @{ $self->{query_queue} }, [(sprintf "query %d %s", $flags, $text), $cb];
2974    
2975     $self->send_packet ($self->{query_queue}[0][0])
2976     if @{ $self->{query_queue} } == 1;
2977 root 1.287
2978     1
2979 root 1.95 }
2980    
2981     cf::client->attach (
2982 root 1.290 on_connect => sub {
2983     my ($ns) = @_;
2984    
2985     $ns->{json_coder} = JSON::XS->new->utf8->max_size (1e6)->convert_blessed;
2986     },
2987 root 1.95 on_reply => sub {
2988     my ($ns, $msg) = @_;
2989    
2990     # this weird shuffling is so that direct followup queries
2991     # get handled first
2992 root 1.128 my $queue = delete $ns->{query_queue}
2993 root 1.129 or return; # be conservative, not sure how that can happen, but we saw a crash here
2994 root 1.95
2995     (shift @$queue)->[1]->($msg);
2996 root 1.202 return unless $ns->valid; # temporary(?) workaround for callback destroying socket
2997 root 1.95
2998     push @{ $ns->{query_queue} }, @$queue;
2999    
3000     if (@{ $ns->{query_queue} } == @$queue) {
3001     if (@$queue) {
3002     $ns->send_packet ($ns->{query_queue}[0][0]);
3003     } else {
3004 root 1.98 $ns->state (ST_PLAYING) if $ns->state == ST_CUSTOM;
3005 root 1.95 }
3006     }
3007     },
3008 root 1.287 on_exticmd => sub {
3009     my ($ns, $buf) = @_;
3010    
3011 root 1.290 my $msg = eval { $ns->{json_coder}->decode ($buf) };
3012 root 1.287
3013     if (ref $msg) {
3014 root 1.316 my ($type, $reply, @payload) =
3015     "ARRAY" eq ref $msg
3016     ? @$msg
3017     : ($msg->{msgtype}, $msg->{msgid}, %$msg); # TODO: version 1, remove
3018    
3019 root 1.338 my @reply;
3020    
3021 root 1.316 if (my $cb = $EXTICMD{$type}) {
3022 root 1.338 @reply = $cb->($ns, @payload);
3023     }
3024    
3025     $ns->ext_reply ($reply, @reply)
3026     if $reply;
3027 root 1.316
3028 root 1.287 } else {
3029     warn "client " . ($ns->pl ? $ns->pl->ob->name : $ns->host) . " sent unparseable exti message: <$buf>\n";
3030     }
3031    
3032     cf::override;
3033     },
3034 root 1.95 );
3035    
3036 root 1.140 =item $client->async (\&cb)
3037 root 1.96
3038     Create a new coroutine, running the specified callback. The coroutine will
3039     be automatically cancelled when the client gets destroyed (e.g. on logout,
3040     or loss of connection).
3041    
3042     =cut
3043    
3044 root 1.140 sub cf::client::async {
3045 root 1.96 my ($self, $cb) = @_;
3046    
3047 root 1.140 my $coro = &Coro::async ($cb);
3048 root 1.103
3049     $coro->on_destroy (sub {
3050 root 1.96 delete $self->{_coro}{$coro+0};
3051 root 1.103 });
3052 root 1.96
3053     $self->{_coro}{$coro+0} = $coro;
3054 root 1.103
3055     $coro
3056 root 1.96 }
3057    
3058     cf::client->attach (
3059     on_destroy => sub {
3060     my ($ns) = @_;
3061    
3062 root 1.97 $_->cancel for values %{ (delete $ns->{_coro}) || {} };
3063 root 1.96 },
3064     );
3065    
3066 root 1.95 =back
3067    
3068 root 1.70
3069     =head2 SAFE SCRIPTING
3070    
3071     Functions that provide a safe environment to compile and execute
3072     snippets of perl code without them endangering the safety of the server
3073     itself. Looping constructs, I/O operators and other built-in functionality
3074     is not available in the safe scripting environment, and the number of
3075 root 1.79 functions and methods that can be called is greatly reduced.
3076 root 1.70
3077     =cut
3078 root 1.23
3079 root 1.42 our $safe = new Safe "safe";
3080 root 1.23 our $safe_hole = new Safe::Hole;
3081    
3082     $SIG{FPE} = 'IGNORE';
3083    
3084 root 1.328 $safe->permit_only (Opcode::opset qw(
3085     :base_core :base_mem :base_orig :base_math
3086     grepstart grepwhile mapstart mapwhile
3087     sort time
3088     ));
3089 root 1.23
3090 root 1.25 # here we export the classes and methods available to script code
3091    
3092 root 1.70 =pod
3093    
3094 root 1.228 The following functions and methods are available within a safe environment:
3095 root 1.70
3096 root 1.297 cf::object
3097 root 1.383 contr pay_amount pay_player map x y force_find force_add destroy
3098 root 1.425 insert remove name archname title slaying race decrease split
3099 root 1.297
3100     cf::object::player
3101     player
3102    
3103     cf::player
3104     peaceful
3105    
3106     cf::map
3107     trigger
3108 root 1.70
3109     =cut
3110    
3111 root 1.25 for (
3112 root 1.297 ["cf::object" => qw(contr pay_amount pay_player map force_find force_add x y
3113 elmex 1.431 insert remove inv nrof name archname title slaying race
3114 elmex 1.438 decrease split destroy change_exp)],
3115 root 1.25 ["cf::object::player" => qw(player)],
3116     ["cf::player" => qw(peaceful)],
3117 elmex 1.91 ["cf::map" => qw(trigger)],
3118 root 1.25 ) {
3119     no strict 'refs';
3120     my ($pkg, @funs) = @$_;
3121 root 1.41 *{"safe::$pkg\::$_"} = $safe_hole->wrap (\&{"$pkg\::$_"})
3122 root 1.25 for @funs;
3123     }
3124 root 1.23
3125 root 1.70 =over 4
3126    
3127     =item @retval = safe_eval $code, [var => value, ...]
3128    
3129     Compiled and executes the given perl code snippet. additional var/value
3130     pairs result in temporary local (my) scalar variables of the given name
3131     that are available in the code snippet. Example:
3132    
3133     my $five = safe_eval '$first + $second', first => 1, second => 4;
3134    
3135     =cut
3136    
3137 root 1.23 sub safe_eval($;@) {
3138     my ($code, %vars) = @_;
3139    
3140     my $qcode = $code;
3141     $qcode =~ s/"/‟/g; # not allowed in #line filenames
3142     $qcode =~ s/\n/\\n/g;
3143    
3144     local $_;
3145 root 1.41 local @safe::cf::_safe_eval_args = values %vars;
3146 root 1.23
3147 root 1.42 my $eval =
3148 root 1.23 "do {\n"
3149     . "my (" . (join ",", map "\$$_", keys %vars) . ") = \@cf::_safe_eval_args;\n"
3150     . "#line 0 \"{$qcode}\"\n"
3151     . $code
3152     . "\n}"
3153 root 1.25 ;
3154    
3155     sub_generation_inc;
3156 root 1.42 my @res = wantarray ? $safe->reval ($eval) : scalar $safe->reval ($eval);
3157 root 1.25 sub_generation_inc;
3158    
3159 root 1.42 if ($@) {
3160     warn "$@";
3161     warn "while executing safe code '$code'\n";
3162     warn "with arguments " . (join " ", %vars) . "\n";
3163     }
3164    
3165 root 1.25 wantarray ? @res : $res[0]
3166 root 1.23 }
3167    
3168 root 1.69 =item cf::register_script_function $function => $cb
3169    
3170     Register a function that can be called from within map/npc scripts. The
3171     function should be reasonably secure and should be put into a package name
3172     like the extension.
3173    
3174     Example: register a function that gets called whenever a map script calls
3175     C<rent::overview>, as used by the C<rent> extension.
3176    
3177     cf::register_script_function "rent::overview" => sub {
3178     ...
3179     };
3180    
3181     =cut
3182    
3183 root 1.23 sub register_script_function {
3184     my ($fun, $cb) = @_;
3185    
3186     no strict 'refs';
3187 root 1.41 *{"safe::$fun"} = $safe_hole->wrap ($cb);
3188 root 1.23 }
3189    
3190 root 1.70 =back
3191    
3192 root 1.71 =cut
3193    
3194 root 1.23 #############################################################################
3195 root 1.203 # the server's init and main functions
3196    
3197 root 1.246 sub load_facedata($) {
3198     my ($path) = @_;
3199 root 1.223
3200 root 1.348 # HACK to clear player env face cache, we need some signal framework
3201     # for this (global event?)
3202     %ext::player_env::MUSIC_FACE_CACHE = ();
3203    
3204 root 1.344 my $enc = JSON::XS->new->utf8->canonical->relaxed;
3205 root 1.334
3206 root 1.229 warn "loading facedata from $path\n";
3207 root 1.223
3208 root 1.236 my $facedata;
3209     0 < aio_load $path, $facedata
3210 root 1.223 or die "$path: $!";
3211    
3212 root 1.237 $facedata = Coro::Storable::thaw $facedata;
3213 root 1.223
3214 root 1.236 $facedata->{version} == 2
3215 root 1.226 or cf::cleanup "$path: version mismatch, cannot proceed.";
3216    
3217 root 1.334 # patch in the exptable
3218     $facedata->{resource}{"res/exp_table"} = {
3219     type => FT_RSRC,
3220 root 1.337 data => $enc->encode ([map cf::level_to_min_exp $_, 1 .. cf::settings->max_level]),
3221 root 1.334 };
3222     cf::cede_to_tick;
3223    
3224 root 1.236 {
3225     my $faces = $facedata->{faceinfo};
3226    
3227     while (my ($face, $info) = each %$faces) {
3228     my $idx = (cf::face::find $face) || cf::face::alloc $face;
3229 root 1.405
3230 root 1.302 cf::face::set_visibility $idx, $info->{visibility};
3231     cf::face::set_magicmap $idx, $info->{magicmap};
3232 root 1.334 cf::face::set_data $idx, 0, $info->{data32}, Digest::MD5::md5 $info->{data32};
3233     cf::face::set_data $idx, 1, $info->{data64}, Digest::MD5::md5 $info->{data64};
3234 root 1.302
3235     cf::cede_to_tick;
3236 root 1.236 }
3237    
3238     while (my ($face, $info) = each %$faces) {
3239     next unless $info->{smooth};
3240 root 1.405
3241 root 1.236 my $idx = cf::face::find $face
3242     or next;
3243 root 1.405
3244 root 1.236 if (my $smooth = cf::face::find $info->{smooth}) {
3245 root 1.302 cf::face::set_smooth $idx, $smooth;
3246     cf::face::set_smoothlevel $idx, $info->{smoothlevel};
3247 root 1.236 } else {
3248     warn "smooth face '$info->{smooth}' not found for face '$face'";
3249     }
3250 root 1.302
3251     cf::cede_to_tick;
3252 root 1.236 }
3253 root 1.223 }
3254    
3255 root 1.236 {
3256     my $anims = $facedata->{animinfo};
3257    
3258     while (my ($anim, $info) = each %$anims) {
3259     cf::anim::set $anim, $info->{frames}, $info->{facings};
3260 root 1.302 cf::cede_to_tick;
3261 root 1.225 }
3262 root 1.236
3263     cf::anim::invalidate_all; # d'oh
3264 root 1.225 }
3265    
3266 root 1.302 {
3267     # TODO: for gcfclient pleasure, we should give resources
3268     # that gcfclient doesn't grok a >10000 face index.
3269     my $res = $facedata->{resource};
3270    
3271     while (my ($name, $info) = each %$res) {
3272 root 1.405 if (defined $info->{type}) {
3273     my $idx = (cf::face::find $name) || cf::face::alloc $name;
3274     my $data;
3275    
3276     if ($info->{type} & 1) {
3277     # prepend meta info
3278    
3279     my $meta = $enc->encode ({
3280     name => $name,
3281     %{ $info->{meta} || {} },
3282     });
3283 root 1.307
3284 root 1.405 $data = pack "(w/a*)*", $meta, $info->{data};
3285     } else {
3286     $data = $info->{data};
3287     }
3288 root 1.318
3289 root 1.405 cf::face::set_data $idx, 0, $data, Digest::MD5::md5 $data;
3290     cf::face::set_type $idx, $info->{type};
3291 root 1.337 } else {
3292 root 1.405 $RESOURCE{$name} = $info;
3293 root 1.307 }
3294 root 1.302
3295     cf::cede_to_tick;
3296     }
3297 root 1.406 }
3298    
3299     cf::global->invoke (EVENT_GLOBAL_RESOURCE_UPDATE);
3300 root 1.321
3301 root 1.406 1
3302     }
3303    
3304     cf::global->attach (on_resource_update => sub {
3305     if (my $soundconf = $RESOURCE{"res/sound.conf"}) {
3306     $soundconf = JSON::XS->new->utf8->relaxed->decode ($soundconf->{data});
3307    
3308     for (0 .. SOUND_CAST_SPELL_0 - 1) {
3309     my $sound = $soundconf->{compat}[$_]
3310     or next;
3311 root 1.321
3312 root 1.406 my $face = cf::face::find "sound/$sound->[1]";
3313     cf::sound::set $sound->[0] => $face;
3314     cf::sound::old_sound_index $_, $face; # gcfclient-compat
3315     }
3316 root 1.321
3317 root 1.406 while (my ($k, $v) = each %{$soundconf->{event}}) {
3318     my $face = cf::face::find "sound/$v";
3319     cf::sound::set $k => $face;
3320 root 1.321 }
3321 root 1.302 }
3322 root 1.406 });
3323 root 1.223
3324 root 1.318 register_exticmd fx_want => sub {
3325     my ($ns, $want) = @_;
3326    
3327     while (my ($k, $v) = each %$want) {
3328     $ns->fx_want ($k, $v);
3329     }
3330     };
3331    
3332 root 1.423 sub load_resource_file($) {
3333 root 1.424 my $guard = lock_acquire "load_resource_file";
3334    
3335 root 1.423 my $status = load_resource_file_ $_[0];
3336     get_slot 0.1, 100;
3337     cf::arch::commit_load;
3338 root 1.424
3339 root 1.423 $status
3340     }
3341    
3342 root 1.253 sub reload_regions {
3343 root 1.348 # HACK to clear player env face cache, we need some signal framework
3344     # for this (global event?)
3345     %ext::player_env::MUSIC_FACE_CACHE = ();
3346    
3347 root 1.253 load_resource_file "$MAPDIR/regions"
3348     or die "unable to load regions file\n";
3349 root 1.304
3350     for (cf::region::list) {
3351     $_->{match} = qr/$_->{match}/
3352     if exists $_->{match};
3353     }
3354 root 1.253 }
3355    
3356 root 1.246 sub reload_facedata {
3357 root 1.253 load_facedata "$DATADIR/facedata"
3358 root 1.246 or die "unable to load facedata\n";
3359     }
3360    
3361     sub reload_archetypes {
3362 root 1.253 load_resource_file "$DATADIR/archetypes"
3363 root 1.246 or die "unable to load archetypes\n";
3364 root 1.241 }
3365    
3366 root 1.246 sub reload_treasures {
3367 root 1.253 load_resource_file "$DATADIR/treasures"
3368 root 1.246 or die "unable to load treasurelists\n";
3369 root 1.241 }
3370    
3371 root 1.223 sub reload_resources {
3372 root 1.245 warn "reloading resource files...\n";
3373    
3374 root 1.246 reload_facedata;
3375     reload_archetypes;
3376 root 1.423 reload_regions;
3377 root 1.246 reload_treasures;
3378 root 1.245
3379     warn "finished reloading resource files\n";
3380 root 1.223 }
3381    
3382 root 1.345 sub reload_config {
3383 root 1.253 open my $fh, "<:utf8", "$CONFDIR/config"
3384 root 1.72 or return;
3385    
3386     local $/;
3387 root 1.408 *CFG = YAML::Load <$fh>;
3388 root 1.131
3389     $EMERGENCY_POSITION = $CFG{emergency_position} || ["/world/world_105_115", 5, 37];
3390    
3391 root 1.139 $cf::map::MAX_RESET = $CFG{map_max_reset} if exists $CFG{map_max_reset};
3392     $cf::map::DEFAULT_RESET = $CFG{map_default_reset} if exists $CFG{map_default_reset};
3393    
3394 root 1.131 if (exists $CFG{mlockall}) {
3395     eval {
3396 root 1.147 $CFG{mlockall} ? eval "mlockall()" : eval "munlockall()"
3397 root 1.131 and die "WARNING: m(un)lockall failed: $!\n";
3398     };
3399     warn $@ if $@;
3400     }
3401 root 1.72 }
3402    
3403 root 1.445 sub pidfile() {
3404     sysopen my $fh, $PIDFILE, O_RDWR | O_CREAT
3405     or die "$PIDFILE: $!";
3406     flock $fh, &Fcntl::LOCK_EX
3407     or die "$PIDFILE: flock: $!";
3408     $fh
3409     }
3410    
3411     # make sure only one server instance is running at any one time
3412     sub atomic {
3413     my $fh = pidfile;
3414    
3415     my $pid = <$fh>;
3416     kill 9, $pid if $pid > 0;
3417    
3418     seek $fh, 0, 0;
3419     print $fh $$;
3420     }
3421    
3422 root 1.39 sub main {
3423 root 1.453 cf::init_globals; # initialise logging
3424    
3425     LOG llevInfo, "Welcome to Deliantra, v" . VERSION;
3426     LOG llevInfo, "Copyright (C) 2005-2008 Marc Alexander Lehmann / Robin Redeker / the Deliantra team.";
3427     LOG llevInfo, "Copyright (C) 1994 Mark Wedel.";
3428     LOG llevInfo, "Copyright (C) 1992 Frank Tore Johansen.";
3429    
3430     cf::init_experience;
3431     cf::init_anim;
3432     cf::init_attackmess;
3433     cf::init_dynamic;
3434     cf::init_block;
3435    
3436     $Coro::current->prio (Coro::PRIO_MAX); # give the main loop max. priority
3437 root 1.445
3438 root 1.108 # we must not ever block the main coroutine
3439     local $Coro::idle = sub {
3440 root 1.115 Carp::cluck "FATAL: Coro::idle was called, major BUG, use cf::sync_job!\n";#d#
3441 root 1.175 (async {
3442 root 1.374 $Coro::current->{desc} = "IDLE BUG HANDLER";
3443 root 1.396 EV::loop EV::LOOP_ONESHOT;
3444 root 1.175 })->prio (Coro::PRIO_MAX);
3445 root 1.108 };
3446    
3447 root 1.453 evthread_start IO::AIO::poll_fileno;
3448    
3449     cf::sync_job {
3450     reload_resources;
3451 root 1.423 reload_config;
3452     db_init;
3453 root 1.453
3454     cf::load_settings;
3455     cf::load_materials;
3456     cf::init_uuid;
3457     cf::init_signals;
3458     cf::init_commands;
3459     cf::init_skills;
3460    
3461     cf::init_beforeplay;
3462    
3463     atomic;
3464    
3465 root 1.423 load_extensions;
3466    
3467 root 1.453 utime time, time, $RUNTIMEFILE;
3468 root 1.183
3469 root 1.453 # no (long-running) fork's whatsoever before this point(!)
3470     POSIX::close delete $ENV{LOCKUTIL_LOCK_FD} if exists $ENV{LOCKUTIL_LOCK_FD};
3471 root 1.445
3472 root 1.453 (pop @POST_INIT)->(0) while @POST_INIT;
3473     };
3474 root 1.445
3475 root 1.396 EV::loop;
3476 root 1.34 }
3477    
3478     #############################################################################
3479 root 1.155 # initialisation and cleanup
3480    
3481     # install some emergency cleanup handlers
3482     BEGIN {
3483 root 1.396 our %SIGWATCHER = ();
3484 root 1.155 for my $signal (qw(INT HUP TERM)) {
3485 root 1.396 $SIGWATCHER{$signal} = EV::signal $signal, sub {
3486     cf::cleanup "SIG$signal";
3487     };
3488 root 1.155 }
3489     }
3490    
3491 root 1.417 sub write_runtime_sync {
3492 root 1.281 # first touch the runtime file to show we are still running:
3493     # the fsync below can take a very very long time.
3494    
3495 root 1.445 IO::AIO::aio_utime $RUNTIMEFILE, undef, undef;
3496 root 1.281
3497     my $guard = cf::lock_acquire "write_runtime";
3498    
3499 root 1.445 my $fh = aio_open "$RUNTIMEFILE~", O_WRONLY | O_CREAT, 0644
3500 root 1.281 or return;
3501    
3502     my $value = $cf::RUNTIME + 90 + 10;
3503     # 10 is the runtime save interval, for a monotonic clock
3504     # 60 allows for the watchdog to kill the server.
3505    
3506     (aio_write $fh, 0, (length $value), $value, 0) <= 0
3507     and return;
3508    
3509     # always fsync - this file is important
3510     aio_fsync $fh
3511     and return;
3512    
3513     # touch it again to show we are up-to-date
3514     aio_utime $fh, undef, undef;
3515    
3516     close $fh
3517     or return;
3518    
3519 root 1.445 aio_rename "$RUNTIMEFILE~", $RUNTIMEFILE
3520 root 1.281 and return;
3521    
3522     warn "runtime file written.\n";
3523    
3524     1
3525     }
3526    
3527 root 1.416 our $uuid_lock;
3528     our $uuid_skip;
3529    
3530     sub write_uuid_sync($) {
3531     $uuid_skip ||= $_[0];
3532    
3533     return if $uuid_lock;
3534     local $uuid_lock = 1;
3535    
3536     my $uuid = "$LOCALDIR/uuid";
3537    
3538     my $fh = aio_open "$uuid~", O_WRONLY | O_CREAT, 0644
3539     or return;
3540    
3541 root 1.454 my $value = uuid_seq uuid_cur;
3542    
3543 root 1.455 unless ($value) {
3544     warn "cowardly refusing to write zero uuid value!\n";
3545 root 1.454 return;
3546     }
3547    
3548     my $value = uuid_str $value + $uuid_skip;
3549 root 1.416 $uuid_skip = 0;
3550    
3551     (aio_write $fh, 0, (length $value), $value, 0) <= 0
3552     and return;
3553    
3554     # always fsync - this file is important
3555     aio_fsync $fh
3556     and return;
3557    
3558     close $fh
3559     or return;
3560    
3561     aio_rename "$uuid~", $uuid
3562     and return;
3563    
3564     warn "uuid file written ($value).\n";
3565    
3566     1
3567    
3568     }
3569    
3570     sub write_uuid($$) {
3571     my ($skip, $sync) = @_;
3572    
3573     $sync ? write_uuid_sync $skip
3574     : async { write_uuid_sync $skip };
3575     }
3576    
3577 root 1.156 sub emergency_save() {
3578 root 1.155 my $freeze_guard = cf::freeze_mainloop;
3579    
3580 root 1.457 warn "emergency_perl_save: enter\n";
3581 root 1.155
3582     cf::sync_job {
3583 root 1.457 # this is a trade-off: we want to be very quick here, so
3584     # save all maps without fsync, and later call a global sync
3585     # (which in turn might be very very slow)
3586     local $USE_FSYNC = 0;
3587    
3588 root 1.155 # use a peculiar iteration method to avoid tripping on perl
3589     # refcount bugs in for. also avoids problems with players
3590 root 1.167 # and maps saved/destroyed asynchronously.
3591 root 1.457 warn "emergency_perl_save: begin player save\n";
3592 root 1.155 for my $login (keys %cf::PLAYER) {
3593     my $pl = $cf::PLAYER{$login} or next;
3594     $pl->valid or next;
3595 root 1.382 delete $pl->{unclean_save}; # not strictly necessary, but cannot hurt
3596 root 1.155 $pl->save;
3597     }
3598 root 1.457 warn "emergency_perl_save: end player save\n";
3599 root 1.155
3600 root 1.457 warn "emergency_perl_save: begin map save\n";
3601 root 1.155 for my $path (keys %cf::MAP) {
3602     my $map = $cf::MAP{$path} or next;
3603     $map->valid or next;
3604     $map->save;
3605     }
3606 root 1.457 warn "emergency_perl_save: end map save\n";
3607 root 1.208
3608 root 1.457 warn "emergency_perl_save: begin database checkpoint\n";
3609 root 1.208 BDB::db_env_txn_checkpoint $DB_ENV;
3610 root 1.457 warn "emergency_perl_save: end database checkpoint\n";
3611 root 1.416
3612 root 1.457 warn "emergency_perl_save: begin write uuid\n";
3613 root 1.416 write_uuid_sync 1;
3614 root 1.457 warn "emergency_perl_save: end write uuid\n";
3615 root 1.155 };
3616    
3617 root 1.457 warn "emergency_perl_save: starting sync()\n";
3618     IO::AIO::aio_sync sub {
3619     warn "emergency_perl_save: finished sync()\n";
3620     };
3621    
3622     warn "emergency_perl_save: leave\n";
3623 root 1.155 }
3624 root 1.22
3625 root 1.211 sub post_cleanup {
3626     my ($make_core) = @_;
3627    
3628     warn Carp::longmess "post_cleanup backtrace"
3629     if $make_core;
3630 root 1.445
3631     my $fh = pidfile;
3632     unlink $PIDFILE if <$fh> == $$;
3633 root 1.211 }
3634    
3635 root 1.441 # a safer delete_package, copied from Symbol
3636     sub clear_package($) {
3637     my $pkg = shift;
3638    
3639     # expand to full symbol table name if needed
3640     unless ($pkg =~ /^main::.*::$/) {
3641     $pkg = "main$pkg" if $pkg =~ /^::/;
3642     $pkg = "main::$pkg" unless $pkg =~ /^main::/;
3643     $pkg .= '::' unless $pkg =~ /::$/;
3644     }
3645    
3646     my($stem, $leaf) = $pkg =~ m/(.*::)(\w+::)$/;
3647     my $stem_symtab = *{$stem}{HASH};
3648    
3649     defined $stem_symtab and exists $stem_symtab->{$leaf}
3650     or return;
3651    
3652     # clear all symbols
3653     my $leaf_symtab = *{$stem_symtab->{$leaf}}{HASH};
3654     for my $name (keys %$leaf_symtab) {
3655     _gv_clear *{"$pkg$name"};
3656     # use PApp::Util; PApp::Util::sv_dump *{"$pkg$name"};
3657     }
3658 root 1.451 warn "cleared package $pkg\n";#d#
3659 root 1.441 }
3660    
3661 root 1.246 sub do_reload_perl() {
3662 root 1.106 # can/must only be called in main
3663     if ($Coro::current != $Coro::main) {
3664 root 1.183 warn "can only reload from main coroutine";
3665 root 1.106 return;
3666     }
3667    
3668 root 1.441 return if $RELOAD++;
3669    
3670 root 1.457 my $t1 = EV::time;
3671    
3672 root 1.441 while ($RELOAD) {
3673     warn "reloading...";
3674 root 1.103
3675 root 1.441 warn "entering sync_job";
3676 root 1.212
3677 root 1.441 cf::sync_job {
3678     cf::write_runtime_sync; # external watchdog should not bark
3679     cf::emergency_save;
3680     cf::write_runtime_sync; # external watchdog should not bark
3681 root 1.183
3682 root 1.441 warn "syncing database to disk";
3683     BDB::db_env_txn_checkpoint $DB_ENV;
3684 root 1.106
3685 root 1.441 # if anything goes wrong in here, we should simply crash as we already saved
3686 root 1.65
3687 root 1.441 warn "flushing outstanding aio requests";
3688     while (IO::AIO::nreqs || BDB::nreqs) {
3689     Coro::EV::timer_once 0.01; # let the sync_job do it's thing
3690     }
3691 root 1.183
3692 root 1.441 warn "cancelling all extension coros";
3693     $_->cancel for values %EXT_CORO;
3694     %EXT_CORO = ();
3695 root 1.223
3696 root 1.441 warn "removing commands";
3697     %COMMAND = ();
3698 root 1.103
3699 root 1.441 warn "removing ext/exti commands";
3700     %EXTCMD = ();
3701     %EXTICMD = ();
3702 root 1.159
3703 root 1.441 warn "unloading/nuking all extensions";
3704     for my $pkg (@EXTS) {
3705     warn "... unloading $pkg";
3706 root 1.159
3707 root 1.441 if (my $cb = $pkg->can ("unload")) {
3708     eval {
3709     $cb->($pkg);
3710     1
3711     } or warn "$pkg unloaded, but with errors: $@";
3712     }
3713 root 1.159
3714 root 1.441 warn "... clearing $pkg";
3715     clear_package $pkg;
3716 root 1.159 }
3717    
3718 root 1.441 warn "unloading all perl modules loaded from $LIBDIR";
3719     while (my ($k, $v) = each %INC) {
3720     next unless $v =~ /^\Q$LIBDIR\E\/.*\.pm$/;
3721 root 1.65
3722 root 1.441 warn "... unloading $k";
3723     delete $INC{$k};
3724 root 1.65
3725 root 1.441 $k =~ s/\.pm$//;
3726     $k =~ s/\//::/g;
3727 root 1.65
3728 root 1.441 if (my $cb = $k->can ("unload_module")) {
3729     $cb->();
3730     }
3731 root 1.65
3732 root 1.441 clear_package $k;
3733 root 1.65 }
3734    
3735 root 1.441 warn "getting rid of safe::, as good as possible";
3736     clear_package "safe::$_"
3737     for qw(cf::attachable cf::object cf::object::player cf::client cf::player cf::map cf::party cf::region);
3738 root 1.65
3739 root 1.441 warn "unloading cf.pm \"a bit\"";
3740     delete $INC{"cf.pm"};
3741     delete $INC{"cf/pod.pm"};
3742 root 1.65
3743 root 1.441 # don't, removes xs symbols, too,
3744     # and global variables created in xs
3745     #clear_package __PACKAGE__;
3746 root 1.65
3747 root 1.441 warn "unload completed, starting to reload now";
3748 root 1.65
3749 root 1.441 warn "reloading cf.pm";
3750     require cf;
3751     cf::_connect_to_perl; # nominally unnecessary, but cannot hurt
3752 root 1.183
3753 root 1.441 warn "loading config and database again";
3754     cf::reload_config;
3755 root 1.100
3756 root 1.441 warn "loading extensions";
3757     cf::load_extensions;
3758 root 1.65
3759 root 1.457 if ($REATTACH_ON_RELOAD) {
3760     warn "reattaching attachments to objects/players";
3761     _global_reattach; # objects, sockets
3762     warn "reattaching attachments to maps";
3763     reattach $_ for values %MAP;
3764     warn "reattaching attachments to players";
3765     reattach $_ for values %PLAYER;
3766     }
3767 root 1.65
3768 root 1.457 warn "running post_init jobs";
3769 root 1.453 (pop @POST_INIT)->(1) while @POST_INIT;
3770    
3771 root 1.441 warn "leaving sync_job";
3772 root 1.183
3773 root 1.441 1
3774     } or do {
3775     warn $@;
3776     cf::cleanup "error while reloading, exiting.";
3777     };
3778 root 1.183
3779 root 1.441 warn "reloaded";
3780     --$RELOAD;
3781     }
3782 root 1.457
3783     $t1 = EV::time - $t1;
3784     warn "reload completed in ${t1}s\n";
3785 root 1.65 };
3786    
3787 root 1.175 our $RELOAD_WATCHER; # used only during reload
3788    
3789 root 1.246 sub reload_perl() {
3790     # doing reload synchronously and two reloads happen back-to-back,
3791     # coro crashes during coro_state_free->destroy here.
3792    
3793 root 1.457 $RELOAD_WATCHER ||= cf::async {
3794     Coro::AIO::aio_wait cache_extensions;
3795    
3796     $RELOAD_WATCHER = EV::timer $TICK * 1.5, 0, sub {
3797     do_reload_perl;
3798     undef $RELOAD_WATCHER;
3799     };
3800 root 1.396 };
3801 root 1.246 }
3802    
3803 root 1.111 register_command "reload" => sub {
3804 root 1.65 my ($who, $arg) = @_;
3805    
3806     if ($who->flag (FLAG_WIZ)) {
3807 root 1.175 $who->message ("reloading server.");
3808 root 1.374 async {
3809     $Coro::current->{desc} = "perl_reload";
3810     reload_perl;
3811     };
3812 root 1.65 }
3813     };
3814    
3815 root 1.27 unshift @INC, $LIBDIR;
3816 root 1.17
3817 root 1.183 my $bug_warning = 0;
3818    
3819 root 1.239 our @WAIT_FOR_TICK;
3820     our @WAIT_FOR_TICK_BEGIN;
3821    
3822     sub wait_for_tick {
3823 root 1.423 return if tick_inhibit || $Coro::current == $Coro::main;
3824 root 1.241
3825 root 1.239 my $signal = new Coro::Signal;
3826     push @WAIT_FOR_TICK, $signal;
3827     $signal->wait;
3828     }
3829    
3830     sub wait_for_tick_begin {
3831 root 1.423 return if tick_inhibit || $Coro::current == $Coro::main;
3832 root 1.241
3833 root 1.239 my $signal = new Coro::Signal;
3834     push @WAIT_FOR_TICK_BEGIN, $signal;
3835     $signal->wait;
3836     }
3837    
3838 root 1.412 sub tick {
3839 root 1.396 if ($Coro::current != $Coro::main) {
3840     Carp::cluck "major BUG: server tick called outside of main coro, skipping it"
3841     unless ++$bug_warning > 10;
3842     return;
3843     }
3844    
3845     cf::server_tick; # one server iteration
3846 root 1.245
3847 root 1.396 if ($NOW >= $NEXT_RUNTIME_WRITE) {
3848 root 1.402 $NEXT_RUNTIME_WRITE = List::Util::max $NEXT_RUNTIME_WRITE + 10, $NOW + 5.;
3849 root 1.396 Coro::async_pool {
3850     $Coro::current->{desc} = "runtime saver";
3851 root 1.417 write_runtime_sync
3852 root 1.396 or warn "ERROR: unable to write runtime file: $!";
3853     };
3854     }
3855 root 1.265
3856 root 1.396 if (my $sig = shift @WAIT_FOR_TICK_BEGIN) {
3857     $sig->send;
3858     }
3859     while (my $sig = shift @WAIT_FOR_TICK) {
3860     $sig->send;
3861     }
3862 root 1.265
3863 root 1.412 $LOAD = ($NOW - $TICK_START) / $TICK;
3864 root 1.396 $LOADAVG = $LOADAVG * 0.75 + $LOAD * 0.25;
3865 root 1.265
3866 root 1.412 if (0) {
3867     if ($NEXT_TICK) {
3868     my $jitter = $TICK_START - $NEXT_TICK;
3869     $JITTER = $JITTER * 0.75 + $jitter * 0.25;
3870     warn "jitter $JITTER\n";#d#
3871     }
3872     }
3873     }
3874 root 1.35
3875 root 1.206 {
3876 root 1.401 # configure BDB
3877    
3878 root 1.363 BDB::min_parallel 8;
3879 root 1.400 BDB::max_poll_reqs $TICK * 0.1;
3880 root 1.433 $AnyEvent::BDB::WATCHER->priority (1);
3881 root 1.77
3882 root 1.206 unless ($DB_ENV) {
3883     $DB_ENV = BDB::db_env_create;
3884 root 1.437 $DB_ENV->set_flags (BDB::AUTO_COMMIT | BDB::REGION_INIT);
3885     $DB_ENV->set_flags (&BDB::LOG_AUTOREMOVE ) if BDB::VERSION v0, v4.7;
3886     $DB_ENV->log_set_config (&BDB::LOG_AUTO_REMOVE) if BDB::VERSION v4.7;
3887 root 1.371 $DB_ENV->set_timeout (30, BDB::SET_TXN_TIMEOUT);
3888     $DB_ENV->set_timeout (30, BDB::SET_LOCK_TIMEOUT);
3889 root 1.206
3890     cf::sync_job {
3891 root 1.208 eval {
3892     BDB::db_env_open
3893     $DB_ENV,
3894 root 1.253 $BDBDIR,
3895 root 1.208 BDB::INIT_LOCK | BDB::INIT_LOG | BDB::INIT_MPOOL | BDB::INIT_TXN
3896     | BDB::RECOVER | BDB::REGISTER | BDB::USE_ENVIRON | BDB::CREATE,
3897     0666;
3898    
3899 root 1.253 cf::cleanup "db_env_open($BDBDIR): $!" if $!;
3900 root 1.208 };
3901    
3902     cf::cleanup "db_env_open(db): $@" if $@;
3903 root 1.206 };
3904     }
3905 root 1.363
3906 root 1.396 $BDB_DEADLOCK_WATCHER = EV::periodic 0, 3, 0, sub {
3907     BDB::db_env_lock_detect $DB_ENV, 0, BDB::LOCK_DEFAULT, 0, sub { };
3908     };
3909     $BDB_CHECKPOINT_WATCHER = EV::periodic 0, 60, 0, sub {
3910     BDB::db_env_txn_checkpoint $DB_ENV, 0, 0, 0, sub { };
3911     };
3912     $BDB_TRICKLE_WATCHER = EV::periodic 0, 10, 0, sub {
3913     BDB::db_env_memp_trickle $DB_ENV, 20, 0, sub { };
3914     };
3915 root 1.206 }
3916    
3917     {
3918 root 1.401 # configure IO::AIO
3919    
3920 root 1.206 IO::AIO::min_parallel 8;
3921     IO::AIO::max_poll_time $TICK * 0.1;
3922 root 1.435 undef $AnyEvent::AIO::WATCHER;
3923 root 1.206 }
3924 root 1.108
3925 root 1.262 my $_log_backtrace;
3926    
3927 root 1.260 sub _log_backtrace {
3928     my ($msg, @addr) = @_;
3929    
3930 root 1.262 $msg =~ s/\n//;
3931 root 1.260
3932 root 1.262 # limit the # of concurrent backtraces
3933     if ($_log_backtrace < 2) {
3934     ++$_log_backtrace;
3935 root 1.446 my $perl_bt = Carp::longmess $msg;
3936 root 1.262 async {
3937 root 1.374 $Coro::current->{desc} = "abt $msg";
3938    
3939 root 1.262 my @bt = fork_call {
3940     @addr = map { sprintf "%x", $_ } @addr;
3941     my $self = (-f "/proc/$$/exe") ? "/proc/$$/exe" : $^X;
3942     open my $fh, "exec addr2line -C -f -i -e \Q$self\E @addr 2>&1 |"
3943     or die "addr2line: $!";
3944    
3945     my @funcs;
3946     my @res = <$fh>;
3947     chomp for @res;
3948     while (@res) {
3949     my ($func, $line) = splice @res, 0, 2, ();
3950     push @funcs, "[$func] $line";
3951     }
3952 root 1.260
3953 root 1.262 @funcs
3954     };
3955 root 1.260
3956 root 1.446 LOG llevInfo, "[ABT] $perl_bt\n";
3957     LOG llevInfo, "[ABT] --- C backtrace follows ---\n";
3958 root 1.262 LOG llevInfo, "[ABT] $_\n" for @bt;
3959     --$_log_backtrace;
3960     };
3961     } else {
3962 root 1.260 LOG llevInfo, "[ABT] $msg\n";
3963 root 1.262 LOG llevInfo, "[ABT] [suppressed]\n";
3964     }
3965 root 1.260 }
3966    
3967 root 1.249 # load additional modules
3968     use cf::pod;
3969    
3970 root 1.125 END { cf::emergency_save }
3971    
3972 root 1.1 1
3973