ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/lib/cf.pm
Revision: 1.556
Committed: Sat Jul 3 01:49:18 2010 UTC (13 years, 10 months ago) by root
Branch: MAIN
Changes since 1.555: +1 -5 lines
Log Message:
isolation remover would try to tunnel along the border, but make_tunnel refused, leading to isolated areas

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.556 $self->_create_random_map ($rmp);
1867 root 1.110 }
1868    
1869 root 1.187 =item cf::map->register ($regex, $prio)
1870    
1871     Register a handler for the map path matching the given regex at the
1872     givne priority (higher is better, built-in handlers have priority 0, the
1873     default).
1874    
1875     =cut
1876    
1877 root 1.166 sub register {
1878 root 1.187 my (undef, $regex, $prio) = @_;
1879 root 1.166 my $pkg = caller;
1880    
1881     push @{"$pkg\::ISA"}, __PACKAGE__;
1882    
1883 root 1.187 $EXT_MAP{$pkg} = [$prio, qr<$regex>];
1884 root 1.166 }
1885    
1886     # also paths starting with '/'
1887 root 1.524 $EXT_MAP{"cf::map::wrap"} = [0, qr{^(?=/)}];
1888 root 1.166
1889 root 1.170 sub thawer_merge {
1890 root 1.172 my ($self, $merge) = @_;
1891    
1892 root 1.170 # we have to keep some variables in memory intact
1893 root 1.172 local $self->{path};
1894     local $self->{load_path};
1895 root 1.170
1896 root 1.172 $self->SUPER::thawer_merge ($merge);
1897 root 1.170 }
1898    
1899 root 1.166 sub normalise {
1900     my ($path, $base) = @_;
1901    
1902 root 1.543 $path = "$path"; # make sure it's a string
1903 root 1.192
1904 root 1.199 $path =~ s/\.map$//;
1905    
1906 root 1.166 # map plan:
1907     #
1908     # /! non-realised random map exit (special hack!)
1909     # {... are special paths that are not being touched
1910     # ?xxx/... are special absolute paths
1911     # ?random/... random maps
1912     # /... normal maps
1913     # ~user/... per-player map of a specific user
1914    
1915     $path =~ s/$PATH_SEP/\//go;
1916    
1917     # treat it as relative path if it starts with
1918     # something that looks reasonable
1919     if ($path =~ m{^(?:\./|\.\./|\w)}) {
1920     $base or Carp::carp "normalise called with relative path and no base: '$path'";
1921    
1922     $base =~ s{[^/]+/?$}{};
1923     $path = "$base/$path";
1924     }
1925    
1926     for ($path) {
1927     redo if s{/\.?/}{/};
1928     redo if s{/[^/]+/\.\./}{/};
1929     }
1930    
1931     $path
1932     }
1933    
1934     sub new_from_path {
1935     my (undef, $path, $base) = @_;
1936    
1937     return $path if UNIVERSAL::isa $path, "cf::map"; # already a map object
1938    
1939     $path = normalise $path, $base;
1940    
1941 root 1.187 for my $pkg (sort { $EXT_MAP{$b}[0] <=> $EXT_MAP{$a}[0] } keys %EXT_MAP) {
1942     if ($path =~ $EXT_MAP{$pkg}[1]) {
1943 root 1.166 my $self = bless cf::map::new, $pkg;
1944     $self->{path} = $path; $self->path ($path);
1945     $self->init; # pass $1 etc.
1946     return $self;
1947     }
1948     }
1949    
1950 root 1.543 Carp::cluck "unable to resolve path '$path' (base '$base')";
1951 root 1.166 ()
1952     }
1953    
1954     sub init {
1955     my ($self) = @_;
1956    
1957     $self
1958     }
1959    
1960     sub as_string {
1961     my ($self) = @_;
1962    
1963     "$self->{path}"
1964     }
1965    
1966     # the displayed name, this is a one way mapping
1967     sub visible_name {
1968     &as_string
1969     }
1970    
1971     # the original (read-only) location
1972     sub load_path {
1973     my ($self) = @_;
1974    
1975 root 1.254 "$MAPDIR/$self->{path}.map"
1976 root 1.166 }
1977    
1978     # the temporary/swap location
1979     sub save_path {
1980     my ($self) = @_;
1981    
1982 root 1.419 (my $path = $_[0]{path}) =~ s/\//$PATH_SEP/go;
1983 root 1.254 "$TMPDIR/$path.map"
1984 root 1.166 }
1985    
1986     # the unique path, undef == no special unique path
1987     sub uniq_path {
1988     my ($self) = @_;
1989    
1990 root 1.419 (my $path = $_[0]{path}) =~ s/\//$PATH_SEP/go;
1991 root 1.253 "$UNIQUEDIR/$path"
1992 root 1.166 }
1993    
1994 root 1.275 sub decay_objects {
1995     my ($self) = @_;
1996    
1997     return if $self->{deny_reset};
1998    
1999     $self->do_decay_objects;
2000     }
2001    
2002 root 1.166 sub unlink_save {
2003     my ($self) = @_;
2004    
2005     utf8::encode (my $save = $self->save_path);
2006 root 1.170 IO::AIO::aioreq_pri 4; Coro::AIO::aio_unlink $save;
2007     IO::AIO::aioreq_pri 4; Coro::AIO::aio_unlink "$save.pst";
2008 root 1.166 }
2009    
2010     sub load_header_from($) {
2011     my ($self, $path) = @_;
2012 root 1.110
2013     utf8::encode $path;
2014 root 1.356 my $f = new_from_file cf::object::thawer $path
2015     or return;
2016 root 1.110
2017 root 1.356 $self->_load_header ($f)
2018 root 1.110 or return;
2019    
2020 root 1.356 local $MAP_LOADING{$self->{path}} = $self;
2021     $f->resolve_delayed_derefs;
2022    
2023 root 1.166 $self->{load_path} = $path;
2024 root 1.135
2025 root 1.166 1
2026     }
2027 root 1.110
2028 root 1.188 sub load_header_orig {
2029 root 1.166 my ($self) = @_;
2030 root 1.110
2031 root 1.166 $self->load_header_from ($self->load_path)
2032 root 1.110 }
2033    
2034 root 1.188 sub load_header_temp {
2035 root 1.166 my ($self) = @_;
2036 root 1.110
2037 root 1.166 $self->load_header_from ($self->save_path)
2038     }
2039 root 1.110
2040 root 1.188 sub prepare_temp {
2041     my ($self) = @_;
2042    
2043     $self->last_access ((delete $self->{last_access})
2044     || $cf::RUNTIME); #d#
2045     # safety
2046     $self->{instantiate_time} = $cf::RUNTIME
2047     if $self->{instantiate_time} > $cf::RUNTIME;
2048     }
2049    
2050     sub prepare_orig {
2051     my ($self) = @_;
2052    
2053     $self->{load_original} = 1;
2054     $self->{instantiate_time} = $cf::RUNTIME;
2055     $self->last_access ($cf::RUNTIME);
2056     $self->instantiate;
2057     }
2058    
2059 root 1.166 sub load_header {
2060     my ($self) = @_;
2061 root 1.110
2062 root 1.188 if ($self->load_header_temp) {
2063     $self->prepare_temp;
2064 root 1.166 } else {
2065 root 1.188 $self->load_header_orig
2066 root 1.166 or return;
2067 root 1.188 $self->prepare_orig;
2068 root 1.166 }
2069 root 1.120
2070 root 1.275 $self->{deny_reset} = 1
2071     if $self->no_reset;
2072    
2073 root 1.238 $self->default_region (cf::region::find_by_path $self->{path})
2074     unless $self->default_region;
2075    
2076 root 1.166 1
2077     }
2078 root 1.110
2079 root 1.166 sub find;
2080     sub find {
2081     my ($path, $origin) = @_;
2082 root 1.134
2083 root 1.543 cf::cede_to_tick;
2084    
2085 root 1.166 $path = normalise $path, $origin && $origin->path;
2086 root 1.110
2087 root 1.459 my $guard1 = cf::lock_acquire "map_data:$path";#d#remove
2088     my $guard2 = cf::lock_acquire "map_find:$path";
2089 root 1.110
2090 root 1.166 $cf::MAP{$path} || do {
2091     my $map = new_from_path cf::map $path
2092     or return;
2093 root 1.110
2094 root 1.116 $map->{last_save} = $cf::RUNTIME;
2095 root 1.110
2096 root 1.166 $map->load_header
2097     or return;
2098 root 1.134
2099 root 1.275 if ($map->should_reset) {#d#TODO# disabled, crashy (locking issue?)
2100 root 1.185 # doing this can freeze the server in a sync job, obviously
2101     #$cf::WAIT_FOR_TICK->wait;
2102 root 1.429 undef $guard2;
2103 root 1.358 undef $guard1;
2104 root 1.112 $map->reset;
2105 root 1.192 return find $path;
2106 root 1.112 }
2107 root 1.110
2108 root 1.166 $cf::MAP{$path} = $map
2109 root 1.110 }
2110     }
2111    
2112 root 1.500 sub pre_load { }
2113     #sub post_load { } # XS
2114 root 1.188
2115 root 1.110 sub load {
2116     my ($self) = @_;
2117    
2118 root 1.196 local $self->{deny_reset} = 1; # loading can take a long time
2119    
2120 root 1.120 my $path = $self->{path};
2121    
2122 root 1.256 {
2123 root 1.357 my $guard = cf::lock_acquire "map_data:$path";
2124 root 1.256
2125 root 1.357 return unless $self->valid;
2126 root 1.360 return unless $self->in_memory == cf::MAP_SWAPPED;
2127 root 1.110
2128 root 1.256 $self->in_memory (cf::MAP_LOADING);
2129 root 1.110
2130 root 1.256 $self->alloc;
2131 root 1.188
2132 root 1.256 $self->pre_load;
2133 root 1.346 cf::cede_to_tick;
2134 root 1.188
2135 root 1.356 my $f = new_from_file cf::object::thawer $self->{load_path};
2136     $f->skip_block;
2137     $self->_load_objects ($f)
2138 root 1.256 or return;
2139 root 1.110
2140 root 1.439 $self->post_load_original
2141 root 1.256 if delete $self->{load_original};
2142 root 1.111
2143 root 1.256 if (my $uniq = $self->uniq_path) {
2144     utf8::encode $uniq;
2145 root 1.356 unless (aio_stat $uniq) {
2146     if (my $f = new_from_file cf::object::thawer $uniq) {
2147     $self->clear_unique_items;
2148     $self->_load_objects ($f);
2149     $f->resolve_delayed_derefs;
2150     }
2151 root 1.256 }
2152 root 1.110 }
2153    
2154 root 1.356 $f->resolve_delayed_derefs;
2155    
2156 root 1.346 cf::cede_to_tick;
2157 root 1.256 # now do the right thing for maps
2158     $self->link_multipart_objects;
2159 root 1.110 $self->difficulty ($self->estimate_difficulty)
2160     unless $self->difficulty;
2161 root 1.346 cf::cede_to_tick;
2162 root 1.256
2163     unless ($self->{deny_activate}) {
2164     $self->decay_objects;
2165     $self->fix_auto_apply;
2166     $self->update_buttons;
2167 root 1.346 cf::cede_to_tick;
2168 root 1.256 $self->activate;
2169     }
2170    
2171 root 1.325 $self->{last_save} = $cf::RUNTIME;
2172     $self->last_access ($cf::RUNTIME);
2173 root 1.324
2174 root 1.420 $self->in_memory (cf::MAP_ACTIVE);
2175 root 1.110 }
2176    
2177 root 1.188 $self->post_load;
2178 root 1.553
2179     1
2180 root 1.166 }
2181    
2182 root 1.507 # customize the map for a given player, i.e.
2183     # return the _real_ map. used by e.g. per-player
2184     # maps to change the path to ~playername/mappath
2185 root 1.166 sub customise_for {
2186     my ($self, $ob) = @_;
2187    
2188     return find "~" . $ob->name . "/" . $self->{path}
2189     if $self->per_player;
2190 root 1.134
2191 root 1.275 # return find "?party/" . $ob->name . "/" . $self->{path}
2192     # if $self->per_party;
2193    
2194 root 1.166 $self
2195 root 1.110 }
2196    
2197 root 1.157 # find and load all maps in the 3x3 area around a map
2198 root 1.333 sub load_neighbours {
2199 root 1.157 my ($map) = @_;
2200    
2201 root 1.333 my @neigh; # diagonal neighbours
2202 root 1.157
2203     for (0 .. 3) {
2204     my $neigh = $map->tile_path ($_)
2205     or next;
2206     $neigh = find $neigh, $map
2207     or next;
2208     $neigh->load;
2209    
2210 root 1.527 # now find the diagonal neighbours
2211 root 1.333 push @neigh,
2212     [$neigh->tile_path (($_ + 3) % 4), $neigh],
2213     [$neigh->tile_path (($_ + 1) % 4), $neigh];
2214 root 1.157 }
2215    
2216 root 1.333 for (grep defined $_->[0], @neigh) {
2217     my ($path, $origin) = @$_;
2218     my $neigh = find $path, $origin
2219 root 1.157 or next;
2220     $neigh->load;
2221     }
2222     }
2223    
2224 root 1.133 sub find_sync {
2225 root 1.110 my ($path, $origin) = @_;
2226    
2227 root 1.534 return cf::LOG cf::llevError | cf::logBacktrace, "do_find_sync"
2228     if $Coro::current == $Coro::main;
2229    
2230     find $path, $origin
2231 root 1.133 }
2232    
2233     sub do_load_sync {
2234     my ($map) = @_;
2235 root 1.110
2236 root 1.534 return cf::LOG cf::llevError | cf::logBacktrace, "do_load_sync"
2237 root 1.342 if $Coro::current == $Coro::main;
2238 root 1.339
2239 root 1.534 $map->load;
2240 root 1.110 }
2241    
2242 root 1.157 our %MAP_PREFETCH;
2243 root 1.183 our $MAP_PREFETCHER = undef;
2244 root 1.157
2245     sub find_async {
2246 root 1.339 my ($path, $origin, $load) = @_;
2247 root 1.157
2248 root 1.166 $path = normalise $path, $origin && $origin->{path};
2249 root 1.157
2250 root 1.166 if (my $map = $cf::MAP{$path}) {
2251 root 1.420 return $map if !$load || $map->in_memory == cf::MAP_ACTIVE;
2252 root 1.157 }
2253    
2254 root 1.339 $MAP_PREFETCH{$path} |= $load;
2255    
2256 root 1.183 $MAP_PREFETCHER ||= cf::async {
2257 root 1.374 $Coro::current->{desc} = "map prefetcher";
2258    
2259 root 1.183 while (%MAP_PREFETCH) {
2260 root 1.339 while (my ($k, $v) = each %MAP_PREFETCH) {
2261     if (my $map = find $k) {
2262     $map->load if $v;
2263 root 1.308 }
2264 root 1.183
2265 root 1.339 delete $MAP_PREFETCH{$k};
2266 root 1.183 }
2267     }
2268     undef $MAP_PREFETCHER;
2269     };
2270 root 1.189 $MAP_PREFETCHER->prio (6);
2271 root 1.157
2272     ()
2273     }
2274    
2275 root 1.518 # common code, used by both ->save and ->swapout
2276     sub _save {
2277 root 1.110 my ($self) = @_;
2278    
2279     $self->{last_save} = $cf::RUNTIME;
2280    
2281     return unless $self->dirty;
2282    
2283 root 1.166 my $save = $self->save_path; utf8::encode $save;
2284     my $uniq = $self->uniq_path; utf8::encode $uniq;
2285 root 1.117
2286 root 1.110 $self->{load_path} = $save;
2287    
2288     return if $self->{deny_save};
2289    
2290 root 1.132 local $self->{last_access} = $self->last_access;#d#
2291    
2292 root 1.143 cf::async {
2293 root 1.374 $Coro::current->{desc} = "map player save";
2294 root 1.143 $_->contr->save for $self->players;
2295     };
2296    
2297 root 1.420 cf::get_slot 0.02;
2298    
2299 root 1.110 if ($uniq) {
2300 root 1.166 $self->_save_objects ($save, cf::IO_HEADER | cf::IO_OBJECTS);
2301     $self->_save_objects ($uniq, cf::IO_UNIQUES);
2302 root 1.110 } else {
2303 root 1.166 $self->_save_objects ($save, cf::IO_HEADER | cf::IO_OBJECTS | cf::IO_UNIQUES);
2304 root 1.110 }
2305     }
2306    
2307 root 1.518 sub save {
2308     my ($self) = @_;
2309    
2310     my $lock = cf::lock_acquire "map_data:$self->{path}";
2311    
2312     $self->_save;
2313     }
2314    
2315 root 1.110 sub swap_out {
2316     my ($self) = @_;
2317    
2318 root 1.345 my $lock = cf::lock_acquire "map_data:$self->{path}";
2319 root 1.137
2320 root 1.420 return if $self->in_memory != cf::MAP_ACTIVE;
2321 root 1.110 return if $self->{deny_save};
2322 root 1.518 return if $self->players;
2323 root 1.110
2324 root 1.518 # first deactivate the map and "unlink" it from the core
2325     $self->deactivate;
2326     $_->clear_links_to ($self) for values %cf::MAP;
2327 root 1.359 $self->in_memory (cf::MAP_SWAPPED);
2328    
2329 root 1.518 # then atomically save
2330     $self->_save;
2331    
2332     # then free the map
2333 root 1.110 $self->clear;
2334     }
2335    
2336 root 1.112 sub reset_at {
2337     my ($self) = @_;
2338 root 1.110
2339     # TODO: safety, remove and allow resettable per-player maps
2340 root 1.114 return 1e99 if $self->{deny_reset};
2341 root 1.110
2342 root 1.112 my $time = $self->fixed_resettime ? $self->{instantiate_time} : $self->last_access;
2343 root 1.114 my $to = List::Util::min $MAX_RESET, $self->reset_timeout || $DEFAULT_RESET;
2344 root 1.110
2345 root 1.112 $time + $to
2346     }
2347    
2348     sub should_reset {
2349     my ($self) = @_;
2350    
2351     $self->reset_at <= $cf::RUNTIME
2352 root 1.111 }
2353    
2354 root 1.110 sub reset {
2355     my ($self) = @_;
2356    
2357 root 1.167 my $lock = cf::lock_acquire "map_data:$self->{path}";
2358 root 1.137
2359 root 1.110 return if $self->players;
2360    
2361 root 1.532 cf::trace "resetting map ", $self->path, "\n";
2362 root 1.110
2363 root 1.210 $self->in_memory (cf::MAP_SWAPPED);
2364    
2365     # need to save uniques path
2366     unless ($self->{deny_save}) {
2367     my $uniq = $self->uniq_path; utf8::encode $uniq;
2368    
2369     $self->_save_objects ($uniq, cf::IO_UNIQUES)
2370     if $uniq;
2371     }
2372    
2373 root 1.111 delete $cf::MAP{$self->path};
2374 root 1.110
2375 root 1.358 $self->deactivate;
2376 root 1.359 $_->clear_links_to ($self) for values %cf::MAP;
2377 root 1.167 $self->clear;
2378    
2379 root 1.166 $self->unlink_save;
2380 root 1.111 $self->destroy;
2381 root 1.110 }
2382    
2383 root 1.114 my $nuke_counter = "aaaa";
2384    
2385     sub nuke {
2386     my ($self) = @_;
2387    
2388 root 1.349 {
2389     my $lock = cf::lock_acquire "map_data:$self->{path}";
2390    
2391     delete $cf::MAP{$self->path};
2392 root 1.174
2393 root 1.351 $self->unlink_save;
2394    
2395 root 1.524 bless $self, "cf::map::wrap";
2396 root 1.349 delete $self->{deny_reset};
2397     $self->{deny_save} = 1;
2398     $self->reset_timeout (1);
2399     $self->path ($self->{path} = "{nuke}/" . ($nuke_counter++));
2400 root 1.174
2401 root 1.349 $cf::MAP{$self->path} = $self;
2402     }
2403 root 1.174
2404 root 1.114 $self->reset; # polite request, might not happen
2405     }
2406    
2407 root 1.276 =item $maps = cf::map::tmp_maps
2408    
2409     Returns an arrayref with all map paths of currently instantiated and saved
2410 root 1.277 maps. May block.
2411 root 1.276
2412     =cut
2413    
2414     sub tmp_maps() {
2415     [
2416     map {
2417     utf8::decode $_;
2418 root 1.277 /\.map$/
2419 root 1.276 ? normalise $_
2420     : ()
2421     } @{ aio_readdir $TMPDIR or [] }
2422     ]
2423     }
2424    
2425 root 1.277 =item $maps = cf::map::random_maps
2426    
2427     Returns an arrayref with all map paths of currently instantiated and saved
2428     random maps. May block.
2429    
2430     =cut
2431    
2432     sub random_maps() {
2433     [
2434     map {
2435     utf8::decode $_;
2436     /\.map$/
2437     ? normalise "?random/$_"
2438     : ()
2439     } @{ aio_readdir $RANDOMDIR or [] }
2440     ]
2441     }
2442    
2443 root 1.158 =item cf::map::unique_maps
2444    
2445 root 1.166 Returns an arrayref of paths of all shared maps that have
2446 root 1.158 instantiated unique items. May block.
2447    
2448     =cut
2449    
2450     sub unique_maps() {
2451 root 1.276 [
2452     map {
2453     utf8::decode $_;
2454 root 1.419 s/\.map$//; # TODO future compatibility hack
2455     /\.pst$/ || !/^$PATH_SEP/o # TODO unique maps apparebntly lack the .map suffix :/
2456     ? ()
2457     : normalise $_
2458 root 1.276 } @{ aio_readdir $UNIQUEDIR or [] }
2459     ]
2460 root 1.158 }
2461    
2462 root 1.489 =item cf::map::static_maps
2463    
2464     Returns an arrayref if paths of all static maps (all preinstalled F<.map>
2465 root 1.491 file in the shared directory excluding F</styles> and F</editor>). May
2466     block.
2467 root 1.489
2468     =cut
2469    
2470     sub static_maps() {
2471     my @dirs = "";
2472     my @maps;
2473    
2474     while (@dirs) {
2475     my $dir = shift @dirs;
2476    
2477 root 1.491 next if $dir eq "/styles" || $dir eq "/editor";
2478 root 1.490
2479 root 1.489 my ($dirs, $files) = Coro::AIO::aio_scandir "$MAPDIR$dir", 2
2480     or return;
2481    
2482     for (@$files) {
2483     s/\.map$// or next;
2484     utf8::decode $_;
2485     push @maps, "$dir/$_";
2486     }
2487    
2488     push @dirs, map "$dir/$_", @$dirs;
2489     }
2490    
2491     \@maps
2492     }
2493    
2494 root 1.155 =back
2495    
2496     =head3 cf::object
2497    
2498     =cut
2499    
2500     package cf::object;
2501    
2502     =over 4
2503    
2504     =item $ob->inv_recursive
2505 root 1.110
2506 root 1.419 Returns the inventory of the object I<and> their inventories, recursively,
2507     but I<not> the object itself.
2508 root 1.110
2509 root 1.155 =cut
2510 root 1.144
2511 root 1.155 sub inv_recursive_;
2512     sub inv_recursive_ {
2513     map { $_, inv_recursive_ $_->inv } @_
2514     }
2515 root 1.110
2516 root 1.155 sub inv_recursive {
2517     inv_recursive_ inv $_[0]
2518 root 1.110 }
2519    
2520 root 1.356 =item $ref = $ob->ref
2521    
2522 root 1.419 Creates and returns a persistent reference to an object that can be stored as a string.
2523 root 1.356
2524     =item $ob = cf::object::deref ($refstring)
2525    
2526     returns the objetc referenced by refstring. may return undef when it cnanot find the object,
2527     even if the object actually exists. May block.
2528    
2529     =cut
2530    
2531     sub deref {
2532     my ($ref) = @_;
2533    
2534 root 1.377 if ($ref =~ m{^player\/(<1\.[0-9a-f]+>)/(.*)$}) {
2535 root 1.356 my ($uuid, $name) = ($1, $2);
2536     my $pl = $cf::PLAYER_LOADING{$name} || cf::player::find $name
2537     or return;
2538     $pl->ob->uuid eq $uuid
2539     or return;
2540    
2541     $pl->ob
2542     } else {
2543     warn "$ref: cannot resolve object reference\n";
2544     undef
2545     }
2546     }
2547    
2548 root 1.110 package cf;
2549    
2550     =back
2551    
2552 root 1.95 =head3 cf::object::player
2553    
2554     =over 4
2555    
2556 root 1.79 =item $player_object->reply ($npc, $msg[, $flags])
2557 root 1.28
2558     Sends a message to the player, as if the npc C<$npc> replied. C<$npc>
2559     can be C<undef>. Does the right thing when the player is currently in a
2560     dialogue with the given NPC character.
2561    
2562     =cut
2563    
2564 root 1.428 our $SAY_CHANNEL = {
2565     id => "say",
2566     title => "Map",
2567     reply => "say ",
2568 root 1.468 tooltip => "Things said to and replied from NPCs near you and other players on the same map only.",
2569 root 1.428 };
2570    
2571     our $CHAT_CHANNEL = {
2572     id => "chat",
2573     title => "Chat",
2574     reply => "chat ",
2575     tooltip => "Player chat and shouts, global to the server.",
2576     };
2577    
2578 root 1.22 # rough implementation of a future "reply" method that works
2579     # with dialog boxes.
2580 root 1.95 #TODO: the first argument must go, split into a $npc->reply_to ( method
2581 root 1.23 sub cf::object::player::reply($$$;$) {
2582     my ($self, $npc, $msg, $flags) = @_;
2583    
2584     $flags = cf::NDI_BROWN | cf::NDI_UNIQUE unless @_ >= 4;
2585 root 1.22
2586 root 1.24 if ($self->{record_replies}) {
2587     push @{ $self->{record_replies} }, [$npc, $msg, $flags];
2588 elmex 1.282
2589 root 1.24 } else {
2590 elmex 1.282 my $pl = $self->contr;
2591    
2592     if ($pl->{npc_dialog} && $pl->{npc_dialog}->{id}) {
2593 root 1.316 my $dialog = $pl->{npc_dialog};
2594     $dialog->{pl}->ext_msg ($dialog->{id}, update => msg => $dialog->{pl}->expand_cfpod ($msg));
2595 elmex 1.282
2596     } else {
2597     $msg = $npc->name . " says: $msg" if $npc;
2598 root 1.428 $self->send_msg ($SAY_CHANNEL => $msg, $flags);
2599 elmex 1.282 }
2600 root 1.24 }
2601 root 1.22 }
2602    
2603 root 1.329 =item $object->send_msg ($channel, $msg, $color, [extra...])
2604    
2605     =cut
2606    
2607     sub cf::object::send_msg {
2608     my $pl = shift->contr
2609     or return;
2610     $pl->send_msg (@_);
2611     }
2612    
2613 root 1.79 =item $player_object->may ("access")
2614    
2615     Returns wether the given player is authorized to access resource "access"
2616     (e.g. "command_wizcast").
2617    
2618     =cut
2619    
2620     sub cf::object::player::may {
2621     my ($self, $access) = @_;
2622    
2623     $self->flag (cf::FLAG_WIZ) ||
2624     (ref $cf::CFG{"may_$access"}
2625     ? scalar grep $self->name eq $_, @{$cf::CFG{"may_$access"}}
2626     : $cf::CFG{"may_$access"})
2627     }
2628 root 1.70
2629 root 1.115 =item $player_object->enter_link
2630    
2631     Freezes the player and moves him/her to a special map (C<{link}>).
2632    
2633 root 1.446 The player should be reasonably safe there for short amounts of time (e.g.
2634     for loading a map). You I<MUST> call C<leave_link> as soon as possible,
2635 root 1.527 though, as the player cannot control the character while it is on the link
2636 root 1.446 map.
2637 root 1.115
2638 root 1.166 Will never block.
2639    
2640 root 1.115 =item $player_object->leave_link ($map, $x, $y)
2641    
2642 root 1.166 Moves the player out of the special C<{link}> map onto the specified
2643     map. If the map is not valid (or omitted), the player will be moved back
2644     to the location he/she was before the call to C<enter_link>, or, if that
2645     fails, to the emergency map position.
2646 root 1.115
2647     Might block.
2648    
2649     =cut
2650    
2651 root 1.166 sub link_map {
2652     unless ($LINK_MAP) {
2653     $LINK_MAP = cf::map::find "{link}"
2654 root 1.196 or cf::cleanup "FATAL: unable to provide {link} map, exiting.";
2655 root 1.166 $LINK_MAP->load;
2656     }
2657    
2658     $LINK_MAP
2659     }
2660    
2661 root 1.110 sub cf::object::player::enter_link {
2662     my ($self) = @_;
2663    
2664 root 1.259 $self->deactivate_recursive;
2665 root 1.258
2666 root 1.527 ++$self->{_link_recursion};
2667    
2668 root 1.166 return if UNIVERSAL::isa $self->map, "ext::map_link";
2669 root 1.110
2670 root 1.120 $self->{_link_pos} ||= [$self->map->{path}, $self->x, $self->y]
2671 root 1.270 if $self->map && $self->map->{path} ne "{link}";
2672 root 1.110
2673 root 1.519 $self->enter_map ($LINK_MAP || link_map, 3, 3);
2674 root 1.110 }
2675    
2676     sub cf::object::player::leave_link {
2677     my ($self, $map, $x, $y) = @_;
2678    
2679 root 1.270 return unless $self->contr->active;
2680    
2681 root 1.110 my $link_pos = delete $self->{_link_pos};
2682    
2683     unless ($map) {
2684     # restore original map position
2685     ($map, $x, $y) = @{ $link_pos || [] };
2686 root 1.133 $map = cf::map::find $map;
2687 root 1.110
2688     unless ($map) {
2689     ($map, $x, $y) = @$EMERGENCY_POSITION;
2690 root 1.133 $map = cf::map::find $map
2691 root 1.110 or die "FATAL: cannot load emergency map\n";
2692     }
2693     }
2694    
2695     ($x, $y) = (-1, -1)
2696     unless (defined $x) && (defined $y);
2697    
2698     # use -1 or undef as default coordinates, not 0, 0
2699     ($x, $y) = ($map->enter_x, $map->enter_y)
2700 root 1.492 if $x <= 0 && $y <= 0;
2701 root 1.110
2702     $map->load;
2703 root 1.333 $map->load_neighbours;
2704 root 1.110
2705 root 1.143 return unless $self->contr->active;
2706 root 1.215
2707     local $self->{_prev_pos} = $link_pos; # ugly hack for rent.ext
2708 root 1.527 if ($self->enter_map ($map, $x, $y)) {
2709     # entering was successful
2710     delete $self->{_link_recursion};
2711     # only activate afterwards, to support waiting in hooks
2712     $self->activate_recursive;
2713     }
2714 root 1.476
2715 root 1.110 }
2716    
2717 root 1.527 =item $player_object->goto ($path, $x, $y[, $check->($map, $x, $y, $player)[, $done->($player)]])
2718 root 1.268
2719     Moves the player to the given map-path and coordinates by first freezing
2720     her, loading and preparing them map, calling the provided $check callback
2721     that has to return the map if sucecssful, and then unfreezes the player on
2722 root 1.306 the new (success) or old (failed) map position. In either case, $done will
2723     be called at the end of this process.
2724 root 1.110
2725 root 1.436 Note that $check will be called with a potentially non-loaded map, so if
2726     it needs a loaded map it has to call C<< ->load >>.
2727    
2728 root 1.110 =cut
2729    
2730 root 1.270 our $GOTOGEN;
2731    
2732 root 1.136 sub cf::object::player::goto {
2733 root 1.306 my ($self, $path, $x, $y, $check, $done) = @_;
2734 root 1.268
2735 root 1.527 if ($self->{_link_recursion} >= $MAX_LINKS) {
2736 root 1.532 error "FATAL: link recursion exceeded, ", $self->name, " goto $path $x $y, redirecting.";
2737 root 1.527 $self->failmsg ("Something went wrong inside the server - please contact an administrator!");
2738     ($path, $x, $y) = @$EMERGENCY_POSITION;
2739     }
2740    
2741 root 1.270 # do generation counting so two concurrent goto's will be executed in-order
2742     my $gen = $self->{_goto_generation} = ++$GOTOGEN;
2743    
2744 root 1.110 $self->enter_link;
2745    
2746 root 1.140 (async {
2747 root 1.374 $Coro::current->{desc} = "player::goto $path $x $y";
2748    
2749 root 1.365 # *tag paths override both path and x|y
2750     if ($path =~ /^\*(.*)$/) {
2751     if (my @obs = grep $_->map, ext::map_tags::find $1) {
2752     my $ob = $obs[rand @obs];
2753 root 1.366
2754 root 1.367 # see if we actually can go there
2755 root 1.368 if (@obs = grep !$self->blocked ($_->map, $_->x, $_->y), $ob, $ob->tail) {
2756     $ob = $obs[rand @obs];
2757 root 1.369 } else {
2758     $self->message ("Wow, it's pretty crowded in there.", cf::NDI_UNIQUE | cf::NDI_RED);
2759 root 1.368 }
2760 root 1.369 # else put us there anyways for now #d#
2761 root 1.366
2762 root 1.365 ($path, $x, $y) = ($ob->map, $ob->x, $ob->y);
2763 root 1.369 } else {
2764     ($path, $x, $y) = (undef, undef, undef);
2765 root 1.365 }
2766     }
2767    
2768 root 1.197 my $map = eval {
2769 root 1.369 my $map = defined $path ? cf::map::find $path : undef;
2770 root 1.268
2771     if ($map) {
2772     $map = $map->customise_for ($self);
2773 root 1.527 $map = $check->($map, $x, $y, $self) if $check && $map;
2774 root 1.268 } else {
2775 root 1.369 $self->message ("The exit to '$path' is closed.", cf::NDI_UNIQUE | cf::NDI_RED);
2776 root 1.268 }
2777    
2778 root 1.197 $map
2779 root 1.268 };
2780    
2781     if ($@) {
2782     $self->message ("Something went wrong within the server, please report this incident!", cf::NDI_UNIQUE | cf::NDI_RED);
2783     LOG llevError | logBacktrace, Carp::longmess $@;
2784     }
2785 root 1.115
2786 root 1.270 if ($gen == $self->{_goto_generation}) {
2787     delete $self->{_goto_generation};
2788     $self->leave_link ($map, $x, $y);
2789     }
2790 root 1.306
2791 root 1.527 $done->($self) if $done;
2792 root 1.110 })->prio (1);
2793     }
2794    
2795     =item $player_object->enter_exit ($exit_object)
2796    
2797     =cut
2798    
2799     sub parse_random_map_params {
2800     my ($spec) = @_;
2801    
2802     my $rmp = { # defaults
2803 root 1.181 xsize => (cf::rndm 15, 40),
2804     ysize => (cf::rndm 15, 40),
2805     symmetry => (cf::rndm 1, cf::SYMMETRY_XY),
2806 root 1.182 #layout => string,
2807 root 1.110 };
2808    
2809     for (split /\n/, $spec) {
2810     my ($k, $v) = split /\s+/, $_, 2;
2811    
2812     $rmp->{lc $k} = $v if (length $k) && (length $v);
2813     }
2814    
2815     $rmp
2816     }
2817    
2818     sub prepare_random_map {
2819     my ($exit) = @_;
2820    
2821     # all this does is basically replace the /! path by
2822     # a new random map path (?random/...) with a seed
2823     # that depends on the exit object
2824    
2825     my $rmp = parse_random_map_params $exit->msg;
2826    
2827     if ($exit->map) {
2828 root 1.198 $rmp->{region} = $exit->region->name;
2829 root 1.110 $rmp->{origin_map} = $exit->map->path;
2830     $rmp->{origin_x} = $exit->x;
2831     $rmp->{origin_y} = $exit->y;
2832 root 1.430
2833     $exit->map->touch;
2834 root 1.110 }
2835    
2836     $rmp->{random_seed} ||= $exit->random_seed;
2837    
2838 root 1.422 my $data = JSON::XS->new->utf8->pretty->canonical->encode ($rmp);
2839 root 1.110 my $md5 = Digest::MD5::md5_hex $data;
2840 root 1.253 my $meta = "$RANDOMDIR/$md5.meta";
2841 root 1.110
2842 root 1.177 if (my $fh = aio_open "$meta~", O_WRONLY | O_CREAT, 0666) {
2843 root 1.110 aio_write $fh, 0, (length $data), $data, 0;
2844 root 1.177 undef $fh;
2845     aio_rename "$meta~", $meta;
2846 root 1.110
2847 root 1.430 my $slaying = "?random/$md5";
2848    
2849     if ($exit->valid) {
2850     $exit->slaying ("?random/$md5");
2851     $exit->msg (undef);
2852     }
2853 root 1.110 }
2854     }
2855    
2856     sub cf::object::player::enter_exit {
2857     my ($self, $exit) = @_;
2858    
2859     return unless $self->type == cf::PLAYER;
2860    
2861 root 1.430 $self->enter_link;
2862    
2863     (async {
2864     $Coro::current->{desc} = "enter_exit";
2865    
2866     unless (eval {
2867     $self->deactivate_recursive; # just to be sure
2868 root 1.195
2869 root 1.430 # random map handling
2870     {
2871     my $guard = cf::lock_acquire "exit_prepare:$exit";
2872 root 1.195
2873 root 1.430 prepare_random_map $exit
2874     if $exit->slaying eq "/!";
2875     }
2876 root 1.110
2877 root 1.430 my $map = cf::map::normalise $exit->slaying, $exit->map && $exit->map->path;
2878     my $x = $exit->stats->hp;
2879     my $y = $exit->stats->sp;
2880 root 1.296
2881 root 1.430 $self->goto ($map, $x, $y);
2882 root 1.374
2883 root 1.430 # if exit is damned, update players death & WoR home-position
2884     $self->contr->savebed ($map, $x, $y)
2885     if $exit->flag (cf::FLAG_DAMNED);
2886 root 1.110
2887 root 1.430 1
2888 root 1.110 }) {
2889 root 1.447 $self->message ("Something went wrong deep within the deliantra server. "
2890 root 1.233 . "I'll try to bring you back to the map you were before. "
2891     . "Please report this to the dungeon master!",
2892     cf::NDI_UNIQUE | cf::NDI_RED);
2893 root 1.110
2894 root 1.532 error "ERROR in enter_exit: $@";
2895 root 1.110 $self->leave_link;
2896     }
2897     })->prio (1);
2898     }
2899    
2900 root 1.95 =head3 cf::client
2901    
2902     =over 4
2903    
2904     =item $client->send_drawinfo ($text, $flags)
2905    
2906     Sends a drawinfo packet to the client. Circumvents output buffering so
2907     should not be used under normal circumstances.
2908    
2909 root 1.70 =cut
2910    
2911 root 1.95 sub cf::client::send_drawinfo {
2912     my ($self, $text, $flags) = @_;
2913    
2914     utf8::encode $text;
2915 root 1.225 $self->send_packet (sprintf "drawinfo %d %s", $flags || cf::NDI_BLACK, $text);
2916 root 1.95 }
2917    
2918 root 1.494 =item $client->send_big_packet ($pkt)
2919    
2920     Like C<send_packet>, but tries to compress large packets, and fragments
2921     them as required.
2922    
2923     =cut
2924    
2925     our $MAXFRAGSIZE = cf::MAXSOCKBUF - 64;
2926    
2927     sub cf::client::send_big_packet {
2928     my ($self, $pkt) = @_;
2929    
2930     # try lzf for large packets
2931     $pkt = "lzf " . Compress::LZF::compress $pkt
2932     if 1024 <= length $pkt and $self->{can_lzf};
2933    
2934     # split very large packets
2935     if ($MAXFRAGSIZE < length $pkt and $self->{can_lzf}) {
2936     $self->send_packet ("frag $_") for unpack "(a$MAXFRAGSIZE)*", $pkt;
2937     $pkt = "frag";
2938     }
2939    
2940     $self->send_packet ($pkt);
2941     }
2942    
2943 root 1.311 =item $client->send_msg ($channel, $msg, $color, [extra...])
2944 root 1.283
2945     Send a drawinfo or msg packet to the client, formatting the msg for the
2946     client if neccessary. C<$type> should be a string identifying the type of
2947     the message, with C<log> being the default. If C<$color> is negative, suppress
2948     the message unless the client supports the msg packet.
2949    
2950     =cut
2951    
2952 root 1.391 # non-persistent channels (usually the info channel)
2953 root 1.350 our %CHANNEL = (
2954 root 1.486 "c/motd" => {
2955     id => "infobox",
2956     title => "MOTD",
2957     reply => undef,
2958     tooltip => "The message of the day",
2959     },
2960 root 1.350 "c/identify" => {
2961 root 1.375 id => "infobox",
2962 root 1.350 title => "Identify",
2963     reply => undef,
2964     tooltip => "Items recently identified",
2965     },
2966 root 1.352 "c/examine" => {
2967 root 1.375 id => "infobox",
2968 root 1.352 title => "Examine",
2969     reply => undef,
2970     tooltip => "Signs and other items you examined",
2971     },
2972 root 1.487 "c/shopinfo" => {
2973     id => "infobox",
2974     title => "Shop Info",
2975     reply => undef,
2976     tooltip => "What your bargaining skill tells you about the shop",
2977     },
2978 root 1.389 "c/book" => {
2979     id => "infobox",
2980     title => "Book",
2981     reply => undef,
2982     tooltip => "The contents of a note or book",
2983     },
2984 root 1.375 "c/lookat" => {
2985     id => "infobox",
2986     title => "Look",
2987     reply => undef,
2988     tooltip => "What you saw there",
2989     },
2990 root 1.390 "c/who" => {
2991     id => "infobox",
2992     title => "Players",
2993     reply => undef,
2994     tooltip => "Shows players who are currently online",
2995     },
2996     "c/body" => {
2997     id => "infobox",
2998     title => "Body Parts",
2999     reply => undef,
3000     tooltip => "Shows which body parts you posess and are available",
3001     },
3002 root 1.465 "c/statistics" => {
3003     id => "infobox",
3004     title => "Statistics",
3005     reply => undef,
3006     tooltip => "Shows your primary statistics",
3007     },
3008 root 1.450 "c/skills" => {
3009     id => "infobox",
3010     title => "Skills",
3011     reply => undef,
3012     tooltip => "Shows your experience per skill and item power",
3013     },
3014 root 1.470 "c/shopitems" => {
3015     id => "infobox",
3016     title => "Shop Items",
3017     reply => undef,
3018     tooltip => "Shows the items currently for sale in this shop",
3019     },
3020 root 1.465 "c/resistances" => {
3021     id => "infobox",
3022     title => "Resistances",
3023     reply => undef,
3024     tooltip => "Shows your resistances",
3025     },
3026     "c/pets" => {
3027     id => "infobox",
3028     title => "Pets",
3029     reply => undef,
3030     tooltip => "Shows information abotu your pets/a specific pet",
3031     },
3032 root 1.471 "c/perceiveself" => {
3033     id => "infobox",
3034     title => "Perceive Self",
3035     reply => undef,
3036     tooltip => "You gained detailed knowledge about yourself",
3037     },
3038 root 1.390 "c/uptime" => {
3039     id => "infobox",
3040     title => "Uptime",
3041     reply => undef,
3042 root 1.391 tooltip => "How long the server has been running since last restart",
3043 root 1.390 },
3044     "c/mapinfo" => {
3045     id => "infobox",
3046     title => "Map Info",
3047     reply => undef,
3048     tooltip => "Information related to the maps",
3049     },
3050 root 1.426 "c/party" => {
3051     id => "party",
3052     title => "Party",
3053     reply => "gsay ",
3054     tooltip => "Messages and chat related to your party",
3055     },
3056 root 1.464 "c/death" => {
3057     id => "death",
3058     title => "Death",
3059     reply => undef,
3060     tooltip => "Reason for and more info about your most recent death",
3061     },
3062 root 1.462 "c/say" => $SAY_CHANNEL,
3063     "c/chat" => $CHAT_CHANNEL,
3064 root 1.350 );
3065    
3066 root 1.283 sub cf::client::send_msg {
3067 root 1.311 my ($self, $channel, $msg, $color, @extra) = @_;
3068 root 1.283
3069 root 1.447 $msg = $self->pl->expand_cfpod ($msg)
3070     unless $color & cf::NDI_VERBATIM;
3071 root 1.283
3072 root 1.323 $color &= cf::NDI_CLIENT_MASK; # just in case...
3073 root 1.311
3074 root 1.350 # check predefined channels, for the benefit of C
3075 root 1.375 if ($CHANNEL{$channel}) {
3076     $channel = $CHANNEL{$channel};
3077    
3078 root 1.463 $self->ext_msg (channel_info => $channel);
3079 root 1.375 $channel = $channel->{id};
3080 root 1.350
3081 root 1.375 } elsif (ref $channel) {
3082 root 1.311 # send meta info to client, if not yet sent
3083     unless (exists $self->{channel}{$channel->{id}}) {
3084     $self->{channel}{$channel->{id}} = $channel;
3085 root 1.463 $self->ext_msg (channel_info => $channel);
3086 root 1.311 }
3087    
3088     $channel = $channel->{id};
3089     }
3090    
3091 root 1.313 return unless @extra || length $msg;
3092    
3093 root 1.463 # default colour, mask it out
3094     $color &= ~(cf::NDI_COLOR_MASK | cf::NDI_DEF)
3095     if $color & cf::NDI_DEF;
3096    
3097     my $pkt = "msg "
3098     . $self->{json_coder}->encode (
3099     [$color & cf::NDI_CLIENT_MASK, $channel, $msg, @extra]
3100     );
3101    
3102 root 1.494 $self->send_big_packet ($pkt);
3103 root 1.283 }
3104    
3105 root 1.316 =item $client->ext_msg ($type, @msg)
3106 root 1.232
3107 root 1.287 Sends an ext event to the client.
3108 root 1.232
3109     =cut
3110    
3111 root 1.316 sub cf::client::ext_msg($$@) {
3112     my ($self, $type, @msg) = @_;
3113 root 1.232
3114 root 1.343 if ($self->extcmd == 2) {
3115 root 1.494 $self->send_big_packet ("ext " . $self->{json_coder}->encode ([$type, @msg]));
3116 root 1.343 } elsif ($self->extcmd == 1) { # TODO: remove
3117 root 1.316 push @msg, msgtype => "event_$type";
3118 root 1.494 $self->send_big_packet ("ext " . $self->{json_coder}->encode ({@msg}));
3119 root 1.316 }
3120 root 1.232 }
3121 root 1.95
3122 root 1.336 =item $client->ext_reply ($msgid, @msg)
3123    
3124     Sends an ext reply to the client.
3125    
3126     =cut
3127    
3128     sub cf::client::ext_reply($$@) {
3129     my ($self, $id, @msg) = @_;
3130    
3131     if ($self->extcmd == 2) {
3132 root 1.494 $self->send_big_packet ("ext " . $self->{json_coder}->encode (["reply-$id", @msg]));
3133 root 1.343 } elsif ($self->extcmd == 1) {
3134 root 1.336 #TODO: version 1, remove
3135     unshift @msg, msgtype => "reply", msgid => $id;
3136 root 1.494 $self->send_big_packet ("ext " . $self->{json_coder}->encode ({@msg}));
3137 root 1.336 }
3138     }
3139    
3140 root 1.95 =item $success = $client->query ($flags, "text", \&cb)
3141    
3142     Queues a query to the client, calling the given callback with
3143     the reply text on a reply. flags can be C<cf::CS_QUERY_YESNO>,
3144     C<cf::CS_QUERY_SINGLECHAR> or C<cf::CS_QUERY_HIDEINPUT> or C<0>.
3145    
3146 root 1.287 Queries can fail, so check the return code. Or don't, as queries will
3147     become reliable at some point in the future.
3148 root 1.95
3149     =cut
3150    
3151     sub cf::client::query {
3152     my ($self, $flags, $text, $cb) = @_;
3153    
3154     return unless $self->state == ST_PLAYING
3155     || $self->state == ST_SETUP
3156     || $self->state == ST_CUSTOM;
3157    
3158     $self->state (ST_CUSTOM);
3159    
3160     utf8::encode $text;
3161     push @{ $self->{query_queue} }, [(sprintf "query %d %s", $flags, $text), $cb];
3162    
3163     $self->send_packet ($self->{query_queue}[0][0])
3164     if @{ $self->{query_queue} } == 1;
3165 root 1.287
3166     1
3167 root 1.95 }
3168    
3169     cf::client->attach (
3170 root 1.290 on_connect => sub {
3171     my ($ns) = @_;
3172    
3173     $ns->{json_coder} = JSON::XS->new->utf8->max_size (1e6)->convert_blessed;
3174     },
3175 root 1.95 on_reply => sub {
3176     my ($ns, $msg) = @_;
3177    
3178     # this weird shuffling is so that direct followup queries
3179     # get handled first
3180 root 1.128 my $queue = delete $ns->{query_queue}
3181 root 1.129 or return; # be conservative, not sure how that can happen, but we saw a crash here
3182 root 1.95
3183     (shift @$queue)->[1]->($msg);
3184 root 1.202 return unless $ns->valid; # temporary(?) workaround for callback destroying socket
3185 root 1.95
3186     push @{ $ns->{query_queue} }, @$queue;
3187    
3188     if (@{ $ns->{query_queue} } == @$queue) {
3189     if (@$queue) {
3190     $ns->send_packet ($ns->{query_queue}[0][0]);
3191     } else {
3192 root 1.98 $ns->state (ST_PLAYING) if $ns->state == ST_CUSTOM;
3193 root 1.95 }
3194     }
3195     },
3196 root 1.287 on_exticmd => sub {
3197     my ($ns, $buf) = @_;
3198    
3199 root 1.290 my $msg = eval { $ns->{json_coder}->decode ($buf) };
3200 root 1.287
3201     if (ref $msg) {
3202 root 1.316 my ($type, $reply, @payload) =
3203     "ARRAY" eq ref $msg
3204     ? @$msg
3205     : ($msg->{msgtype}, $msg->{msgid}, %$msg); # TODO: version 1, remove
3206    
3207 root 1.338 my @reply;
3208    
3209 root 1.316 if (my $cb = $EXTICMD{$type}) {
3210 root 1.338 @reply = $cb->($ns, @payload);
3211     }
3212    
3213     $ns->ext_reply ($reply, @reply)
3214     if $reply;
3215 root 1.316
3216 root 1.287 } else {
3217 root 1.532 error "client " . ($ns->pl ? $ns->pl->ob->name : $ns->host) . " sent unparseable exti message: <$buf>\n";
3218 root 1.287 }
3219    
3220     cf::override;
3221     },
3222 root 1.95 );
3223    
3224 root 1.140 =item $client->async (\&cb)
3225 root 1.96
3226     Create a new coroutine, running the specified callback. The coroutine will
3227     be automatically cancelled when the client gets destroyed (e.g. on logout,
3228     or loss of connection).
3229    
3230     =cut
3231    
3232 root 1.140 sub cf::client::async {
3233 root 1.96 my ($self, $cb) = @_;
3234    
3235 root 1.140 my $coro = &Coro::async ($cb);
3236 root 1.103
3237     $coro->on_destroy (sub {
3238 root 1.96 delete $self->{_coro}{$coro+0};
3239 root 1.103 });
3240 root 1.96
3241     $self->{_coro}{$coro+0} = $coro;
3242 root 1.103
3243     $coro
3244 root 1.96 }
3245    
3246     cf::client->attach (
3247 root 1.509 on_client_destroy => sub {
3248 root 1.96 my ($ns) = @_;
3249    
3250 root 1.97 $_->cancel for values %{ (delete $ns->{_coro}) || {} };
3251 root 1.96 },
3252     );
3253    
3254 root 1.95 =back
3255    
3256 root 1.70
3257     =head2 SAFE SCRIPTING
3258    
3259     Functions that provide a safe environment to compile and execute
3260     snippets of perl code without them endangering the safety of the server
3261     itself. Looping constructs, I/O operators and other built-in functionality
3262     is not available in the safe scripting environment, and the number of
3263 root 1.79 functions and methods that can be called is greatly reduced.
3264 root 1.70
3265     =cut
3266 root 1.23
3267 root 1.42 our $safe = new Safe "safe";
3268 root 1.23 our $safe_hole = new Safe::Hole;
3269    
3270     $SIG{FPE} = 'IGNORE';
3271    
3272 root 1.328 $safe->permit_only (Opcode::opset qw(
3273 elmex 1.498 :base_core :base_mem :base_orig :base_math :base_loop
3274 root 1.328 grepstart grepwhile mapstart mapwhile
3275     sort time
3276     ));
3277 root 1.23
3278 root 1.25 # here we export the classes and methods available to script code
3279    
3280 root 1.70 =pod
3281    
3282 root 1.228 The following functions and methods are available within a safe environment:
3283 root 1.70
3284 root 1.297 cf::object
3285 root 1.383 contr pay_amount pay_player map x y force_find force_add destroy
3286 root 1.425 insert remove name archname title slaying race decrease split
3287 root 1.466 value
3288 root 1.297
3289     cf::object::player
3290     player
3291    
3292     cf::player
3293     peaceful
3294    
3295     cf::map
3296     trigger
3297 root 1.70
3298     =cut
3299    
3300 root 1.25 for (
3301 root 1.297 ["cf::object" => qw(contr pay_amount pay_player map force_find force_add x y
3302 elmex 1.431 insert remove inv nrof name archname title slaying race
3303 root 1.466 decrease split destroy change_exp value msg lore send_msg)],
3304 root 1.25 ["cf::object::player" => qw(player)],
3305 root 1.466 ["cf::player" => qw(peaceful send_msg)],
3306 elmex 1.91 ["cf::map" => qw(trigger)],
3307 root 1.25 ) {
3308     my ($pkg, @funs) = @$_;
3309 root 1.41 *{"safe::$pkg\::$_"} = $safe_hole->wrap (\&{"$pkg\::$_"})
3310 root 1.25 for @funs;
3311     }
3312 root 1.23
3313 root 1.70 =over 4
3314    
3315     =item @retval = safe_eval $code, [var => value, ...]
3316    
3317     Compiled and executes the given perl code snippet. additional var/value
3318     pairs result in temporary local (my) scalar variables of the given name
3319     that are available in the code snippet. Example:
3320    
3321     my $five = safe_eval '$first + $second', first => 1, second => 4;
3322    
3323     =cut
3324    
3325 root 1.23 sub safe_eval($;@) {
3326     my ($code, %vars) = @_;
3327    
3328     my $qcode = $code;
3329     $qcode =~ s/"/‟/g; # not allowed in #line filenames
3330     $qcode =~ s/\n/\\n/g;
3331    
3332 root 1.466 %vars = (_dummy => 0) unless %vars;
3333    
3334 root 1.499 my @res;
3335 root 1.23 local $_;
3336    
3337 root 1.42 my $eval =
3338 root 1.23 "do {\n"
3339     . "my (" . (join ",", map "\$$_", keys %vars) . ") = \@cf::_safe_eval_args;\n"
3340     . "#line 0 \"{$qcode}\"\n"
3341     . $code
3342     . "\n}"
3343 root 1.25 ;
3344    
3345 root 1.499 if ($CFG{safe_eval}) {
3346     sub_generation_inc;
3347     local @safe::cf::_safe_eval_args = values %vars;
3348     @res = wantarray ? $safe->reval ($eval) : scalar $safe->reval ($eval);
3349     sub_generation_inc;
3350     } else {
3351     local @cf::_safe_eval_args = values %vars;
3352     @res = wantarray ? eval eval : scalar eval $eval;
3353     }
3354 root 1.25
3355 root 1.42 if ($@) {
3356 root 1.532 warn "$@",
3357     "while executing safe code '$code'\n",
3358     "with arguments " . (join " ", %vars) . "\n";
3359 root 1.42 }
3360    
3361 root 1.25 wantarray ? @res : $res[0]
3362 root 1.23 }
3363    
3364 root 1.69 =item cf::register_script_function $function => $cb
3365    
3366     Register a function that can be called from within map/npc scripts. The
3367     function should be reasonably secure and should be put into a package name
3368     like the extension.
3369    
3370     Example: register a function that gets called whenever a map script calls
3371     C<rent::overview>, as used by the C<rent> extension.
3372    
3373     cf::register_script_function "rent::overview" => sub {
3374     ...
3375     };
3376    
3377     =cut
3378    
3379 root 1.23 sub register_script_function {
3380     my ($fun, $cb) = @_;
3381    
3382 root 1.501 $fun = "safe::$fun" if $CFG{safe_eval};
3383     *$fun = $safe_hole->wrap ($cb);
3384 root 1.23 }
3385    
3386 root 1.70 =back
3387    
3388 root 1.71 =cut
3389    
3390 root 1.23 #############################################################################
3391 root 1.203 # the server's init and main functions
3392    
3393 root 1.246 sub load_facedata($) {
3394     my ($path) = @_;
3395 root 1.223
3396 root 1.348 # HACK to clear player env face cache, we need some signal framework
3397     # for this (global event?)
3398     %ext::player_env::MUSIC_FACE_CACHE = ();
3399    
3400 root 1.344 my $enc = JSON::XS->new->utf8->canonical->relaxed;
3401 root 1.334
3402 root 1.532 trace "loading facedata from $path\n";
3403 root 1.223
3404 root 1.546 0 < aio_load $path, my $facedata
3405 root 1.223 or die "$path: $!";
3406    
3407 root 1.237 $facedata = Coro::Storable::thaw $facedata;
3408 root 1.223
3409 root 1.236 $facedata->{version} == 2
3410 root 1.226 or cf::cleanup "$path: version mismatch, cannot proceed.";
3411    
3412 root 1.334 # patch in the exptable
3413 root 1.500 my $exp_table = $enc->encode ([map cf::level_to_min_exp $_, 1 .. cf::settings->max_level]);
3414 root 1.334 $facedata->{resource}{"res/exp_table"} = {
3415     type => FT_RSRC,
3416 root 1.500 data => $exp_table,
3417     hash => (Digest::MD5::md5 $exp_table),
3418 root 1.334 };
3419     cf::cede_to_tick;
3420    
3421 root 1.236 {
3422     my $faces = $facedata->{faceinfo};
3423    
3424     while (my ($face, $info) = each %$faces) {
3425     my $idx = (cf::face::find $face) || cf::face::alloc $face;
3426 root 1.405
3427 root 1.302 cf::face::set_visibility $idx, $info->{visibility};
3428     cf::face::set_magicmap $idx, $info->{magicmap};
3429 root 1.496 cf::face::set_data $idx, 0, $info->{data32}, $info->{hash32};
3430     cf::face::set_data $idx, 1, $info->{data64}, $info->{hash64};
3431 root 1.302
3432     cf::cede_to_tick;
3433 root 1.236 }
3434    
3435     while (my ($face, $info) = each %$faces) {
3436     next unless $info->{smooth};
3437 root 1.405
3438 root 1.236 my $idx = cf::face::find $face
3439     or next;
3440 root 1.405
3441 root 1.236 if (my $smooth = cf::face::find $info->{smooth}) {
3442 root 1.302 cf::face::set_smooth $idx, $smooth;
3443     cf::face::set_smoothlevel $idx, $info->{smoothlevel};
3444 root 1.236 } else {
3445 root 1.532 error "smooth face '$info->{smooth}' not found for face '$face'";
3446 root 1.236 }
3447 root 1.302
3448     cf::cede_to_tick;
3449 root 1.236 }
3450 root 1.223 }
3451    
3452 root 1.236 {
3453     my $anims = $facedata->{animinfo};
3454    
3455     while (my ($anim, $info) = each %$anims) {
3456     cf::anim::set $anim, $info->{frames}, $info->{facings};
3457 root 1.302 cf::cede_to_tick;
3458 root 1.225 }
3459 root 1.236
3460     cf::anim::invalidate_all; # d'oh
3461 root 1.225 }
3462    
3463 root 1.302 {
3464     my $res = $facedata->{resource};
3465    
3466     while (my ($name, $info) = each %$res) {
3467 root 1.405 if (defined $info->{type}) {
3468     my $idx = (cf::face::find $name) || cf::face::alloc $name;
3469    
3470 root 1.496 cf::face::set_data $idx, 0, $info->{data}, $info->{hash};
3471 root 1.405 cf::face::set_type $idx, $info->{type};
3472 root 1.337 } else {
3473 root 1.530 $RESOURCE{$name} = $info; # unused
3474 root 1.307 }
3475 root 1.302
3476     cf::cede_to_tick;
3477     }
3478 root 1.406 }
3479    
3480     cf::global->invoke (EVENT_GLOBAL_RESOURCE_UPDATE);
3481 root 1.321
3482 root 1.406 1
3483     }
3484    
3485 root 1.318 register_exticmd fx_want => sub {
3486     my ($ns, $want) = @_;
3487    
3488     while (my ($k, $v) = each %$want) {
3489     $ns->fx_want ($k, $v);
3490     }
3491     };
3492    
3493 root 1.423 sub load_resource_file($) {
3494 root 1.424 my $guard = lock_acquire "load_resource_file";
3495    
3496 root 1.423 my $status = load_resource_file_ $_[0];
3497     get_slot 0.1, 100;
3498     cf::arch::commit_load;
3499 root 1.424
3500 root 1.423 $status
3501     }
3502    
3503 root 1.253 sub reload_regions {
3504 root 1.348 # HACK to clear player env face cache, we need some signal framework
3505     # for this (global event?)
3506     %ext::player_env::MUSIC_FACE_CACHE = ();
3507    
3508 root 1.253 load_resource_file "$MAPDIR/regions"
3509     or die "unable to load regions file\n";
3510 root 1.304
3511     for (cf::region::list) {
3512     $_->{match} = qr/$_->{match}/
3513     if exists $_->{match};
3514     }
3515 root 1.253 }
3516    
3517 root 1.246 sub reload_facedata {
3518 root 1.253 load_facedata "$DATADIR/facedata"
3519 root 1.246 or die "unable to load facedata\n";
3520     }
3521    
3522     sub reload_archetypes {
3523 root 1.253 load_resource_file "$DATADIR/archetypes"
3524 root 1.246 or die "unable to load archetypes\n";
3525 root 1.241 }
3526    
3527 root 1.246 sub reload_treasures {
3528 root 1.253 load_resource_file "$DATADIR/treasures"
3529 root 1.246 or die "unable to load treasurelists\n";
3530 root 1.241 }
3531    
3532 root 1.530 sub reload_sound {
3533 root 1.532 trace "loading sound config from $DATADIR/sound\n";
3534 root 1.531
3535 root 1.530 0 < Coro::AIO::aio_load "$DATADIR/sound", my $data
3536     or die "$DATADIR/sound $!";
3537    
3538     my $soundconf = JSON::XS->new->utf8->relaxed->decode ($data);
3539    
3540     for (0 .. SOUND_CAST_SPELL_0 - 1) {
3541     my $sound = $soundconf->{compat}[$_]
3542     or next;
3543    
3544     my $face = cf::face::find "sound/$sound->[1]";
3545     cf::sound::set $sound->[0] => $face;
3546     cf::sound::old_sound_index $_, $face; # gcfclient-compat
3547     }
3548    
3549     while (my ($k, $v) = each %{$soundconf->{event}}) {
3550     my $face = cf::face::find "sound/$v";
3551     cf::sound::set $k => $face;
3552     }
3553     }
3554    
3555 root 1.223 sub reload_resources {
3556 root 1.532 trace "reloading resource files...\n";
3557 root 1.245
3558 root 1.545 reload_exp_table;
3559     reload_materials;
3560 root 1.246 reload_facedata;
3561 root 1.530 reload_sound;
3562 root 1.246 reload_archetypes;
3563 root 1.423 reload_regions;
3564 root 1.246 reload_treasures;
3565 root 1.245
3566 root 1.532 trace "finished reloading resource files\n";
3567 root 1.223 }
3568    
3569 root 1.345 sub reload_config {
3570 root 1.532 trace "reloading config file...\n";
3571 root 1.485
3572 root 1.546 0 < aio_load "$CONFDIR/config", my $config
3573     or die "$CONFDIR/config: $!";
3574    
3575     utf8::decode $config;
3576 root 1.548 *CFG = yaml_load $config;
3577 root 1.131
3578 root 1.527 $EMERGENCY_POSITION = $CFG{emergency_position} || ["/world/world_104_115", 49, 38];
3579 root 1.131
3580 root 1.139 $cf::map::MAX_RESET = $CFG{map_max_reset} if exists $CFG{map_max_reset};
3581     $cf::map::DEFAULT_RESET = $CFG{map_default_reset} if exists $CFG{map_default_reset};
3582    
3583 root 1.131 if (exists $CFG{mlockall}) {
3584     eval {
3585 root 1.147 $CFG{mlockall} ? eval "mlockall()" : eval "munlockall()"
3586 root 1.131 and die "WARNING: m(un)lockall failed: $!\n";
3587     };
3588     warn $@ if $@;
3589     }
3590 root 1.72 }
3591    
3592 root 1.445 sub pidfile() {
3593     sysopen my $fh, $PIDFILE, O_RDWR | O_CREAT
3594     or die "$PIDFILE: $!";
3595     flock $fh, &Fcntl::LOCK_EX
3596     or die "$PIDFILE: flock: $!";
3597     $fh
3598     }
3599    
3600     # make sure only one server instance is running at any one time
3601     sub atomic {
3602     my $fh = pidfile;
3603    
3604     my $pid = <$fh>;
3605     kill 9, $pid if $pid > 0;
3606    
3607     seek $fh, 0, 0;
3608     print $fh $$;
3609     }
3610    
3611 root 1.474 sub main_loop {
3612 root 1.532 trace "EV::loop starting\n";
3613 root 1.474 if (1) {
3614     EV::loop;
3615     }
3616 root 1.532 trace "EV::loop returned\n";
3617 root 1.474 goto &main_loop unless $REALLY_UNLOOP;
3618     }
3619    
3620 root 1.39 sub main {
3621 root 1.453 cf::init_globals; # initialise logging
3622    
3623     LOG llevInfo, "Welcome to Deliantra, v" . VERSION;
3624 root 1.540 LOG llevInfo, "Copyright (C) 2005-2010 Marc Alexander Lehmann / Robin Redeker / the Deliantra team.";
3625 root 1.453 LOG llevInfo, "Copyright (C) 1994 Mark Wedel.";
3626     LOG llevInfo, "Copyright (C) 1992 Frank Tore Johansen.";
3627    
3628     $Coro::current->prio (Coro::PRIO_MAX); # give the main loop max. priority
3629 root 1.445
3630 root 1.108 # we must not ever block the main coroutine
3631     local $Coro::idle = sub {
3632 root 1.115 Carp::cluck "FATAL: Coro::idle was called, major BUG, use cf::sync_job!\n";#d#
3633 root 1.175 (async {
3634 root 1.374 $Coro::current->{desc} = "IDLE BUG HANDLER";
3635 root 1.396 EV::loop EV::LOOP_ONESHOT;
3636 root 1.175 })->prio (Coro::PRIO_MAX);
3637 root 1.108 };
3638    
3639 root 1.453 evthread_start IO::AIO::poll_fileno;
3640    
3641     cf::sync_job {
3642 root 1.543 cf::incloader::init ();
3643 root 1.540
3644 root 1.515 cf::init_anim;
3645     cf::init_attackmess;
3646     cf::init_dynamic;
3647    
3648 root 1.495 cf::load_settings;
3649    
3650 root 1.453 reload_resources;
3651 root 1.423 reload_config;
3652     db_init;
3653 root 1.453
3654     cf::init_uuid;
3655     cf::init_signals;
3656     cf::init_skills;
3657    
3658     cf::init_beforeplay;
3659    
3660     atomic;
3661    
3662 root 1.423 load_extensions;
3663    
3664 root 1.453 utime time, time, $RUNTIMEFILE;
3665 root 1.183
3666 root 1.453 # no (long-running) fork's whatsoever before this point(!)
3667 root 1.475 use POSIX ();
3668 root 1.453 POSIX::close delete $ENV{LOCKUTIL_LOCK_FD} if exists $ENV{LOCKUTIL_LOCK_FD};
3669 root 1.445
3670 root 1.550 cf::_post_init 0;
3671 root 1.453 };
3672 root 1.445
3673 root 1.516 cf::object::thawer::errors_are_fatal 0;
3674 root 1.532 info "parse errors in files are no longer fatal from this point on.\n";
3675 root 1.516
3676 root 1.540 my $free_main; $free_main = EV::idle sub {
3677     undef $free_main;
3678     undef &main; # free gobs of memory :)
3679     };
3680    
3681     goto &main_loop;
3682 root 1.34 }
3683    
3684     #############################################################################
3685 root 1.155 # initialisation and cleanup
3686    
3687     # install some emergency cleanup handlers
3688     BEGIN {
3689 root 1.396 our %SIGWATCHER = ();
3690 root 1.155 for my $signal (qw(INT HUP TERM)) {
3691 root 1.512 $SIGWATCHER{$signal} = AE::signal $signal, sub {
3692 root 1.396 cf::cleanup "SIG$signal";
3693     };
3694 root 1.155 }
3695     }
3696    
3697 root 1.417 sub write_runtime_sync {
3698 root 1.512 my $t0 = AE::time;
3699 root 1.506
3700 root 1.281 # first touch the runtime file to show we are still running:
3701     # the fsync below can take a very very long time.
3702    
3703 root 1.445 IO::AIO::aio_utime $RUNTIMEFILE, undef, undef;
3704 root 1.281
3705     my $guard = cf::lock_acquire "write_runtime";
3706    
3707 root 1.505 my $fh = aio_open "$RUNTIMEFILE~", O_WRONLY | O_CREAT | O_TRUNC, 0644
3708 root 1.281 or return;
3709    
3710     my $value = $cf::RUNTIME + 90 + 10;
3711     # 10 is the runtime save interval, for a monotonic clock
3712     # 60 allows for the watchdog to kill the server.
3713    
3714     (aio_write $fh, 0, (length $value), $value, 0) <= 0
3715     and return;
3716    
3717     # always fsync - this file is important
3718     aio_fsync $fh
3719     and return;
3720    
3721     # touch it again to show we are up-to-date
3722     aio_utime $fh, undef, undef;
3723    
3724     close $fh
3725     or return;
3726    
3727 root 1.445 aio_rename "$RUNTIMEFILE~", $RUNTIMEFILE
3728 root 1.281 and return;
3729    
3730 root 1.532 trace sprintf "runtime file written (%gs).\n", AE::time - $t0;
3731 root 1.281
3732     1
3733     }
3734    
3735 root 1.416 our $uuid_lock;
3736     our $uuid_skip;
3737    
3738     sub write_uuid_sync($) {
3739     $uuid_skip ||= $_[0];
3740    
3741     return if $uuid_lock;
3742     local $uuid_lock = 1;
3743    
3744     my $uuid = "$LOCALDIR/uuid";
3745    
3746     my $fh = aio_open "$uuid~", O_WRONLY | O_CREAT, 0644
3747     or return;
3748    
3749 root 1.454 my $value = uuid_seq uuid_cur;
3750    
3751 root 1.455 unless ($value) {
3752 root 1.532 info "cowardly refusing to write zero uuid value!\n";
3753 root 1.454 return;
3754     }
3755    
3756     my $value = uuid_str $value + $uuid_skip;
3757 root 1.416 $uuid_skip = 0;
3758    
3759     (aio_write $fh, 0, (length $value), $value, 0) <= 0
3760     and return;
3761    
3762     # always fsync - this file is important
3763     aio_fsync $fh
3764     and return;
3765    
3766     close $fh
3767     or return;
3768    
3769     aio_rename "$uuid~", $uuid
3770     and return;
3771    
3772 root 1.532 trace "uuid file written ($value).\n";
3773 root 1.416
3774     1
3775    
3776     }
3777    
3778     sub write_uuid($$) {
3779     my ($skip, $sync) = @_;
3780    
3781     $sync ? write_uuid_sync $skip
3782     : async { write_uuid_sync $skip };
3783     }
3784    
3785 root 1.156 sub emergency_save() {
3786 root 1.155 my $freeze_guard = cf::freeze_mainloop;
3787    
3788 root 1.532 info "emergency_perl_save: enter\n";
3789 root 1.155
3790 root 1.534 # this is a trade-off: we want to be very quick here, so
3791     # save all maps without fsync, and later call a global sync
3792     # (which in turn might be very very slow)
3793     local $USE_FSYNC = 0;
3794    
3795 root 1.155 cf::sync_job {
3796 root 1.535 cf::write_runtime_sync; # external watchdog should not bark
3797    
3798 root 1.155 # use a peculiar iteration method to avoid tripping on perl
3799     # refcount bugs in for. also avoids problems with players
3800 root 1.167 # and maps saved/destroyed asynchronously.
3801 root 1.532 info "emergency_perl_save: begin player save\n";
3802 root 1.155 for my $login (keys %cf::PLAYER) {
3803     my $pl = $cf::PLAYER{$login} or next;
3804     $pl->valid or next;
3805 root 1.382 delete $pl->{unclean_save}; # not strictly necessary, but cannot hurt
3806 root 1.155 $pl->save;
3807     }
3808 root 1.532 info "emergency_perl_save: end player save\n";
3809 root 1.155
3810 root 1.535 cf::write_runtime_sync; # external watchdog should not bark
3811    
3812 root 1.532 info "emergency_perl_save: begin map save\n";
3813 root 1.155 for my $path (keys %cf::MAP) {
3814     my $map = $cf::MAP{$path} or next;
3815     $map->valid or next;
3816     $map->save;
3817     }
3818 root 1.532 info "emergency_perl_save: end map save\n";
3819 root 1.208
3820 root 1.535 cf::write_runtime_sync; # external watchdog should not bark
3821    
3822 root 1.532 info "emergency_perl_save: begin database checkpoint\n";
3823 root 1.208 BDB::db_env_txn_checkpoint $DB_ENV;
3824 root 1.532 info "emergency_perl_save: end database checkpoint\n";
3825 root 1.416
3826 root 1.532 info "emergency_perl_save: begin write uuid\n";
3827 root 1.416 write_uuid_sync 1;
3828 root 1.532 info "emergency_perl_save: end write uuid\n";
3829 root 1.155
3830 root 1.535 cf::write_runtime_sync; # external watchdog should not bark
3831    
3832     trace "emergency_perl_save: syncing database to disk";
3833     BDB::db_env_txn_checkpoint $DB_ENV;
3834    
3835 root 1.536 info "emergency_perl_save: starting sync\n";
3836 root 1.535 IO::AIO::aio_sync sub {
3837 root 1.536 info "emergency_perl_save: finished sync\n";
3838 root 1.535 };
3839    
3840     cf::write_runtime_sync; # external watchdog should not bark
3841    
3842     trace "emergency_perl_save: flushing outstanding aio requests";
3843     while (IO::AIO::nreqs || BDB::nreqs) {
3844     Coro::EV::timer_once 0.01; # let the sync_job do it's thing
3845     }
3846    
3847     cf::write_runtime_sync; # external watchdog should not bark
3848 root 1.457 };
3849    
3850 root 1.532 info "emergency_perl_save: leave\n";
3851 root 1.155 }
3852 root 1.22
3853 root 1.211 sub post_cleanup {
3854     my ($make_core) = @_;
3855    
3856 root 1.535 IO::AIO::flush;
3857    
3858 root 1.532 error Carp::longmess "post_cleanup backtrace"
3859 root 1.211 if $make_core;
3860 root 1.445
3861     my $fh = pidfile;
3862     unlink $PIDFILE if <$fh> == $$;
3863 root 1.211 }
3864    
3865 root 1.441 # a safer delete_package, copied from Symbol
3866     sub clear_package($) {
3867     my $pkg = shift;
3868    
3869     # expand to full symbol table name if needed
3870     unless ($pkg =~ /^main::.*::$/) {
3871     $pkg = "main$pkg" if $pkg =~ /^::/;
3872     $pkg = "main::$pkg" unless $pkg =~ /^main::/;
3873     $pkg .= '::' unless $pkg =~ /::$/;
3874     }
3875    
3876     my($stem, $leaf) = $pkg =~ m/(.*::)(\w+::)$/;
3877     my $stem_symtab = *{$stem}{HASH};
3878    
3879     defined $stem_symtab and exists $stem_symtab->{$leaf}
3880     or return;
3881    
3882     # clear all symbols
3883     my $leaf_symtab = *{$stem_symtab->{$leaf}}{HASH};
3884     for my $name (keys %$leaf_symtab) {
3885     _gv_clear *{"$pkg$name"};
3886     # use PApp::Util; PApp::Util::sv_dump *{"$pkg$name"};
3887     }
3888     }
3889    
3890 root 1.246 sub do_reload_perl() {
3891 root 1.106 # can/must only be called in main
3892 root 1.543 unless (in_main) {
3893 root 1.532 error "can only reload from main coroutine";
3894 root 1.106 return;
3895     }
3896    
3897 root 1.441 return if $RELOAD++;
3898    
3899 root 1.512 my $t1 = AE::time;
3900 root 1.457
3901 root 1.441 while ($RELOAD) {
3902 root 1.543 cf::get_slot 0.1, -1, "reload_perl";
3903 root 1.550 info "perl_reload: reloading...";
3904 root 1.103
3905 root 1.550 trace "perl_reload: entering sync_job";
3906 root 1.212
3907 root 1.441 cf::sync_job {
3908 root 1.543 #cf::emergency_save;
3909 root 1.183
3910 root 1.550 trace "perl_reload: cancelling all extension coros";
3911 root 1.441 $_->cancel for values %EXT_CORO;
3912     %EXT_CORO = ();
3913 root 1.223
3914 root 1.550 trace "perl_reload: removing commands";
3915 root 1.441 %COMMAND = ();
3916 root 1.103
3917 root 1.550 trace "perl_reload: removing ext/exti commands";
3918 root 1.441 %EXTCMD = ();
3919     %EXTICMD = ();
3920 root 1.159
3921 root 1.550 trace "perl_reload: unloading/nuking all extensions";
3922 root 1.441 for my $pkg (@EXTS) {
3923 root 1.532 trace "... unloading $pkg";
3924 root 1.159
3925 root 1.441 if (my $cb = $pkg->can ("unload")) {
3926     eval {
3927     $cb->($pkg);
3928     1
3929 root 1.532 } or error "$pkg unloaded, but with errors: $@";
3930 root 1.441 }
3931 root 1.159
3932 root 1.532 trace "... clearing $pkg";
3933 root 1.441 clear_package $pkg;
3934 root 1.159 }
3935    
3936 root 1.550 trace "perl_reload: unloading all perl modules loaded from $LIBDIR";
3937 root 1.441 while (my ($k, $v) = each %INC) {
3938     next unless $v =~ /^\Q$LIBDIR\E\/.*\.pm$/;
3939 root 1.65
3940 root 1.532 trace "... unloading $k";
3941 root 1.441 delete $INC{$k};
3942 root 1.65
3943 root 1.441 $k =~ s/\.pm$//;
3944     $k =~ s/\//::/g;
3945 root 1.65
3946 root 1.441 if (my $cb = $k->can ("unload_module")) {
3947     $cb->();
3948     }
3949 root 1.65
3950 root 1.441 clear_package $k;
3951 root 1.65 }
3952    
3953 root 1.550 trace "perl_reload: getting rid of safe::, as good as possible";
3954 root 1.441 clear_package "safe::$_"
3955     for qw(cf::attachable cf::object cf::object::player cf::client cf::player cf::map cf::party cf::region);
3956 root 1.65
3957 root 1.550 trace "perl_reload: unloading cf.pm \"a bit\"";
3958 root 1.441 delete $INC{"cf.pm"};
3959 root 1.466 delete $INC{"cf/$_.pm"} for @EXTRA_MODULES;
3960 root 1.65
3961 root 1.441 # don't, removes xs symbols, too,
3962     # and global variables created in xs
3963     #clear_package __PACKAGE__;
3964 root 1.65
3965 root 1.550 info "perl_reload: unload completed, starting to reload now";
3966 root 1.65
3967 root 1.550 trace "perl_reload: reloading cf.pm";
3968 root 1.441 require cf;
3969 root 1.483 cf::_connect_to_perl_1;
3970 root 1.183
3971 root 1.550 trace "perl_reload: loading config and database again";
3972 root 1.441 cf::reload_config;
3973 root 1.100
3974 root 1.550 trace "perl_reload: loading extensions";
3975 root 1.441 cf::load_extensions;
3976 root 1.65
3977 root 1.457 if ($REATTACH_ON_RELOAD) {
3978 root 1.550 trace "perl_reload: reattaching attachments to objects/players";
3979 root 1.457 _global_reattach; # objects, sockets
3980 root 1.550 trace "perl_reload: reattaching attachments to maps";
3981 root 1.457 reattach $_ for values %MAP;
3982 root 1.550 trace "perl_reload: reattaching attachments to players";
3983 root 1.457 reattach $_ for values %PLAYER;
3984     }
3985 root 1.65
3986 root 1.550 cf::_post_init 1;
3987 root 1.453
3988 root 1.550 trace "perl_reload: leaving sync_job";
3989 root 1.183
3990 root 1.441 1
3991     } or do {
3992 root 1.532 error $@;
3993 root 1.550 cf::cleanup "perl_reload: error, exiting.";
3994 root 1.441 };
3995 root 1.183
3996 root 1.441 --$RELOAD;
3997     }
3998 root 1.457
3999 root 1.512 $t1 = AE::time - $t1;
4000 root 1.550 info "perl_reload: completed in ${t1}s\n";
4001 root 1.65 };
4002    
4003 root 1.175 our $RELOAD_WATCHER; # used only during reload
4004    
4005 root 1.246 sub reload_perl() {
4006     # doing reload synchronously and two reloads happen back-to-back,
4007     # coro crashes during coro_state_free->destroy here.
4008    
4009 root 1.457 $RELOAD_WATCHER ||= cf::async {
4010     Coro::AIO::aio_wait cache_extensions;
4011    
4012 root 1.512 $RELOAD_WATCHER = AE::timer $TICK * 1.5, 0, sub {
4013 root 1.457 do_reload_perl;
4014     undef $RELOAD_WATCHER;
4015     };
4016 root 1.396 };
4017 root 1.246 }
4018    
4019 root 1.111 register_command "reload" => sub {
4020 root 1.65 my ($who, $arg) = @_;
4021    
4022     if ($who->flag (FLAG_WIZ)) {
4023 root 1.175 $who->message ("reloading server.");
4024 root 1.374 async {
4025     $Coro::current->{desc} = "perl_reload";
4026     reload_perl;
4027     };
4028 root 1.65 }
4029     };
4030    
4031 root 1.540 #############################################################################
4032 root 1.17
4033 root 1.183 my $bug_warning = 0;
4034    
4035 root 1.239 our @WAIT_FOR_TICK;
4036     our @WAIT_FOR_TICK_BEGIN;
4037    
4038 root 1.546 sub wait_for_tick() {
4039 root 1.497 return Coro::cede if tick_inhibit || $Coro::current == $Coro::main;
4040 root 1.241
4041 root 1.239 my $signal = new Coro::Signal;
4042     push @WAIT_FOR_TICK, $signal;
4043     $signal->wait;
4044     }
4045    
4046 root 1.546 sub wait_for_tick_begin() {
4047 root 1.497 return Coro::cede if tick_inhibit || $Coro::current == $Coro::main;
4048 root 1.241
4049 root 1.239 my $signal = new Coro::Signal;
4050     push @WAIT_FOR_TICK_BEGIN, $signal;
4051     $signal->wait;
4052     }
4053    
4054 root 1.412 sub tick {
4055 root 1.396 if ($Coro::current != $Coro::main) {
4056     Carp::cluck "major BUG: server tick called outside of main coro, skipping it"
4057     unless ++$bug_warning > 10;
4058     return;
4059     }
4060    
4061     cf::server_tick; # one server iteration
4062 root 1.245
4063 root 1.512 #for(1..3e6){} AE::now_update; $NOW=AE::now; # generate load #d#
4064 root 1.502
4065 root 1.396 if ($NOW >= $NEXT_RUNTIME_WRITE) {
4066 root 1.402 $NEXT_RUNTIME_WRITE = List::Util::max $NEXT_RUNTIME_WRITE + 10, $NOW + 5.;
4067 root 1.396 Coro::async_pool {
4068     $Coro::current->{desc} = "runtime saver";
4069 root 1.417 write_runtime_sync
4070 root 1.532 or error "ERROR: unable to write runtime file: $!";
4071 root 1.396 };
4072     }
4073 root 1.265
4074 root 1.396 if (my $sig = shift @WAIT_FOR_TICK_BEGIN) {
4075     $sig->send;
4076     }
4077     while (my $sig = shift @WAIT_FOR_TICK) {
4078     $sig->send;
4079     }
4080 root 1.265
4081 root 1.412 $LOAD = ($NOW - $TICK_START) / $TICK;
4082 root 1.396 $LOADAVG = $LOADAVG * 0.75 + $LOAD * 0.25;
4083 root 1.265
4084 root 1.412 if (0) {
4085     if ($NEXT_TICK) {
4086     my $jitter = $TICK_START - $NEXT_TICK;
4087     $JITTER = $JITTER * 0.75 + $jitter * 0.25;
4088 root 1.532 debug "jitter $JITTER\n";#d#
4089 root 1.412 }
4090     }
4091     }
4092 root 1.35
4093 root 1.206 {
4094 root 1.401 # configure BDB
4095    
4096 root 1.503 BDB::min_parallel 16;
4097 root 1.400 BDB::max_poll_reqs $TICK * 0.1;
4098 root 1.433 $AnyEvent::BDB::WATCHER->priority (1);
4099 root 1.77
4100 root 1.206 unless ($DB_ENV) {
4101     $DB_ENV = BDB::db_env_create;
4102 root 1.437 $DB_ENV->set_flags (BDB::AUTO_COMMIT | BDB::REGION_INIT);
4103     $DB_ENV->set_flags (&BDB::LOG_AUTOREMOVE ) if BDB::VERSION v0, v4.7;
4104     $DB_ENV->log_set_config (&BDB::LOG_AUTO_REMOVE) if BDB::VERSION v4.7;
4105 root 1.371 $DB_ENV->set_timeout (30, BDB::SET_TXN_TIMEOUT);
4106     $DB_ENV->set_timeout (30, BDB::SET_LOCK_TIMEOUT);
4107 root 1.206
4108 root 1.534 cf::sync_job {
4109     eval {
4110     BDB::db_env_open
4111     $DB_ENV,
4112     $BDBDIR,
4113     BDB::INIT_LOCK | BDB::INIT_LOG | BDB::INIT_MPOOL | BDB::INIT_TXN
4114     | BDB::RECOVER | BDB::REGISTER | BDB::USE_ENVIRON | BDB::CREATE,
4115     0666;
4116 root 1.208
4117 root 1.534 cf::cleanup "db_env_open($BDBDIR): $!" if $!;
4118     };
4119 root 1.533
4120 root 1.534 cf::cleanup "db_env_open(db): $@" if $@;
4121     };
4122 root 1.206 }
4123 root 1.363
4124 root 1.396 $BDB_DEADLOCK_WATCHER = EV::periodic 0, 3, 0, sub {
4125     BDB::db_env_lock_detect $DB_ENV, 0, BDB::LOCK_DEFAULT, 0, sub { };
4126     };
4127     $BDB_CHECKPOINT_WATCHER = EV::periodic 0, 60, 0, sub {
4128     BDB::db_env_txn_checkpoint $DB_ENV, 0, 0, 0, sub { };
4129     };
4130     $BDB_TRICKLE_WATCHER = EV::periodic 0, 10, 0, sub {
4131     BDB::db_env_memp_trickle $DB_ENV, 20, 0, sub { };
4132     };
4133 root 1.206 }
4134    
4135     {
4136 root 1.401 # configure IO::AIO
4137    
4138 root 1.206 IO::AIO::min_parallel 8;
4139     IO::AIO::max_poll_time $TICK * 0.1;
4140 root 1.435 undef $AnyEvent::AIO::WATCHER;
4141 root 1.206 }
4142 root 1.108
4143 root 1.552 our $_log_backtrace;
4144     our $_log_backtrace_last;
4145 root 1.262
4146 root 1.260 sub _log_backtrace {
4147     my ($msg, @addr) = @_;
4148    
4149 root 1.552 $msg =~ s/\n$//;
4150 root 1.260
4151 root 1.552 if ($_log_backtrace_last eq $msg) {
4152     LOG llevInfo, "[ABT] $msg\n";
4153     LOG llevInfo, "[ABT] [duplicate, suppressed]\n";
4154 root 1.262 # limit the # of concurrent backtraces
4155 root 1.552 } elsif ($_log_backtrace < 2) {
4156     $_log_backtrace_last = $msg;
4157 root 1.262 ++$_log_backtrace;
4158 root 1.446 my $perl_bt = Carp::longmess $msg;
4159 root 1.262 async {
4160 root 1.374 $Coro::current->{desc} = "abt $msg";
4161    
4162 root 1.262 my @bt = fork_call {
4163     @addr = map { sprintf "%x", $_ } @addr;
4164     my $self = (-f "/proc/$$/exe") ? "/proc/$$/exe" : $^X;
4165     open my $fh, "exec addr2line -C -f -i -e \Q$self\E @addr 2>&1 |"
4166     or die "addr2line: $!";
4167    
4168     my @funcs;
4169     my @res = <$fh>;
4170     chomp for @res;
4171     while (@res) {
4172     my ($func, $line) = splice @res, 0, 2, ();
4173     push @funcs, "[$func] $line";
4174     }
4175 root 1.260
4176 root 1.262 @funcs
4177     };
4178 root 1.260
4179 root 1.446 LOG llevInfo, "[ABT] $perl_bt\n";
4180     LOG llevInfo, "[ABT] --- C backtrace follows ---\n";
4181 root 1.262 LOG llevInfo, "[ABT] $_\n" for @bt;
4182     --$_log_backtrace;
4183     };
4184     } else {
4185 root 1.260 LOG llevInfo, "[ABT] $msg\n";
4186 root 1.552 LOG llevInfo, "[ABT] [overload, suppressed]\n";
4187 root 1.262 }
4188 root 1.260 }
4189    
4190 root 1.249 # load additional modules
4191 root 1.467 require "cf/$_.pm" for @EXTRA_MODULES;
4192 root 1.483 cf::_connect_to_perl_2;
4193 root 1.249
4194 root 1.125 END { cf::emergency_save }
4195    
4196 root 1.1 1
4197