ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/lib/cf.pm
Revision: 1.236
Committed: Thu Apr 12 14:18:05 2007 UTC (17 years, 1 month ago) by root
Branch: MAIN
Changes since 1.235: +34 -20 lines
Log Message:
move animation info into facedata and make it reloadable at runtime

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