ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/lib/cf.pm
Revision: 1.237
Committed: Fri Apr 13 05:08:51 2007 UTC (17 years, 1 month ago) by root
Branch: MAIN
Changes since 1.236: +3 -3 lines
Log Message:
move to Coro::Storable for face loading

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