ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/lib/cf.pm
Revision: 1.624
Committed: Sat Nov 17 23:40:02 2018 UTC (5 years, 6 months ago) by root
Branch: MAIN
CVS Tags: HEAD
Changes since 1.623: +3 -1 lines
Log Message:
copyright update 2018

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