ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/lib/cf.pm
Revision: 1.579
Committed: Wed Jan 4 03:22:28 2012 UTC (12 years, 4 months ago) by root
Branch: MAIN
Changes since 1.578: +3 -3 lines
Log Message:
*** empty log message ***

File Contents

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