ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/lib/cf.pm
Revision: 1.278
Committed: Mon Jun 11 21:38:14 2007 UTC (16 years, 11 months ago) by root
Branch: MAIN
Changes since 1.277: +63 -35 lines
Log Message:
port micropather to c++...

File Contents

# User Rev Content
1 root 1.1 package cf;
2    
3 root 1.96 use utf8;
4     use strict;
5    
6 root 1.1 use Symbol;
7     use List::Util;
8 root 1.250 use Socket;
9 root 1.6 use Storable;
10 root 1.224 use Event;
11 root 1.23 use Opcode;
12     use Safe;
13     use Safe::Hole;
14 root 1.19
15 root 1.244 use Coro 3.61 ();
16 root 1.224 use Coro::State;
17 root 1.250 use Coro::Handle;
18 root 1.96 use Coro::Event;
19     use Coro::Timer;
20     use Coro::Signal;
21     use Coro::Semaphore;
22 root 1.105 use Coro::AIO;
23 root 1.237 use Coro::Storable;
24 root 1.96
25 root 1.206 use BDB ();
26 root 1.154 use Data::Dumper;
27 root 1.108 use Digest::MD5;
28 root 1.105 use Fcntl;
29 root 1.227 use YAML::Syck ();
30 root 1.145 use IO::AIO 2.32 ();
31 root 1.32 use Time::HiRes;
32 root 1.208 use Compress::LZF;
33    
34 root 1.227 # configure various modules to our taste
35     #
36 root 1.237 $Storable::canonical = 1; # reduce rsync transfers
37 root 1.224 Coro::State::cctx_stacksize 256000; # 1-2MB stack, for deep recursions in maze generator
38 root 1.208 Compress::LZF::sfreeze_cr { }; # prime Compress::LZF so it does not use require later
39 root 1.227
40 root 1.224 $Event::Eval = 1; # no idea why this is required, but it is
41 root 1.1
42 root 1.72 # work around bug in YAML::Syck - bad news for perl6, will it be as broken wrt. unicode?
43     $YAML::Syck::ImplicitUnicode = 1;
44    
45 root 1.139 $Coro::main->prio (Coro::PRIO_MAX); # run main coroutine ("the server") with very high priority
46 root 1.1
47 root 1.227 sub WF_AUTOCANCEL () { 1 } # automatically cancel this watcher on reload
48    
49 root 1.85 our %COMMAND = ();
50     our %COMMAND_TIME = ();
51 root 1.159
52     our @EXTS = (); # list of extension package names
53 root 1.85 our %EXTCMD = ();
54 root 1.159 our %EXT_CORO = (); # coroutines bound to extensions
55 root 1.161 our %EXT_MAP = (); # pluggable maps
56 root 1.85
57 root 1.223 our $RELOAD; # number of reloads so far
58 root 1.1 our @EVENT;
59 root 1.253
60     our $CONFDIR = confdir;
61     our $DATADIR = datadir;
62     our $LIBDIR = "$DATADIR/ext";
63     our $PODDIR = "$DATADIR/pod";
64     our $MAPDIR = "$DATADIR/" . mapdir;
65     our $LOCALDIR = localdir;
66     our $TMPDIR = "$LOCALDIR/" . tmpdir;
67     our $UNIQUEDIR = "$LOCALDIR/" . uniquedir;
68     our $PLAYERDIR = "$LOCALDIR/" . playerdir;
69     our $RANDOMDIR = "$LOCALDIR/random";
70     our $BDBDIR = "$LOCALDIR/db";
71 root 1.1
72 root 1.245 our $TICK = MAX_TIME * 1e-6; # this is a CONSTANT(!)
73 root 1.35 our $TICK_WATCHER;
74 root 1.168 our $AIO_POLL_WATCHER;
75 root 1.214 our $NEXT_RUNTIME_WRITE; # when should the runtime file be written
76 root 1.35 our $NEXT_TICK;
77 root 1.103 our $NOW;
78 root 1.205 our $USE_FSYNC = 1; # use fsync to write maps - default off
79 root 1.35
80 root 1.206 our $BDB_POLL_WATCHER;
81     our $DB_ENV;
82    
83 root 1.70 our %CFG;
84    
85 root 1.84 our $UPTIME; $UPTIME ||= time;
86 root 1.103 our $RUNTIME;
87    
88 root 1.143 our %PLAYER; # all users
89     our %MAP; # all maps
90 root 1.166 our $LINK_MAP; # the special {link} map, which is always available
91 root 1.103
92 root 1.166 # used to convert map paths into valid unix filenames by replacing / by ∕
93     our $PATH_SEP = "∕"; # U+2215, chosen purely for visual reasons
94    
95 root 1.265 our $LOAD; # a number between 0 (idle) and 1 (too many objects)
96     our $LOADAVG; # same thing, but with alpha-smoothing
97     our $tick_start; # for load detecting purposes
98    
99 root 1.103 binmode STDOUT;
100     binmode STDERR;
101    
102     # read virtual server time, if available
103 root 1.253 unless ($RUNTIME || !-e "$LOCALDIR/runtime") {
104     open my $fh, "<", "$LOCALDIR/runtime"
105 root 1.103 or die "unable to read runtime file: $!";
106     $RUNTIME = <$fh> + 0.;
107     }
108    
109 root 1.253 mkdir $_
110     for $LOCALDIR, $TMPDIR, $UNIQUEDIR, $PLAYERDIR, $RANDOMDIR, $BDBDIR;
111 root 1.103
112 root 1.131 our $EMERGENCY_POSITION;
113 root 1.110
114 root 1.199 sub cf::map::normalise;
115    
116 root 1.70 #############################################################################
117    
118     =head2 GLOBAL VARIABLES
119    
120     =over 4
121    
122 root 1.83 =item $cf::UPTIME
123    
124     The timestamp of the server start (so not actually an uptime).
125    
126 root 1.103 =item $cf::RUNTIME
127    
128     The time this server has run, starts at 0 and is increased by $cf::TICK on
129     every server tick.
130    
131 root 1.253 =item $cf::CONFDIR $cf::DATADIR $cf::LIBDIR $cf::PODDIR
132     $cf::MAPDIR $cf::LOCALDIR $cf::TMPDIR $cf::UNIQUEDIR
133     $cf::PLAYERDIR $cf::RANDOMDIR $cf::BDBDIR
134    
135     Various directories - "/etc", read-only install directory, perl-library
136     directory, pod-directory, read-only maps directory, "/var", "/var/tmp",
137     unique-items directory, player file directory, random maps directory and
138     database environment.
139 root 1.70
140 root 1.103 =item $cf::NOW
141    
142     The time of the last (current) server tick.
143    
144 root 1.70 =item $cf::TICK
145    
146     The interval between server ticks, in seconds.
147    
148 root 1.265 =item $cf::LOADAVG
149    
150     The current CPU load on the server (alpha-smoothed), as a value between 0
151     (none) and 1 (overloaded), indicating how much time is spent on processing
152     objects per tick. Healthy values are < 0.5.
153    
154     =item $cf::LOAD
155    
156     The raw value load value from the last tick.
157    
158 root 1.70 =item %cf::CFG
159    
160     Configuration for the server, loaded from C</etc/crossfire/config>, or
161     from wherever your confdir points to.
162    
163 root 1.239 =item cf::wait_for_tick, cf::wait_for_tick_begin
164 root 1.155
165 root 1.239 These are functions that inhibit the current coroutine one tick. cf::wait_for_tick_begin only
166     returns directly I<after> the tick processing (and consequently, can only wake one process
167     per tick), while cf::wait_for_tick wakes up all waiters after tick processing.
168 root 1.155
169 root 1.70 =back
170    
171     =cut
172    
173 root 1.1 BEGIN {
174     *CORE::GLOBAL::warn = sub {
175     my $msg = join "", @_;
176 root 1.103
177 root 1.1 $msg .= "\n"
178     unless $msg =~ /\n$/;
179    
180 root 1.255 $msg =~ s/([\x00-\x08\x0b-\x1f])/sprintf "\\x%02x", ord $1/ge;
181 root 1.250
182     utf8::encode $msg;
183 root 1.146 LOG llevError, $msg;
184 root 1.1 };
185     }
186    
187 root 1.93 @safe::cf::global::ISA = @cf::global::ISA = 'cf::attachable';
188     @safe::cf::object::ISA = @cf::object::ISA = 'cf::attachable';
189     @safe::cf::player::ISA = @cf::player::ISA = 'cf::attachable';
190     @safe::cf::client::ISA = @cf::client::ISA = 'cf::attachable';
191     @safe::cf::map::ISA = @cf::map::ISA = 'cf::attachable';
192 root 1.273 @safe::cf::arch::ISA = @cf::arch::ISA = 'cf::object';
193     @safe::cf::object::player::ISA = @cf::object::player::ISA = 'cf::object'; # not really true (yet)
194 root 1.25
195 root 1.41 # we bless all objects into (empty) derived classes to force a method lookup
196 root 1.25 # within the Safe compartment.
197 root 1.86 for my $pkg (qw(
198 root 1.100 cf::global cf::attachable
199 root 1.86 cf::object cf::object::player
200 root 1.89 cf::client cf::player
201 root 1.86 cf::arch cf::living
202     cf::map cf::party cf::region
203     )) {
204 root 1.25 no strict 'refs';
205 root 1.41 @{"safe::$pkg\::wrap::ISA"} = @{"$pkg\::wrap::ISA"} = $pkg;
206 root 1.25 }
207 root 1.1
208 root 1.18 $Event::DIED = sub {
209     warn "error in event callback: @_";
210     };
211    
212 root 1.70 =head2 UTILITY FUNCTIONS
213    
214     =over 4
215    
216 root 1.154 =item dumpval $ref
217    
218 root 1.70 =cut
219 root 1.44
220 root 1.154 sub dumpval {
221     eval {
222     local $SIG{__DIE__};
223     my $d;
224     if (1) {
225     $d = new Data::Dumper([$_[0]], ["*var"]);
226     $d->Terse(1);
227     $d->Indent(2);
228     $d->Quotekeys(0);
229     $d->Useqq(1);
230     #$d->Bless(...);
231     $d->Seen($_[1]) if @_ > 1;
232     $d = $d->Dump();
233     }
234     $d =~ s/([\x00-\x07\x09\x0b\x0c\x0e-\x1f])/sprintf "\\x%02x", ord($1)/ge;
235     $d
236     } || "[unable to dump $_[0]: '$@']";
237     }
238    
239 root 1.227 use JSON::XS qw(to_json from_json); # TODO# replace by JSON::PC once working
240 root 1.44
241 root 1.70 =item $ref = cf::from_json $json
242    
243     Converts a JSON string into the corresponding perl data structure.
244    
245     =item $json = cf::to_json $ref
246    
247     Converts a perl data structure into its JSON representation.
248    
249 root 1.120 =item cf::lock_wait $string
250    
251     Wait until the given lock is available. See cf::lock_acquire.
252    
253     =item my $lock = cf::lock_acquire $string
254    
255     Wait until the given lock is available and then acquires it and returns
256 root 1.135 a Coro::guard object. If the guard object gets destroyed (goes out of scope,
257 root 1.120 for example when the coroutine gets canceled), the lock is automatically
258     returned.
259    
260 root 1.133 Lock names should begin with a unique identifier (for example, cf::map::find
261     uses map_find and cf::map::load uses map_load).
262 root 1.120
263 root 1.253 =item $locked = cf::lock_active $string
264    
265     Return true if the lock is currently active, i.e. somebody has locked it.
266    
267 root 1.120 =cut
268    
269     our %LOCK;
270    
271     sub lock_wait($) {
272     my ($key) = @_;
273    
274     # wait for lock, if any
275     while ($LOCK{$key}) {
276     push @{ $LOCK{$key} }, $Coro::current;
277     Coro::schedule;
278     }
279     }
280    
281     sub lock_acquire($) {
282     my ($key) = @_;
283    
284     # wait, to be sure we are not locked
285     lock_wait $key;
286    
287     $LOCK{$key} = [];
288    
289 root 1.135 Coro::guard {
290 root 1.120 # wake up all waiters, to be on the safe side
291     $_->ready for @{ delete $LOCK{$key} };
292     }
293     }
294    
295 root 1.253 sub lock_active($) {
296     my ($key) = @_;
297    
298     ! ! $LOCK{$key}
299     }
300    
301 root 1.133 sub freeze_mainloop {
302     return unless $TICK_WATCHER->is_active;
303    
304 root 1.168 my $guard = Coro::guard {
305     $TICK_WATCHER->start;
306     };
307 root 1.133 $TICK_WATCHER->stop;
308     $guard
309     }
310    
311 root 1.140 =item cf::async { BLOCK }
312    
313     Currently the same as Coro::async_pool, meaning you cannot use
314     C<on_destroy>, C<join> or other gimmicks on these coroutines. The only
315     thing you are allowed to do is call C<prio> on it.
316    
317     =cut
318    
319     BEGIN { *async = \&Coro::async_pool }
320    
321 root 1.106 =item cf::sync_job { BLOCK }
322    
323     The design of crossfire+ requires that the main coro ($Coro::main) is
324     always able to handle events or runnable, as crossfire+ is only partly
325     reentrant. Thus "blocking" it by e.g. waiting for I/O is not acceptable.
326    
327     If it must be done, put the blocking parts into C<sync_job>. This will run
328     the given BLOCK in another coroutine while waiting for the result. The
329     server will be frozen during this time, so the block should either finish
330     fast or be very important.
331    
332     =cut
333    
334 root 1.105 sub sync_job(&) {
335     my ($job) = @_;
336    
337     if ($Coro::current == $Coro::main) {
338 root 1.265 my $time = Event::time;
339    
340 root 1.112 # this is the main coro, too bad, we have to block
341     # till the operation succeeds, freezing the server :/
342    
343 root 1.110 # TODO: use suspend/resume instead
344 root 1.112 # (but this is cancel-safe)
345 root 1.133 my $freeze_guard = freeze_mainloop;
346 root 1.112
347     my $busy = 1;
348     my @res;
349    
350 root 1.140 (async {
351 root 1.112 @res = eval { $job->() };
352     warn $@ if $@;
353     undef $busy;
354     })->prio (Coro::PRIO_MAX);
355    
356 root 1.105 while ($busy) {
357 root 1.141 Coro::cede or Event::one_event;
358 root 1.105 }
359 root 1.112
360 root 1.265 $time = Event::time - $time;
361    
362 root 1.266 LOG llevError | logBacktrace, Carp::longmess "long sync job"
363     if $time > $TICK * 0.5 && $TICK_WATCHER->is_active;
364 root 1.265
365     $tick_start += $time; # do not account sync jobs to server load
366    
367 root 1.112 wantarray ? @res : $res[0]
368 root 1.105 } else {
369 root 1.112 # we are in another coroutine, how wonderful, everything just works
370    
371     $job->()
372 root 1.105 }
373     }
374    
375 root 1.140 =item $coro = cf::async_ext { BLOCK }
376 root 1.103
377 root 1.159 Like async, but this coro is automatically being canceled when the
378 root 1.140 extension calling this is being unloaded.
379 root 1.103
380     =cut
381    
382 root 1.140 sub async_ext(&) {
383 root 1.103 my $cb = shift;
384    
385 root 1.140 my $coro = &Coro::async ($cb);
386 root 1.103
387     $coro->on_destroy (sub {
388     delete $EXT_CORO{$coro+0};
389     });
390     $EXT_CORO{$coro+0} = $coro;
391    
392     $coro
393     }
394    
395 root 1.108 sub write_runtime {
396 root 1.264 my $runtime = "$LOCALDIR/runtime";
397    
398     # first touch the runtime file to show we are still running:
399     # the fsync below can take a very very long time.
400    
401 root 1.271 IO::AIO::aio_utime $runtime, undef, undef;
402 root 1.264
403 root 1.219 my $guard = cf::lock_acquire "write_runtime";
404    
405 root 1.108 my $fh = aio_open "$runtime~", O_WRONLY | O_CREAT, 0644
406     or return;
407    
408 root 1.186 my $value = $cf::RUNTIME + 90 + 10;
409     # 10 is the runtime save interval, for a monotonic clock
410     # 60 allows for the watchdog to kill the server.
411    
412 root 1.108 (aio_write $fh, 0, (length $value), $value, 0) <= 0
413     and return;
414    
415 root 1.204 # always fsync - this file is important
416 root 1.108 aio_fsync $fh
417     and return;
418    
419 root 1.264 # touch it again to show we are up-to-date
420 root 1.271 aio_utime $fh, undef, undef;
421 root 1.264
422 root 1.108 close $fh
423     or return;
424    
425     aio_rename "$runtime~", $runtime
426     and return;
427    
428 root 1.274 warn "runtime file written.\n";
429 root 1.263
430 root 1.108 1
431     }
432    
433 root 1.230 =item cf::datalog type => key => value, ...
434    
435     Log a datalog packet of the given type with the given key-value pairs.
436    
437     =cut
438    
439     sub datalog($@) {
440     my ($type, %kv) = @_;
441     warn "DATALOG ", JSON::XS->new->ascii->encode ({ %kv, type => $type });
442     }
443    
444 root 1.70 =back
445    
446 root 1.71 =cut
447    
448 root 1.44 #############################################################################
449 root 1.39
450 root 1.93 =head2 ATTACHABLE OBJECTS
451    
452 root 1.94 Many objects in crossfire are so-called attachable objects. That means you can
453     attach callbacks/event handlers (a collection of which is called an "attachment")
454     to it. All such attachable objects support the following methods.
455    
456     In the following description, CLASS can be any of C<global>, C<object>
457     C<player>, C<client> or C<map> (i.e. the attachable objects in
458     crossfire+).
459 root 1.55
460     =over 4
461    
462 root 1.94 =item $attachable->attach ($attachment, key => $value...)
463    
464     =item $attachable->detach ($attachment)
465    
466     Attach/detach a pre-registered attachment to a specific object and give it
467     the specified key/value pairs as arguments.
468    
469     Example, attach a minesweeper attachment to the given object, making it a
470     10x10 minesweeper game:
471 root 1.46
472 root 1.94 $obj->attach (minesweeper => width => 10, height => 10);
473 root 1.53
474 root 1.93 =item $bool = $attachable->attached ($name)
475 root 1.46
476 root 1.93 Checks wether the named attachment is currently attached to the object.
477 root 1.46
478 root 1.94 =item cf::CLASS->attach ...
479 root 1.46
480 root 1.94 =item cf::CLASS->detach ...
481 root 1.92
482 root 1.94 Define an anonymous attachment and attach it to all objects of the given
483     CLASS. See the next function for an explanation of its arguments.
484 root 1.92
485 root 1.93 You can attach to global events by using the C<cf::global> class.
486 root 1.92
487 root 1.94 Example, log all player logins:
488    
489     cf::player->attach (
490     on_login => sub {
491     my ($pl) = @_;
492     ...
493     },
494     );
495    
496     Example, attach to the jeweler skill:
497    
498     cf::object->attach (
499     type => cf::SKILL,
500     subtype => cf::SK_JEWELER,
501     on_use_skill => sub {
502     my ($sk, $ob, $part, $dir, $msg) = @_;
503     ...
504     },
505     );
506    
507     =item cf::CLASS::attachment $name, ...
508    
509     Register an attachment by C<$name> through which attachable objects of the
510     given CLASS can refer to this attachment.
511    
512     Some classes such as crossfire maps and objects can specify attachments
513     that are attached at load/instantiate time, thus the need for a name.
514    
515     These calls expect any number of the following handler/hook descriptions:
516 root 1.46
517     =over 4
518    
519     =item prio => $number
520    
521     Set the priority for all following handlers/hooks (unless overwritten
522     by another C<prio> setting). Lower priority handlers get executed
523     earlier. The default priority is C<0>, and many built-in handlers are
524     registered at priority C<-1000>, so lower priorities should not be used
525     unless you know what you are doing.
526    
527 root 1.93 =item type => $type
528    
529     (Only for C<< cf::object->attach >> calls), limits the attachment to the
530     given type of objects only (the additional parameter C<subtype> can be
531     used to further limit to the given subtype).
532    
533 root 1.46 =item on_I<event> => \&cb
534    
535     Call the given code reference whenever the named event happens (event is
536     something like C<instantiate>, C<apply>, C<use_skill> and so on, and which
537     handlers are recognised generally depends on the type of object these
538     handlers attach to).
539    
540     See F<include/eventinc.h> for the full list of events supported, and their
541     class.
542    
543     =item package => package::
544    
545     Look for sub functions of the name C<< on_I<event> >> in the given
546     package and register them. Only handlers for eevents supported by the
547     object/class are recognised.
548    
549     =back
550    
551 root 1.94 Example, define an attachment called "sockpuppet" that calls the given
552     event handler when a monster attacks:
553    
554     cf::object::attachment sockpuppet =>
555     on_skill_attack => sub {
556     my ($self, $victim) = @_;
557     ...
558     }
559     }
560    
561 root 1.96 =item $attachable->valid
562    
563     Just because you have a perl object does not mean that the corresponding
564     C-level object still exists. If you try to access an object that has no
565     valid C counterpart anymore you get an exception at runtime. This method
566     can be used to test for existence of the C object part without causing an
567     exception.
568    
569 root 1.39 =cut
570    
571 root 1.40 # the following variables are defined in .xs and must not be re-created
572 root 1.100 our @CB_GLOBAL = (); # registry for all global events
573     our @CB_ATTACHABLE = (); # registry for all attachables
574     our @CB_OBJECT = (); # all objects (should not be used except in emergency)
575     our @CB_PLAYER = ();
576     our @CB_CLIENT = ();
577     our @CB_TYPE = (); # registry for type (cf-object class) based events
578     our @CB_MAP = ();
579 root 1.39
580 root 1.45 my %attachment;
581    
582 root 1.170 sub cf::attachable::thawer_merge {
583     # simply override everything except _meta
584     local $_[0]{_meta};
585     %{$_[0]} = %{$_[1]};
586     }
587    
588 root 1.93 sub _attach_cb($$$$) {
589     my ($registry, $event, $prio, $cb) = @_;
590 root 1.39
591     use sort 'stable';
592    
593     $cb = [$prio, $cb];
594    
595     @{$registry->[$event]} = sort
596     { $a->[0] cmp $b->[0] }
597     @{$registry->[$event] || []}, $cb;
598     }
599    
600 root 1.100 # hack
601     my %attachable_klass = map +($_ => 1), KLASS_OBJECT, KLASS_CLIENT, KLASS_PLAYER, KLASS_MAP;
602    
603 root 1.39 # attach handles attaching event callbacks
604     # the only thing the caller has to do is pass the correct
605     # registry (== where the callback attaches to).
606 root 1.93 sub _attach {
607 root 1.45 my ($registry, $klass, @arg) = @_;
608 root 1.39
609 root 1.93 my $object_type;
610 root 1.39 my $prio = 0;
611     my %cb_id = map +("on_" . lc $EVENT[$_][0], $_) , grep $EVENT[$_][1] == $klass, 0 .. $#EVENT;
612    
613 root 1.100 #TODO: get rid of this hack
614     if ($attachable_klass{$klass}) {
615     %cb_id = (%cb_id, map +("on_" . lc $EVENT[$_][0], $_) , grep $EVENT[$_][1] == KLASS_ATTACHABLE, 0 .. $#EVENT);
616     }
617    
618 root 1.45 while (@arg) {
619     my $type = shift @arg;
620 root 1.39
621     if ($type eq "prio") {
622 root 1.45 $prio = shift @arg;
623 root 1.39
624 root 1.93 } elsif ($type eq "type") {
625     $object_type = shift @arg;
626     $registry = $CB_TYPE[$object_type] ||= [];
627    
628     } elsif ($type eq "subtype") {
629     defined $object_type or Carp::croak "subtype specified without type";
630     my $object_subtype = shift @arg;
631 root 1.267 $registry = $CB_TYPE[$object_type + $object_subtype * NUM_TYPES] ||= [];
632 root 1.93
633 root 1.39 } elsif ($type eq "package") {
634 root 1.45 my $pkg = shift @arg;
635 root 1.39
636     while (my ($name, $id) = each %cb_id) {
637     if (my $cb = $pkg->can ($name)) {
638 root 1.93 _attach_cb $registry, $id, $prio, $cb;
639 root 1.39 }
640     }
641    
642     } elsif (exists $cb_id{$type}) {
643 root 1.93 _attach_cb $registry, $cb_id{$type}, $prio, shift @arg;
644 root 1.39
645     } elsif (ref $type) {
646     warn "attaching objects not supported, ignoring.\n";
647    
648     } else {
649 root 1.45 shift @arg;
650 root 1.39 warn "attach argument '$type' not supported, ignoring.\n";
651     }
652     }
653     }
654    
655 root 1.93 sub _object_attach {
656 root 1.48 my ($obj, $name, %arg) = @_;
657 root 1.46
658 root 1.55 return if exists $obj->{_attachment}{$name};
659    
660 root 1.46 if (my $attach = $attachment{$name}) {
661     my $registry = $obj->registry;
662    
663 root 1.47 for (@$attach) {
664     my ($klass, @attach) = @$_;
665 root 1.93 _attach $registry, $klass, @attach;
666 root 1.47 }
667 root 1.46
668 root 1.48 $obj->{$name} = \%arg;
669 root 1.46 } else {
670     warn "object uses attachment '$name' that is not available, postponing.\n";
671     }
672    
673 root 1.50 $obj->{_attachment}{$name} = undef;
674 root 1.46 }
675    
676 root 1.93 sub cf::attachable::attach {
677     if (ref $_[0]) {
678     _object_attach @_;
679     } else {
680     _attach shift->_attach_registry, @_;
681     }
682 root 1.267 _recalc_want;
683 root 1.55 };
684 root 1.46
685 root 1.54 # all those should be optimised
686 root 1.93 sub cf::attachable::detach {
687 root 1.54 my ($obj, $name) = @_;
688 root 1.46
689 root 1.93 if (ref $obj) {
690     delete $obj->{_attachment}{$name};
691     reattach ($obj);
692     } else {
693     Carp::croak "cannot, currently, detach class attachments";
694     }
695 root 1.267 _recalc_want;
696 root 1.55 };
697    
698 root 1.93 sub cf::attachable::attached {
699 root 1.55 my ($obj, $name) = @_;
700    
701     exists $obj->{_attachment}{$name}
702 root 1.39 }
703    
704 root 1.100 for my $klass (qw(ATTACHABLE GLOBAL OBJECT PLAYER CLIENT MAP)) {
705 root 1.93 eval "#line " . __LINE__ . " 'cf.pm'
706     sub cf::\L$klass\E::_attach_registry {
707     (\\\@CB_$klass, KLASS_$klass)
708     }
709 root 1.45
710 root 1.93 sub cf::\L$klass\E::attachment {
711     my \$name = shift;
712 root 1.39
713 root 1.93 \$attachment{\$name} = [[KLASS_$klass, \@_]];
714     }
715     ";
716     die if $@;
717 root 1.52 }
718    
719 root 1.39 our $override;
720 root 1.45 our @invoke_results = (); # referenced from .xs code. TODO: play tricks with reify and mortals?
721 root 1.39
722 root 1.45 sub override {
723     $override = 1;
724     @invoke_results = ();
725 root 1.39 }
726    
727 root 1.45 sub do_invoke {
728 root 1.39 my $event = shift;
729 root 1.40 my $callbacks = shift;
730 root 1.39
731 root 1.45 @invoke_results = ();
732    
733 root 1.39 local $override;
734    
735 root 1.40 for (@$callbacks) {
736 root 1.39 eval { &{$_->[1]} };
737    
738     if ($@) {
739     warn "$@";
740 root 1.64 warn "... while processing $EVENT[$event][0](@_) event, skipping processing altogether.\n";
741 root 1.39 override;
742     }
743    
744     return 1 if $override;
745     }
746    
747     0
748     }
749    
750 root 1.96 =item $bool = cf::global::invoke (EVENT_CLASS_XXX, ...)
751 root 1.55
752 root 1.96 =item $bool = $attachable->invoke (EVENT_CLASS_XXX, ...)
753 root 1.55
754 root 1.96 Generate an object-specific event with the given arguments.
755 root 1.55
756 root 1.96 This API is preliminary (most likely, the EVENT_CLASS_xxx prefix will be
757 root 1.55 removed in future versions), and there is no public API to access override
758     results (if you must, access C<@cf::invoke_results> directly).
759    
760     =back
761    
762 root 1.71 =cut
763    
764 root 1.70 #############################################################################
765 root 1.45 # object support
766    
767 root 1.102 sub reattach {
768     # basically do the same as instantiate, without calling instantiate
769     my ($obj) = @_;
770    
771 root 1.169 bless $obj, ref $obj; # re-bless in case extensions have been reloaded
772    
773 root 1.102 my $registry = $obj->registry;
774    
775     @$registry = ();
776    
777     delete $obj->{_attachment} unless scalar keys %{ $obj->{_attachment} || {} };
778    
779     for my $name (keys %{ $obj->{_attachment} || {} }) {
780     if (my $attach = $attachment{$name}) {
781     for (@$attach) {
782     my ($klass, @attach) = @$_;
783     _attach $registry, $klass, @attach;
784     }
785     } else {
786     warn "object uses attachment '$name' that is not available, postponing.\n";
787     }
788     }
789     }
790    
791 root 1.100 cf::attachable->attach (
792     prio => -1000000,
793     on_instantiate => sub {
794     my ($obj, $data) = @_;
795 root 1.45
796 root 1.100 $data = from_json $data;
797 root 1.45
798 root 1.100 for (@$data) {
799     my ($name, $args) = @$_;
800 root 1.49
801 root 1.100 $obj->attach ($name, %{$args || {} });
802     }
803     },
804 root 1.102 on_reattach => \&reattach,
805 root 1.100 on_clone => sub {
806     my ($src, $dst) = @_;
807    
808     @{$dst->registry} = @{$src->registry};
809    
810     %$dst = %$src;
811    
812     %{$dst->{_attachment}} = %{$src->{_attachment}}
813     if exists $src->{_attachment};
814     },
815     );
816 root 1.45
817 root 1.46 sub object_freezer_save {
818 root 1.59 my ($filename, $rdata, $objs) = @_;
819 root 1.46
820 root 1.105 sync_job {
821     if (length $$rdata) {
822     warn sprintf "saving %s (%d,%d)\n",
823     $filename, length $$rdata, scalar @$objs;
824 root 1.60
825 root 1.105 if (my $fh = aio_open "$filename~", O_WRONLY | O_CREAT, 0600) {
826 root 1.60 chmod SAVE_MODE, $fh;
827 root 1.105 aio_write $fh, 0, (length $$rdata), $$rdata, 0;
828 root 1.204 aio_fsync $fh if $cf::USE_FSYNC;
829 root 1.60 close $fh;
830 root 1.105
831     if (@$objs) {
832     if (my $fh = aio_open "$filename.pst~", O_WRONLY | O_CREAT, 0600) {
833     chmod SAVE_MODE, $fh;
834     my $data = Storable::nfreeze { version => 1, objs => $objs };
835     aio_write $fh, 0, (length $data), $data, 0;
836 root 1.204 aio_fsync $fh if $cf::USE_FSYNC;
837 root 1.105 close $fh;
838     aio_rename "$filename.pst~", "$filename.pst";
839     }
840     } else {
841     aio_unlink "$filename.pst";
842     }
843    
844     aio_rename "$filename~", $filename;
845 root 1.60 } else {
846 root 1.105 warn "FATAL: $filename~: $!\n";
847 root 1.60 }
848 root 1.59 } else {
849 root 1.105 aio_unlink $filename;
850     aio_unlink "$filename.pst";
851 root 1.59 }
852 root 1.45 }
853     }
854    
855 root 1.80 sub object_freezer_as_string {
856     my ($rdata, $objs) = @_;
857    
858     use Data::Dumper;
859    
860 root 1.81 $$rdata . Dumper $objs
861 root 1.80 }
862    
863 root 1.46 sub object_thawer_load {
864     my ($filename) = @_;
865    
866 root 1.105 my ($data, $av);
867 root 1.61
868 root 1.105 (aio_load $filename, $data) >= 0
869     or return;
870 root 1.61
871 root 1.105 unless (aio_stat "$filename.pst") {
872     (aio_load "$filename.pst", $av) >= 0
873     or return;
874 root 1.113 $av = eval { (Storable::thaw $av)->{objs} };
875 root 1.61 }
876 root 1.45
877 root 1.118 warn sprintf "loading %s (%d)\n",
878 root 1.274 $filename, length $data, scalar @{$av || []};
879 root 1.105 return ($data, $av);
880 root 1.45 }
881    
882     #############################################################################
883 root 1.85 # command handling &c
884 root 1.39
885 root 1.85 =item cf::register_command $name => \&callback($ob,$args);
886 root 1.1
887 root 1.85 Register a callback for execution when the client sends the user command
888     $name.
889 root 1.5
890 root 1.85 =cut
891 root 1.5
892 root 1.85 sub register_command {
893     my ($name, $cb) = @_;
894 root 1.5
895 root 1.85 my $caller = caller;
896     #warn "registering command '$name/$time' to '$caller'";
897 root 1.1
898 root 1.85 push @{ $COMMAND{$name} }, [$caller, $cb];
899 root 1.1 }
900    
901 root 1.85 =item cf::register_extcmd $name => \&callback($pl,$packet);
902 root 1.1
903 root 1.85 Register a callbackf ro execution when the client sends an extcmd packet.
904 root 1.1
905 root 1.85 If the callback returns something, it is sent back as if reply was being
906     called.
907 root 1.1
908 root 1.85 =cut
909 root 1.1
910 root 1.16 sub register_extcmd {
911     my ($name, $cb) = @_;
912    
913 root 1.159 $EXTCMD{$name} = $cb;
914 root 1.16 }
915    
916 root 1.93 cf::player->attach (
917 root 1.85 on_command => sub {
918     my ($pl, $name, $params) = @_;
919    
920     my $cb = $COMMAND{$name}
921     or return;
922    
923     for my $cmd (@$cb) {
924     $cmd->[1]->($pl->ob, $params);
925     }
926    
927     cf::override;
928     },
929     on_extcmd => sub {
930     my ($pl, $buf) = @_;
931    
932     my $msg = eval { from_json $buf };
933    
934     if (ref $msg) {
935     if (my $cb = $EXTCMD{$msg->{msgtype}}) {
936 root 1.159 if (my %reply = $cb->($pl, $msg)) {
937 root 1.85 $pl->ext_reply ($msg->{msgid}, %reply);
938     }
939     }
940     } else {
941     warn "player " . ($pl->ob->name) . " sent unparseable ext message: <$buf>\n";
942     }
943    
944     cf::override;
945     },
946 root 1.93 );
947 root 1.85
948 root 1.278 sub load_extensions {
949     cf::sync_job {
950     my %todo;
951    
952     for my $path (<$LIBDIR/*.ext>) {
953     next unless -r $path;
954    
955     $path =~ /([^\/\\]+)\.ext$/ or die "$path";
956     my $base = $1;
957     my $pkg = $1;
958     $pkg =~ s/[^[:word:]]/_/g;
959     $pkg = "ext::$pkg";
960    
961     open my $fh, "<:utf8", $path
962     or die "$path: $!";
963    
964     my $source = do { local $/; <$fh> };
965 root 1.1
966 root 1.278 my %ext = (
967     path => $path,
968     base => $base,
969     pkg => $pkg,
970     );
971 root 1.1
972 root 1.278 $ext{meta} = { map { split /=/, $_, 2 } split /\s+/, $1 }
973     if $source =~ /^#!.*?perl.*?#\s*(.*)$/;
974 root 1.1
975 root 1.278 $ext{source} =
976     "package $pkg; use strict; use utf8;\n"
977     . "#line 1 \"$path\"\n{\n"
978     . $source
979     . "\n};\n1";
980 root 1.1
981 root 1.278 $todo{$base} = \%ext;
982 root 1.166 }
983 root 1.1
984 root 1.278 my %done;
985     while (%todo) {
986     my $progress;
987    
988     while (my ($k, $v) = each %todo) {
989     for (split /,\s*/, $ext{meta}{depends}) {
990     goto skip
991     unless exists $done{$_};
992     }
993    
994     warn "... loading '$k' into '$v->{pkg}'\n";
995    
996     unless (eval $v->{source}) {
997     my $msg = $@ ? "$v->{path}: $@\n"
998     : "extension disabled.\n";
999    
1000     if (exists $v->{meta}{mandatory}) {
1001     warn $msg;
1002     warn "mandatory extension failed to load, exiting.\n";
1003     exit 1;
1004     }
1005    
1006     die $msg;
1007     }
1008    
1009     $done{$k} = delete $todo{$k};
1010     push @EXTS, $v->{pkg};
1011     }
1012 root 1.1
1013 root 1.278 skip:
1014     die "cannot load " . (join ", ", keys %todo) . ": unable to resolve dependencies\n"
1015     unless $progress;
1016     }
1017     };
1018 root 1.1 }
1019    
1020 root 1.8 #############################################################################
1021 root 1.70
1022     =head2 CORE EXTENSIONS
1023    
1024     Functions and methods that extend core crossfire objects.
1025    
1026 root 1.143 =cut
1027    
1028     package cf::player;
1029    
1030 root 1.154 use Coro::AIO;
1031    
1032 root 1.95 =head3 cf::player
1033    
1034 root 1.70 =over 4
1035 root 1.22
1036 root 1.143 =item cf::player::find $login
1037 root 1.23
1038 root 1.143 Returns the given player object, loading it if necessary (might block).
1039 root 1.23
1040     =cut
1041    
1042 root 1.145 sub playerdir($) {
1043 root 1.253 "$PLAYERDIR/"
1044 root 1.145 . (ref $_[0] ? $_[0]->ob->name : $_[0])
1045     }
1046    
1047 root 1.143 sub path($) {
1048 root 1.145 my $login = ref $_[0] ? $_[0]->ob->name : $_[0];
1049    
1050 root 1.234 (playerdir $login) . "/playerdata"
1051 root 1.143 }
1052    
1053     sub find_active($) {
1054     $cf::PLAYER{$_[0]}
1055     and $cf::PLAYER{$_[0]}->active
1056     and $cf::PLAYER{$_[0]}
1057     }
1058    
1059     sub exists($) {
1060     my ($login) = @_;
1061    
1062     $cf::PLAYER{$login}
1063 root 1.180 or cf::sync_job { !aio_stat path $login }
1064 root 1.143 }
1065    
1066     sub find($) {
1067     return $cf::PLAYER{$_[0]} || do {
1068     my $login = $_[0];
1069    
1070     my $guard = cf::lock_acquire "user_find:$login";
1071    
1072 root 1.151 $cf::PLAYER{$_[0]} || do {
1073 root 1.234 # rename old playerfiles to new ones
1074     #TODO: remove when no longer required
1075     aio_link +(playerdir $login) . "/$login.pl.pst", (playerdir $login) . "/playerdata.pst";
1076     aio_link +(playerdir $login) . "/$login.pl" , (playerdir $login) . "/playerdata";
1077     aio_unlink +(playerdir $login) . "/$login.pl.pst";
1078     aio_unlink +(playerdir $login) . "/$login.pl";
1079    
1080 root 1.151 my $pl = load_pl path $login
1081     or return;
1082     $cf::PLAYER{$login} = $pl
1083     }
1084     }
1085 root 1.143 }
1086    
1087     sub save($) {
1088     my ($pl) = @_;
1089    
1090     return if $pl->{deny_save};
1091    
1092     my $path = path $pl;
1093     my $guard = cf::lock_acquire "user_save:$path";
1094    
1095     return if $pl->{deny_save};
1096 root 1.146
1097 root 1.154 aio_mkdir playerdir $pl, 0770;
1098 root 1.143 $pl->{last_save} = $cf::RUNTIME;
1099    
1100     $pl->save_pl ($path);
1101     Coro::cede;
1102     }
1103    
1104     sub new($) {
1105     my ($login) = @_;
1106    
1107     my $self = create;
1108    
1109     $self->ob->name ($login);
1110     $self->{deny_save} = 1;
1111    
1112     $cf::PLAYER{$login} = $self;
1113    
1114     $self
1115 root 1.23 }
1116    
1117 root 1.154 =item $pl->quit_character
1118    
1119     Nukes the player without looking back. If logged in, the connection will
1120     be destroyed. May block for a long time.
1121    
1122     =cut
1123    
1124 root 1.145 sub quit_character {
1125     my ($pl) = @_;
1126    
1127 root 1.220 my $name = $pl->ob->name;
1128    
1129 root 1.145 $pl->{deny_save} = 1;
1130     $pl->password ("*"); # this should lock out the player until we nuked the dir
1131    
1132     $pl->invoke (cf::EVENT_PLAYER_LOGOUT, 1) if $pl->active;
1133     $pl->deactivate;
1134     $pl->invoke (cf::EVENT_PLAYER_QUIT);
1135     $pl->ns->destroy if $pl->ns;
1136    
1137     my $path = playerdir $pl;
1138     my $temp = "$path~$cf::RUNTIME~deleting~";
1139 root 1.154 aio_rename $path, $temp;
1140 root 1.150 delete $cf::PLAYER{$pl->ob->name};
1141     $pl->destroy;
1142 root 1.220
1143     my $prefix = qr<^~\Q$name\E/>;
1144    
1145     # nuke player maps
1146     $cf::MAP{$_}->nuke for grep /$prefix/, keys %cf::MAP;
1147    
1148 root 1.150 IO::AIO::aio_rmtree $temp;
1149 root 1.145 }
1150    
1151 pippijn 1.221 =item $pl->kick
1152    
1153     Kicks a player out of the game. This destroys the connection.
1154    
1155     =cut
1156    
1157     sub kick {
1158     my ($pl, $kicker) = @_;
1159    
1160     $pl->invoke (cf::EVENT_PLAYER_KICK, $kicker);
1161     $pl->killer ("kicked");
1162     $pl->ns->destroy;
1163     }
1164    
1165 root 1.154 =item cf::player::list_logins
1166    
1167     Returns am arrayref of all valid playernames in the system, can take a
1168     while and may block, so not sync_job-capable, ever.
1169    
1170     =cut
1171    
1172     sub list_logins {
1173 root 1.253 my $dirs = aio_readdir $PLAYERDIR
1174 root 1.154 or return [];
1175    
1176     my @logins;
1177    
1178     for my $login (@$dirs) {
1179     my $fh = aio_open path $login, Fcntl::O_RDONLY, 0 or next;
1180     aio_read $fh, 0, 512, my $buf, 0 or next;
1181 root 1.155 $buf !~ /^password -------------$/m or next; # official not-valid tag
1182 root 1.154
1183     utf8::decode $login;
1184     push @logins, $login;
1185     }
1186    
1187     \@logins
1188     }
1189    
1190     =item $player->maps
1191    
1192 root 1.166 Returns an arrayref of map paths that are private for this
1193 root 1.154 player. May block.
1194    
1195     =cut
1196    
1197     sub maps($) {
1198     my ($pl) = @_;
1199    
1200 root 1.201 $pl = ref $pl ? $pl->ob->name : $pl;
1201    
1202 root 1.154 my $files = aio_readdir playerdir $pl
1203     or return;
1204    
1205     my @paths;
1206    
1207     for (@$files) {
1208     utf8::decode $_;
1209     next if /\.(?:pl|pst)$/;
1210 root 1.158 next unless /^$PATH_SEP/o;
1211 root 1.154
1212 root 1.201 push @paths, cf::map::normalise "~$pl/$_";
1213 root 1.154 }
1214    
1215     \@paths
1216     }
1217    
1218 root 1.231 =item $player->ext_reply ($msgid, %msg)
1219 root 1.95
1220     Sends an ext reply to the player.
1221    
1222     =cut
1223    
1224 root 1.231 sub ext_reply($$%) {
1225 root 1.95 my ($self, $id, %msg) = @_;
1226    
1227     $msg{msgid} = $id;
1228    
1229 root 1.143 $self->send ("ext " . cf::to_json \%msg);
1230 root 1.95 }
1231    
1232 root 1.231 =item $player->ext_event ($type, %msg)
1233    
1234     Sends an ext event to the client.
1235    
1236     =cut
1237    
1238     sub ext_event($$%) {
1239     my ($self, $type, %msg) = @_;
1240    
1241 root 1.232 $self->ns->ext_event ($type, %msg);
1242 root 1.231 }
1243    
1244 root 1.238 =head3 cf::region
1245    
1246     =over 4
1247    
1248     =cut
1249    
1250     package cf::region;
1251    
1252     =item cf::region::find_by_path $path
1253    
1254     Tries to decuce the probable region for a map knowing only its path.
1255    
1256     =cut
1257    
1258     sub find_by_path($) {
1259     my ($path) = @_;
1260    
1261     my ($match, $specificity);
1262    
1263     for my $region (list) {
1264     if ($region->match && $path =~ $region->match) {
1265     ($match, $specificity) = ($region, $region->specificity)
1266     if $region->specificity > $specificity;
1267     }
1268     }
1269    
1270     $match
1271     }
1272 root 1.143
1273 root 1.95 =back
1274    
1275 root 1.110 =head3 cf::map
1276    
1277     =over 4
1278    
1279     =cut
1280    
1281     package cf::map;
1282    
1283     use Fcntl;
1284     use Coro::AIO;
1285    
1286 root 1.166 use overload
1287 root 1.173 '""' => \&as_string,
1288     fallback => 1;
1289 root 1.166
1290 root 1.133 our $MAX_RESET = 3600;
1291     our $DEFAULT_RESET = 3000;
1292 root 1.110
1293     sub generate_random_map {
1294 root 1.166 my ($self, $rmp) = @_;
1295 root 1.110 # mit "rum" bekleckern, nicht
1296 root 1.166 $self->_create_random_map (
1297 root 1.110 $rmp->{wallstyle}, $rmp->{wall_name}, $rmp->{floorstyle}, $rmp->{monsterstyle},
1298     $rmp->{treasurestyle}, $rmp->{layoutstyle}, $rmp->{doorstyle}, $rmp->{decorstyle},
1299     $rmp->{origin_map}, $rmp->{final_map}, $rmp->{exitstyle}, $rmp->{this_map},
1300     $rmp->{exit_on_final_map},
1301     $rmp->{xsize}, $rmp->{ysize},
1302     $rmp->{expand2x}, $rmp->{layoutoptions1}, $rmp->{layoutoptions2}, $rmp->{layoutoptions3},
1303     $rmp->{symmetry}, $rmp->{difficulty}, $rmp->{difficulty_given}, $rmp->{difficulty_increase},
1304     $rmp->{dungeon_level}, $rmp->{dungeon_depth}, $rmp->{decoroptions}, $rmp->{orientation},
1305     $rmp->{origin_y}, $rmp->{origin_x}, $rmp->{random_seed}, $rmp->{total_map_hp},
1306     $rmp->{map_layout_style}, $rmp->{treasureoptions}, $rmp->{symmetry_used},
1307 root 1.162 (cf::region::find $rmp->{region}), $rmp->{custom}
1308     )
1309 root 1.110 }
1310    
1311 root 1.187 =item cf::map->register ($regex, $prio)
1312    
1313     Register a handler for the map path matching the given regex at the
1314     givne priority (higher is better, built-in handlers have priority 0, the
1315     default).
1316    
1317     =cut
1318    
1319 root 1.166 sub register {
1320 root 1.187 my (undef, $regex, $prio) = @_;
1321 root 1.166 my $pkg = caller;
1322    
1323     no strict;
1324     push @{"$pkg\::ISA"}, __PACKAGE__;
1325    
1326 root 1.187 $EXT_MAP{$pkg} = [$prio, qr<$regex>];
1327 root 1.166 }
1328    
1329     # also paths starting with '/'
1330 root 1.187 $EXT_MAP{"cf::map"} = [0, qr{^(?=/)}];
1331 root 1.166
1332 root 1.170 sub thawer_merge {
1333 root 1.172 my ($self, $merge) = @_;
1334    
1335 root 1.170 # we have to keep some variables in memory intact
1336 root 1.172 local $self->{path};
1337     local $self->{load_path};
1338 root 1.170
1339 root 1.172 $self->SUPER::thawer_merge ($merge);
1340 root 1.170 }
1341    
1342 root 1.166 sub normalise {
1343     my ($path, $base) = @_;
1344    
1345 root 1.192 $path = "$path"; # make sure its a string
1346    
1347 root 1.199 $path =~ s/\.map$//;
1348    
1349 root 1.166 # map plan:
1350     #
1351     # /! non-realised random map exit (special hack!)
1352     # {... are special paths that are not being touched
1353     # ?xxx/... are special absolute paths
1354     # ?random/... random maps
1355     # /... normal maps
1356     # ~user/... per-player map of a specific user
1357    
1358     $path =~ s/$PATH_SEP/\//go;
1359    
1360     # treat it as relative path if it starts with
1361     # something that looks reasonable
1362     if ($path =~ m{^(?:\./|\.\./|\w)}) {
1363     $base or Carp::carp "normalise called with relative path and no base: '$path'";
1364    
1365     $base =~ s{[^/]+/?$}{};
1366     $path = "$base/$path";
1367     }
1368    
1369     for ($path) {
1370     redo if s{//}{/};
1371     redo if s{/\.?/}{/};
1372     redo if s{/[^/]+/\.\./}{/};
1373     }
1374    
1375     $path
1376     }
1377    
1378     sub new_from_path {
1379     my (undef, $path, $base) = @_;
1380    
1381     return $path if UNIVERSAL::isa $path, "cf::map"; # already a map object
1382    
1383     $path = normalise $path, $base;
1384    
1385 root 1.187 for my $pkg (sort { $EXT_MAP{$b}[0] <=> $EXT_MAP{$a}[0] } keys %EXT_MAP) {
1386     if ($path =~ $EXT_MAP{$pkg}[1]) {
1387 root 1.166 my $self = bless cf::map::new, $pkg;
1388     $self->{path} = $path; $self->path ($path);
1389     $self->init; # pass $1 etc.
1390     return $self;
1391     }
1392     }
1393    
1394 root 1.192 Carp::carp "unable to resolve path '$path' (base '$base').";
1395 root 1.166 ()
1396     }
1397    
1398     sub init {
1399     my ($self) = @_;
1400    
1401     $self
1402     }
1403    
1404     sub as_string {
1405     my ($self) = @_;
1406    
1407     "$self->{path}"
1408     }
1409    
1410     # the displayed name, this is a one way mapping
1411     sub visible_name {
1412     &as_string
1413     }
1414    
1415     # the original (read-only) location
1416     sub load_path {
1417     my ($self) = @_;
1418    
1419 root 1.254 "$MAPDIR/$self->{path}.map"
1420 root 1.166 }
1421    
1422     # the temporary/swap location
1423     sub save_path {
1424     my ($self) = @_;
1425    
1426 root 1.167 (my $path = $_[0]{path}) =~ s/\//$PATH_SEP/g;
1427 root 1.254 "$TMPDIR/$path.map"
1428 root 1.166 }
1429    
1430     # the unique path, undef == no special unique path
1431     sub uniq_path {
1432     my ($self) = @_;
1433    
1434 root 1.167 (my $path = $_[0]{path}) =~ s/\//$PATH_SEP/g;
1435 root 1.253 "$UNIQUEDIR/$path"
1436 root 1.166 }
1437    
1438 root 1.110 # and all this just because we cannot iterate over
1439     # all maps in C++...
1440     sub change_all_map_light {
1441     my ($change) = @_;
1442    
1443 root 1.122 $_->change_map_light ($change)
1444     for grep $_->outdoor, values %cf::MAP;
1445 root 1.110 }
1446    
1447 root 1.275 sub decay_objects {
1448     my ($self) = @_;
1449    
1450     return if $self->{deny_reset};
1451    
1452     $self->do_decay_objects;
1453     }
1454    
1455 root 1.166 sub unlink_save {
1456     my ($self) = @_;
1457    
1458     utf8::encode (my $save = $self->save_path);
1459 root 1.170 IO::AIO::aioreq_pri 4; Coro::AIO::aio_unlink $save;
1460     IO::AIO::aioreq_pri 4; Coro::AIO::aio_unlink "$save.pst";
1461 root 1.166 }
1462    
1463     sub load_header_from($) {
1464     my ($self, $path) = @_;
1465 root 1.110
1466     utf8::encode $path;
1467 root 1.200 #aio_open $path, O_RDONLY, 0
1468     # or return;
1469 root 1.110
1470 root 1.166 $self->_load_header ($path)
1471 root 1.110 or return;
1472    
1473 root 1.166 $self->{load_path} = $path;
1474 root 1.135
1475 root 1.166 1
1476     }
1477 root 1.110
1478 root 1.188 sub load_header_orig {
1479 root 1.166 my ($self) = @_;
1480 root 1.110
1481 root 1.166 $self->load_header_from ($self->load_path)
1482 root 1.110 }
1483    
1484 root 1.188 sub load_header_temp {
1485 root 1.166 my ($self) = @_;
1486 root 1.110
1487 root 1.166 $self->load_header_from ($self->save_path)
1488     }
1489 root 1.110
1490 root 1.188 sub prepare_temp {
1491     my ($self) = @_;
1492    
1493     $self->last_access ((delete $self->{last_access})
1494     || $cf::RUNTIME); #d#
1495     # safety
1496     $self->{instantiate_time} = $cf::RUNTIME
1497     if $self->{instantiate_time} > $cf::RUNTIME;
1498     }
1499    
1500     sub prepare_orig {
1501     my ($self) = @_;
1502    
1503     $self->{load_original} = 1;
1504     $self->{instantiate_time} = $cf::RUNTIME;
1505     $self->last_access ($cf::RUNTIME);
1506     $self->instantiate;
1507     }
1508    
1509 root 1.166 sub load_header {
1510     my ($self) = @_;
1511 root 1.110
1512 root 1.188 if ($self->load_header_temp) {
1513     $self->prepare_temp;
1514 root 1.166 } else {
1515 root 1.188 $self->load_header_orig
1516 root 1.166 or return;
1517 root 1.188 $self->prepare_orig;
1518 root 1.166 }
1519 root 1.120
1520 root 1.275 $self->{deny_reset} = 1
1521     if $self->no_reset;
1522    
1523 root 1.238 $self->default_region (cf::region::find_by_path $self->{path})
1524     unless $self->default_region;
1525    
1526 root 1.166 1
1527     }
1528 root 1.110
1529 root 1.166 sub find;
1530     sub find {
1531     my ($path, $origin) = @_;
1532 root 1.134
1533 root 1.166 $path = normalise $path, $origin && $origin->path;
1534 root 1.110
1535 root 1.166 cf::lock_wait "map_find:$path";
1536 root 1.110
1537 root 1.166 $cf::MAP{$path} || do {
1538     my $guard = cf::lock_acquire "map_find:$path";
1539     my $map = new_from_path cf::map $path
1540     or return;
1541 root 1.110
1542 root 1.116 $map->{last_save} = $cf::RUNTIME;
1543 root 1.110
1544 root 1.166 $map->load_header
1545     or return;
1546 root 1.134
1547 root 1.275 if ($map->should_reset) {#d#TODO# disabled, crashy (locking issue?)
1548 root 1.185 # doing this can freeze the server in a sync job, obviously
1549     #$cf::WAIT_FOR_TICK->wait;
1550 root 1.112 $map->reset;
1551 root 1.123 undef $guard;
1552 root 1.192 return find $path;
1553 root 1.112 }
1554 root 1.110
1555 root 1.166 $cf::MAP{$path} = $map
1556 root 1.110 }
1557     }
1558    
1559 root 1.188 sub pre_load { }
1560     sub post_load { }
1561    
1562 root 1.110 sub load {
1563     my ($self) = @_;
1564    
1565 root 1.196 local $self->{deny_reset} = 1; # loading can take a long time
1566    
1567 root 1.120 my $path = $self->{path};
1568    
1569 root 1.256 {
1570     my $guard = cf::lock_acquire "map_load:$path";
1571    
1572     return if $self->in_memory != cf::MAP_SWAPPED;
1573 root 1.110
1574 root 1.256 $self->in_memory (cf::MAP_LOADING);
1575 root 1.110
1576 root 1.256 $self->alloc;
1577 root 1.188
1578 root 1.256 $self->pre_load;
1579     Coro::cede;
1580 root 1.188
1581 root 1.256 $self->_load_objects ($self->{load_path}, 1)
1582     or return;
1583 root 1.110
1584 root 1.256 $self->set_object_flag (cf::FLAG_OBJ_ORIGINAL, 1)
1585     if delete $self->{load_original};
1586 root 1.111
1587 root 1.256 if (my $uniq = $self->uniq_path) {
1588     utf8::encode $uniq;
1589     if (aio_open $uniq, O_RDONLY, 0) {
1590     $self->clear_unique_items;
1591     $self->_load_objects ($uniq, 0);
1592     }
1593 root 1.110 }
1594    
1595 root 1.166 Coro::cede;
1596 root 1.256 # now do the right thing for maps
1597     $self->link_multipart_objects;
1598 root 1.110 $self->difficulty ($self->estimate_difficulty)
1599     unless $self->difficulty;
1600 root 1.166 Coro::cede;
1601 root 1.256
1602     unless ($self->{deny_activate}) {
1603     $self->decay_objects;
1604     $self->fix_auto_apply;
1605     $self->update_buttons;
1606     Coro::cede;
1607     $self->set_darkness_map;
1608     Coro::cede;
1609     $self->activate;
1610     }
1611    
1612     $self->in_memory (cf::MAP_IN_MEMORY);
1613 root 1.110 }
1614    
1615 root 1.188 $self->post_load;
1616 root 1.166 }
1617    
1618     sub customise_for {
1619     my ($self, $ob) = @_;
1620    
1621     return find "~" . $ob->name . "/" . $self->{path}
1622     if $self->per_player;
1623 root 1.134
1624 root 1.275 # return find "?party/" . $ob->name . "/" . $self->{path}
1625     # if $self->per_party;
1626    
1627 root 1.166 $self
1628 root 1.110 }
1629    
1630 root 1.157 # find and load all maps in the 3x3 area around a map
1631     sub load_diag {
1632     my ($map) = @_;
1633    
1634     my @diag; # diagonal neighbours
1635    
1636     for (0 .. 3) {
1637     my $neigh = $map->tile_path ($_)
1638     or next;
1639     $neigh = find $neigh, $map
1640     or next;
1641     $neigh->load;
1642    
1643     push @diag, [$neigh->tile_path (($_ + 3) % 4), $neigh],
1644     [$neigh->tile_path (($_ + 1) % 4), $neigh];
1645     }
1646    
1647     for (@diag) {
1648     my $neigh = find @$_
1649     or next;
1650     $neigh->load;
1651     }
1652     }
1653    
1654 root 1.133 sub find_sync {
1655 root 1.110 my ($path, $origin) = @_;
1656    
1657 root 1.157 cf::sync_job { find $path, $origin }
1658 root 1.133 }
1659    
1660     sub do_load_sync {
1661     my ($map) = @_;
1662 root 1.110
1663 root 1.133 cf::sync_job { $map->load };
1664 root 1.110 }
1665    
1666 root 1.157 our %MAP_PREFETCH;
1667 root 1.183 our $MAP_PREFETCHER = undef;
1668 root 1.157
1669     sub find_async {
1670     my ($path, $origin) = @_;
1671    
1672 root 1.166 $path = normalise $path, $origin && $origin->{path};
1673 root 1.157
1674 root 1.166 if (my $map = $cf::MAP{$path}) {
1675 root 1.157 return $map if $map->in_memory == cf::MAP_IN_MEMORY;
1676     }
1677    
1678 root 1.183 undef $MAP_PREFETCH{$path};
1679     $MAP_PREFETCHER ||= cf::async {
1680     while (%MAP_PREFETCH) {
1681     for my $path (keys %MAP_PREFETCH) {
1682     my $map = find $path
1683     or next;
1684     $map->load;
1685    
1686     delete $MAP_PREFETCH{$path};
1687     }
1688     }
1689     undef $MAP_PREFETCHER;
1690     };
1691 root 1.189 $MAP_PREFETCHER->prio (6);
1692 root 1.157
1693     ()
1694     }
1695    
1696 root 1.110 sub save {
1697     my ($self) = @_;
1698    
1699 root 1.137 my $lock = cf::lock_acquire "map_data:" . $self->path;
1700    
1701 root 1.110 $self->{last_save} = $cf::RUNTIME;
1702    
1703     return unless $self->dirty;
1704    
1705 root 1.166 my $save = $self->save_path; utf8::encode $save;
1706     my $uniq = $self->uniq_path; utf8::encode $uniq;
1707 root 1.117
1708 root 1.110 $self->{load_path} = $save;
1709    
1710     return if $self->{deny_save};
1711    
1712 root 1.132 local $self->{last_access} = $self->last_access;#d#
1713    
1714 root 1.143 cf::async {
1715     $_->contr->save for $self->players;
1716     };
1717    
1718 root 1.110 if ($uniq) {
1719 root 1.166 $self->_save_objects ($save, cf::IO_HEADER | cf::IO_OBJECTS);
1720     $self->_save_objects ($uniq, cf::IO_UNIQUES);
1721 root 1.110 } else {
1722 root 1.166 $self->_save_objects ($save, cf::IO_HEADER | cf::IO_OBJECTS | cf::IO_UNIQUES);
1723 root 1.110 }
1724     }
1725    
1726     sub swap_out {
1727     my ($self) = @_;
1728    
1729 root 1.130 # save first because save cedes
1730     $self->save;
1731    
1732 root 1.137 my $lock = cf::lock_acquire "map_data:" . $self->path;
1733    
1734 root 1.110 return if $self->players;
1735     return if $self->in_memory != cf::MAP_IN_MEMORY;
1736     return if $self->{deny_save};
1737    
1738     $self->clear;
1739     $self->in_memory (cf::MAP_SWAPPED);
1740     }
1741    
1742 root 1.112 sub reset_at {
1743     my ($self) = @_;
1744 root 1.110
1745     # TODO: safety, remove and allow resettable per-player maps
1746 root 1.114 return 1e99 if $self->{deny_reset};
1747 root 1.110
1748 root 1.112 my $time = $self->fixed_resettime ? $self->{instantiate_time} : $self->last_access;
1749 root 1.114 my $to = List::Util::min $MAX_RESET, $self->reset_timeout || $DEFAULT_RESET;
1750 root 1.110
1751 root 1.112 $time + $to
1752     }
1753    
1754     sub should_reset {
1755     my ($self) = @_;
1756    
1757     $self->reset_at <= $cf::RUNTIME
1758 root 1.111 }
1759    
1760 root 1.110 sub reset {
1761     my ($self) = @_;
1762    
1763 root 1.167 my $lock = cf::lock_acquire "map_data:$self->{path}";
1764 root 1.137
1765 root 1.110 return if $self->players;
1766    
1767 root 1.274 warn "resetting map ", $self->path;
1768 root 1.110
1769 root 1.210 $self->in_memory (cf::MAP_SWAPPED);
1770    
1771     # need to save uniques path
1772     unless ($self->{deny_save}) {
1773     my $uniq = $self->uniq_path; utf8::encode $uniq;
1774    
1775     $self->_save_objects ($uniq, cf::IO_UNIQUES)
1776     if $uniq;
1777     }
1778    
1779 root 1.111 delete $cf::MAP{$self->path};
1780 root 1.110
1781 root 1.167 $self->clear;
1782    
1783 root 1.110 $_->clear_links_to ($self) for values %cf::MAP;
1784    
1785 root 1.166 $self->unlink_save;
1786 root 1.111 $self->destroy;
1787 root 1.110 }
1788    
1789 root 1.114 my $nuke_counter = "aaaa";
1790    
1791     sub nuke {
1792     my ($self) = @_;
1793    
1794 root 1.174 delete $cf::MAP{$self->path};
1795    
1796     $self->unlink_save;
1797    
1798     bless $self, "cf::map";
1799     delete $self->{deny_reset};
1800 root 1.114 $self->{deny_save} = 1;
1801     $self->reset_timeout (1);
1802 root 1.174 $self->path ($self->{path} = "{nuke}/" . ($nuke_counter++));
1803    
1804     $cf::MAP{$self->path} = $self;
1805    
1806 root 1.114 $self->reset; # polite request, might not happen
1807     }
1808    
1809 root 1.276 =item $maps = cf::map::tmp_maps
1810    
1811     Returns an arrayref with all map paths of currently instantiated and saved
1812 root 1.277 maps. May block.
1813 root 1.276
1814     =cut
1815    
1816     sub tmp_maps() {
1817     [
1818     map {
1819     utf8::decode $_;
1820 root 1.277 /\.map$/
1821 root 1.276 ? normalise $_
1822     : ()
1823     } @{ aio_readdir $TMPDIR or [] }
1824     ]
1825     }
1826    
1827 root 1.277 =item $maps = cf::map::random_maps
1828    
1829     Returns an arrayref with all map paths of currently instantiated and saved
1830     random maps. May block.
1831    
1832     =cut
1833    
1834     sub random_maps() {
1835     [
1836     map {
1837     utf8::decode $_;
1838     /\.map$/
1839     ? normalise "?random/$_"
1840     : ()
1841     } @{ aio_readdir $RANDOMDIR or [] }
1842     ]
1843     }
1844    
1845 root 1.158 =item cf::map::unique_maps
1846    
1847 root 1.166 Returns an arrayref of paths of all shared maps that have
1848 root 1.158 instantiated unique items. May block.
1849    
1850     =cut
1851    
1852     sub unique_maps() {
1853 root 1.276 [
1854     map {
1855     utf8::decode $_;
1856 root 1.277 /\.map$/
1857 root 1.276 ? normalise $_
1858     : ()
1859     } @{ aio_readdir $UNIQUEDIR or [] }
1860     ]
1861 root 1.158 }
1862    
1863 root 1.155 package cf;
1864    
1865     =back
1866    
1867     =head3 cf::object
1868    
1869     =cut
1870    
1871     package cf::object;
1872    
1873     =over 4
1874    
1875     =item $ob->inv_recursive
1876 root 1.110
1877 root 1.155 Returns the inventory of the object _and_ their inventories, recursively.
1878 root 1.110
1879 root 1.155 =cut
1880 root 1.144
1881 root 1.155 sub inv_recursive_;
1882     sub inv_recursive_ {
1883     map { $_, inv_recursive_ $_->inv } @_
1884     }
1885 root 1.110
1886 root 1.155 sub inv_recursive {
1887     inv_recursive_ inv $_[0]
1888 root 1.110 }
1889    
1890     package cf;
1891    
1892     =back
1893    
1894 root 1.95 =head3 cf::object::player
1895    
1896     =over 4
1897    
1898 root 1.79 =item $player_object->reply ($npc, $msg[, $flags])
1899 root 1.28
1900     Sends a message to the player, as if the npc C<$npc> replied. C<$npc>
1901     can be C<undef>. Does the right thing when the player is currently in a
1902     dialogue with the given NPC character.
1903    
1904     =cut
1905    
1906 root 1.22 # rough implementation of a future "reply" method that works
1907     # with dialog boxes.
1908 root 1.95 #TODO: the first argument must go, split into a $npc->reply_to ( method
1909 root 1.23 sub cf::object::player::reply($$$;$) {
1910     my ($self, $npc, $msg, $flags) = @_;
1911    
1912     $flags = cf::NDI_BROWN | cf::NDI_UNIQUE unless @_ >= 4;
1913 root 1.22
1914 root 1.24 if ($self->{record_replies}) {
1915     push @{ $self->{record_replies} }, [$npc, $msg, $flags];
1916     } else {
1917     $msg = $npc->name . " says: $msg" if $npc;
1918     $self->message ($msg, $flags);
1919     }
1920 root 1.22 }
1921    
1922 root 1.79 =item $player_object->may ("access")
1923    
1924     Returns wether the given player is authorized to access resource "access"
1925     (e.g. "command_wizcast").
1926    
1927     =cut
1928    
1929     sub cf::object::player::may {
1930     my ($self, $access) = @_;
1931    
1932     $self->flag (cf::FLAG_WIZ) ||
1933     (ref $cf::CFG{"may_$access"}
1934     ? scalar grep $self->name eq $_, @{$cf::CFG{"may_$access"}}
1935     : $cf::CFG{"may_$access"})
1936     }
1937 root 1.70
1938 root 1.115 =item $player_object->enter_link
1939    
1940     Freezes the player and moves him/her to a special map (C<{link}>).
1941    
1942 root 1.166 The player should be reasonably safe there for short amounts of time. You
1943 root 1.115 I<MUST> call C<leave_link> as soon as possible, though.
1944    
1945 root 1.166 Will never block.
1946    
1947 root 1.115 =item $player_object->leave_link ($map, $x, $y)
1948    
1949 root 1.166 Moves the player out of the special C<{link}> map onto the specified
1950     map. If the map is not valid (or omitted), the player will be moved back
1951     to the location he/she was before the call to C<enter_link>, or, if that
1952     fails, to the emergency map position.
1953 root 1.115
1954     Might block.
1955    
1956     =cut
1957    
1958 root 1.166 sub link_map {
1959     unless ($LINK_MAP) {
1960     $LINK_MAP = cf::map::find "{link}"
1961 root 1.196 or cf::cleanup "FATAL: unable to provide {link} map, exiting.";
1962 root 1.166 $LINK_MAP->load;
1963     }
1964    
1965     $LINK_MAP
1966     }
1967    
1968 root 1.110 sub cf::object::player::enter_link {
1969     my ($self) = @_;
1970    
1971 root 1.259 $self->deactivate_recursive;
1972 root 1.258
1973 root 1.166 return if UNIVERSAL::isa $self->map, "ext::map_link";
1974 root 1.110
1975 root 1.120 $self->{_link_pos} ||= [$self->map->{path}, $self->x, $self->y]
1976 root 1.270 if $self->map && $self->map->{path} ne "{link}";
1977 root 1.110
1978 root 1.194 $self->enter_map ($LINK_MAP || link_map, 10, 10);
1979 root 1.110 }
1980    
1981     sub cf::object::player::leave_link {
1982     my ($self, $map, $x, $y) = @_;
1983    
1984 root 1.270 return unless $self->contr->active;
1985    
1986 root 1.110 my $link_pos = delete $self->{_link_pos};
1987    
1988     unless ($map) {
1989     # restore original map position
1990     ($map, $x, $y) = @{ $link_pos || [] };
1991 root 1.133 $map = cf::map::find $map;
1992 root 1.110
1993     unless ($map) {
1994     ($map, $x, $y) = @$EMERGENCY_POSITION;
1995 root 1.133 $map = cf::map::find $map
1996 root 1.110 or die "FATAL: cannot load emergency map\n";
1997     }
1998     }
1999    
2000     ($x, $y) = (-1, -1)
2001     unless (defined $x) && (defined $y);
2002    
2003     # use -1 or undef as default coordinates, not 0, 0
2004     ($x, $y) = ($map->enter_x, $map->enter_y)
2005     if $x <=0 && $y <= 0;
2006    
2007     $map->load;
2008 root 1.157 $map->load_diag;
2009 root 1.110
2010 root 1.143 return unless $self->contr->active;
2011 root 1.110 $self->activate_recursive;
2012 root 1.215
2013     local $self->{_prev_pos} = $link_pos; # ugly hack for rent.ext
2014 root 1.110 $self->enter_map ($map, $x, $y);
2015     }
2016    
2017 root 1.268 =item $player_object->goto ($path, $x, $y[, $check->($map)])
2018    
2019     Moves the player to the given map-path and coordinates by first freezing
2020     her, loading and preparing them map, calling the provided $check callback
2021     that has to return the map if sucecssful, and then unfreezes the player on
2022     the new (success) or old (failed) map position.
2023 root 1.110
2024     =cut
2025    
2026 root 1.270 our $GOTOGEN;
2027    
2028 root 1.136 sub cf::object::player::goto {
2029 root 1.268 my ($self, $path, $x, $y, $check) = @_;
2030    
2031 root 1.270 # do generation counting so two concurrent goto's will be executed in-order
2032     my $gen = $self->{_goto_generation} = ++$GOTOGEN;
2033    
2034 root 1.110 $self->enter_link;
2035    
2036 root 1.140 (async {
2037 root 1.197 my $map = eval {
2038     my $map = cf::map::find $path;
2039 root 1.268
2040     if ($map) {
2041     $map = $map->customise_for ($self);
2042     $map = $check->($map) if $check && $map;
2043     } else {
2044     $self->message ("The exit to '$path' is closed", cf::NDI_UNIQUE | cf::NDI_RED);
2045     }
2046    
2047 root 1.197 $map
2048 root 1.268 };
2049    
2050     if ($@) {
2051     $self->message ("Something went wrong within the server, please report this incident!", cf::NDI_UNIQUE | cf::NDI_RED);
2052     LOG llevError | logBacktrace, Carp::longmess $@;
2053     }
2054 root 1.115
2055 root 1.270 if ($gen == $self->{_goto_generation}) {
2056     delete $self->{_goto_generation};
2057     $self->leave_link ($map, $x, $y);
2058     }
2059 root 1.110 })->prio (1);
2060     }
2061    
2062     =item $player_object->enter_exit ($exit_object)
2063    
2064     =cut
2065    
2066     sub parse_random_map_params {
2067     my ($spec) = @_;
2068    
2069     my $rmp = { # defaults
2070 root 1.181 xsize => (cf::rndm 15, 40),
2071     ysize => (cf::rndm 15, 40),
2072     symmetry => (cf::rndm 1, cf::SYMMETRY_XY),
2073 root 1.182 #layout => string,
2074 root 1.110 };
2075    
2076     for (split /\n/, $spec) {
2077     my ($k, $v) = split /\s+/, $_, 2;
2078    
2079     $rmp->{lc $k} = $v if (length $k) && (length $v);
2080     }
2081    
2082     $rmp
2083     }
2084    
2085     sub prepare_random_map {
2086     my ($exit) = @_;
2087    
2088 root 1.179 my $guard = cf::lock_acquire "exit_prepare:$exit";
2089    
2090 root 1.110 # all this does is basically replace the /! path by
2091     # a new random map path (?random/...) with a seed
2092     # that depends on the exit object
2093    
2094     my $rmp = parse_random_map_params $exit->msg;
2095    
2096     if ($exit->map) {
2097 root 1.198 $rmp->{region} = $exit->region->name;
2098 root 1.110 $rmp->{origin_map} = $exit->map->path;
2099     $rmp->{origin_x} = $exit->x;
2100     $rmp->{origin_y} = $exit->y;
2101     }
2102    
2103     $rmp->{random_seed} ||= $exit->random_seed;
2104    
2105     my $data = cf::to_json $rmp;
2106     my $md5 = Digest::MD5::md5_hex $data;
2107 root 1.253 my $meta = "$RANDOMDIR/$md5.meta";
2108 root 1.110
2109 root 1.177 if (my $fh = aio_open "$meta~", O_WRONLY | O_CREAT, 0666) {
2110 root 1.110 aio_write $fh, 0, (length $data), $data, 0;
2111 root 1.177 undef $fh;
2112     aio_rename "$meta~", $meta;
2113 root 1.110
2114     $exit->slaying ("?random/$md5");
2115     $exit->msg (undef);
2116     }
2117     }
2118    
2119     sub cf::object::player::enter_exit {
2120     my ($self, $exit) = @_;
2121    
2122     return unless $self->type == cf::PLAYER;
2123    
2124 root 1.195 if ($exit->slaying eq "/!") {
2125     #TODO: this should de-fi-ni-te-ly not be a sync-job
2126 root 1.233 # the problem is that $exit might not survive long enough
2127     # so it needs to be done right now, right here
2128 root 1.195 cf::sync_job { prepare_random_map $exit };
2129     }
2130    
2131     my $slaying = cf::map::normalise $exit->slaying, $exit->map && $exit->map->path;
2132     my $hp = $exit->stats->hp;
2133     my $sp = $exit->stats->sp;
2134    
2135 root 1.110 $self->enter_link;
2136    
2137 root 1.140 (async {
2138 root 1.133 $self->deactivate_recursive; # just to be sure
2139 root 1.110 unless (eval {
2140 root 1.195 $self->goto ($slaying, $hp, $sp);
2141 root 1.110
2142     1;
2143     }) {
2144     $self->message ("Something went wrong deep within the crossfire server. "
2145 root 1.233 . "I'll try to bring you back to the map you were before. "
2146     . "Please report this to the dungeon master!",
2147     cf::NDI_UNIQUE | cf::NDI_RED);
2148 root 1.110
2149     warn "ERROR in enter_exit: $@";
2150     $self->leave_link;
2151     }
2152     })->prio (1);
2153     }
2154    
2155 root 1.95 =head3 cf::client
2156    
2157     =over 4
2158    
2159     =item $client->send_drawinfo ($text, $flags)
2160    
2161     Sends a drawinfo packet to the client. Circumvents output buffering so
2162     should not be used under normal circumstances.
2163    
2164 root 1.70 =cut
2165    
2166 root 1.95 sub cf::client::send_drawinfo {
2167     my ($self, $text, $flags) = @_;
2168    
2169     utf8::encode $text;
2170 root 1.225 $self->send_packet (sprintf "drawinfo %d %s", $flags || cf::NDI_BLACK, $text);
2171 root 1.95 }
2172    
2173 root 1.232 =item $client->ext_event ($type, %msg)
2174    
2175     Sends an exti event to the client.
2176    
2177     =cut
2178    
2179     sub cf::client::ext_event($$%) {
2180     my ($self, $type, %msg) = @_;
2181    
2182     $msg{msgtype} = "event_$type";
2183     $self->send_packet ("ext " . cf::to_json \%msg);
2184     }
2185 root 1.95
2186     =item $success = $client->query ($flags, "text", \&cb)
2187    
2188     Queues a query to the client, calling the given callback with
2189     the reply text on a reply. flags can be C<cf::CS_QUERY_YESNO>,
2190     C<cf::CS_QUERY_SINGLECHAR> or C<cf::CS_QUERY_HIDEINPUT> or C<0>.
2191    
2192     Queries can fail, so check the return code. Or don't, as queries will become
2193     reliable at some point in the future.
2194    
2195     =cut
2196    
2197     sub cf::client::query {
2198     my ($self, $flags, $text, $cb) = @_;
2199    
2200     return unless $self->state == ST_PLAYING
2201     || $self->state == ST_SETUP
2202     || $self->state == ST_CUSTOM;
2203    
2204     $self->state (ST_CUSTOM);
2205    
2206     utf8::encode $text;
2207     push @{ $self->{query_queue} }, [(sprintf "query %d %s", $flags, $text), $cb];
2208    
2209     $self->send_packet ($self->{query_queue}[0][0])
2210     if @{ $self->{query_queue} } == 1;
2211     }
2212    
2213     cf::client->attach (
2214     on_reply => sub {
2215     my ($ns, $msg) = @_;
2216    
2217     # this weird shuffling is so that direct followup queries
2218     # get handled first
2219 root 1.128 my $queue = delete $ns->{query_queue}
2220 root 1.129 or return; # be conservative, not sure how that can happen, but we saw a crash here
2221 root 1.95
2222     (shift @$queue)->[1]->($msg);
2223 root 1.202 return unless $ns->valid; # temporary(?) workaround for callback destroying socket
2224 root 1.95
2225     push @{ $ns->{query_queue} }, @$queue;
2226    
2227     if (@{ $ns->{query_queue} } == @$queue) {
2228     if (@$queue) {
2229     $ns->send_packet ($ns->{query_queue}[0][0]);
2230     } else {
2231 root 1.98 $ns->state (ST_PLAYING) if $ns->state == ST_CUSTOM;
2232 root 1.95 }
2233     }
2234     },
2235     );
2236    
2237 root 1.140 =item $client->async (\&cb)
2238 root 1.96
2239     Create a new coroutine, running the specified callback. The coroutine will
2240     be automatically cancelled when the client gets destroyed (e.g. on logout,
2241     or loss of connection).
2242    
2243     =cut
2244    
2245 root 1.140 sub cf::client::async {
2246 root 1.96 my ($self, $cb) = @_;
2247    
2248 root 1.140 my $coro = &Coro::async ($cb);
2249 root 1.103
2250     $coro->on_destroy (sub {
2251 root 1.96 delete $self->{_coro}{$coro+0};
2252 root 1.103 });
2253 root 1.96
2254     $self->{_coro}{$coro+0} = $coro;
2255 root 1.103
2256     $coro
2257 root 1.96 }
2258    
2259     cf::client->attach (
2260     on_destroy => sub {
2261     my ($ns) = @_;
2262    
2263 root 1.97 $_->cancel for values %{ (delete $ns->{_coro}) || {} };
2264 root 1.96 },
2265     );
2266    
2267 root 1.95 =back
2268    
2269 root 1.70
2270     =head2 SAFE SCRIPTING
2271    
2272     Functions that provide a safe environment to compile and execute
2273     snippets of perl code without them endangering the safety of the server
2274     itself. Looping constructs, I/O operators and other built-in functionality
2275     is not available in the safe scripting environment, and the number of
2276 root 1.79 functions and methods that can be called is greatly reduced.
2277 root 1.70
2278     =cut
2279 root 1.23
2280 root 1.42 our $safe = new Safe "safe";
2281 root 1.23 our $safe_hole = new Safe::Hole;
2282    
2283     $SIG{FPE} = 'IGNORE';
2284    
2285     $safe->permit_only (Opcode::opset qw(:base_core :base_mem :base_orig :base_math sort time));
2286    
2287 root 1.25 # here we export the classes and methods available to script code
2288    
2289 root 1.70 =pod
2290    
2291 root 1.228 The following functions and methods are available within a safe environment:
2292 root 1.70
2293 elmex 1.91 cf::object contr pay_amount pay_player map
2294 root 1.70 cf::object::player player
2295     cf::player peaceful
2296 elmex 1.91 cf::map trigger
2297 root 1.70
2298     =cut
2299    
2300 root 1.25 for (
2301 elmex 1.91 ["cf::object" => qw(contr pay_amount pay_player map)],
2302 root 1.25 ["cf::object::player" => qw(player)],
2303     ["cf::player" => qw(peaceful)],
2304 elmex 1.91 ["cf::map" => qw(trigger)],
2305 root 1.25 ) {
2306     no strict 'refs';
2307     my ($pkg, @funs) = @$_;
2308 root 1.41 *{"safe::$pkg\::$_"} = $safe_hole->wrap (\&{"$pkg\::$_"})
2309 root 1.25 for @funs;
2310     }
2311 root 1.23
2312 root 1.70 =over 4
2313    
2314     =item @retval = safe_eval $code, [var => value, ...]
2315    
2316     Compiled and executes the given perl code snippet. additional var/value
2317     pairs result in temporary local (my) scalar variables of the given name
2318     that are available in the code snippet. Example:
2319    
2320     my $five = safe_eval '$first + $second', first => 1, second => 4;
2321    
2322     =cut
2323    
2324 root 1.23 sub safe_eval($;@) {
2325     my ($code, %vars) = @_;
2326    
2327     my $qcode = $code;
2328     $qcode =~ s/"/‟/g; # not allowed in #line filenames
2329     $qcode =~ s/\n/\\n/g;
2330    
2331     local $_;
2332 root 1.41 local @safe::cf::_safe_eval_args = values %vars;
2333 root 1.23
2334 root 1.42 my $eval =
2335 root 1.23 "do {\n"
2336     . "my (" . (join ",", map "\$$_", keys %vars) . ") = \@cf::_safe_eval_args;\n"
2337     . "#line 0 \"{$qcode}\"\n"
2338     . $code
2339     . "\n}"
2340 root 1.25 ;
2341    
2342     sub_generation_inc;
2343 root 1.42 my @res = wantarray ? $safe->reval ($eval) : scalar $safe->reval ($eval);
2344 root 1.25 sub_generation_inc;
2345    
2346 root 1.42 if ($@) {
2347     warn "$@";
2348     warn "while executing safe code '$code'\n";
2349     warn "with arguments " . (join " ", %vars) . "\n";
2350     }
2351    
2352 root 1.25 wantarray ? @res : $res[0]
2353 root 1.23 }
2354    
2355 root 1.69 =item cf::register_script_function $function => $cb
2356    
2357     Register a function that can be called from within map/npc scripts. The
2358     function should be reasonably secure and should be put into a package name
2359     like the extension.
2360    
2361     Example: register a function that gets called whenever a map script calls
2362     C<rent::overview>, as used by the C<rent> extension.
2363    
2364     cf::register_script_function "rent::overview" => sub {
2365     ...
2366     };
2367    
2368     =cut
2369    
2370 root 1.23 sub register_script_function {
2371     my ($fun, $cb) = @_;
2372    
2373     no strict 'refs';
2374 root 1.41 *{"safe::$fun"} = $safe_hole->wrap ($cb);
2375 root 1.23 }
2376    
2377 root 1.70 =back
2378    
2379 root 1.71 =cut
2380    
2381 root 1.23 #############################################################################
2382 root 1.65
2383     =head2 EXTENSION DATABASE SUPPORT
2384    
2385     Crossfire maintains a very simple database for extension use. It can
2386 root 1.250 currently store binary data only (use Compress::LZF::sfreeze_cr/sthaw to
2387     convert to/from binary).
2388 root 1.65
2389     The parameter C<$family> should best start with the name of the extension
2390     using it, it should be unique.
2391    
2392     =over 4
2393    
2394     =item $value = cf::db_get $family => $key
2395    
2396 root 1.208 Returns a single value from the database.
2397 root 1.65
2398     =item cf::db_put $family => $key => $value
2399    
2400 root 1.208 Stores the given C<$value> in the family.
2401 root 1.65
2402     =cut
2403    
2404 root 1.78 our $DB;
2405    
2406 root 1.210 sub db_init {
2407     unless ($DB) {
2408     $DB = BDB::db_create $DB_ENV;
2409 root 1.65
2410 root 1.210 cf::sync_job {
2411     eval {
2412     $DB->set_flags (BDB::CHKSUM);
2413 root 1.65
2414 root 1.210 BDB::db_open $DB, undef, "db", undef, BDB::BTREE,
2415     BDB::CREATE | BDB::AUTO_COMMIT, 0666;
2416     cf::cleanup "db_open(db): $!" if $!;
2417     };
2418     cf::cleanup "db_open(db): $@" if $@;
2419 root 1.208 };
2420 root 1.65 }
2421 root 1.208 }
2422 root 1.65
2423 root 1.208 sub db_get($$) {
2424     my $key = "$_[0]/$_[1]";
2425 root 1.65
2426 root 1.208 cf::sync_job {
2427     BDB::db_get $DB, undef, $key, my $data;
2428 root 1.65
2429 root 1.208 $! ? ()
2430 root 1.250 : $data
2431 root 1.65 }
2432 root 1.208 }
2433 root 1.65
2434 root 1.208 sub db_put($$$) {
2435     BDB::dbreq_pri 4;
2436 root 1.250 BDB::db_put $DB, undef, "$_[0]/$_[1]", $_[2], 0, sub { };
2437 root 1.65 }
2438    
2439 root 1.250 =item cf::cache $id => [$paths...], $processversion => $process
2440 root 1.249
2441     Generic caching function that returns the value of the resource $id,
2442     caching and regenerating as required.
2443    
2444     This function can block.
2445    
2446     =cut
2447    
2448     sub cache {
2449 root 1.250 my ($id, $src, $processversion, $process) = @_;
2450 root 1.249
2451 root 1.250 my $meta =
2452     join "\x00",
2453     $processversion,
2454     map {
2455     aio_stat $_
2456     and Carp::croak "$_: $!";
2457    
2458     ($_, (stat _)[7,9])
2459     } @$src;
2460    
2461     my $dbmeta = db_get cache => "$id/meta";
2462     if ($dbmeta ne $meta) {
2463     # changed, we may need to process
2464    
2465     my @data;
2466     my $md5;
2467    
2468     for (0 .. $#$src) {
2469     0 <= aio_load $src->[$_], $data[$_]
2470     or Carp::croak "$src->[$_]: $!";
2471     }
2472    
2473     # if processing is expensive, check
2474     # checksum first
2475     if (1) {
2476     $md5 =
2477     join "\x00",
2478     $processversion,
2479     map {
2480     Coro::cede;
2481     ($src->[$_], Digest::MD5::md5_hex $data[$_])
2482     } 0.. $#$src;
2483    
2484    
2485     my $dbmd5 = db_get cache => "$id/md5";
2486     if ($dbmd5 eq $md5) {
2487     db_put cache => "$id/meta", $meta;
2488    
2489     return db_get cache => "$id/data";
2490     }
2491     }
2492 root 1.249
2493 root 1.253 my $t1 = Time::HiRes::time;
2494 root 1.250 my $data = $process->(\@data);
2495 root 1.253 my $t2 = Time::HiRes::time;
2496    
2497     warn "cache: '$id' processed in ", $t2 - $t1, "s\n";
2498 root 1.249
2499 root 1.250 db_put cache => "$id/data", $data;
2500     db_put cache => "$id/md5" , $md5;
2501     db_put cache => "$id/meta", $meta;
2502 root 1.249
2503 root 1.250 return $data;
2504 root 1.249 }
2505    
2506 root 1.250 db_get cache => "$id/data"
2507     }
2508    
2509     =item fork_call { }, $args
2510    
2511     Executes the given code block with the given arguments in a seperate
2512     process, returning the results. Everything must be serialisable with
2513     Coro::Storable. May, of course, block. Note that the executed sub may
2514     never block itself or use any form of Event handling.
2515    
2516     =cut
2517    
2518     sub fork_call(&@) {
2519     my ($cb, @args) = @_;
2520    
2521     # socketpair my $fh1, my $fh2, Socket::AF_UNIX, Socket::SOCK_STREAM, Socket::PF_UNSPEC
2522     # or die "socketpair: $!";
2523     pipe my $fh1, my $fh2
2524     or die "pipe: $!";
2525    
2526     if (my $pid = fork) {
2527     close $fh2;
2528    
2529     my $res = (Coro::Handle::unblock $fh1)->readline (undef);
2530     $res = Coro::Storable::thaw $res;
2531    
2532     waitpid $pid, 0; # should not block anymore, we expect the child to simply behave
2533    
2534     die $$res unless "ARRAY" eq ref $res;
2535    
2536     return wantarray ? @$res : $res->[-1];
2537 root 1.249 } else {
2538 root 1.262 reset_signals;
2539 root 1.251 local $SIG{__WARN__};
2540 root 1.262 local $SIG{__DIE__};
2541 root 1.250 eval {
2542     close $fh1;
2543    
2544     my @res = eval { $cb->(@args) };
2545     syswrite $fh2, Coro::Storable::freeze +($@ ? \"$@" : \@res);
2546     };
2547    
2548 root 1.251 warn $@ if $@;
2549 root 1.250 _exit 0;
2550 root 1.249 }
2551 root 1.250 }
2552 root 1.249
2553 root 1.65 #############################################################################
2554 root 1.203 # the server's init and main functions
2555    
2556 root 1.246 sub load_facedata($) {
2557     my ($path) = @_;
2558 root 1.223
2559 root 1.229 warn "loading facedata from $path\n";
2560 root 1.223
2561 root 1.236 my $facedata;
2562     0 < aio_load $path, $facedata
2563 root 1.223 or die "$path: $!";
2564    
2565 root 1.237 $facedata = Coro::Storable::thaw $facedata;
2566 root 1.223
2567 root 1.236 $facedata->{version} == 2
2568 root 1.226 or cf::cleanup "$path: version mismatch, cannot proceed.";
2569    
2570 root 1.236 {
2571     my $faces = $facedata->{faceinfo};
2572    
2573     while (my ($face, $info) = each %$faces) {
2574     my $idx = (cf::face::find $face) || cf::face::alloc $face;
2575     cf::face::set $idx, $info->{visibility}, $info->{magicmap};
2576     cf::face::set_data $idx, 0, $info->{data32}, $info->{chksum32};
2577     cf::face::set_data $idx, 1, $info->{data64}, $info->{chksum64};
2578     Coro::cede;
2579     }
2580    
2581     while (my ($face, $info) = each %$faces) {
2582     next unless $info->{smooth};
2583     my $idx = cf::face::find $face
2584     or next;
2585     if (my $smooth = cf::face::find $info->{smooth}) {
2586     cf::face::set_smooth $idx, $smooth, $info->{smoothlevel};
2587     } else {
2588     warn "smooth face '$info->{smooth}' not found for face '$face'";
2589     }
2590     Coro::cede;
2591     }
2592 root 1.223 }
2593    
2594 root 1.236 {
2595     my $anims = $facedata->{animinfo};
2596    
2597     while (my ($anim, $info) = each %$anims) {
2598     cf::anim::set $anim, $info->{frames}, $info->{facings};
2599     Coro::cede;
2600 root 1.225 }
2601 root 1.236
2602     cf::anim::invalidate_all; # d'oh
2603 root 1.225 }
2604    
2605 root 1.223 1
2606     }
2607    
2608 root 1.253 sub reload_regions {
2609     load_resource_file "$MAPDIR/regions"
2610     or die "unable to load regions file\n";
2611     }
2612    
2613 root 1.246 sub reload_facedata {
2614 root 1.253 load_facedata "$DATADIR/facedata"
2615 root 1.246 or die "unable to load facedata\n";
2616     }
2617    
2618     sub reload_archetypes {
2619 root 1.253 load_resource_file "$DATADIR/archetypes"
2620 root 1.246 or die "unable to load archetypes\n";
2621 root 1.241 }
2622    
2623 root 1.246 sub reload_treasures {
2624 root 1.253 load_resource_file "$DATADIR/treasures"
2625 root 1.246 or die "unable to load treasurelists\n";
2626 root 1.241 }
2627    
2628 root 1.223 sub reload_resources {
2629 root 1.245 warn "reloading resource files...\n";
2630    
2631 root 1.246 reload_regions;
2632     reload_facedata;
2633 root 1.274 #reload_archetypes;#d#
2634 root 1.246 reload_archetypes;
2635     reload_treasures;
2636 root 1.245
2637     warn "finished reloading resource files\n";
2638 root 1.223 }
2639    
2640     sub init {
2641     reload_resources;
2642 root 1.203 }
2643 root 1.34
2644 root 1.73 sub cfg_load {
2645 root 1.253 open my $fh, "<:utf8", "$CONFDIR/config"
2646 root 1.72 or return;
2647    
2648     local $/;
2649     *CFG = YAML::Syck::Load <$fh>;
2650 root 1.131
2651     $EMERGENCY_POSITION = $CFG{emergency_position} || ["/world/world_105_115", 5, 37];
2652    
2653 root 1.139 $cf::map::MAX_RESET = $CFG{map_max_reset} if exists $CFG{map_max_reset};
2654     $cf::map::DEFAULT_RESET = $CFG{map_default_reset} if exists $CFG{map_default_reset};
2655    
2656 root 1.131 if (exists $CFG{mlockall}) {
2657     eval {
2658 root 1.147 $CFG{mlockall} ? eval "mlockall()" : eval "munlockall()"
2659 root 1.131 and die "WARNING: m(un)lockall failed: $!\n";
2660     };
2661     warn $@ if $@;
2662     }
2663 root 1.72 }
2664    
2665 root 1.39 sub main {
2666 root 1.108 # we must not ever block the main coroutine
2667     local $Coro::idle = sub {
2668 root 1.115 Carp::cluck "FATAL: Coro::idle was called, major BUG, use cf::sync_job!\n";#d#
2669 root 1.175 (async {
2670     Event::one_event;
2671     })->prio (Coro::PRIO_MAX);
2672 root 1.108 };
2673    
2674 root 1.73 cfg_load;
2675 root 1.210 db_init;
2676 root 1.61 load_extensions;
2677 root 1.183
2678     $TICK_WATCHER->start;
2679 root 1.34 Event::loop;
2680     }
2681    
2682     #############################################################################
2683 root 1.155 # initialisation and cleanup
2684    
2685     # install some emergency cleanup handlers
2686     BEGIN {
2687     for my $signal (qw(INT HUP TERM)) {
2688     Event->signal (
2689 root 1.189 reentrant => 0,
2690     data => WF_AUTOCANCEL,
2691     signal => $signal,
2692 root 1.191 prio => 0,
2693 root 1.189 cb => sub {
2694 root 1.155 cf::cleanup "SIG$signal";
2695     },
2696     );
2697     }
2698     }
2699    
2700 root 1.156 sub emergency_save() {
2701 root 1.155 my $freeze_guard = cf::freeze_mainloop;
2702    
2703     warn "enter emergency perl save\n";
2704    
2705     cf::sync_job {
2706     # use a peculiar iteration method to avoid tripping on perl
2707     # refcount bugs in for. also avoids problems with players
2708 root 1.167 # and maps saved/destroyed asynchronously.
2709 root 1.155 warn "begin emergency player save\n";
2710     for my $login (keys %cf::PLAYER) {
2711     my $pl = $cf::PLAYER{$login} or next;
2712     $pl->valid or next;
2713     $pl->save;
2714     }
2715     warn "end emergency player save\n";
2716    
2717     warn "begin emergency map save\n";
2718     for my $path (keys %cf::MAP) {
2719     my $map = $cf::MAP{$path} or next;
2720     $map->valid or next;
2721     $map->save;
2722     }
2723     warn "end emergency map save\n";
2724 root 1.208
2725     warn "begin emergency database checkpoint\n";
2726     BDB::db_env_txn_checkpoint $DB_ENV;
2727     warn "end emergency database checkpoint\n";
2728 root 1.155 };
2729    
2730     warn "leave emergency perl save\n";
2731     }
2732 root 1.22
2733 root 1.211 sub post_cleanup {
2734     my ($make_core) = @_;
2735    
2736     warn Carp::longmess "post_cleanup backtrace"
2737     if $make_core;
2738     }
2739    
2740 root 1.246 sub do_reload_perl() {
2741 root 1.106 # can/must only be called in main
2742     if ($Coro::current != $Coro::main) {
2743 root 1.183 warn "can only reload from main coroutine";
2744 root 1.106 return;
2745     }
2746    
2747 root 1.103 warn "reloading...";
2748    
2749 root 1.212 warn "entering sync_job";
2750    
2751 root 1.213 cf::sync_job {
2752 root 1.214 cf::write_runtime; # external watchdog should not bark
2753 root 1.212 cf::emergency_save;
2754 root 1.214 cf::write_runtime; # external watchdog should not bark
2755 root 1.183
2756 root 1.212 warn "syncing database to disk";
2757     BDB::db_env_txn_checkpoint $DB_ENV;
2758 root 1.106
2759     # if anything goes wrong in here, we should simply crash as we already saved
2760 root 1.65
2761 root 1.183 warn "cancelling all WF_AUTOCANCEL watchers";
2762 root 1.87 for (Event::all_watchers) {
2763     $_->cancel if $_->data & WF_AUTOCANCEL;
2764     }
2765 root 1.65
2766 root 1.183 warn "flushing outstanding aio requests";
2767     for (;;) {
2768 root 1.208 BDB::flush;
2769 root 1.183 IO::AIO::flush;
2770     Coro::cede;
2771 root 1.208 last unless IO::AIO::nreqs || BDB::nreqs;
2772 root 1.183 warn "iterate...";
2773     }
2774    
2775 root 1.223 ++$RELOAD;
2776    
2777 root 1.183 warn "cancelling all extension coros";
2778 root 1.103 $_->cancel for values %EXT_CORO;
2779     %EXT_CORO = ();
2780    
2781 root 1.183 warn "removing commands";
2782 root 1.159 %COMMAND = ();
2783    
2784 root 1.183 warn "removing ext commands";
2785 root 1.159 %EXTCMD = ();
2786    
2787 root 1.183 warn "unloading/nuking all extensions";
2788 root 1.159 for my $pkg (@EXTS) {
2789 root 1.160 warn "... unloading $pkg";
2790 root 1.159
2791     if (my $cb = $pkg->can ("unload")) {
2792     eval {
2793     $cb->($pkg);
2794     1
2795     } or warn "$pkg unloaded, but with errors: $@";
2796     }
2797    
2798 root 1.160 warn "... nuking $pkg";
2799 root 1.159 Symbol::delete_package $pkg;
2800 root 1.65 }
2801    
2802 root 1.183 warn "unloading all perl modules loaded from $LIBDIR";
2803 root 1.65 while (my ($k, $v) = each %INC) {
2804     next unless $v =~ /^\Q$LIBDIR\E\/.*\.pm$/;
2805    
2806 root 1.183 warn "... unloading $k";
2807 root 1.65 delete $INC{$k};
2808    
2809     $k =~ s/\.pm$//;
2810     $k =~ s/\//::/g;
2811    
2812     if (my $cb = $k->can ("unload_module")) {
2813     $cb->();
2814     }
2815    
2816     Symbol::delete_package $k;
2817     }
2818    
2819 root 1.183 warn "getting rid of safe::, as good as possible";
2820 root 1.65 Symbol::delete_package "safe::$_"
2821 root 1.103 for qw(cf::attachable cf::object cf::object::player cf::client cf::player cf::map cf::party cf::region);
2822 root 1.65
2823 root 1.183 warn "unloading cf.pm \"a bit\"";
2824 root 1.65 delete $INC{"cf.pm"};
2825 root 1.252 delete $INC{"cf/pod.pm"};
2826 root 1.65
2827     # don't, removes xs symbols, too,
2828     # and global variables created in xs
2829     #Symbol::delete_package __PACKAGE__;
2830    
2831 root 1.183 warn "unload completed, starting to reload now";
2832    
2833 root 1.103 warn "reloading cf.pm";
2834 root 1.65 require cf;
2835 root 1.100 cf::_connect_to_perl; # nominally unnecessary, but cannot hurt
2836    
2837 root 1.183 warn "loading config and database again";
2838 root 1.73 cf::cfg_load;
2839 root 1.65
2840 root 1.183 warn "loading extensions";
2841 root 1.65 cf::load_extensions;
2842    
2843 root 1.183 warn "reattaching attachments to objects/players";
2844 root 1.222 _global_reattach; # objects, sockets
2845 root 1.183 warn "reattaching attachments to maps";
2846 root 1.144 reattach $_ for values %MAP;
2847 root 1.222 warn "reattaching attachments to players";
2848     reattach $_ for values %PLAYER;
2849 root 1.183
2850 root 1.212 warn "leaving sync_job";
2851 root 1.183
2852 root 1.212 1
2853     } or do {
2854 root 1.106 warn $@;
2855     warn "error while reloading, exiting.";
2856     exit 1;
2857 root 1.212 };
2858 root 1.106
2859 root 1.159 warn "reloaded";
2860 root 1.65 };
2861    
2862 root 1.175 our $RELOAD_WATCHER; # used only during reload
2863    
2864 root 1.246 sub reload_perl() {
2865     # doing reload synchronously and two reloads happen back-to-back,
2866     # coro crashes during coro_state_free->destroy here.
2867    
2868     $RELOAD_WATCHER ||= Event->timer (
2869     reentrant => 0,
2870     after => 0,
2871     data => WF_AUTOCANCEL,
2872     cb => sub {
2873     do_reload_perl;
2874     undef $RELOAD_WATCHER;
2875     },
2876     );
2877     }
2878    
2879 root 1.111 register_command "reload" => sub {
2880 root 1.65 my ($who, $arg) = @_;
2881    
2882     if ($who->flag (FLAG_WIZ)) {
2883 root 1.175 $who->message ("reloading server.");
2884 root 1.246 async { reload_perl };
2885 root 1.65 }
2886     };
2887    
2888 root 1.27 unshift @INC, $LIBDIR;
2889 root 1.17
2890 root 1.183 my $bug_warning = 0;
2891    
2892 root 1.239 our @WAIT_FOR_TICK;
2893     our @WAIT_FOR_TICK_BEGIN;
2894    
2895     sub wait_for_tick {
2896 root 1.240 return unless $TICK_WATCHER->is_active;
2897 root 1.241 return if $Coro::current == $Coro::main;
2898    
2899 root 1.239 my $signal = new Coro::Signal;
2900     push @WAIT_FOR_TICK, $signal;
2901     $signal->wait;
2902     }
2903    
2904     sub wait_for_tick_begin {
2905 root 1.240 return unless $TICK_WATCHER->is_active;
2906 root 1.241 return if $Coro::current == $Coro::main;
2907    
2908 root 1.239 my $signal = new Coro::Signal;
2909     push @WAIT_FOR_TICK_BEGIN, $signal;
2910     $signal->wait;
2911     }
2912    
2913 root 1.268 my $min = 1e6;#d#
2914     my $avg = 10;
2915 root 1.35 $TICK_WATCHER = Event->timer (
2916 root 1.104 reentrant => 0,
2917 root 1.183 parked => 1,
2918 root 1.191 prio => 0,
2919 root 1.104 at => $NEXT_TICK || $TICK,
2920     data => WF_AUTOCANCEL,
2921     cb => sub {
2922 root 1.183 if ($Coro::current != $Coro::main) {
2923     Carp::cluck "major BUG: server tick called outside of main coro, skipping it"
2924     unless ++$bug_warning > 10;
2925     return;
2926     }
2927    
2928 root 1.265 $NOW = $tick_start = Event::time;
2929 root 1.163
2930 root 1.133 cf::server_tick; # one server iteration
2931 root 1.245
2932 root 1.268 0 && sync_job {#d#
2933     for(1..10) {
2934     my $t = Event::time;
2935     my $map = my $map = new_from_path cf::map "/tmp/x.map"
2936     or die;
2937    
2938     $map->width (50);
2939     $map->height (50);
2940     $map->alloc;
2941     $map->_load_objects ("/tmp/x.map", 1);
2942     my $t = Event::time - $t;
2943    
2944     #next unless $t < 0.0013;#d#
2945     if ($t < $min) {
2946     $min = $t;
2947     }
2948     $avg = $avg * 0.99 + $t * 0.01;
2949     }
2950     warn "XXXXXXXXXXXXXXXXXX min $min avg $avg\n";#d#
2951     exit 0;
2952     # 2007-05-22 02:33:04.569 min 0.00112509727478027 avg 0.0012259249572477
2953     };
2954    
2955 root 1.133 $RUNTIME += $TICK;
2956 root 1.35 $NEXT_TICK += $TICK;
2957    
2958 root 1.214 if ($NOW >= $NEXT_RUNTIME_WRITE) {
2959     $NEXT_RUNTIME_WRITE = $NOW + 10;
2960     Coro::async_pool {
2961     write_runtime
2962     or warn "ERROR: unable to write runtime file: $!";
2963     };
2964     }
2965    
2966 root 1.191 # my $AFTER = Event::time;
2967     # warn $AFTER - $NOW;#d#
2968 root 1.190
2969 root 1.245 if (my $sig = shift @WAIT_FOR_TICK_BEGIN) {
2970     $sig->send;
2971     }
2972     while (my $sig = shift @WAIT_FOR_TICK) {
2973     $sig->send;
2974     }
2975    
2976 root 1.265 $NOW = Event::time;
2977    
2978     # if we are delayed by four ticks or more, skip them all
2979     $NEXT_TICK = $NOW if $NOW >= $NEXT_TICK + $TICK * 4;
2980    
2981     $TICK_WATCHER->at ($NEXT_TICK);
2982     $TICK_WATCHER->start;
2983    
2984     $LOAD = ($NOW - $tick_start) / $TICK;
2985     $LOADAVG = $LOADAVG * 0.75 + $LOAD * 0.25;
2986    
2987 root 1.245 _post_tick;
2988 root 1.265
2989    
2990 root 1.35 },
2991     );
2992    
2993 root 1.206 {
2994     BDB::max_poll_time $TICK * 0.1;
2995     $BDB_POLL_WATCHER = Event->io (
2996     reentrant => 0,
2997     fd => BDB::poll_fileno,
2998     poll => 'r',
2999     prio => 0,
3000     data => WF_AUTOCANCEL,
3001     cb => \&BDB::poll_cb,
3002     );
3003     BDB::min_parallel 8;
3004    
3005     BDB::set_sync_prepare {
3006     my $status;
3007     my $current = $Coro::current;
3008     (
3009     sub {
3010     $status = $!;
3011     $current->ready; undef $current;
3012     },
3013     sub {
3014     Coro::schedule while defined $current;
3015     $! = $status;
3016     },
3017     )
3018     };
3019 root 1.77
3020 root 1.206 unless ($DB_ENV) {
3021     $DB_ENV = BDB::db_env_create;
3022    
3023     cf::sync_job {
3024 root 1.208 eval {
3025     BDB::db_env_open
3026     $DB_ENV,
3027 root 1.253 $BDBDIR,
3028 root 1.208 BDB::INIT_LOCK | BDB::INIT_LOG | BDB::INIT_MPOOL | BDB::INIT_TXN
3029     | BDB::RECOVER | BDB::REGISTER | BDB::USE_ENVIRON | BDB::CREATE,
3030     0666;
3031    
3032 root 1.253 cf::cleanup "db_env_open($BDBDIR): $!" if $!;
3033 root 1.208
3034     $DB_ENV->set_flags (BDB::AUTO_COMMIT | BDB::REGION_INIT | BDB::TXN_NOSYNC, 1);
3035     $DB_ENV->set_lk_detect;
3036     };
3037    
3038     cf::cleanup "db_env_open(db): $@" if $@;
3039 root 1.206 };
3040     }
3041     }
3042    
3043     {
3044     IO::AIO::min_parallel 8;
3045    
3046     undef $Coro::AIO::WATCHER;
3047     IO::AIO::max_poll_time $TICK * 0.1;
3048     $AIO_POLL_WATCHER = Event->io (
3049     reentrant => 0,
3050 root 1.214 data => WF_AUTOCANCEL,
3051 root 1.206 fd => IO::AIO::poll_fileno,
3052     poll => 'r',
3053     prio => 6,
3054     cb => \&IO::AIO::poll_cb,
3055     );
3056     }
3057 root 1.108
3058 root 1.262 my $_log_backtrace;
3059    
3060 root 1.260 sub _log_backtrace {
3061     my ($msg, @addr) = @_;
3062    
3063 root 1.262 $msg =~ s/\n//;
3064 root 1.260
3065 root 1.262 # limit the # of concurrent backtraces
3066     if ($_log_backtrace < 2) {
3067     ++$_log_backtrace;
3068     async {
3069     my @bt = fork_call {
3070     @addr = map { sprintf "%x", $_ } @addr;
3071     my $self = (-f "/proc/$$/exe") ? "/proc/$$/exe" : $^X;
3072     open my $fh, "exec addr2line -C -f -i -e \Q$self\E @addr 2>&1 |"
3073     or die "addr2line: $!";
3074    
3075     my @funcs;
3076     my @res = <$fh>;
3077     chomp for @res;
3078     while (@res) {
3079     my ($func, $line) = splice @res, 0, 2, ();
3080     push @funcs, "[$func] $line";
3081     }
3082 root 1.260
3083 root 1.262 @funcs
3084     };
3085 root 1.260
3086 root 1.262 LOG llevInfo, "[ABT] $msg\n";
3087     LOG llevInfo, "[ABT] $_\n" for @bt;
3088     --$_log_backtrace;
3089     };
3090     } else {
3091 root 1.260 LOG llevInfo, "[ABT] $msg\n";
3092 root 1.262 LOG llevInfo, "[ABT] [suppressed]\n";
3093     }
3094 root 1.260 }
3095    
3096 root 1.249 # load additional modules
3097     use cf::pod;
3098    
3099 root 1.125 END { cf::emergency_save }
3100    
3101 root 1.1 1
3102