ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/lib/cf.pm
Revision: 1.268
Committed: Tue May 22 10:50:00 2007 UTC (17 years ago) by root
Branch: MAIN
Changes since 1.267: +52 -5 lines
Log Message:
- fix players frozen on movers
- allow overriding of existing spells

implement town portal:
- new fields portasl_maap|x|y for regions
- new ext town_portsla completelyx implementing it
- some debugging code, some check code

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