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