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