ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/lib/cf.pm
Revision: 1.618
Committed: Mon Aug 10 18:48:41 2015 UTC (8 years, 9 months ago) by root
Branch: MAIN
Changes since 1.617: +1 -1 lines
Log Message:
*** empty log message ***

File Contents

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