ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/lib/cf.pm
Revision: 1.265
Committed: Fri May 11 08:00:00 2007 UTC (17 years ago) by root
Branch: MAIN
Changes since 1.264: +38 -10 lines
Log Message:
- introduce a notion of cpu load average within the server
- use it to more gracefully increase swap intervals in the map-scheduler
- add clip and lerp utility functions.

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