ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/lib/cf.pm
Revision: 1.598
Committed: Sun Nov 11 02:38:10 2012 UTC (11 years, 6 months ago) by root
Branch: MAIN
Changes since 1.597: +2 -3 lines
Log Message:
-Time::HiRes

File Contents

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