ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/lib/cf.pm
Revision: 1.277
Committed: Sun Jun 10 04:24:50 2007 UTC (16 years, 11 months ago) by root
Branch: MAIN
Changes since 1.276: +21 -3 lines
Log Message:
some tweaking, preload random maps now, too

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