ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/lib/cf.pm
Revision: 1.213
Committed: Tue Feb 13 20:01:04 2007 UTC (17 years, 3 months ago) by root
Branch: MAIN
Changes since 1.212: +4 -3 lines
Log Message:
do write runtime file again

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