ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/lib/cf.pm
Revision: 1.279
Committed: Mon Jun 11 22:16:53 2007 UTC (16 years, 11 months ago) by root
Branch: MAIN
Changes since 1.278: +6 -5 lines
Log Message:
add dependency handling to extension loading process (alreday checked in earlier)

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.279 $ext{meta} = { map { (split /=/, $_, 2)[0, 1] } split /\s+/, $1 }
973     if $source =~ /\A#!.*?perl.*?#\s*(.*)$/m;
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 root 1.279 for (split /,\s*/, $v->{meta}{depends}) {
990 root 1.278 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 root 1.279 : "$v->{base}: extension inactive.\n";
999 root 1.278
1000     if (exists $v->{meta}{mandatory}) {
1001     warn $msg;
1002     warn "mandatory extension failed to load, exiting.\n";
1003     exit 1;
1004     }
1005    
1006 root 1.279 warn $msg;
1007 root 1.278 }
1008    
1009     $done{$k} = delete $todo{$k};
1010     push @EXTS, $v->{pkg};
1011 root 1.279 $progress = 1;
1012 root 1.278 }
1013 root 1.1
1014 root 1.278 skip:
1015     die "cannot load " . (join ", ", keys %todo) . ": unable to resolve dependencies\n"
1016     unless $progress;
1017     }
1018     };
1019 root 1.1 }
1020    
1021 root 1.8 #############################################################################
1022 root 1.70
1023     =head2 CORE EXTENSIONS
1024    
1025     Functions and methods that extend core crossfire objects.
1026    
1027 root 1.143 =cut
1028    
1029     package cf::player;
1030    
1031 root 1.154 use Coro::AIO;
1032    
1033 root 1.95 =head3 cf::player
1034    
1035 root 1.70 =over 4
1036 root 1.22
1037 root 1.143 =item cf::player::find $login
1038 root 1.23
1039 root 1.143 Returns the given player object, loading it if necessary (might block).
1040 root 1.23
1041     =cut
1042    
1043 root 1.145 sub playerdir($) {
1044 root 1.253 "$PLAYERDIR/"
1045 root 1.145 . (ref $_[0] ? $_[0]->ob->name : $_[0])
1046     }
1047    
1048 root 1.143 sub path($) {
1049 root 1.145 my $login = ref $_[0] ? $_[0]->ob->name : $_[0];
1050    
1051 root 1.234 (playerdir $login) . "/playerdata"
1052 root 1.143 }
1053    
1054     sub find_active($) {
1055     $cf::PLAYER{$_[0]}
1056     and $cf::PLAYER{$_[0]}->active
1057     and $cf::PLAYER{$_[0]}
1058     }
1059    
1060     sub exists($) {
1061     my ($login) = @_;
1062    
1063     $cf::PLAYER{$login}
1064 root 1.180 or cf::sync_job { !aio_stat path $login }
1065 root 1.143 }
1066    
1067     sub find($) {
1068     return $cf::PLAYER{$_[0]} || do {
1069     my $login = $_[0];
1070    
1071     my $guard = cf::lock_acquire "user_find:$login";
1072    
1073 root 1.151 $cf::PLAYER{$_[0]} || do {
1074 root 1.234 # rename old playerfiles to new ones
1075     #TODO: remove when no longer required
1076     aio_link +(playerdir $login) . "/$login.pl.pst", (playerdir $login) . "/playerdata.pst";
1077     aio_link +(playerdir $login) . "/$login.pl" , (playerdir $login) . "/playerdata";
1078     aio_unlink +(playerdir $login) . "/$login.pl.pst";
1079     aio_unlink +(playerdir $login) . "/$login.pl";
1080    
1081 root 1.151 my $pl = load_pl path $login
1082     or return;
1083     $cf::PLAYER{$login} = $pl
1084     }
1085     }
1086 root 1.143 }
1087    
1088     sub save($) {
1089     my ($pl) = @_;
1090    
1091     return if $pl->{deny_save};
1092    
1093     my $path = path $pl;
1094     my $guard = cf::lock_acquire "user_save:$path";
1095    
1096     return if $pl->{deny_save};
1097 root 1.146
1098 root 1.154 aio_mkdir playerdir $pl, 0770;
1099 root 1.143 $pl->{last_save} = $cf::RUNTIME;
1100    
1101     $pl->save_pl ($path);
1102     Coro::cede;
1103     }
1104    
1105     sub new($) {
1106     my ($login) = @_;
1107    
1108     my $self = create;
1109    
1110     $self->ob->name ($login);
1111     $self->{deny_save} = 1;
1112    
1113     $cf::PLAYER{$login} = $self;
1114    
1115     $self
1116 root 1.23 }
1117    
1118 root 1.154 =item $pl->quit_character
1119    
1120     Nukes the player without looking back. If logged in, the connection will
1121     be destroyed. May block for a long time.
1122    
1123     =cut
1124    
1125 root 1.145 sub quit_character {
1126     my ($pl) = @_;
1127    
1128 root 1.220 my $name = $pl->ob->name;
1129    
1130 root 1.145 $pl->{deny_save} = 1;
1131     $pl->password ("*"); # this should lock out the player until we nuked the dir
1132    
1133     $pl->invoke (cf::EVENT_PLAYER_LOGOUT, 1) if $pl->active;
1134     $pl->deactivate;
1135     $pl->invoke (cf::EVENT_PLAYER_QUIT);
1136     $pl->ns->destroy if $pl->ns;
1137    
1138     my $path = playerdir $pl;
1139     my $temp = "$path~$cf::RUNTIME~deleting~";
1140 root 1.154 aio_rename $path, $temp;
1141 root 1.150 delete $cf::PLAYER{$pl->ob->name};
1142     $pl->destroy;
1143 root 1.220
1144     my $prefix = qr<^~\Q$name\E/>;
1145    
1146     # nuke player maps
1147     $cf::MAP{$_}->nuke for grep /$prefix/, keys %cf::MAP;
1148    
1149 root 1.150 IO::AIO::aio_rmtree $temp;
1150 root 1.145 }
1151    
1152 pippijn 1.221 =item $pl->kick
1153    
1154     Kicks a player out of the game. This destroys the connection.
1155    
1156     =cut
1157    
1158     sub kick {
1159     my ($pl, $kicker) = @_;
1160    
1161     $pl->invoke (cf::EVENT_PLAYER_KICK, $kicker);
1162     $pl->killer ("kicked");
1163     $pl->ns->destroy;
1164     }
1165    
1166 root 1.154 =item cf::player::list_logins
1167    
1168     Returns am arrayref of all valid playernames in the system, can take a
1169     while and may block, so not sync_job-capable, ever.
1170    
1171     =cut
1172    
1173     sub list_logins {
1174 root 1.253 my $dirs = aio_readdir $PLAYERDIR
1175 root 1.154 or return [];
1176    
1177     my @logins;
1178    
1179     for my $login (@$dirs) {
1180     my $fh = aio_open path $login, Fcntl::O_RDONLY, 0 or next;
1181     aio_read $fh, 0, 512, my $buf, 0 or next;
1182 root 1.155 $buf !~ /^password -------------$/m or next; # official not-valid tag
1183 root 1.154
1184     utf8::decode $login;
1185     push @logins, $login;
1186     }
1187    
1188     \@logins
1189     }
1190    
1191     =item $player->maps
1192    
1193 root 1.166 Returns an arrayref of map paths that are private for this
1194 root 1.154 player. May block.
1195    
1196     =cut
1197    
1198     sub maps($) {
1199     my ($pl) = @_;
1200    
1201 root 1.201 $pl = ref $pl ? $pl->ob->name : $pl;
1202    
1203 root 1.154 my $files = aio_readdir playerdir $pl
1204     or return;
1205    
1206     my @paths;
1207    
1208     for (@$files) {
1209     utf8::decode $_;
1210     next if /\.(?:pl|pst)$/;
1211 root 1.158 next unless /^$PATH_SEP/o;
1212 root 1.154
1213 root 1.201 push @paths, cf::map::normalise "~$pl/$_";
1214 root 1.154 }
1215    
1216     \@paths
1217     }
1218    
1219 root 1.231 =item $player->ext_reply ($msgid, %msg)
1220 root 1.95
1221     Sends an ext reply to the player.
1222    
1223     =cut
1224    
1225 root 1.231 sub ext_reply($$%) {
1226 root 1.95 my ($self, $id, %msg) = @_;
1227    
1228     $msg{msgid} = $id;
1229    
1230 root 1.143 $self->send ("ext " . cf::to_json \%msg);
1231 root 1.95 }
1232    
1233 root 1.231 =item $player->ext_event ($type, %msg)
1234    
1235     Sends an ext event to the client.
1236    
1237     =cut
1238    
1239     sub ext_event($$%) {
1240     my ($self, $type, %msg) = @_;
1241    
1242 root 1.232 $self->ns->ext_event ($type, %msg);
1243 root 1.231 }
1244    
1245 root 1.238 =head3 cf::region
1246    
1247     =over 4
1248    
1249     =cut
1250    
1251     package cf::region;
1252    
1253     =item cf::region::find_by_path $path
1254    
1255     Tries to decuce the probable region for a map knowing only its path.
1256    
1257     =cut
1258    
1259     sub find_by_path($) {
1260     my ($path) = @_;
1261    
1262     my ($match, $specificity);
1263    
1264     for my $region (list) {
1265     if ($region->match && $path =~ $region->match) {
1266     ($match, $specificity) = ($region, $region->specificity)
1267     if $region->specificity > $specificity;
1268     }
1269     }
1270    
1271     $match
1272     }
1273 root 1.143
1274 root 1.95 =back
1275    
1276 root 1.110 =head3 cf::map
1277    
1278     =over 4
1279    
1280     =cut
1281    
1282     package cf::map;
1283    
1284     use Fcntl;
1285     use Coro::AIO;
1286    
1287 root 1.166 use overload
1288 root 1.173 '""' => \&as_string,
1289     fallback => 1;
1290 root 1.166
1291 root 1.133 our $MAX_RESET = 3600;
1292     our $DEFAULT_RESET = 3000;
1293 root 1.110
1294     sub generate_random_map {
1295 root 1.166 my ($self, $rmp) = @_;
1296 root 1.110 # mit "rum" bekleckern, nicht
1297 root 1.166 $self->_create_random_map (
1298 root 1.110 $rmp->{wallstyle}, $rmp->{wall_name}, $rmp->{floorstyle}, $rmp->{monsterstyle},
1299     $rmp->{treasurestyle}, $rmp->{layoutstyle}, $rmp->{doorstyle}, $rmp->{decorstyle},
1300     $rmp->{origin_map}, $rmp->{final_map}, $rmp->{exitstyle}, $rmp->{this_map},
1301     $rmp->{exit_on_final_map},
1302     $rmp->{xsize}, $rmp->{ysize},
1303     $rmp->{expand2x}, $rmp->{layoutoptions1}, $rmp->{layoutoptions2}, $rmp->{layoutoptions3},
1304     $rmp->{symmetry}, $rmp->{difficulty}, $rmp->{difficulty_given}, $rmp->{difficulty_increase},
1305     $rmp->{dungeon_level}, $rmp->{dungeon_depth}, $rmp->{decoroptions}, $rmp->{orientation},
1306     $rmp->{origin_y}, $rmp->{origin_x}, $rmp->{random_seed}, $rmp->{total_map_hp},
1307     $rmp->{map_layout_style}, $rmp->{treasureoptions}, $rmp->{symmetry_used},
1308 root 1.162 (cf::region::find $rmp->{region}), $rmp->{custom}
1309     )
1310 root 1.110 }
1311    
1312 root 1.187 =item cf::map->register ($regex, $prio)
1313    
1314     Register a handler for the map path matching the given regex at the
1315     givne priority (higher is better, built-in handlers have priority 0, the
1316     default).
1317    
1318     =cut
1319    
1320 root 1.166 sub register {
1321 root 1.187 my (undef, $regex, $prio) = @_;
1322 root 1.166 my $pkg = caller;
1323    
1324     no strict;
1325     push @{"$pkg\::ISA"}, __PACKAGE__;
1326    
1327 root 1.187 $EXT_MAP{$pkg} = [$prio, qr<$regex>];
1328 root 1.166 }
1329    
1330     # also paths starting with '/'
1331 root 1.187 $EXT_MAP{"cf::map"} = [0, qr{^(?=/)}];
1332 root 1.166
1333 root 1.170 sub thawer_merge {
1334 root 1.172 my ($self, $merge) = @_;
1335    
1336 root 1.170 # we have to keep some variables in memory intact
1337 root 1.172 local $self->{path};
1338     local $self->{load_path};
1339 root 1.170
1340 root 1.172 $self->SUPER::thawer_merge ($merge);
1341 root 1.170 }
1342    
1343 root 1.166 sub normalise {
1344     my ($path, $base) = @_;
1345    
1346 root 1.192 $path = "$path"; # make sure its a string
1347    
1348 root 1.199 $path =~ s/\.map$//;
1349    
1350 root 1.166 # map plan:
1351     #
1352     # /! non-realised random map exit (special hack!)
1353     # {... are special paths that are not being touched
1354     # ?xxx/... are special absolute paths
1355     # ?random/... random maps
1356     # /... normal maps
1357     # ~user/... per-player map of a specific user
1358    
1359     $path =~ s/$PATH_SEP/\//go;
1360    
1361     # treat it as relative path if it starts with
1362     # something that looks reasonable
1363     if ($path =~ m{^(?:\./|\.\./|\w)}) {
1364     $base or Carp::carp "normalise called with relative path and no base: '$path'";
1365    
1366     $base =~ s{[^/]+/?$}{};
1367     $path = "$base/$path";
1368     }
1369    
1370     for ($path) {
1371     redo if s{//}{/};
1372     redo if s{/\.?/}{/};
1373     redo if s{/[^/]+/\.\./}{/};
1374     }
1375    
1376     $path
1377     }
1378    
1379     sub new_from_path {
1380     my (undef, $path, $base) = @_;
1381    
1382     return $path if UNIVERSAL::isa $path, "cf::map"; # already a map object
1383    
1384     $path = normalise $path, $base;
1385    
1386 root 1.187 for my $pkg (sort { $EXT_MAP{$b}[0] <=> $EXT_MAP{$a}[0] } keys %EXT_MAP) {
1387     if ($path =~ $EXT_MAP{$pkg}[1]) {
1388 root 1.166 my $self = bless cf::map::new, $pkg;
1389     $self->{path} = $path; $self->path ($path);
1390     $self->init; # pass $1 etc.
1391     return $self;
1392     }
1393     }
1394    
1395 root 1.192 Carp::carp "unable to resolve path '$path' (base '$base').";
1396 root 1.166 ()
1397     }
1398    
1399     sub init {
1400     my ($self) = @_;
1401    
1402     $self
1403     }
1404    
1405     sub as_string {
1406     my ($self) = @_;
1407    
1408     "$self->{path}"
1409     }
1410    
1411     # the displayed name, this is a one way mapping
1412     sub visible_name {
1413     &as_string
1414     }
1415    
1416     # the original (read-only) location
1417     sub load_path {
1418     my ($self) = @_;
1419    
1420 root 1.254 "$MAPDIR/$self->{path}.map"
1421 root 1.166 }
1422    
1423     # the temporary/swap location
1424     sub save_path {
1425     my ($self) = @_;
1426    
1427 root 1.167 (my $path = $_[0]{path}) =~ s/\//$PATH_SEP/g;
1428 root 1.254 "$TMPDIR/$path.map"
1429 root 1.166 }
1430    
1431     # the unique path, undef == no special unique path
1432     sub uniq_path {
1433     my ($self) = @_;
1434    
1435 root 1.167 (my $path = $_[0]{path}) =~ s/\//$PATH_SEP/g;
1436 root 1.253 "$UNIQUEDIR/$path"
1437 root 1.166 }
1438    
1439 root 1.110 # and all this just because we cannot iterate over
1440     # all maps in C++...
1441     sub change_all_map_light {
1442     my ($change) = @_;
1443    
1444 root 1.122 $_->change_map_light ($change)
1445     for grep $_->outdoor, values %cf::MAP;
1446 root 1.110 }
1447    
1448 root 1.275 sub decay_objects {
1449     my ($self) = @_;
1450    
1451     return if $self->{deny_reset};
1452    
1453     $self->do_decay_objects;
1454     }
1455    
1456 root 1.166 sub unlink_save {
1457     my ($self) = @_;
1458    
1459     utf8::encode (my $save = $self->save_path);
1460 root 1.170 IO::AIO::aioreq_pri 4; Coro::AIO::aio_unlink $save;
1461     IO::AIO::aioreq_pri 4; Coro::AIO::aio_unlink "$save.pst";
1462 root 1.166 }
1463    
1464     sub load_header_from($) {
1465     my ($self, $path) = @_;
1466 root 1.110
1467     utf8::encode $path;
1468 root 1.200 #aio_open $path, O_RDONLY, 0
1469     # or return;
1470 root 1.110
1471 root 1.166 $self->_load_header ($path)
1472 root 1.110 or return;
1473    
1474 root 1.166 $self->{load_path} = $path;
1475 root 1.135
1476 root 1.166 1
1477     }
1478 root 1.110
1479 root 1.188 sub load_header_orig {
1480 root 1.166 my ($self) = @_;
1481 root 1.110
1482 root 1.166 $self->load_header_from ($self->load_path)
1483 root 1.110 }
1484    
1485 root 1.188 sub load_header_temp {
1486 root 1.166 my ($self) = @_;
1487 root 1.110
1488 root 1.166 $self->load_header_from ($self->save_path)
1489     }
1490 root 1.110
1491 root 1.188 sub prepare_temp {
1492     my ($self) = @_;
1493    
1494     $self->last_access ((delete $self->{last_access})
1495     || $cf::RUNTIME); #d#
1496     # safety
1497     $self->{instantiate_time} = $cf::RUNTIME
1498     if $self->{instantiate_time} > $cf::RUNTIME;
1499     }
1500    
1501     sub prepare_orig {
1502     my ($self) = @_;
1503    
1504     $self->{load_original} = 1;
1505     $self->{instantiate_time} = $cf::RUNTIME;
1506     $self->last_access ($cf::RUNTIME);
1507     $self->instantiate;
1508     }
1509    
1510 root 1.166 sub load_header {
1511     my ($self) = @_;
1512 root 1.110
1513 root 1.188 if ($self->load_header_temp) {
1514     $self->prepare_temp;
1515 root 1.166 } else {
1516 root 1.188 $self->load_header_orig
1517 root 1.166 or return;
1518 root 1.188 $self->prepare_orig;
1519 root 1.166 }
1520 root 1.120
1521 root 1.275 $self->{deny_reset} = 1
1522     if $self->no_reset;
1523    
1524 root 1.238 $self->default_region (cf::region::find_by_path $self->{path})
1525     unless $self->default_region;
1526    
1527 root 1.166 1
1528     }
1529 root 1.110
1530 root 1.166 sub find;
1531     sub find {
1532     my ($path, $origin) = @_;
1533 root 1.134
1534 root 1.166 $path = normalise $path, $origin && $origin->path;
1535 root 1.110
1536 root 1.166 cf::lock_wait "map_find:$path";
1537 root 1.110
1538 root 1.166 $cf::MAP{$path} || do {
1539     my $guard = cf::lock_acquire "map_find:$path";
1540     my $map = new_from_path cf::map $path
1541     or return;
1542 root 1.110
1543 root 1.116 $map->{last_save} = $cf::RUNTIME;
1544 root 1.110
1545 root 1.166 $map->load_header
1546     or return;
1547 root 1.134
1548 root 1.275 if ($map->should_reset) {#d#TODO# disabled, crashy (locking issue?)
1549 root 1.185 # doing this can freeze the server in a sync job, obviously
1550     #$cf::WAIT_FOR_TICK->wait;
1551 root 1.112 $map->reset;
1552 root 1.123 undef $guard;
1553 root 1.192 return find $path;
1554 root 1.112 }
1555 root 1.110
1556 root 1.166 $cf::MAP{$path} = $map
1557 root 1.110 }
1558     }
1559    
1560 root 1.188 sub pre_load { }
1561     sub post_load { }
1562    
1563 root 1.110 sub load {
1564     my ($self) = @_;
1565    
1566 root 1.196 local $self->{deny_reset} = 1; # loading can take a long time
1567    
1568 root 1.120 my $path = $self->{path};
1569    
1570 root 1.256 {
1571     my $guard = cf::lock_acquire "map_load:$path";
1572    
1573     return if $self->in_memory != cf::MAP_SWAPPED;
1574 root 1.110
1575 root 1.256 $self->in_memory (cf::MAP_LOADING);
1576 root 1.110
1577 root 1.256 $self->alloc;
1578 root 1.188
1579 root 1.256 $self->pre_load;
1580     Coro::cede;
1581 root 1.188
1582 root 1.256 $self->_load_objects ($self->{load_path}, 1)
1583     or return;
1584 root 1.110
1585 root 1.256 $self->set_object_flag (cf::FLAG_OBJ_ORIGINAL, 1)
1586     if delete $self->{load_original};
1587 root 1.111
1588 root 1.256 if (my $uniq = $self->uniq_path) {
1589     utf8::encode $uniq;
1590     if (aio_open $uniq, O_RDONLY, 0) {
1591     $self->clear_unique_items;
1592     $self->_load_objects ($uniq, 0);
1593     }
1594 root 1.110 }
1595    
1596 root 1.166 Coro::cede;
1597 root 1.256 # now do the right thing for maps
1598     $self->link_multipart_objects;
1599 root 1.110 $self->difficulty ($self->estimate_difficulty)
1600     unless $self->difficulty;
1601 root 1.166 Coro::cede;
1602 root 1.256
1603     unless ($self->{deny_activate}) {
1604     $self->decay_objects;
1605     $self->fix_auto_apply;
1606     $self->update_buttons;
1607     Coro::cede;
1608     $self->set_darkness_map;
1609     Coro::cede;
1610     $self->activate;
1611     }
1612    
1613     $self->in_memory (cf::MAP_IN_MEMORY);
1614 root 1.110 }
1615    
1616 root 1.188 $self->post_load;
1617 root 1.166 }
1618    
1619     sub customise_for {
1620     my ($self, $ob) = @_;
1621    
1622     return find "~" . $ob->name . "/" . $self->{path}
1623     if $self->per_player;
1624 root 1.134
1625 root 1.275 # return find "?party/" . $ob->name . "/" . $self->{path}
1626     # if $self->per_party;
1627    
1628 root 1.166 $self
1629 root 1.110 }
1630    
1631 root 1.157 # find and load all maps in the 3x3 area around a map
1632     sub load_diag {
1633     my ($map) = @_;
1634    
1635     my @diag; # diagonal neighbours
1636    
1637     for (0 .. 3) {
1638     my $neigh = $map->tile_path ($_)
1639     or next;
1640     $neigh = find $neigh, $map
1641     or next;
1642     $neigh->load;
1643    
1644     push @diag, [$neigh->tile_path (($_ + 3) % 4), $neigh],
1645     [$neigh->tile_path (($_ + 1) % 4), $neigh];
1646     }
1647    
1648     for (@diag) {
1649     my $neigh = find @$_
1650     or next;
1651     $neigh->load;
1652     }
1653     }
1654    
1655 root 1.133 sub find_sync {
1656 root 1.110 my ($path, $origin) = @_;
1657    
1658 root 1.157 cf::sync_job { find $path, $origin }
1659 root 1.133 }
1660    
1661     sub do_load_sync {
1662     my ($map) = @_;
1663 root 1.110
1664 root 1.133 cf::sync_job { $map->load };
1665 root 1.110 }
1666    
1667 root 1.157 our %MAP_PREFETCH;
1668 root 1.183 our $MAP_PREFETCHER = undef;
1669 root 1.157
1670     sub find_async {
1671     my ($path, $origin) = @_;
1672    
1673 root 1.166 $path = normalise $path, $origin && $origin->{path};
1674 root 1.157
1675 root 1.166 if (my $map = $cf::MAP{$path}) {
1676 root 1.157 return $map if $map->in_memory == cf::MAP_IN_MEMORY;
1677     }
1678    
1679 root 1.183 undef $MAP_PREFETCH{$path};
1680     $MAP_PREFETCHER ||= cf::async {
1681     while (%MAP_PREFETCH) {
1682     for my $path (keys %MAP_PREFETCH) {
1683     my $map = find $path
1684     or next;
1685     $map->load;
1686    
1687     delete $MAP_PREFETCH{$path};
1688     }
1689     }
1690     undef $MAP_PREFETCHER;
1691     };
1692 root 1.189 $MAP_PREFETCHER->prio (6);
1693 root 1.157
1694     ()
1695     }
1696    
1697 root 1.110 sub save {
1698     my ($self) = @_;
1699    
1700 root 1.137 my $lock = cf::lock_acquire "map_data:" . $self->path;
1701    
1702 root 1.110 $self->{last_save} = $cf::RUNTIME;
1703    
1704     return unless $self->dirty;
1705    
1706 root 1.166 my $save = $self->save_path; utf8::encode $save;
1707     my $uniq = $self->uniq_path; utf8::encode $uniq;
1708 root 1.117
1709 root 1.110 $self->{load_path} = $save;
1710    
1711     return if $self->{deny_save};
1712    
1713 root 1.132 local $self->{last_access} = $self->last_access;#d#
1714    
1715 root 1.143 cf::async {
1716     $_->contr->save for $self->players;
1717     };
1718    
1719 root 1.110 if ($uniq) {
1720 root 1.166 $self->_save_objects ($save, cf::IO_HEADER | cf::IO_OBJECTS);
1721     $self->_save_objects ($uniq, cf::IO_UNIQUES);
1722 root 1.110 } else {
1723 root 1.166 $self->_save_objects ($save, cf::IO_HEADER | cf::IO_OBJECTS | cf::IO_UNIQUES);
1724 root 1.110 }
1725     }
1726    
1727     sub swap_out {
1728     my ($self) = @_;
1729    
1730 root 1.130 # save first because save cedes
1731     $self->save;
1732    
1733 root 1.137 my $lock = cf::lock_acquire "map_data:" . $self->path;
1734    
1735 root 1.110 return if $self->players;
1736     return if $self->in_memory != cf::MAP_IN_MEMORY;
1737     return if $self->{deny_save};
1738    
1739     $self->clear;
1740     $self->in_memory (cf::MAP_SWAPPED);
1741     }
1742    
1743 root 1.112 sub reset_at {
1744     my ($self) = @_;
1745 root 1.110
1746     # TODO: safety, remove and allow resettable per-player maps
1747 root 1.114 return 1e99 if $self->{deny_reset};
1748 root 1.110
1749 root 1.112 my $time = $self->fixed_resettime ? $self->{instantiate_time} : $self->last_access;
1750 root 1.114 my $to = List::Util::min $MAX_RESET, $self->reset_timeout || $DEFAULT_RESET;
1751 root 1.110
1752 root 1.112 $time + $to
1753     }
1754    
1755     sub should_reset {
1756     my ($self) = @_;
1757    
1758     $self->reset_at <= $cf::RUNTIME
1759 root 1.111 }
1760    
1761 root 1.110 sub reset {
1762     my ($self) = @_;
1763    
1764 root 1.167 my $lock = cf::lock_acquire "map_data:$self->{path}";
1765 root 1.137
1766 root 1.110 return if $self->players;
1767    
1768 root 1.274 warn "resetting map ", $self->path;
1769 root 1.110
1770 root 1.210 $self->in_memory (cf::MAP_SWAPPED);
1771    
1772     # need to save uniques path
1773     unless ($self->{deny_save}) {
1774     my $uniq = $self->uniq_path; utf8::encode $uniq;
1775    
1776     $self->_save_objects ($uniq, cf::IO_UNIQUES)
1777     if $uniq;
1778     }
1779    
1780 root 1.111 delete $cf::MAP{$self->path};
1781 root 1.110
1782 root 1.167 $self->clear;
1783    
1784 root 1.110 $_->clear_links_to ($self) for values %cf::MAP;
1785    
1786 root 1.166 $self->unlink_save;
1787 root 1.111 $self->destroy;
1788 root 1.110 }
1789    
1790 root 1.114 my $nuke_counter = "aaaa";
1791    
1792     sub nuke {
1793     my ($self) = @_;
1794    
1795 root 1.174 delete $cf::MAP{$self->path};
1796    
1797     $self->unlink_save;
1798    
1799     bless $self, "cf::map";
1800     delete $self->{deny_reset};
1801 root 1.114 $self->{deny_save} = 1;
1802     $self->reset_timeout (1);
1803 root 1.174 $self->path ($self->{path} = "{nuke}/" . ($nuke_counter++));
1804    
1805     $cf::MAP{$self->path} = $self;
1806    
1807 root 1.114 $self->reset; # polite request, might not happen
1808     }
1809    
1810 root 1.276 =item $maps = cf::map::tmp_maps
1811    
1812     Returns an arrayref with all map paths of currently instantiated and saved
1813 root 1.277 maps. May block.
1814 root 1.276
1815     =cut
1816    
1817     sub tmp_maps() {
1818     [
1819     map {
1820     utf8::decode $_;
1821 root 1.277 /\.map$/
1822 root 1.276 ? normalise $_
1823     : ()
1824     } @{ aio_readdir $TMPDIR or [] }
1825     ]
1826     }
1827    
1828 root 1.277 =item $maps = cf::map::random_maps
1829    
1830     Returns an arrayref with all map paths of currently instantiated and saved
1831     random maps. May block.
1832    
1833     =cut
1834    
1835     sub random_maps() {
1836     [
1837     map {
1838     utf8::decode $_;
1839     /\.map$/
1840     ? normalise "?random/$_"
1841     : ()
1842     } @{ aio_readdir $RANDOMDIR or [] }
1843     ]
1844     }
1845    
1846 root 1.158 =item cf::map::unique_maps
1847    
1848 root 1.166 Returns an arrayref of paths of all shared maps that have
1849 root 1.158 instantiated unique items. May block.
1850    
1851     =cut
1852    
1853     sub unique_maps() {
1854 root 1.276 [
1855     map {
1856     utf8::decode $_;
1857 root 1.277 /\.map$/
1858 root 1.276 ? normalise $_
1859     : ()
1860     } @{ aio_readdir $UNIQUEDIR or [] }
1861     ]
1862 root 1.158 }
1863    
1864 root 1.155 package cf;
1865    
1866     =back
1867    
1868     =head3 cf::object
1869    
1870     =cut
1871    
1872     package cf::object;
1873    
1874     =over 4
1875    
1876     =item $ob->inv_recursive
1877 root 1.110
1878 root 1.155 Returns the inventory of the object _and_ their inventories, recursively.
1879 root 1.110
1880 root 1.155 =cut
1881 root 1.144
1882 root 1.155 sub inv_recursive_;
1883     sub inv_recursive_ {
1884     map { $_, inv_recursive_ $_->inv } @_
1885     }
1886 root 1.110
1887 root 1.155 sub inv_recursive {
1888     inv_recursive_ inv $_[0]
1889 root 1.110 }
1890    
1891     package cf;
1892    
1893     =back
1894    
1895 root 1.95 =head3 cf::object::player
1896    
1897     =over 4
1898    
1899 root 1.79 =item $player_object->reply ($npc, $msg[, $flags])
1900 root 1.28
1901     Sends a message to the player, as if the npc C<$npc> replied. C<$npc>
1902     can be C<undef>. Does the right thing when the player is currently in a
1903     dialogue with the given NPC character.
1904    
1905     =cut
1906    
1907 root 1.22 # rough implementation of a future "reply" method that works
1908     # with dialog boxes.
1909 root 1.95 #TODO: the first argument must go, split into a $npc->reply_to ( method
1910 root 1.23 sub cf::object::player::reply($$$;$) {
1911     my ($self, $npc, $msg, $flags) = @_;
1912    
1913     $flags = cf::NDI_BROWN | cf::NDI_UNIQUE unless @_ >= 4;
1914 root 1.22
1915 root 1.24 if ($self->{record_replies}) {
1916     push @{ $self->{record_replies} }, [$npc, $msg, $flags];
1917     } else {
1918     $msg = $npc->name . " says: $msg" if $npc;
1919     $self->message ($msg, $flags);
1920     }
1921 root 1.22 }
1922    
1923 root 1.79 =item $player_object->may ("access")
1924    
1925     Returns wether the given player is authorized to access resource "access"
1926     (e.g. "command_wizcast").
1927    
1928     =cut
1929    
1930     sub cf::object::player::may {
1931     my ($self, $access) = @_;
1932    
1933     $self->flag (cf::FLAG_WIZ) ||
1934     (ref $cf::CFG{"may_$access"}
1935     ? scalar grep $self->name eq $_, @{$cf::CFG{"may_$access"}}
1936     : $cf::CFG{"may_$access"})
1937     }
1938 root 1.70
1939 root 1.115 =item $player_object->enter_link
1940    
1941     Freezes the player and moves him/her to a special map (C<{link}>).
1942    
1943 root 1.166 The player should be reasonably safe there for short amounts of time. You
1944 root 1.115 I<MUST> call C<leave_link> as soon as possible, though.
1945    
1946 root 1.166 Will never block.
1947    
1948 root 1.115 =item $player_object->leave_link ($map, $x, $y)
1949    
1950 root 1.166 Moves the player out of the special C<{link}> map onto the specified
1951     map. If the map is not valid (or omitted), the player will be moved back
1952     to the location he/she was before the call to C<enter_link>, or, if that
1953     fails, to the emergency map position.
1954 root 1.115
1955     Might block.
1956    
1957     =cut
1958    
1959 root 1.166 sub link_map {
1960     unless ($LINK_MAP) {
1961     $LINK_MAP = cf::map::find "{link}"
1962 root 1.196 or cf::cleanup "FATAL: unable to provide {link} map, exiting.";
1963 root 1.166 $LINK_MAP->load;
1964     }
1965    
1966     $LINK_MAP
1967     }
1968    
1969 root 1.110 sub cf::object::player::enter_link {
1970     my ($self) = @_;
1971    
1972 root 1.259 $self->deactivate_recursive;
1973 root 1.258
1974 root 1.166 return if UNIVERSAL::isa $self->map, "ext::map_link";
1975 root 1.110
1976 root 1.120 $self->{_link_pos} ||= [$self->map->{path}, $self->x, $self->y]
1977 root 1.270 if $self->map && $self->map->{path} ne "{link}";
1978 root 1.110
1979 root 1.194 $self->enter_map ($LINK_MAP || link_map, 10, 10);
1980 root 1.110 }
1981    
1982     sub cf::object::player::leave_link {
1983     my ($self, $map, $x, $y) = @_;
1984    
1985 root 1.270 return unless $self->contr->active;
1986    
1987 root 1.110 my $link_pos = delete $self->{_link_pos};
1988    
1989     unless ($map) {
1990     # restore original map position
1991     ($map, $x, $y) = @{ $link_pos || [] };
1992 root 1.133 $map = cf::map::find $map;
1993 root 1.110
1994     unless ($map) {
1995     ($map, $x, $y) = @$EMERGENCY_POSITION;
1996 root 1.133 $map = cf::map::find $map
1997 root 1.110 or die "FATAL: cannot load emergency map\n";
1998     }
1999     }
2000    
2001     ($x, $y) = (-1, -1)
2002     unless (defined $x) && (defined $y);
2003    
2004     # use -1 or undef as default coordinates, not 0, 0
2005     ($x, $y) = ($map->enter_x, $map->enter_y)
2006     if $x <=0 && $y <= 0;
2007    
2008     $map->load;
2009 root 1.157 $map->load_diag;
2010 root 1.110
2011 root 1.143 return unless $self->contr->active;
2012 root 1.110 $self->activate_recursive;
2013 root 1.215
2014     local $self->{_prev_pos} = $link_pos; # ugly hack for rent.ext
2015 root 1.110 $self->enter_map ($map, $x, $y);
2016     }
2017    
2018 root 1.268 =item $player_object->goto ($path, $x, $y[, $check->($map)])
2019    
2020     Moves the player to the given map-path and coordinates by first freezing
2021     her, loading and preparing them map, calling the provided $check callback
2022     that has to return the map if sucecssful, and then unfreezes the player on
2023     the new (success) or old (failed) map position.
2024 root 1.110
2025     =cut
2026    
2027 root 1.270 our $GOTOGEN;
2028    
2029 root 1.136 sub cf::object::player::goto {
2030 root 1.268 my ($self, $path, $x, $y, $check) = @_;
2031    
2032 root 1.270 # do generation counting so two concurrent goto's will be executed in-order
2033     my $gen = $self->{_goto_generation} = ++$GOTOGEN;
2034    
2035 root 1.110 $self->enter_link;
2036    
2037 root 1.140 (async {
2038 root 1.197 my $map = eval {
2039     my $map = cf::map::find $path;
2040 root 1.268
2041     if ($map) {
2042     $map = $map->customise_for ($self);
2043     $map = $check->($map) if $check && $map;
2044     } else {
2045     $self->message ("The exit to '$path' is closed", cf::NDI_UNIQUE | cf::NDI_RED);
2046     }
2047    
2048 root 1.197 $map
2049 root 1.268 };
2050    
2051     if ($@) {
2052     $self->message ("Something went wrong within the server, please report this incident!", cf::NDI_UNIQUE | cf::NDI_RED);
2053     LOG llevError | logBacktrace, Carp::longmess $@;
2054     }
2055 root 1.115
2056 root 1.270 if ($gen == $self->{_goto_generation}) {
2057     delete $self->{_goto_generation};
2058     $self->leave_link ($map, $x, $y);
2059     }
2060 root 1.110 })->prio (1);
2061     }
2062    
2063     =item $player_object->enter_exit ($exit_object)
2064    
2065     =cut
2066    
2067     sub parse_random_map_params {
2068     my ($spec) = @_;
2069    
2070     my $rmp = { # defaults
2071 root 1.181 xsize => (cf::rndm 15, 40),
2072     ysize => (cf::rndm 15, 40),
2073     symmetry => (cf::rndm 1, cf::SYMMETRY_XY),
2074 root 1.182 #layout => string,
2075 root 1.110 };
2076    
2077     for (split /\n/, $spec) {
2078     my ($k, $v) = split /\s+/, $_, 2;
2079    
2080     $rmp->{lc $k} = $v if (length $k) && (length $v);
2081     }
2082    
2083     $rmp
2084     }
2085    
2086     sub prepare_random_map {
2087     my ($exit) = @_;
2088    
2089 root 1.179 my $guard = cf::lock_acquire "exit_prepare:$exit";
2090    
2091 root 1.110 # all this does is basically replace the /! path by
2092     # a new random map path (?random/...) with a seed
2093     # that depends on the exit object
2094    
2095     my $rmp = parse_random_map_params $exit->msg;
2096    
2097     if ($exit->map) {
2098 root 1.198 $rmp->{region} = $exit->region->name;
2099 root 1.110 $rmp->{origin_map} = $exit->map->path;
2100     $rmp->{origin_x} = $exit->x;
2101     $rmp->{origin_y} = $exit->y;
2102     }
2103    
2104     $rmp->{random_seed} ||= $exit->random_seed;
2105    
2106     my $data = cf::to_json $rmp;
2107     my $md5 = Digest::MD5::md5_hex $data;
2108 root 1.253 my $meta = "$RANDOMDIR/$md5.meta";
2109 root 1.110
2110 root 1.177 if (my $fh = aio_open "$meta~", O_WRONLY | O_CREAT, 0666) {
2111 root 1.110 aio_write $fh, 0, (length $data), $data, 0;
2112 root 1.177 undef $fh;
2113     aio_rename "$meta~", $meta;
2114 root 1.110
2115     $exit->slaying ("?random/$md5");
2116     $exit->msg (undef);
2117     }
2118     }
2119    
2120     sub cf::object::player::enter_exit {
2121     my ($self, $exit) = @_;
2122    
2123     return unless $self->type == cf::PLAYER;
2124    
2125 root 1.195 if ($exit->slaying eq "/!") {
2126     #TODO: this should de-fi-ni-te-ly not be a sync-job
2127 root 1.233 # the problem is that $exit might not survive long enough
2128     # so it needs to be done right now, right here
2129 root 1.195 cf::sync_job { prepare_random_map $exit };
2130     }
2131    
2132     my $slaying = cf::map::normalise $exit->slaying, $exit->map && $exit->map->path;
2133     my $hp = $exit->stats->hp;
2134     my $sp = $exit->stats->sp;
2135    
2136 root 1.110 $self->enter_link;
2137    
2138 root 1.140 (async {
2139 root 1.133 $self->deactivate_recursive; # just to be sure
2140 root 1.110 unless (eval {
2141 root 1.195 $self->goto ($slaying, $hp, $sp);
2142 root 1.110
2143     1;
2144     }) {
2145     $self->message ("Something went wrong deep within the crossfire server. "
2146 root 1.233 . "I'll try to bring you back to the map you were before. "
2147     . "Please report this to the dungeon master!",
2148     cf::NDI_UNIQUE | cf::NDI_RED);
2149 root 1.110
2150     warn "ERROR in enter_exit: $@";
2151     $self->leave_link;
2152     }
2153     })->prio (1);
2154     }
2155    
2156 root 1.95 =head3 cf::client
2157    
2158     =over 4
2159    
2160     =item $client->send_drawinfo ($text, $flags)
2161    
2162     Sends a drawinfo packet to the client. Circumvents output buffering so
2163     should not be used under normal circumstances.
2164    
2165 root 1.70 =cut
2166    
2167 root 1.95 sub cf::client::send_drawinfo {
2168     my ($self, $text, $flags) = @_;
2169    
2170     utf8::encode $text;
2171 root 1.225 $self->send_packet (sprintf "drawinfo %d %s", $flags || cf::NDI_BLACK, $text);
2172 root 1.95 }
2173    
2174 root 1.232 =item $client->ext_event ($type, %msg)
2175    
2176     Sends an exti event to the client.
2177    
2178     =cut
2179    
2180     sub cf::client::ext_event($$%) {
2181     my ($self, $type, %msg) = @_;
2182    
2183     $msg{msgtype} = "event_$type";
2184     $self->send_packet ("ext " . cf::to_json \%msg);
2185     }
2186 root 1.95
2187     =item $success = $client->query ($flags, "text", \&cb)
2188    
2189     Queues a query to the client, calling the given callback with
2190     the reply text on a reply. flags can be C<cf::CS_QUERY_YESNO>,
2191     C<cf::CS_QUERY_SINGLECHAR> or C<cf::CS_QUERY_HIDEINPUT> or C<0>.
2192    
2193     Queries can fail, so check the return code. Or don't, as queries will become
2194     reliable at some point in the future.
2195    
2196     =cut
2197    
2198     sub cf::client::query {
2199     my ($self, $flags, $text, $cb) = @_;
2200    
2201     return unless $self->state == ST_PLAYING
2202     || $self->state == ST_SETUP
2203     || $self->state == ST_CUSTOM;
2204    
2205     $self->state (ST_CUSTOM);
2206    
2207     utf8::encode $text;
2208     push @{ $self->{query_queue} }, [(sprintf "query %d %s", $flags, $text), $cb];
2209    
2210     $self->send_packet ($self->{query_queue}[0][0])
2211     if @{ $self->{query_queue} } == 1;
2212     }
2213    
2214     cf::client->attach (
2215     on_reply => sub {
2216     my ($ns, $msg) = @_;
2217    
2218     # this weird shuffling is so that direct followup queries
2219     # get handled first
2220 root 1.128 my $queue = delete $ns->{query_queue}
2221 root 1.129 or return; # be conservative, not sure how that can happen, but we saw a crash here
2222 root 1.95
2223     (shift @$queue)->[1]->($msg);
2224 root 1.202 return unless $ns->valid; # temporary(?) workaround for callback destroying socket
2225 root 1.95
2226     push @{ $ns->{query_queue} }, @$queue;
2227    
2228     if (@{ $ns->{query_queue} } == @$queue) {
2229     if (@$queue) {
2230     $ns->send_packet ($ns->{query_queue}[0][0]);
2231     } else {
2232 root 1.98 $ns->state (ST_PLAYING) if $ns->state == ST_CUSTOM;
2233 root 1.95 }
2234     }
2235     },
2236     );
2237    
2238 root 1.140 =item $client->async (\&cb)
2239 root 1.96
2240     Create a new coroutine, running the specified callback. The coroutine will
2241     be automatically cancelled when the client gets destroyed (e.g. on logout,
2242     or loss of connection).
2243    
2244     =cut
2245    
2246 root 1.140 sub cf::client::async {
2247 root 1.96 my ($self, $cb) = @_;
2248    
2249 root 1.140 my $coro = &Coro::async ($cb);
2250 root 1.103
2251     $coro->on_destroy (sub {
2252 root 1.96 delete $self->{_coro}{$coro+0};
2253 root 1.103 });
2254 root 1.96
2255     $self->{_coro}{$coro+0} = $coro;
2256 root 1.103
2257     $coro
2258 root 1.96 }
2259    
2260     cf::client->attach (
2261     on_destroy => sub {
2262     my ($ns) = @_;
2263    
2264 root 1.97 $_->cancel for values %{ (delete $ns->{_coro}) || {} };
2265 root 1.96 },
2266     );
2267    
2268 root 1.95 =back
2269    
2270 root 1.70
2271     =head2 SAFE SCRIPTING
2272    
2273     Functions that provide a safe environment to compile and execute
2274     snippets of perl code without them endangering the safety of the server
2275     itself. Looping constructs, I/O operators and other built-in functionality
2276     is not available in the safe scripting environment, and the number of
2277 root 1.79 functions and methods that can be called is greatly reduced.
2278 root 1.70
2279     =cut
2280 root 1.23
2281 root 1.42 our $safe = new Safe "safe";
2282 root 1.23 our $safe_hole = new Safe::Hole;
2283    
2284     $SIG{FPE} = 'IGNORE';
2285    
2286     $safe->permit_only (Opcode::opset qw(:base_core :base_mem :base_orig :base_math sort time));
2287    
2288 root 1.25 # here we export the classes and methods available to script code
2289    
2290 root 1.70 =pod
2291    
2292 root 1.228 The following functions and methods are available within a safe environment:
2293 root 1.70
2294 elmex 1.91 cf::object contr pay_amount pay_player map
2295 root 1.70 cf::object::player player
2296     cf::player peaceful
2297 elmex 1.91 cf::map trigger
2298 root 1.70
2299     =cut
2300    
2301 root 1.25 for (
2302 elmex 1.91 ["cf::object" => qw(contr pay_amount pay_player map)],
2303 root 1.25 ["cf::object::player" => qw(player)],
2304     ["cf::player" => qw(peaceful)],
2305 elmex 1.91 ["cf::map" => qw(trigger)],
2306 root 1.25 ) {
2307     no strict 'refs';
2308     my ($pkg, @funs) = @$_;
2309 root 1.41 *{"safe::$pkg\::$_"} = $safe_hole->wrap (\&{"$pkg\::$_"})
2310 root 1.25 for @funs;
2311     }
2312 root 1.23
2313 root 1.70 =over 4
2314    
2315     =item @retval = safe_eval $code, [var => value, ...]
2316    
2317     Compiled and executes the given perl code snippet. additional var/value
2318     pairs result in temporary local (my) scalar variables of the given name
2319     that are available in the code snippet. Example:
2320    
2321     my $five = safe_eval '$first + $second', first => 1, second => 4;
2322    
2323     =cut
2324    
2325 root 1.23 sub safe_eval($;@) {
2326     my ($code, %vars) = @_;
2327    
2328     my $qcode = $code;
2329     $qcode =~ s/"/‟/g; # not allowed in #line filenames
2330     $qcode =~ s/\n/\\n/g;
2331    
2332     local $_;
2333 root 1.41 local @safe::cf::_safe_eval_args = values %vars;
2334 root 1.23
2335 root 1.42 my $eval =
2336 root 1.23 "do {\n"
2337     . "my (" . (join ",", map "\$$_", keys %vars) . ") = \@cf::_safe_eval_args;\n"
2338     . "#line 0 \"{$qcode}\"\n"
2339     . $code
2340     . "\n}"
2341 root 1.25 ;
2342    
2343     sub_generation_inc;
2344 root 1.42 my @res = wantarray ? $safe->reval ($eval) : scalar $safe->reval ($eval);
2345 root 1.25 sub_generation_inc;
2346    
2347 root 1.42 if ($@) {
2348     warn "$@";
2349     warn "while executing safe code '$code'\n";
2350     warn "with arguments " . (join " ", %vars) . "\n";
2351     }
2352    
2353 root 1.25 wantarray ? @res : $res[0]
2354 root 1.23 }
2355    
2356 root 1.69 =item cf::register_script_function $function => $cb
2357    
2358     Register a function that can be called from within map/npc scripts. The
2359     function should be reasonably secure and should be put into a package name
2360     like the extension.
2361    
2362     Example: register a function that gets called whenever a map script calls
2363     C<rent::overview>, as used by the C<rent> extension.
2364    
2365     cf::register_script_function "rent::overview" => sub {
2366     ...
2367     };
2368    
2369     =cut
2370    
2371 root 1.23 sub register_script_function {
2372     my ($fun, $cb) = @_;
2373    
2374     no strict 'refs';
2375 root 1.41 *{"safe::$fun"} = $safe_hole->wrap ($cb);
2376 root 1.23 }
2377    
2378 root 1.70 =back
2379    
2380 root 1.71 =cut
2381    
2382 root 1.23 #############################################################################
2383 root 1.65
2384     =head2 EXTENSION DATABASE SUPPORT
2385    
2386     Crossfire maintains a very simple database for extension use. It can
2387 root 1.250 currently store binary data only (use Compress::LZF::sfreeze_cr/sthaw to
2388     convert to/from binary).
2389 root 1.65
2390     The parameter C<$family> should best start with the name of the extension
2391     using it, it should be unique.
2392    
2393     =over 4
2394    
2395     =item $value = cf::db_get $family => $key
2396    
2397 root 1.208 Returns a single value from the database.
2398 root 1.65
2399     =item cf::db_put $family => $key => $value
2400    
2401 root 1.208 Stores the given C<$value> in the family.
2402 root 1.65
2403     =cut
2404    
2405 root 1.78 our $DB;
2406    
2407 root 1.210 sub db_init {
2408     unless ($DB) {
2409     $DB = BDB::db_create $DB_ENV;
2410 root 1.65
2411 root 1.210 cf::sync_job {
2412     eval {
2413     $DB->set_flags (BDB::CHKSUM);
2414 root 1.65
2415 root 1.210 BDB::db_open $DB, undef, "db", undef, BDB::BTREE,
2416     BDB::CREATE | BDB::AUTO_COMMIT, 0666;
2417     cf::cleanup "db_open(db): $!" if $!;
2418     };
2419     cf::cleanup "db_open(db): $@" if $@;
2420 root 1.208 };
2421 root 1.65 }
2422 root 1.208 }
2423 root 1.65
2424 root 1.208 sub db_get($$) {
2425     my $key = "$_[0]/$_[1]";
2426 root 1.65
2427 root 1.208 cf::sync_job {
2428     BDB::db_get $DB, undef, $key, my $data;
2429 root 1.65
2430 root 1.208 $! ? ()
2431 root 1.250 : $data
2432 root 1.65 }
2433 root 1.208 }
2434 root 1.65
2435 root 1.208 sub db_put($$$) {
2436     BDB::dbreq_pri 4;
2437 root 1.250 BDB::db_put $DB, undef, "$_[0]/$_[1]", $_[2], 0, sub { };
2438 root 1.65 }
2439    
2440 root 1.250 =item cf::cache $id => [$paths...], $processversion => $process
2441 root 1.249
2442     Generic caching function that returns the value of the resource $id,
2443     caching and regenerating as required.
2444    
2445     This function can block.
2446    
2447     =cut
2448    
2449     sub cache {
2450 root 1.250 my ($id, $src, $processversion, $process) = @_;
2451 root 1.249
2452 root 1.250 my $meta =
2453     join "\x00",
2454     $processversion,
2455     map {
2456     aio_stat $_
2457     and Carp::croak "$_: $!";
2458    
2459     ($_, (stat _)[7,9])
2460     } @$src;
2461    
2462     my $dbmeta = db_get cache => "$id/meta";
2463     if ($dbmeta ne $meta) {
2464     # changed, we may need to process
2465    
2466     my @data;
2467     my $md5;
2468    
2469     for (0 .. $#$src) {
2470     0 <= aio_load $src->[$_], $data[$_]
2471     or Carp::croak "$src->[$_]: $!";
2472     }
2473    
2474     # if processing is expensive, check
2475     # checksum first
2476     if (1) {
2477     $md5 =
2478     join "\x00",
2479     $processversion,
2480     map {
2481     Coro::cede;
2482     ($src->[$_], Digest::MD5::md5_hex $data[$_])
2483     } 0.. $#$src;
2484    
2485    
2486     my $dbmd5 = db_get cache => "$id/md5";
2487     if ($dbmd5 eq $md5) {
2488     db_put cache => "$id/meta", $meta;
2489    
2490     return db_get cache => "$id/data";
2491     }
2492     }
2493 root 1.249
2494 root 1.253 my $t1 = Time::HiRes::time;
2495 root 1.250 my $data = $process->(\@data);
2496 root 1.253 my $t2 = Time::HiRes::time;
2497    
2498     warn "cache: '$id' processed in ", $t2 - $t1, "s\n";
2499 root 1.249
2500 root 1.250 db_put cache => "$id/data", $data;
2501     db_put cache => "$id/md5" , $md5;
2502     db_put cache => "$id/meta", $meta;
2503 root 1.249
2504 root 1.250 return $data;
2505 root 1.249 }
2506    
2507 root 1.250 db_get cache => "$id/data"
2508     }
2509    
2510     =item fork_call { }, $args
2511    
2512     Executes the given code block with the given arguments in a seperate
2513     process, returning the results. Everything must be serialisable with
2514     Coro::Storable. May, of course, block. Note that the executed sub may
2515     never block itself or use any form of Event handling.
2516    
2517     =cut
2518    
2519     sub fork_call(&@) {
2520     my ($cb, @args) = @_;
2521    
2522     # socketpair my $fh1, my $fh2, Socket::AF_UNIX, Socket::SOCK_STREAM, Socket::PF_UNSPEC
2523     # or die "socketpair: $!";
2524     pipe my $fh1, my $fh2
2525     or die "pipe: $!";
2526    
2527     if (my $pid = fork) {
2528     close $fh2;
2529    
2530     my $res = (Coro::Handle::unblock $fh1)->readline (undef);
2531     $res = Coro::Storable::thaw $res;
2532    
2533     waitpid $pid, 0; # should not block anymore, we expect the child to simply behave
2534    
2535     die $$res unless "ARRAY" eq ref $res;
2536    
2537     return wantarray ? @$res : $res->[-1];
2538 root 1.249 } else {
2539 root 1.262 reset_signals;
2540 root 1.251 local $SIG{__WARN__};
2541 root 1.262 local $SIG{__DIE__};
2542 root 1.250 eval {
2543     close $fh1;
2544    
2545     my @res = eval { $cb->(@args) };
2546     syswrite $fh2, Coro::Storable::freeze +($@ ? \"$@" : \@res);
2547     };
2548    
2549 root 1.251 warn $@ if $@;
2550 root 1.250 _exit 0;
2551 root 1.249 }
2552 root 1.250 }
2553 root 1.249
2554 root 1.65 #############################################################################
2555 root 1.203 # the server's init and main functions
2556    
2557 root 1.246 sub load_facedata($) {
2558     my ($path) = @_;
2559 root 1.223
2560 root 1.229 warn "loading facedata from $path\n";
2561 root 1.223
2562 root 1.236 my $facedata;
2563     0 < aio_load $path, $facedata
2564 root 1.223 or die "$path: $!";
2565    
2566 root 1.237 $facedata = Coro::Storable::thaw $facedata;
2567 root 1.223
2568 root 1.236 $facedata->{version} == 2
2569 root 1.226 or cf::cleanup "$path: version mismatch, cannot proceed.";
2570    
2571 root 1.236 {
2572     my $faces = $facedata->{faceinfo};
2573    
2574     while (my ($face, $info) = each %$faces) {
2575     my $idx = (cf::face::find $face) || cf::face::alloc $face;
2576     cf::face::set $idx, $info->{visibility}, $info->{magicmap};
2577     cf::face::set_data $idx, 0, $info->{data32}, $info->{chksum32};
2578     cf::face::set_data $idx, 1, $info->{data64}, $info->{chksum64};
2579     Coro::cede;
2580     }
2581    
2582     while (my ($face, $info) = each %$faces) {
2583     next unless $info->{smooth};
2584     my $idx = cf::face::find $face
2585     or next;
2586     if (my $smooth = cf::face::find $info->{smooth}) {
2587     cf::face::set_smooth $idx, $smooth, $info->{smoothlevel};
2588     } else {
2589     warn "smooth face '$info->{smooth}' not found for face '$face'";
2590     }
2591     Coro::cede;
2592     }
2593 root 1.223 }
2594    
2595 root 1.236 {
2596     my $anims = $facedata->{animinfo};
2597    
2598     while (my ($anim, $info) = each %$anims) {
2599     cf::anim::set $anim, $info->{frames}, $info->{facings};
2600     Coro::cede;
2601 root 1.225 }
2602 root 1.236
2603     cf::anim::invalidate_all; # d'oh
2604 root 1.225 }
2605    
2606 root 1.223 1
2607     }
2608    
2609 root 1.253 sub reload_regions {
2610     load_resource_file "$MAPDIR/regions"
2611     or die "unable to load regions file\n";
2612     }
2613    
2614 root 1.246 sub reload_facedata {
2615 root 1.253 load_facedata "$DATADIR/facedata"
2616 root 1.246 or die "unable to load facedata\n";
2617     }
2618    
2619     sub reload_archetypes {
2620 root 1.253 load_resource_file "$DATADIR/archetypes"
2621 root 1.246 or die "unable to load archetypes\n";
2622 root 1.241 }
2623    
2624 root 1.246 sub reload_treasures {
2625 root 1.253 load_resource_file "$DATADIR/treasures"
2626 root 1.246 or die "unable to load treasurelists\n";
2627 root 1.241 }
2628    
2629 root 1.223 sub reload_resources {
2630 root 1.245 warn "reloading resource files...\n";
2631    
2632 root 1.246 reload_regions;
2633     reload_facedata;
2634 root 1.274 #reload_archetypes;#d#
2635 root 1.246 reload_archetypes;
2636     reload_treasures;
2637 root 1.245
2638     warn "finished reloading resource files\n";
2639 root 1.223 }
2640    
2641     sub init {
2642     reload_resources;
2643 root 1.203 }
2644 root 1.34
2645 root 1.73 sub cfg_load {
2646 root 1.253 open my $fh, "<:utf8", "$CONFDIR/config"
2647 root 1.72 or return;
2648    
2649     local $/;
2650     *CFG = YAML::Syck::Load <$fh>;
2651 root 1.131
2652     $EMERGENCY_POSITION = $CFG{emergency_position} || ["/world/world_105_115", 5, 37];
2653    
2654 root 1.139 $cf::map::MAX_RESET = $CFG{map_max_reset} if exists $CFG{map_max_reset};
2655     $cf::map::DEFAULT_RESET = $CFG{map_default_reset} if exists $CFG{map_default_reset};
2656    
2657 root 1.131 if (exists $CFG{mlockall}) {
2658     eval {
2659 root 1.147 $CFG{mlockall} ? eval "mlockall()" : eval "munlockall()"
2660 root 1.131 and die "WARNING: m(un)lockall failed: $!\n";
2661     };
2662     warn $@ if $@;
2663     }
2664 root 1.72 }
2665    
2666 root 1.39 sub main {
2667 root 1.108 # we must not ever block the main coroutine
2668     local $Coro::idle = sub {
2669 root 1.115 Carp::cluck "FATAL: Coro::idle was called, major BUG, use cf::sync_job!\n";#d#
2670 root 1.175 (async {
2671     Event::one_event;
2672     })->prio (Coro::PRIO_MAX);
2673 root 1.108 };
2674    
2675 root 1.73 cfg_load;
2676 root 1.210 db_init;
2677 root 1.61 load_extensions;
2678 root 1.183
2679     $TICK_WATCHER->start;
2680 root 1.34 Event::loop;
2681     }
2682    
2683     #############################################################################
2684 root 1.155 # initialisation and cleanup
2685    
2686     # install some emergency cleanup handlers
2687     BEGIN {
2688     for my $signal (qw(INT HUP TERM)) {
2689     Event->signal (
2690 root 1.189 reentrant => 0,
2691     data => WF_AUTOCANCEL,
2692     signal => $signal,
2693 root 1.191 prio => 0,
2694 root 1.189 cb => sub {
2695 root 1.155 cf::cleanup "SIG$signal";
2696     },
2697     );
2698     }
2699     }
2700    
2701 root 1.156 sub emergency_save() {
2702 root 1.155 my $freeze_guard = cf::freeze_mainloop;
2703    
2704     warn "enter emergency perl save\n";
2705    
2706     cf::sync_job {
2707     # use a peculiar iteration method to avoid tripping on perl
2708     # refcount bugs in for. also avoids problems with players
2709 root 1.167 # and maps saved/destroyed asynchronously.
2710 root 1.155 warn "begin emergency player save\n";
2711     for my $login (keys %cf::PLAYER) {
2712     my $pl = $cf::PLAYER{$login} or next;
2713     $pl->valid or next;
2714     $pl->save;
2715     }
2716     warn "end emergency player save\n";
2717    
2718     warn "begin emergency map save\n";
2719     for my $path (keys %cf::MAP) {
2720     my $map = $cf::MAP{$path} or next;
2721     $map->valid or next;
2722     $map->save;
2723     }
2724     warn "end emergency map save\n";
2725 root 1.208
2726     warn "begin emergency database checkpoint\n";
2727     BDB::db_env_txn_checkpoint $DB_ENV;
2728     warn "end emergency database checkpoint\n";
2729 root 1.155 };
2730    
2731     warn "leave emergency perl save\n";
2732     }
2733 root 1.22
2734 root 1.211 sub post_cleanup {
2735     my ($make_core) = @_;
2736    
2737     warn Carp::longmess "post_cleanup backtrace"
2738     if $make_core;
2739     }
2740    
2741 root 1.246 sub do_reload_perl() {
2742 root 1.106 # can/must only be called in main
2743     if ($Coro::current != $Coro::main) {
2744 root 1.183 warn "can only reload from main coroutine";
2745 root 1.106 return;
2746     }
2747    
2748 root 1.103 warn "reloading...";
2749    
2750 root 1.212 warn "entering sync_job";
2751    
2752 root 1.213 cf::sync_job {
2753 root 1.214 cf::write_runtime; # external watchdog should not bark
2754 root 1.212 cf::emergency_save;
2755 root 1.214 cf::write_runtime; # external watchdog should not bark
2756 root 1.183
2757 root 1.212 warn "syncing database to disk";
2758     BDB::db_env_txn_checkpoint $DB_ENV;
2759 root 1.106
2760     # if anything goes wrong in here, we should simply crash as we already saved
2761 root 1.65
2762 root 1.183 warn "cancelling all WF_AUTOCANCEL watchers";
2763 root 1.87 for (Event::all_watchers) {
2764     $_->cancel if $_->data & WF_AUTOCANCEL;
2765     }
2766 root 1.65
2767 root 1.183 warn "flushing outstanding aio requests";
2768     for (;;) {
2769 root 1.208 BDB::flush;
2770 root 1.183 IO::AIO::flush;
2771     Coro::cede;
2772 root 1.208 last unless IO::AIO::nreqs || BDB::nreqs;
2773 root 1.183 warn "iterate...";
2774     }
2775    
2776 root 1.223 ++$RELOAD;
2777    
2778 root 1.183 warn "cancelling all extension coros";
2779 root 1.103 $_->cancel for values %EXT_CORO;
2780     %EXT_CORO = ();
2781    
2782 root 1.183 warn "removing commands";
2783 root 1.159 %COMMAND = ();
2784    
2785 root 1.183 warn "removing ext commands";
2786 root 1.159 %EXTCMD = ();
2787    
2788 root 1.183 warn "unloading/nuking all extensions";
2789 root 1.159 for my $pkg (@EXTS) {
2790 root 1.160 warn "... unloading $pkg";
2791 root 1.159
2792     if (my $cb = $pkg->can ("unload")) {
2793     eval {
2794     $cb->($pkg);
2795     1
2796     } or warn "$pkg unloaded, but with errors: $@";
2797     }
2798    
2799 root 1.160 warn "... nuking $pkg";
2800 root 1.159 Symbol::delete_package $pkg;
2801 root 1.65 }
2802    
2803 root 1.183 warn "unloading all perl modules loaded from $LIBDIR";
2804 root 1.65 while (my ($k, $v) = each %INC) {
2805     next unless $v =~ /^\Q$LIBDIR\E\/.*\.pm$/;
2806    
2807 root 1.183 warn "... unloading $k";
2808 root 1.65 delete $INC{$k};
2809    
2810     $k =~ s/\.pm$//;
2811     $k =~ s/\//::/g;
2812    
2813     if (my $cb = $k->can ("unload_module")) {
2814     $cb->();
2815     }
2816    
2817     Symbol::delete_package $k;
2818     }
2819    
2820 root 1.183 warn "getting rid of safe::, as good as possible";
2821 root 1.65 Symbol::delete_package "safe::$_"
2822 root 1.103 for qw(cf::attachable cf::object cf::object::player cf::client cf::player cf::map cf::party cf::region);
2823 root 1.65
2824 root 1.183 warn "unloading cf.pm \"a bit\"";
2825 root 1.65 delete $INC{"cf.pm"};
2826 root 1.252 delete $INC{"cf/pod.pm"};
2827 root 1.65
2828     # don't, removes xs symbols, too,
2829     # and global variables created in xs
2830     #Symbol::delete_package __PACKAGE__;
2831    
2832 root 1.183 warn "unload completed, starting to reload now";
2833    
2834 root 1.103 warn "reloading cf.pm";
2835 root 1.65 require cf;
2836 root 1.100 cf::_connect_to_perl; # nominally unnecessary, but cannot hurt
2837    
2838 root 1.183 warn "loading config and database again";
2839 root 1.73 cf::cfg_load;
2840 root 1.65
2841 root 1.183 warn "loading extensions";
2842 root 1.65 cf::load_extensions;
2843    
2844 root 1.183 warn "reattaching attachments to objects/players";
2845 root 1.222 _global_reattach; # objects, sockets
2846 root 1.183 warn "reattaching attachments to maps";
2847 root 1.144 reattach $_ for values %MAP;
2848 root 1.222 warn "reattaching attachments to players";
2849     reattach $_ for values %PLAYER;
2850 root 1.183
2851 root 1.212 warn "leaving sync_job";
2852 root 1.183
2853 root 1.212 1
2854     } or do {
2855 root 1.106 warn $@;
2856     warn "error while reloading, exiting.";
2857     exit 1;
2858 root 1.212 };
2859 root 1.106
2860 root 1.159 warn "reloaded";
2861 root 1.65 };
2862    
2863 root 1.175 our $RELOAD_WATCHER; # used only during reload
2864    
2865 root 1.246 sub reload_perl() {
2866     # doing reload synchronously and two reloads happen back-to-back,
2867     # coro crashes during coro_state_free->destroy here.
2868    
2869     $RELOAD_WATCHER ||= Event->timer (
2870     reentrant => 0,
2871     after => 0,
2872     data => WF_AUTOCANCEL,
2873     cb => sub {
2874     do_reload_perl;
2875     undef $RELOAD_WATCHER;
2876     },
2877     );
2878     }
2879    
2880 root 1.111 register_command "reload" => sub {
2881 root 1.65 my ($who, $arg) = @_;
2882    
2883     if ($who->flag (FLAG_WIZ)) {
2884 root 1.175 $who->message ("reloading server.");
2885 root 1.246 async { reload_perl };
2886 root 1.65 }
2887     };
2888    
2889 root 1.27 unshift @INC, $LIBDIR;
2890 root 1.17
2891 root 1.183 my $bug_warning = 0;
2892    
2893 root 1.239 our @WAIT_FOR_TICK;
2894     our @WAIT_FOR_TICK_BEGIN;
2895    
2896     sub wait_for_tick {
2897 root 1.240 return unless $TICK_WATCHER->is_active;
2898 root 1.241 return if $Coro::current == $Coro::main;
2899    
2900 root 1.239 my $signal = new Coro::Signal;
2901     push @WAIT_FOR_TICK, $signal;
2902     $signal->wait;
2903     }
2904    
2905     sub wait_for_tick_begin {
2906 root 1.240 return unless $TICK_WATCHER->is_active;
2907 root 1.241 return if $Coro::current == $Coro::main;
2908    
2909 root 1.239 my $signal = new Coro::Signal;
2910     push @WAIT_FOR_TICK_BEGIN, $signal;
2911     $signal->wait;
2912     }
2913    
2914 root 1.268 my $min = 1e6;#d#
2915     my $avg = 10;
2916 root 1.35 $TICK_WATCHER = Event->timer (
2917 root 1.104 reentrant => 0,
2918 root 1.183 parked => 1,
2919 root 1.191 prio => 0,
2920 root 1.104 at => $NEXT_TICK || $TICK,
2921     data => WF_AUTOCANCEL,
2922     cb => sub {
2923 root 1.183 if ($Coro::current != $Coro::main) {
2924     Carp::cluck "major BUG: server tick called outside of main coro, skipping it"
2925     unless ++$bug_warning > 10;
2926     return;
2927     }
2928    
2929 root 1.265 $NOW = $tick_start = Event::time;
2930 root 1.163
2931 root 1.133 cf::server_tick; # one server iteration
2932 root 1.245
2933 root 1.268 0 && sync_job {#d#
2934     for(1..10) {
2935     my $t = Event::time;
2936     my $map = my $map = new_from_path cf::map "/tmp/x.map"
2937     or die;
2938    
2939     $map->width (50);
2940     $map->height (50);
2941     $map->alloc;
2942     $map->_load_objects ("/tmp/x.map", 1);
2943     my $t = Event::time - $t;
2944    
2945     #next unless $t < 0.0013;#d#
2946     if ($t < $min) {
2947     $min = $t;
2948     }
2949     $avg = $avg * 0.99 + $t * 0.01;
2950     }
2951     warn "XXXXXXXXXXXXXXXXXX min $min avg $avg\n";#d#
2952     exit 0;
2953     # 2007-05-22 02:33:04.569 min 0.00112509727478027 avg 0.0012259249572477
2954     };
2955    
2956 root 1.133 $RUNTIME += $TICK;
2957 root 1.35 $NEXT_TICK += $TICK;
2958    
2959 root 1.214 if ($NOW >= $NEXT_RUNTIME_WRITE) {
2960     $NEXT_RUNTIME_WRITE = $NOW + 10;
2961     Coro::async_pool {
2962     write_runtime
2963     or warn "ERROR: unable to write runtime file: $!";
2964     };
2965     }
2966    
2967 root 1.191 # my $AFTER = Event::time;
2968     # warn $AFTER - $NOW;#d#
2969 root 1.190
2970 root 1.245 if (my $sig = shift @WAIT_FOR_TICK_BEGIN) {
2971     $sig->send;
2972     }
2973     while (my $sig = shift @WAIT_FOR_TICK) {
2974     $sig->send;
2975     }
2976    
2977 root 1.265 $NOW = Event::time;
2978    
2979     # if we are delayed by four ticks or more, skip them all
2980     $NEXT_TICK = $NOW if $NOW >= $NEXT_TICK + $TICK * 4;
2981    
2982     $TICK_WATCHER->at ($NEXT_TICK);
2983     $TICK_WATCHER->start;
2984    
2985     $LOAD = ($NOW - $tick_start) / $TICK;
2986     $LOADAVG = $LOADAVG * 0.75 + $LOAD * 0.25;
2987    
2988 root 1.245 _post_tick;
2989 root 1.265
2990    
2991 root 1.35 },
2992     );
2993    
2994 root 1.206 {
2995     BDB::max_poll_time $TICK * 0.1;
2996     $BDB_POLL_WATCHER = Event->io (
2997     reentrant => 0,
2998     fd => BDB::poll_fileno,
2999     poll => 'r',
3000     prio => 0,
3001     data => WF_AUTOCANCEL,
3002     cb => \&BDB::poll_cb,
3003     );
3004     BDB::min_parallel 8;
3005    
3006     BDB::set_sync_prepare {
3007     my $status;
3008     my $current = $Coro::current;
3009     (
3010     sub {
3011     $status = $!;
3012     $current->ready; undef $current;
3013     },
3014     sub {
3015     Coro::schedule while defined $current;
3016     $! = $status;
3017     },
3018     )
3019     };
3020 root 1.77
3021 root 1.206 unless ($DB_ENV) {
3022     $DB_ENV = BDB::db_env_create;
3023    
3024     cf::sync_job {
3025 root 1.208 eval {
3026     BDB::db_env_open
3027     $DB_ENV,
3028 root 1.253 $BDBDIR,
3029 root 1.208 BDB::INIT_LOCK | BDB::INIT_LOG | BDB::INIT_MPOOL | BDB::INIT_TXN
3030     | BDB::RECOVER | BDB::REGISTER | BDB::USE_ENVIRON | BDB::CREATE,
3031     0666;
3032    
3033 root 1.253 cf::cleanup "db_env_open($BDBDIR): $!" if $!;
3034 root 1.208
3035     $DB_ENV->set_flags (BDB::AUTO_COMMIT | BDB::REGION_INIT | BDB::TXN_NOSYNC, 1);
3036     $DB_ENV->set_lk_detect;
3037     };
3038    
3039     cf::cleanup "db_env_open(db): $@" if $@;
3040 root 1.206 };
3041     }
3042     }
3043    
3044     {
3045     IO::AIO::min_parallel 8;
3046    
3047     undef $Coro::AIO::WATCHER;
3048     IO::AIO::max_poll_time $TICK * 0.1;
3049     $AIO_POLL_WATCHER = Event->io (
3050     reentrant => 0,
3051 root 1.214 data => WF_AUTOCANCEL,
3052 root 1.206 fd => IO::AIO::poll_fileno,
3053     poll => 'r',
3054     prio => 6,
3055     cb => \&IO::AIO::poll_cb,
3056     );
3057     }
3058 root 1.108
3059 root 1.262 my $_log_backtrace;
3060    
3061 root 1.260 sub _log_backtrace {
3062     my ($msg, @addr) = @_;
3063    
3064 root 1.262 $msg =~ s/\n//;
3065 root 1.260
3066 root 1.262 # limit the # of concurrent backtraces
3067     if ($_log_backtrace < 2) {
3068     ++$_log_backtrace;
3069     async {
3070     my @bt = fork_call {
3071     @addr = map { sprintf "%x", $_ } @addr;
3072     my $self = (-f "/proc/$$/exe") ? "/proc/$$/exe" : $^X;
3073     open my $fh, "exec addr2line -C -f -i -e \Q$self\E @addr 2>&1 |"
3074     or die "addr2line: $!";
3075    
3076     my @funcs;
3077     my @res = <$fh>;
3078     chomp for @res;
3079     while (@res) {
3080     my ($func, $line) = splice @res, 0, 2, ();
3081     push @funcs, "[$func] $line";
3082     }
3083 root 1.260
3084 root 1.262 @funcs
3085     };
3086 root 1.260
3087 root 1.262 LOG llevInfo, "[ABT] $msg\n";
3088     LOG llevInfo, "[ABT] $_\n" for @bt;
3089     --$_log_backtrace;
3090     };
3091     } else {
3092 root 1.260 LOG llevInfo, "[ABT] $msg\n";
3093 root 1.262 LOG llevInfo, "[ABT] [suppressed]\n";
3094     }
3095 root 1.260 }
3096    
3097 root 1.249 # load additional modules
3098     use cf::pod;
3099    
3100 root 1.125 END { cf::emergency_save }
3101    
3102 root 1.1 1
3103