ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/lib/cf.pm
Revision: 1.217
Committed: Thu Feb 15 21:07:49 2007 UTC (17 years, 3 months ago) by root
Branch: MAIN
Changes since 1.216: +4 -4 lines
Log Message:
- use a simpler, less fancy loader base design (basically a one-line-lookahead
  top-down parser).

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