ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/lib/cf.pm
Revision: 1.555
Committed: Wed Jun 30 01:32:56 2010 UTC (13 years, 11 months ago) by root
Branch: MAIN
Changes since 1.554: +1 -11 lines
Log Message:
progress?

File Contents

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