ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/lib/cf.pm
Revision: 1.572
Committed: Sun May 8 11:44:43 2011 UTC (13 years, 2 months ago) by root
Branch: MAIN
Changes since 1.571: +2 -0 lines
Log Message:
*** empty log message ***

File Contents

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