ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/lib/cf.pm
Revision: 1.219
Committed: Sat Feb 17 03:19:44 2007 UTC (17 years, 4 months ago) by root
Branch: MAIN
Changes since 1.218: +2 -0 lines
Log Message:
*** empty log message ***

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 root 1.219 my $guard = cf::lock_acquire "write_runtime";
360    
361 root 1.108 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.45 }
793     }
794    
795 root 1.80 sub object_freezer_as_string {
796     my ($rdata, $objs) = @_;
797    
798     use Data::Dumper;
799    
800 root 1.81 $$rdata . Dumper $objs
801 root 1.80 }
802    
803 root 1.46 sub object_thawer_load {
804     my ($filename) = @_;
805    
806 root 1.105 my ($data, $av);
807 root 1.61
808 root 1.105 (aio_load $filename, $data) >= 0
809     or return;
810 root 1.61
811 root 1.105 unless (aio_stat "$filename.pst") {
812     (aio_load "$filename.pst", $av) >= 0
813     or return;
814 root 1.113 $av = eval { (Storable::thaw $av)->{objs} };
815 root 1.61 }
816 root 1.45
817 root 1.118 warn sprintf "loading %s (%d)\n",
818     $filename, length $data, scalar @{$av || []};#d#
819 root 1.105 return ($data, $av);
820 root 1.45 }
821    
822     #############################################################################
823 root 1.85 # command handling &c
824 root 1.39
825 root 1.85 =item cf::register_command $name => \&callback($ob,$args);
826 root 1.1
827 root 1.85 Register a callback for execution when the client sends the user command
828     $name.
829 root 1.5
830 root 1.85 =cut
831 root 1.5
832 root 1.85 sub register_command {
833     my ($name, $cb) = @_;
834 root 1.5
835 root 1.85 my $caller = caller;
836     #warn "registering command '$name/$time' to '$caller'";
837 root 1.1
838 root 1.85 push @{ $COMMAND{$name} }, [$caller, $cb];
839 root 1.1 }
840    
841 root 1.85 =item cf::register_extcmd $name => \&callback($pl,$packet);
842 root 1.1
843 root 1.85 Register a callbackf ro execution when the client sends an extcmd packet.
844 root 1.1
845 root 1.85 If the callback returns something, it is sent back as if reply was being
846     called.
847 root 1.1
848 root 1.85 =cut
849 root 1.1
850 root 1.16 sub register_extcmd {
851     my ($name, $cb) = @_;
852    
853 root 1.159 $EXTCMD{$name} = $cb;
854 root 1.16 }
855    
856 root 1.93 cf::player->attach (
857 root 1.85 on_command => sub {
858     my ($pl, $name, $params) = @_;
859    
860     my $cb = $COMMAND{$name}
861     or return;
862    
863     for my $cmd (@$cb) {
864     $cmd->[1]->($pl->ob, $params);
865     }
866    
867     cf::override;
868     },
869     on_extcmd => sub {
870     my ($pl, $buf) = @_;
871    
872     my $msg = eval { from_json $buf };
873    
874     if (ref $msg) {
875     if (my $cb = $EXTCMD{$msg->{msgtype}}) {
876 root 1.159 if (my %reply = $cb->($pl, $msg)) {
877 root 1.85 $pl->ext_reply ($msg->{msgid}, %reply);
878     }
879     }
880     } else {
881     warn "player " . ($pl->ob->name) . " sent unparseable ext message: <$buf>\n";
882     }
883    
884     cf::override;
885     },
886 root 1.93 );
887 root 1.85
888 root 1.1 sub load_extension {
889     my ($path) = @_;
890    
891     $path =~ /([^\/\\]+)\.ext$/ or die "$path";
892 root 1.5 my $base = $1;
893 root 1.1 my $pkg = $1;
894     $pkg =~ s/[^[:word:]]/_/g;
895 root 1.41 $pkg = "ext::$pkg";
896 root 1.1
897 root 1.160 warn "... loading '$path' into '$pkg'\n";
898 root 1.1
899     open my $fh, "<:utf8", $path
900     or die "$path: $!";
901    
902     my $source =
903     "package $pkg; use strict; use utf8;\n"
904     . "#line 1 \"$path\"\n{\n"
905     . (do { local $/; <$fh> })
906     . "\n};\n1";
907    
908 root 1.166 unless (eval $source) {
909     my $msg = $@ ? "$path: $@\n"
910     : "extension disabled.\n";
911     if ($source =~ /^#!.*perl.*#.*MANDATORY/m) { # ugly match
912     warn $@;
913     warn "mandatory extension failed to load, exiting.\n";
914     exit 1;
915     }
916     die $@;
917     }
918 root 1.1
919 root 1.159 push @EXTS, $pkg;
920 root 1.1 }
921    
922     sub load_extensions {
923     for my $ext (<$LIBDIR/*.ext>) {
924 root 1.3 next unless -r $ext;
925 root 1.2 eval {
926     load_extension $ext;
927     1
928     } or warn "$ext not loaded: $@";
929 root 1.1 }
930     }
931    
932 root 1.8 #############################################################################
933 root 1.70
934     =head2 CORE EXTENSIONS
935    
936     Functions and methods that extend core crossfire objects.
937    
938 root 1.143 =cut
939    
940     package cf::player;
941    
942 root 1.154 use Coro::AIO;
943    
944 root 1.95 =head3 cf::player
945    
946 root 1.70 =over 4
947 root 1.22
948 root 1.143 =item cf::player::find $login
949 root 1.23
950 root 1.143 Returns the given player object, loading it if necessary (might block).
951 root 1.23
952     =cut
953    
954 root 1.145 sub playerdir($) {
955     cf::localdir
956     . "/"
957     . cf::playerdir
958     . "/"
959     . (ref $_[0] ? $_[0]->ob->name : $_[0])
960     }
961    
962 root 1.143 sub path($) {
963 root 1.145 my $login = ref $_[0] ? $_[0]->ob->name : $_[0];
964    
965     (playerdir $login) . "/$login.pl"
966 root 1.143 }
967    
968     sub find_active($) {
969     $cf::PLAYER{$_[0]}
970     and $cf::PLAYER{$_[0]}->active
971     and $cf::PLAYER{$_[0]}
972     }
973    
974     sub exists($) {
975     my ($login) = @_;
976    
977     $cf::PLAYER{$login}
978 root 1.180 or cf::sync_job { !aio_stat path $login }
979 root 1.143 }
980    
981     sub find($) {
982     return $cf::PLAYER{$_[0]} || do {
983     my $login = $_[0];
984    
985     my $guard = cf::lock_acquire "user_find:$login";
986    
987 root 1.151 $cf::PLAYER{$_[0]} || do {
988     my $pl = load_pl path $login
989     or return;
990     $cf::PLAYER{$login} = $pl
991     }
992     }
993 root 1.143 }
994    
995     sub save($) {
996     my ($pl) = @_;
997    
998     return if $pl->{deny_save};
999    
1000     my $path = path $pl;
1001     my $guard = cf::lock_acquire "user_save:$path";
1002    
1003     return if $pl->{deny_save};
1004 root 1.146
1005 root 1.154 aio_mkdir playerdir $pl, 0770;
1006 root 1.143 $pl->{last_save} = $cf::RUNTIME;
1007    
1008     $pl->save_pl ($path);
1009     Coro::cede;
1010     }
1011    
1012     sub new($) {
1013     my ($login) = @_;
1014    
1015     my $self = create;
1016    
1017     $self->ob->name ($login);
1018     $self->{deny_save} = 1;
1019    
1020     $cf::PLAYER{$login} = $self;
1021    
1022     $self
1023 root 1.23 }
1024    
1025 root 1.154 =item $pl->quit_character
1026    
1027     Nukes the player without looking back. If logged in, the connection will
1028     be destroyed. May block for a long time.
1029    
1030     =cut
1031    
1032 root 1.145 sub quit_character {
1033     my ($pl) = @_;
1034    
1035     $pl->{deny_save} = 1;
1036     $pl->password ("*"); # this should lock out the player until we nuked the dir
1037    
1038     $pl->invoke (cf::EVENT_PLAYER_LOGOUT, 1) if $pl->active;
1039     $pl->deactivate;
1040     $pl->invoke (cf::EVENT_PLAYER_QUIT);
1041     $pl->ns->destroy if $pl->ns;
1042    
1043     my $path = playerdir $pl;
1044     my $temp = "$path~$cf::RUNTIME~deleting~";
1045 root 1.154 aio_rename $path, $temp;
1046 root 1.150 delete $cf::PLAYER{$pl->ob->name};
1047     $pl->destroy;
1048     IO::AIO::aio_rmtree $temp;
1049 root 1.145 }
1050    
1051 root 1.154 =item cf::player::list_logins
1052    
1053     Returns am arrayref of all valid playernames in the system, can take a
1054     while and may block, so not sync_job-capable, ever.
1055    
1056     =cut
1057    
1058     sub list_logins {
1059     my $dirs = aio_readdir cf::localdir . "/" . cf::playerdir
1060     or return [];
1061    
1062     my @logins;
1063    
1064     for my $login (@$dirs) {
1065     my $fh = aio_open path $login, Fcntl::O_RDONLY, 0 or next;
1066     aio_read $fh, 0, 512, my $buf, 0 or next;
1067 root 1.155 $buf !~ /^password -------------$/m or next; # official not-valid tag
1068 root 1.154
1069     utf8::decode $login;
1070     push @logins, $login;
1071     }
1072    
1073     \@logins
1074     }
1075    
1076     =item $player->maps
1077    
1078 root 1.166 Returns an arrayref of map paths that are private for this
1079 root 1.154 player. May block.
1080    
1081     =cut
1082    
1083     sub maps($) {
1084     my ($pl) = @_;
1085    
1086 root 1.201 $pl = ref $pl ? $pl->ob->name : $pl;
1087    
1088 root 1.154 my $files = aio_readdir playerdir $pl
1089     or return;
1090    
1091     my @paths;
1092    
1093     for (@$files) {
1094     utf8::decode $_;
1095     next if /\.(?:pl|pst)$/;
1096 root 1.158 next unless /^$PATH_SEP/o;
1097 root 1.154
1098 root 1.201 push @paths, cf::map::normalise "~$pl/$_";
1099 root 1.154 }
1100    
1101     \@paths
1102     }
1103    
1104 root 1.95 =item $player->ext_reply ($msgid, $msgtype, %msg)
1105    
1106     Sends an ext reply to the player.
1107    
1108     =cut
1109    
1110 root 1.143 sub ext_reply($$$%) {
1111 root 1.95 my ($self, $id, %msg) = @_;
1112    
1113     $msg{msgid} = $id;
1114    
1115 root 1.143 $self->send ("ext " . cf::to_json \%msg);
1116 root 1.95 }
1117    
1118 root 1.143 package cf;
1119    
1120 root 1.95 =back
1121    
1122 root 1.110
1123     =head3 cf::map
1124    
1125     =over 4
1126    
1127     =cut
1128    
1129     package cf::map;
1130    
1131     use Fcntl;
1132     use Coro::AIO;
1133    
1134 root 1.166 use overload
1135 root 1.173 '""' => \&as_string,
1136     fallback => 1;
1137 root 1.166
1138 root 1.133 our $MAX_RESET = 3600;
1139     our $DEFAULT_RESET = 3000;
1140 root 1.110
1141     sub generate_random_map {
1142 root 1.166 my ($self, $rmp) = @_;
1143 root 1.110 # mit "rum" bekleckern, nicht
1144 root 1.166 $self->_create_random_map (
1145 root 1.110 $rmp->{wallstyle}, $rmp->{wall_name}, $rmp->{floorstyle}, $rmp->{monsterstyle},
1146     $rmp->{treasurestyle}, $rmp->{layoutstyle}, $rmp->{doorstyle}, $rmp->{decorstyle},
1147     $rmp->{origin_map}, $rmp->{final_map}, $rmp->{exitstyle}, $rmp->{this_map},
1148     $rmp->{exit_on_final_map},
1149     $rmp->{xsize}, $rmp->{ysize},
1150     $rmp->{expand2x}, $rmp->{layoutoptions1}, $rmp->{layoutoptions2}, $rmp->{layoutoptions3},
1151     $rmp->{symmetry}, $rmp->{difficulty}, $rmp->{difficulty_given}, $rmp->{difficulty_increase},
1152     $rmp->{dungeon_level}, $rmp->{dungeon_depth}, $rmp->{decoroptions}, $rmp->{orientation},
1153     $rmp->{origin_y}, $rmp->{origin_x}, $rmp->{random_seed}, $rmp->{total_map_hp},
1154     $rmp->{map_layout_style}, $rmp->{treasureoptions}, $rmp->{symmetry_used},
1155 root 1.162 (cf::region::find $rmp->{region}), $rmp->{custom}
1156     )
1157 root 1.110 }
1158    
1159 root 1.187 =item cf::map->register ($regex, $prio)
1160    
1161     Register a handler for the map path matching the given regex at the
1162     givne priority (higher is better, built-in handlers have priority 0, the
1163     default).
1164    
1165     =cut
1166    
1167 root 1.166 sub register {
1168 root 1.187 my (undef, $regex, $prio) = @_;
1169 root 1.166 my $pkg = caller;
1170    
1171     no strict;
1172     push @{"$pkg\::ISA"}, __PACKAGE__;
1173    
1174 root 1.187 $EXT_MAP{$pkg} = [$prio, qr<$regex>];
1175 root 1.166 }
1176    
1177     # also paths starting with '/'
1178 root 1.187 $EXT_MAP{"cf::map"} = [0, qr{^(?=/)}];
1179 root 1.166
1180 root 1.170 sub thawer_merge {
1181 root 1.172 my ($self, $merge) = @_;
1182    
1183 root 1.170 # we have to keep some variables in memory intact
1184 root 1.172 local $self->{path};
1185     local $self->{load_path};
1186     local $self->{deny_save};
1187     local $self->{deny_reset};
1188 root 1.170
1189 root 1.172 $self->SUPER::thawer_merge ($merge);
1190 root 1.170 }
1191    
1192 root 1.166 sub normalise {
1193     my ($path, $base) = @_;
1194    
1195 root 1.192 $path = "$path"; # make sure its a string
1196    
1197 root 1.199 $path =~ s/\.map$//;
1198    
1199 root 1.166 # map plan:
1200     #
1201     # /! non-realised random map exit (special hack!)
1202     # {... are special paths that are not being touched
1203     # ?xxx/... are special absolute paths
1204     # ?random/... random maps
1205     # /... normal maps
1206     # ~user/... per-player map of a specific user
1207    
1208     $path =~ s/$PATH_SEP/\//go;
1209    
1210     # treat it as relative path if it starts with
1211     # something that looks reasonable
1212     if ($path =~ m{^(?:\./|\.\./|\w)}) {
1213     $base or Carp::carp "normalise called with relative path and no base: '$path'";
1214    
1215     $base =~ s{[^/]+/?$}{};
1216     $path = "$base/$path";
1217     }
1218    
1219     for ($path) {
1220     redo if s{//}{/};
1221     redo if s{/\.?/}{/};
1222     redo if s{/[^/]+/\.\./}{/};
1223     }
1224    
1225     $path
1226     }
1227    
1228     sub new_from_path {
1229     my (undef, $path, $base) = @_;
1230    
1231     return $path if UNIVERSAL::isa $path, "cf::map"; # already a map object
1232    
1233     $path = normalise $path, $base;
1234    
1235 root 1.187 for my $pkg (sort { $EXT_MAP{$b}[0] <=> $EXT_MAP{$a}[0] } keys %EXT_MAP) {
1236     if ($path =~ $EXT_MAP{$pkg}[1]) {
1237 root 1.166 my $self = bless cf::map::new, $pkg;
1238     $self->{path} = $path; $self->path ($path);
1239     $self->init; # pass $1 etc.
1240     return $self;
1241     }
1242     }
1243    
1244 root 1.192 Carp::carp "unable to resolve path '$path' (base '$base').";
1245 root 1.166 ()
1246     }
1247    
1248     sub init {
1249     my ($self) = @_;
1250    
1251     $self
1252     }
1253    
1254     sub as_string {
1255     my ($self) = @_;
1256    
1257     "$self->{path}"
1258     }
1259    
1260     # the displayed name, this is a one way mapping
1261     sub visible_name {
1262     &as_string
1263     }
1264    
1265     # the original (read-only) location
1266     sub load_path {
1267     my ($self) = @_;
1268    
1269 root 1.200 sprintf "%s/%s/%s.map", cf::datadir, cf::mapdir, $self->{path}
1270 root 1.166 }
1271    
1272     # the temporary/swap location
1273     sub save_path {
1274     my ($self) = @_;
1275    
1276 root 1.167 (my $path = $_[0]{path}) =~ s/\//$PATH_SEP/g;
1277 root 1.200 sprintf "%s/%s/%s.map", cf::localdir, cf::tmpdir, $path
1278 root 1.166 }
1279    
1280     # the unique path, undef == no special unique path
1281     sub uniq_path {
1282     my ($self) = @_;
1283    
1284 root 1.167 (my $path = $_[0]{path}) =~ s/\//$PATH_SEP/g;
1285     sprintf "%s/%s/%s", cf::localdir, cf::uniquedir, $path
1286 root 1.166 }
1287    
1288 root 1.110 # and all this just because we cannot iterate over
1289     # all maps in C++...
1290     sub change_all_map_light {
1291     my ($change) = @_;
1292    
1293 root 1.122 $_->change_map_light ($change)
1294     for grep $_->outdoor, values %cf::MAP;
1295 root 1.110 }
1296    
1297 root 1.166 sub unlink_save {
1298     my ($self) = @_;
1299    
1300     utf8::encode (my $save = $self->save_path);
1301 root 1.170 IO::AIO::aioreq_pri 4; Coro::AIO::aio_unlink $save;
1302     IO::AIO::aioreq_pri 4; Coro::AIO::aio_unlink "$save.pst";
1303 root 1.166 }
1304    
1305     sub load_header_from($) {
1306     my ($self, $path) = @_;
1307 root 1.110
1308     utf8::encode $path;
1309 root 1.200 #aio_open $path, O_RDONLY, 0
1310     # or return;
1311 root 1.110
1312 root 1.166 $self->_load_header ($path)
1313 root 1.110 or return;
1314    
1315 root 1.166 $self->{load_path} = $path;
1316 root 1.135
1317 root 1.166 1
1318     }
1319 root 1.110
1320 root 1.188 sub load_header_orig {
1321 root 1.166 my ($self) = @_;
1322 root 1.110
1323 root 1.166 $self->load_header_from ($self->load_path)
1324 root 1.110 }
1325    
1326 root 1.188 sub load_header_temp {
1327 root 1.166 my ($self) = @_;
1328 root 1.110
1329 root 1.166 $self->load_header_from ($self->save_path)
1330     }
1331 root 1.110
1332 root 1.188 sub prepare_temp {
1333     my ($self) = @_;
1334    
1335     $self->last_access ((delete $self->{last_access})
1336     || $cf::RUNTIME); #d#
1337     # safety
1338     $self->{instantiate_time} = $cf::RUNTIME
1339     if $self->{instantiate_time} > $cf::RUNTIME;
1340     }
1341    
1342     sub prepare_orig {
1343     my ($self) = @_;
1344    
1345     $self->{load_original} = 1;
1346     $self->{instantiate_time} = $cf::RUNTIME;
1347     $self->last_access ($cf::RUNTIME);
1348     $self->instantiate;
1349     }
1350    
1351 root 1.166 sub load_header {
1352     my ($self) = @_;
1353 root 1.110
1354 root 1.188 if ($self->load_header_temp) {
1355     $self->prepare_temp;
1356 root 1.166 } else {
1357 root 1.188 $self->load_header_orig
1358 root 1.166 or return;
1359 root 1.188 $self->prepare_orig;
1360 root 1.166 }
1361 root 1.120
1362 root 1.166 1
1363     }
1364 root 1.110
1365 root 1.166 sub find;
1366     sub find {
1367     my ($path, $origin) = @_;
1368 root 1.134
1369 root 1.166 $path = normalise $path, $origin && $origin->path;
1370 root 1.110
1371 root 1.166 cf::lock_wait "map_find:$path";
1372 root 1.110
1373 root 1.166 $cf::MAP{$path} || do {
1374     my $guard = cf::lock_acquire "map_find:$path";
1375     my $map = new_from_path cf::map $path
1376     or return;
1377 root 1.110
1378 root 1.116 $map->{last_save} = $cf::RUNTIME;
1379 root 1.110
1380 root 1.166 $map->load_header
1381     or return;
1382 root 1.134
1383 root 1.195 if ($map->should_reset && 0) {#d#TODO# disabled, crashy (locking issue?)
1384 root 1.185 # doing this can freeze the server in a sync job, obviously
1385     #$cf::WAIT_FOR_TICK->wait;
1386 root 1.112 $map->reset;
1387 root 1.123 undef $guard;
1388 root 1.192 return find $path;
1389 root 1.112 }
1390 root 1.110
1391 root 1.166 $cf::MAP{$path} = $map
1392 root 1.110 }
1393     }
1394    
1395 root 1.188 sub pre_load { }
1396     sub post_load { }
1397    
1398 root 1.110 sub load {
1399     my ($self) = @_;
1400    
1401 root 1.196 local $self->{deny_reset} = 1; # loading can take a long time
1402    
1403 root 1.120 my $path = $self->{path};
1404 root 1.166 my $guard = cf::lock_acquire "map_load:$path";
1405 root 1.120
1406 root 1.110 return if $self->in_memory != cf::MAP_SWAPPED;
1407    
1408     $self->in_memory (cf::MAP_LOADING);
1409    
1410     $self->alloc;
1411 root 1.188
1412     $self->pre_load;
1413    
1414 root 1.166 $self->_load_objects ($self->{load_path}, 1)
1415 root 1.110 or return;
1416    
1417 root 1.112 $self->set_object_flag (cf::FLAG_OBJ_ORIGINAL, 1)
1418     if delete $self->{load_original};
1419 root 1.111
1420 root 1.166 if (my $uniq = $self->uniq_path) {
1421 root 1.110 utf8::encode $uniq;
1422     if (aio_open $uniq, O_RDONLY, 0) {
1423     $self->clear_unique_items;
1424 root 1.166 $self->_load_objects ($uniq, 0);
1425 root 1.110 }
1426     }
1427    
1428 root 1.134 Coro::cede;
1429    
1430 root 1.110 # now do the right thing for maps
1431     $self->link_multipart_objects;
1432    
1433 root 1.166 unless ($self->{deny_activate}) {
1434 root 1.164 $self->decay_objects;
1435 root 1.110 $self->fix_auto_apply;
1436     $self->update_buttons;
1437 root 1.166 Coro::cede;
1438 root 1.110 $self->set_darkness_map;
1439     $self->difficulty ($self->estimate_difficulty)
1440     unless $self->difficulty;
1441 root 1.166 Coro::cede;
1442 root 1.110 $self->activate;
1443     }
1444    
1445 root 1.188 $self->post_load;
1446    
1447 root 1.166 $self->in_memory (cf::MAP_IN_MEMORY);
1448     }
1449    
1450     sub customise_for {
1451     my ($self, $ob) = @_;
1452    
1453     return find "~" . $ob->name . "/" . $self->{path}
1454     if $self->per_player;
1455 root 1.134
1456 root 1.166 $self
1457 root 1.110 }
1458    
1459 root 1.157 # find and load all maps in the 3x3 area around a map
1460     sub load_diag {
1461     my ($map) = @_;
1462    
1463     my @diag; # diagonal neighbours
1464    
1465     for (0 .. 3) {
1466     my $neigh = $map->tile_path ($_)
1467     or next;
1468     $neigh = find $neigh, $map
1469     or next;
1470     $neigh->load;
1471    
1472     push @diag, [$neigh->tile_path (($_ + 3) % 4), $neigh],
1473     [$neigh->tile_path (($_ + 1) % 4), $neigh];
1474     }
1475    
1476     for (@diag) {
1477     my $neigh = find @$_
1478     or next;
1479     $neigh->load;
1480     }
1481     }
1482    
1483 root 1.133 sub find_sync {
1484 root 1.110 my ($path, $origin) = @_;
1485    
1486 root 1.157 cf::sync_job { find $path, $origin }
1487 root 1.133 }
1488    
1489     sub do_load_sync {
1490     my ($map) = @_;
1491 root 1.110
1492 root 1.133 cf::sync_job { $map->load };
1493 root 1.110 }
1494    
1495 root 1.157 our %MAP_PREFETCH;
1496 root 1.183 our $MAP_PREFETCHER = undef;
1497 root 1.157
1498     sub find_async {
1499     my ($path, $origin) = @_;
1500    
1501 root 1.166 $path = normalise $path, $origin && $origin->{path};
1502 root 1.157
1503 root 1.166 if (my $map = $cf::MAP{$path}) {
1504 root 1.157 return $map if $map->in_memory == cf::MAP_IN_MEMORY;
1505     }
1506    
1507 root 1.183 undef $MAP_PREFETCH{$path};
1508     $MAP_PREFETCHER ||= cf::async {
1509     while (%MAP_PREFETCH) {
1510     for my $path (keys %MAP_PREFETCH) {
1511     my $map = find $path
1512     or next;
1513     $map->load;
1514    
1515     delete $MAP_PREFETCH{$path};
1516     }
1517     }
1518     undef $MAP_PREFETCHER;
1519     };
1520 root 1.189 $MAP_PREFETCHER->prio (6);
1521 root 1.157
1522     ()
1523     }
1524    
1525 root 1.110 sub save {
1526     my ($self) = @_;
1527    
1528 root 1.137 my $lock = cf::lock_acquire "map_data:" . $self->path;
1529    
1530 root 1.110 $self->{last_save} = $cf::RUNTIME;
1531    
1532     return unless $self->dirty;
1533    
1534 root 1.166 my $save = $self->save_path; utf8::encode $save;
1535     my $uniq = $self->uniq_path; utf8::encode $uniq;
1536 root 1.117
1537 root 1.110 $self->{load_path} = $save;
1538    
1539     return if $self->{deny_save};
1540    
1541 root 1.132 local $self->{last_access} = $self->last_access;#d#
1542    
1543 root 1.143 cf::async {
1544     $_->contr->save for $self->players;
1545     };
1546    
1547 root 1.110 if ($uniq) {
1548 root 1.166 $self->_save_objects ($save, cf::IO_HEADER | cf::IO_OBJECTS);
1549     $self->_save_objects ($uniq, cf::IO_UNIQUES);
1550 root 1.110 } else {
1551 root 1.166 $self->_save_objects ($save, cf::IO_HEADER | cf::IO_OBJECTS | cf::IO_UNIQUES);
1552 root 1.110 }
1553     }
1554    
1555     sub swap_out {
1556     my ($self) = @_;
1557    
1558 root 1.130 # save first because save cedes
1559     $self->save;
1560    
1561 root 1.137 my $lock = cf::lock_acquire "map_data:" . $self->path;
1562    
1563 root 1.110 return if $self->players;
1564     return if $self->in_memory != cf::MAP_IN_MEMORY;
1565     return if $self->{deny_save};
1566    
1567     $self->clear;
1568     $self->in_memory (cf::MAP_SWAPPED);
1569     }
1570    
1571 root 1.112 sub reset_at {
1572     my ($self) = @_;
1573 root 1.110
1574     # TODO: safety, remove and allow resettable per-player maps
1575 root 1.169 return 1e99 if $self->isa ("ext::map_per_player");#d#
1576 root 1.114 return 1e99 if $self->{deny_reset};
1577 root 1.110
1578 root 1.112 my $time = $self->fixed_resettime ? $self->{instantiate_time} : $self->last_access;
1579 root 1.114 my $to = List::Util::min $MAX_RESET, $self->reset_timeout || $DEFAULT_RESET;
1580 root 1.110
1581 root 1.112 $time + $to
1582     }
1583    
1584     sub should_reset {
1585     my ($self) = @_;
1586    
1587     $self->reset_at <= $cf::RUNTIME
1588 root 1.111 }
1589    
1590 root 1.110 sub reset {
1591     my ($self) = @_;
1592    
1593 root 1.167 my $lock = cf::lock_acquire "map_data:$self->{path}";
1594 root 1.137
1595 root 1.110 return if $self->players;
1596 root 1.166 return if $self->isa ("ext::map_per_player");#d#
1597 root 1.110
1598     warn "resetting map ", $self->path;#d#
1599    
1600 root 1.210 $self->in_memory (cf::MAP_SWAPPED);
1601    
1602     # need to save uniques path
1603     unless ($self->{deny_save}) {
1604     my $uniq = $self->uniq_path; utf8::encode $uniq;
1605    
1606     $self->_save_objects ($uniq, cf::IO_UNIQUES)
1607     if $uniq;
1608     }
1609    
1610 root 1.111 delete $cf::MAP{$self->path};
1611 root 1.110
1612 root 1.167 $self->clear;
1613    
1614 root 1.110 $_->clear_links_to ($self) for values %cf::MAP;
1615    
1616 root 1.166 $self->unlink_save;
1617 root 1.111 $self->destroy;
1618 root 1.110 }
1619    
1620 root 1.114 my $nuke_counter = "aaaa";
1621    
1622     sub nuke {
1623     my ($self) = @_;
1624    
1625 root 1.174 delete $cf::MAP{$self->path};
1626    
1627     $self->unlink_save;
1628    
1629     bless $self, "cf::map";
1630     delete $self->{deny_reset};
1631 root 1.114 $self->{deny_save} = 1;
1632     $self->reset_timeout (1);
1633 root 1.174 $self->path ($self->{path} = "{nuke}/" . ($nuke_counter++));
1634    
1635     $cf::MAP{$self->path} = $self;
1636    
1637 root 1.114 $self->reset; # polite request, might not happen
1638     }
1639    
1640 root 1.158 =item cf::map::unique_maps
1641    
1642 root 1.166 Returns an arrayref of paths of all shared maps that have
1643 root 1.158 instantiated unique items. May block.
1644    
1645     =cut
1646    
1647     sub unique_maps() {
1648     my $files = aio_readdir cf::localdir . "/" . cf::uniquedir
1649     or return;
1650    
1651     my @paths;
1652    
1653     for (@$files) {
1654     utf8::decode $_;
1655     next if /\.pst$/;
1656     next unless /^$PATH_SEP/o;
1657    
1658 root 1.199 push @paths, cf::map::normalise $_;
1659 root 1.158 }
1660    
1661     \@paths
1662     }
1663    
1664 root 1.155 package cf;
1665    
1666     =back
1667    
1668     =head3 cf::object
1669    
1670     =cut
1671    
1672     package cf::object;
1673    
1674     =over 4
1675    
1676     =item $ob->inv_recursive
1677 root 1.110
1678 root 1.155 Returns the inventory of the object _and_ their inventories, recursively.
1679 root 1.110
1680 root 1.155 =cut
1681 root 1.144
1682 root 1.155 sub inv_recursive_;
1683     sub inv_recursive_ {
1684     map { $_, inv_recursive_ $_->inv } @_
1685     }
1686 root 1.110
1687 root 1.155 sub inv_recursive {
1688     inv_recursive_ inv $_[0]
1689 root 1.110 }
1690    
1691     package cf;
1692    
1693     =back
1694    
1695 root 1.95 =head3 cf::object::player
1696    
1697     =over 4
1698    
1699 root 1.79 =item $player_object->reply ($npc, $msg[, $flags])
1700 root 1.28
1701     Sends a message to the player, as if the npc C<$npc> replied. C<$npc>
1702     can be C<undef>. Does the right thing when the player is currently in a
1703     dialogue with the given NPC character.
1704    
1705     =cut
1706    
1707 root 1.22 # rough implementation of a future "reply" method that works
1708     # with dialog boxes.
1709 root 1.95 #TODO: the first argument must go, split into a $npc->reply_to ( method
1710 root 1.23 sub cf::object::player::reply($$$;$) {
1711     my ($self, $npc, $msg, $flags) = @_;
1712    
1713     $flags = cf::NDI_BROWN | cf::NDI_UNIQUE unless @_ >= 4;
1714 root 1.22
1715 root 1.24 if ($self->{record_replies}) {
1716     push @{ $self->{record_replies} }, [$npc, $msg, $flags];
1717     } else {
1718     $msg = $npc->name . " says: $msg" if $npc;
1719     $self->message ($msg, $flags);
1720     }
1721 root 1.22 }
1722    
1723 root 1.79 =item $player_object->may ("access")
1724    
1725     Returns wether the given player is authorized to access resource "access"
1726     (e.g. "command_wizcast").
1727    
1728     =cut
1729    
1730     sub cf::object::player::may {
1731     my ($self, $access) = @_;
1732    
1733     $self->flag (cf::FLAG_WIZ) ||
1734     (ref $cf::CFG{"may_$access"}
1735     ? scalar grep $self->name eq $_, @{$cf::CFG{"may_$access"}}
1736     : $cf::CFG{"may_$access"})
1737     }
1738 root 1.70
1739 root 1.115 =item $player_object->enter_link
1740    
1741     Freezes the player and moves him/her to a special map (C<{link}>).
1742    
1743 root 1.166 The player should be reasonably safe there for short amounts of time. You
1744 root 1.115 I<MUST> call C<leave_link> as soon as possible, though.
1745    
1746 root 1.166 Will never block.
1747    
1748 root 1.115 =item $player_object->leave_link ($map, $x, $y)
1749    
1750 root 1.166 Moves the player out of the special C<{link}> map onto the specified
1751     map. If the map is not valid (or omitted), the player will be moved back
1752     to the location he/she was before the call to C<enter_link>, or, if that
1753     fails, to the emergency map position.
1754 root 1.115
1755     Might block.
1756    
1757     =cut
1758    
1759 root 1.166 sub link_map {
1760     unless ($LINK_MAP) {
1761     $LINK_MAP = cf::map::find "{link}"
1762 root 1.196 or cf::cleanup "FATAL: unable to provide {link} map, exiting.";
1763 root 1.166 $LINK_MAP->load;
1764     }
1765    
1766     $LINK_MAP
1767     }
1768    
1769 root 1.110 sub cf::object::player::enter_link {
1770     my ($self) = @_;
1771    
1772 root 1.120 $self->deactivate_recursive;
1773    
1774 root 1.166 return if UNIVERSAL::isa $self->map, "ext::map_link";
1775 root 1.110
1776 root 1.120 $self->{_link_pos} ||= [$self->map->{path}, $self->x, $self->y]
1777 root 1.110 if $self->map;
1778    
1779 root 1.194 $self->enter_map ($LINK_MAP || link_map, 10, 10);
1780 root 1.110 }
1781    
1782     sub cf::object::player::leave_link {
1783     my ($self, $map, $x, $y) = @_;
1784    
1785     my $link_pos = delete $self->{_link_pos};
1786    
1787     unless ($map) {
1788     # restore original map position
1789     ($map, $x, $y) = @{ $link_pos || [] };
1790 root 1.133 $map = cf::map::find $map;
1791 root 1.110
1792     unless ($map) {
1793     ($map, $x, $y) = @$EMERGENCY_POSITION;
1794 root 1.133 $map = cf::map::find $map
1795 root 1.110 or die "FATAL: cannot load emergency map\n";
1796     }
1797     }
1798    
1799     ($x, $y) = (-1, -1)
1800     unless (defined $x) && (defined $y);
1801    
1802     # use -1 or undef as default coordinates, not 0, 0
1803     ($x, $y) = ($map->enter_x, $map->enter_y)
1804     if $x <=0 && $y <= 0;
1805    
1806     $map->load;
1807 root 1.157 $map->load_diag;
1808 root 1.110
1809 root 1.143 return unless $self->contr->active;
1810 root 1.110 $self->activate_recursive;
1811 root 1.215
1812     local $self->{_prev_pos} = $link_pos; # ugly hack for rent.ext
1813 root 1.110 $self->enter_map ($map, $x, $y);
1814     }
1815    
1816 root 1.120 cf::player->attach (
1817     on_logout => sub {
1818     my ($pl) = @_;
1819    
1820     # abort map switching before logout
1821     if ($pl->ob->{_link_pos}) {
1822     cf::sync_job {
1823     $pl->ob->leave_link
1824     };
1825     }
1826     },
1827     on_login => sub {
1828     my ($pl) = @_;
1829    
1830     # try to abort aborted map switching on player login :)
1831     # should happen only on crashes
1832     if ($pl->ob->{_link_pos}) {
1833     $pl->ob->enter_link;
1834 root 1.140 (async {
1835     $pl->ob->reply (undef,
1836     "There was an internal problem at your last logout, "
1837     . "the server will try to bring you to your intended destination in a second.",
1838     cf::NDI_RED);
1839 root 1.215 # we need this sleep as the login has a concurrent enter_exit running
1840     # and this sleep increases chances of the player not ending up in scorn
1841 root 1.120 Coro::Timer::sleep 1;
1842     $pl->ob->leave_link;
1843 root 1.139 })->prio (2);
1844 root 1.120 }
1845     },
1846     );
1847    
1848 root 1.136 =item $player_object->goto ($path, $x, $y)
1849 root 1.110
1850     =cut
1851    
1852 root 1.136 sub cf::object::player::goto {
1853 root 1.110 my ($self, $path, $x, $y) = @_;
1854    
1855     $self->enter_link;
1856    
1857 root 1.140 (async {
1858 root 1.197 my $map = eval {
1859     my $map = cf::map::find $path;
1860     $map = $map->customise_for ($self) if $map;
1861     $map
1862     } or
1863     $self->message ("The exit to '$path' is closed", cf::NDI_UNIQUE | cf::NDI_RED);
1864 root 1.115
1865 root 1.110 $self->leave_link ($map, $x, $y);
1866     })->prio (1);
1867     }
1868    
1869     =item $player_object->enter_exit ($exit_object)
1870    
1871     =cut
1872    
1873     sub parse_random_map_params {
1874     my ($spec) = @_;
1875    
1876     my $rmp = { # defaults
1877 root 1.181 xsize => (cf::rndm 15, 40),
1878     ysize => (cf::rndm 15, 40),
1879     symmetry => (cf::rndm 1, cf::SYMMETRY_XY),
1880 root 1.182 #layout => string,
1881 root 1.110 };
1882    
1883     for (split /\n/, $spec) {
1884     my ($k, $v) = split /\s+/, $_, 2;
1885    
1886     $rmp->{lc $k} = $v if (length $k) && (length $v);
1887     }
1888    
1889     $rmp
1890     }
1891    
1892     sub prepare_random_map {
1893     my ($exit) = @_;
1894    
1895 root 1.179 my $guard = cf::lock_acquire "exit_prepare:$exit";
1896    
1897 root 1.110 # all this does is basically replace the /! path by
1898     # a new random map path (?random/...) with a seed
1899     # that depends on the exit object
1900    
1901     my $rmp = parse_random_map_params $exit->msg;
1902    
1903     if ($exit->map) {
1904 root 1.198 $rmp->{region} = $exit->region->name;
1905 root 1.110 $rmp->{origin_map} = $exit->map->path;
1906     $rmp->{origin_x} = $exit->x;
1907     $rmp->{origin_y} = $exit->y;
1908     }
1909    
1910     $rmp->{random_seed} ||= $exit->random_seed;
1911    
1912     my $data = cf::to_json $rmp;
1913     my $md5 = Digest::MD5::md5_hex $data;
1914 root 1.177 my $meta = "$cf::RANDOM_MAPS/$md5.meta";
1915 root 1.110
1916 root 1.177 if (my $fh = aio_open "$meta~", O_WRONLY | O_CREAT, 0666) {
1917 root 1.110 aio_write $fh, 0, (length $data), $data, 0;
1918 root 1.177 undef $fh;
1919     aio_rename "$meta~", $meta;
1920 root 1.110
1921     $exit->slaying ("?random/$md5");
1922     $exit->msg (undef);
1923     }
1924     }
1925    
1926     sub cf::object::player::enter_exit {
1927     my ($self, $exit) = @_;
1928    
1929     return unless $self->type == cf::PLAYER;
1930    
1931 root 1.195 if ($exit->slaying eq "/!") {
1932     #TODO: this should de-fi-ni-te-ly not be a sync-job
1933     cf::sync_job { prepare_random_map $exit };
1934     }
1935    
1936     my $slaying = cf::map::normalise $exit->slaying, $exit->map && $exit->map->path;
1937     my $hp = $exit->stats->hp;
1938     my $sp = $exit->stats->sp;
1939    
1940 root 1.110 $self->enter_link;
1941    
1942 root 1.140 (async {
1943 root 1.133 $self->deactivate_recursive; # just to be sure
1944 root 1.110 unless (eval {
1945 root 1.195 $self->goto ($slaying, $hp, $sp);
1946 root 1.110
1947     1;
1948     }) {
1949     $self->message ("Something went wrong deep within the crossfire server. "
1950     . "I'll try to bring you back to the map you were before. "
1951 root 1.158 . "Please report this to the dungeon master!",
1952 root 1.110 cf::NDI_UNIQUE | cf::NDI_RED);
1953    
1954     warn "ERROR in enter_exit: $@";
1955     $self->leave_link;
1956     }
1957     })->prio (1);
1958     }
1959    
1960 root 1.95 =head3 cf::client
1961    
1962     =over 4
1963    
1964     =item $client->send_drawinfo ($text, $flags)
1965    
1966     Sends a drawinfo packet to the client. Circumvents output buffering so
1967     should not be used under normal circumstances.
1968    
1969 root 1.70 =cut
1970    
1971 root 1.95 sub cf::client::send_drawinfo {
1972     my ($self, $text, $flags) = @_;
1973    
1974     utf8::encode $text;
1975     $self->send_packet (sprintf "drawinfo %d %s", $flags, $text);
1976     }
1977    
1978    
1979     =item $success = $client->query ($flags, "text", \&cb)
1980    
1981     Queues a query to the client, calling the given callback with
1982     the reply text on a reply. flags can be C<cf::CS_QUERY_YESNO>,
1983     C<cf::CS_QUERY_SINGLECHAR> or C<cf::CS_QUERY_HIDEINPUT> or C<0>.
1984    
1985     Queries can fail, so check the return code. Or don't, as queries will become
1986     reliable at some point in the future.
1987    
1988     =cut
1989    
1990     sub cf::client::query {
1991     my ($self, $flags, $text, $cb) = @_;
1992    
1993     return unless $self->state == ST_PLAYING
1994     || $self->state == ST_SETUP
1995     || $self->state == ST_CUSTOM;
1996    
1997     $self->state (ST_CUSTOM);
1998    
1999     utf8::encode $text;
2000     push @{ $self->{query_queue} }, [(sprintf "query %d %s", $flags, $text), $cb];
2001    
2002     $self->send_packet ($self->{query_queue}[0][0])
2003     if @{ $self->{query_queue} } == 1;
2004     }
2005    
2006     cf::client->attach (
2007     on_reply => sub {
2008     my ($ns, $msg) = @_;
2009    
2010     # this weird shuffling is so that direct followup queries
2011     # get handled first
2012 root 1.128 my $queue = delete $ns->{query_queue}
2013 root 1.129 or return; # be conservative, not sure how that can happen, but we saw a crash here
2014 root 1.95
2015     (shift @$queue)->[1]->($msg);
2016 root 1.202 return unless $ns->valid; # temporary(?) workaround for callback destroying socket
2017 root 1.95
2018     push @{ $ns->{query_queue} }, @$queue;
2019    
2020     if (@{ $ns->{query_queue} } == @$queue) {
2021     if (@$queue) {
2022     $ns->send_packet ($ns->{query_queue}[0][0]);
2023     } else {
2024 root 1.98 $ns->state (ST_PLAYING) if $ns->state == ST_CUSTOM;
2025 root 1.95 }
2026     }
2027     },
2028     );
2029    
2030 root 1.140 =item $client->async (\&cb)
2031 root 1.96
2032     Create a new coroutine, running the specified callback. The coroutine will
2033     be automatically cancelled when the client gets destroyed (e.g. on logout,
2034     or loss of connection).
2035    
2036     =cut
2037    
2038 root 1.140 sub cf::client::async {
2039 root 1.96 my ($self, $cb) = @_;
2040    
2041 root 1.140 my $coro = &Coro::async ($cb);
2042 root 1.103
2043     $coro->on_destroy (sub {
2044 root 1.96 delete $self->{_coro}{$coro+0};
2045 root 1.103 });
2046 root 1.96
2047     $self->{_coro}{$coro+0} = $coro;
2048 root 1.103
2049     $coro
2050 root 1.96 }
2051    
2052     cf::client->attach (
2053     on_destroy => sub {
2054     my ($ns) = @_;
2055    
2056 root 1.97 $_->cancel for values %{ (delete $ns->{_coro}) || {} };
2057 root 1.96 },
2058     );
2059    
2060 root 1.95 =back
2061    
2062 root 1.70
2063     =head2 SAFE SCRIPTING
2064    
2065     Functions that provide a safe environment to compile and execute
2066     snippets of perl code without them endangering the safety of the server
2067     itself. Looping constructs, I/O operators and other built-in functionality
2068     is not available in the safe scripting environment, and the number of
2069 root 1.79 functions and methods that can be called is greatly reduced.
2070 root 1.70
2071     =cut
2072 root 1.23
2073 root 1.42 our $safe = new Safe "safe";
2074 root 1.23 our $safe_hole = new Safe::Hole;
2075    
2076     $SIG{FPE} = 'IGNORE';
2077    
2078     $safe->permit_only (Opcode::opset qw(:base_core :base_mem :base_orig :base_math sort time));
2079    
2080 root 1.25 # here we export the classes and methods available to script code
2081    
2082 root 1.70 =pod
2083    
2084     The following fucntions and emthods are available within a safe environment:
2085    
2086 elmex 1.91 cf::object contr pay_amount pay_player map
2087 root 1.70 cf::object::player player
2088     cf::player peaceful
2089 elmex 1.91 cf::map trigger
2090 root 1.70
2091     =cut
2092    
2093 root 1.25 for (
2094 elmex 1.91 ["cf::object" => qw(contr pay_amount pay_player map)],
2095 root 1.25 ["cf::object::player" => qw(player)],
2096     ["cf::player" => qw(peaceful)],
2097 elmex 1.91 ["cf::map" => qw(trigger)],
2098 root 1.25 ) {
2099     no strict 'refs';
2100     my ($pkg, @funs) = @$_;
2101 root 1.41 *{"safe::$pkg\::$_"} = $safe_hole->wrap (\&{"$pkg\::$_"})
2102 root 1.25 for @funs;
2103     }
2104 root 1.23
2105 root 1.70 =over 4
2106    
2107     =item @retval = safe_eval $code, [var => value, ...]
2108    
2109     Compiled and executes the given perl code snippet. additional var/value
2110     pairs result in temporary local (my) scalar variables of the given name
2111     that are available in the code snippet. Example:
2112    
2113     my $five = safe_eval '$first + $second', first => 1, second => 4;
2114    
2115     =cut
2116    
2117 root 1.23 sub safe_eval($;@) {
2118     my ($code, %vars) = @_;
2119    
2120     my $qcode = $code;
2121     $qcode =~ s/"/‟/g; # not allowed in #line filenames
2122     $qcode =~ s/\n/\\n/g;
2123    
2124     local $_;
2125 root 1.41 local @safe::cf::_safe_eval_args = values %vars;
2126 root 1.23
2127 root 1.42 my $eval =
2128 root 1.23 "do {\n"
2129     . "my (" . (join ",", map "\$$_", keys %vars) . ") = \@cf::_safe_eval_args;\n"
2130     . "#line 0 \"{$qcode}\"\n"
2131     . $code
2132     . "\n}"
2133 root 1.25 ;
2134    
2135     sub_generation_inc;
2136 root 1.42 my @res = wantarray ? $safe->reval ($eval) : scalar $safe->reval ($eval);
2137 root 1.25 sub_generation_inc;
2138    
2139 root 1.42 if ($@) {
2140     warn "$@";
2141     warn "while executing safe code '$code'\n";
2142     warn "with arguments " . (join " ", %vars) . "\n";
2143     }
2144    
2145 root 1.25 wantarray ? @res : $res[0]
2146 root 1.23 }
2147    
2148 root 1.69 =item cf::register_script_function $function => $cb
2149    
2150     Register a function that can be called from within map/npc scripts. The
2151     function should be reasonably secure and should be put into a package name
2152     like the extension.
2153    
2154     Example: register a function that gets called whenever a map script calls
2155     C<rent::overview>, as used by the C<rent> extension.
2156    
2157     cf::register_script_function "rent::overview" => sub {
2158     ...
2159     };
2160    
2161     =cut
2162    
2163 root 1.23 sub register_script_function {
2164     my ($fun, $cb) = @_;
2165    
2166     no strict 'refs';
2167 root 1.41 *{"safe::$fun"} = $safe_hole->wrap ($cb);
2168 root 1.23 }
2169    
2170 root 1.70 =back
2171    
2172 root 1.71 =cut
2173    
2174 root 1.23 #############################################################################
2175 root 1.65
2176     =head2 EXTENSION DATABASE SUPPORT
2177    
2178     Crossfire maintains a very simple database for extension use. It can
2179     currently store anything that can be serialised using Storable, which
2180     excludes objects.
2181    
2182     The parameter C<$family> should best start with the name of the extension
2183     using it, it should be unique.
2184    
2185     =over 4
2186    
2187     =item $value = cf::db_get $family => $key
2188    
2189 root 1.208 Returns a single value from the database.
2190 root 1.65
2191     =item cf::db_put $family => $key => $value
2192    
2193 root 1.208 Stores the given C<$value> in the family.
2194 root 1.65
2195     =cut
2196    
2197 root 1.78 our $DB;
2198    
2199 root 1.210 sub db_init {
2200     unless ($DB) {
2201     $DB = BDB::db_create $DB_ENV;
2202 root 1.65
2203 root 1.210 cf::sync_job {
2204     eval {
2205     $DB->set_flags (BDB::CHKSUM);
2206 root 1.65
2207 root 1.210 BDB::db_open $DB, undef, "db", undef, BDB::BTREE,
2208     BDB::CREATE | BDB::AUTO_COMMIT, 0666;
2209     cf::cleanup "db_open(db): $!" if $!;
2210     };
2211     cf::cleanup "db_open(db): $@" if $@;
2212 root 1.208 };
2213 root 1.65
2214 root 1.210 my $path = cf::localdir . "/database.pst";
2215     if (stat $path) {
2216     cf::sync_job {
2217     my $pst = Storable::retrieve $path;
2218 root 1.209
2219 root 1.210 cf::db_put (board => data => $pst->{board});
2220     cf::db_put (guildrules => data => $pst->{guildrules});
2221     cf::db_put (rent => balance => $pst->{rent}{balance});
2222     BDB::db_env_txn_checkpoint $DB_ENV;
2223 root 1.65
2224 root 1.210 unlink $path;
2225     };
2226     }
2227 root 1.65 }
2228 root 1.208 }
2229 root 1.65
2230 root 1.208 sub db_get($$) {
2231     my $key = "$_[0]/$_[1]";
2232 root 1.65
2233 root 1.208 cf::sync_job {
2234     BDB::db_get $DB, undef, $key, my $data;
2235 root 1.65
2236 root 1.208 $! ? ()
2237     : Compress::LZF::sthaw $data
2238 root 1.65 }
2239 root 1.208 }
2240 root 1.65
2241 root 1.208 sub db_put($$$) {
2242     BDB::dbreq_pri 4;
2243     BDB::db_put $DB, undef, "$_[0]/$_[1]", Compress::LZF::sfreeze_cr $_[2], 0, sub { };
2244 root 1.65 }
2245    
2246     #############################################################################
2247 root 1.203 # the server's init and main functions
2248    
2249 root 1.217 sub init_resources {
2250     load_resource_file sprintf "%s/%s/regions", cf::datadir, cf::mapdir
2251 root 1.203 or die "unable to load regions file\n";#d#
2252     }
2253 root 1.34
2254 root 1.73 sub cfg_load {
2255 root 1.72 open my $fh, "<:utf8", cf::confdir . "/config"
2256     or return;
2257    
2258     local $/;
2259     *CFG = YAML::Syck::Load <$fh>;
2260 root 1.131
2261     $EMERGENCY_POSITION = $CFG{emergency_position} || ["/world/world_105_115", 5, 37];
2262    
2263 root 1.139 $cf::map::MAX_RESET = $CFG{map_max_reset} if exists $CFG{map_max_reset};
2264     $cf::map::DEFAULT_RESET = $CFG{map_default_reset} if exists $CFG{map_default_reset};
2265    
2266 root 1.131 if (exists $CFG{mlockall}) {
2267     eval {
2268 root 1.147 $CFG{mlockall} ? eval "mlockall()" : eval "munlockall()"
2269 root 1.131 and die "WARNING: m(un)lockall failed: $!\n";
2270     };
2271     warn $@ if $@;
2272     }
2273 root 1.72 }
2274    
2275 root 1.203 sub init {
2276 root 1.217 init_resources;
2277 root 1.203 }
2278    
2279 root 1.39 sub main {
2280 root 1.108 # we must not ever block the main coroutine
2281     local $Coro::idle = sub {
2282 root 1.115 Carp::cluck "FATAL: Coro::idle was called, major BUG, use cf::sync_job!\n";#d#
2283 root 1.175 (async {
2284     Event::one_event;
2285     })->prio (Coro::PRIO_MAX);
2286 root 1.108 };
2287    
2288 root 1.73 cfg_load;
2289 root 1.210 db_init;
2290 root 1.61 load_extensions;
2291 root 1.183
2292     $TICK_WATCHER->start;
2293 root 1.34 Event::loop;
2294     }
2295    
2296     #############################################################################
2297 root 1.155 # initialisation and cleanup
2298    
2299     # install some emergency cleanup handlers
2300     BEGIN {
2301     for my $signal (qw(INT HUP TERM)) {
2302     Event->signal (
2303 root 1.189 reentrant => 0,
2304     data => WF_AUTOCANCEL,
2305     signal => $signal,
2306 root 1.191 prio => 0,
2307 root 1.189 cb => sub {
2308 root 1.155 cf::cleanup "SIG$signal";
2309     },
2310     );
2311     }
2312     }
2313    
2314 root 1.156 sub emergency_save() {
2315 root 1.155 my $freeze_guard = cf::freeze_mainloop;
2316    
2317     warn "enter emergency perl save\n";
2318    
2319     cf::sync_job {
2320     # use a peculiar iteration method to avoid tripping on perl
2321     # refcount bugs in for. also avoids problems with players
2322 root 1.167 # and maps saved/destroyed asynchronously.
2323 root 1.155 warn "begin emergency player save\n";
2324     for my $login (keys %cf::PLAYER) {
2325     my $pl = $cf::PLAYER{$login} or next;
2326     $pl->valid or next;
2327     $pl->save;
2328     }
2329     warn "end emergency player save\n";
2330    
2331     warn "begin emergency map save\n";
2332     for my $path (keys %cf::MAP) {
2333     my $map = $cf::MAP{$path} or next;
2334     $map->valid or next;
2335     $map->save;
2336     }
2337     warn "end emergency map save\n";
2338 root 1.208
2339     warn "begin emergency database checkpoint\n";
2340     BDB::db_env_txn_checkpoint $DB_ENV;
2341     warn "end emergency database checkpoint\n";
2342 root 1.155 };
2343    
2344     warn "leave emergency perl save\n";
2345     }
2346 root 1.22
2347 root 1.211 sub post_cleanup {
2348     my ($make_core) = @_;
2349    
2350     warn Carp::longmess "post_cleanup backtrace"
2351     if $make_core;
2352     }
2353    
2354 root 1.111 sub reload() {
2355 root 1.106 # can/must only be called in main
2356     if ($Coro::current != $Coro::main) {
2357 root 1.183 warn "can only reload from main coroutine";
2358 root 1.106 return;
2359     }
2360    
2361 root 1.103 warn "reloading...";
2362    
2363 root 1.212 warn "entering sync_job";
2364    
2365 root 1.213 cf::sync_job {
2366 root 1.214 cf::write_runtime; # external watchdog should not bark
2367 root 1.212 cf::emergency_save;
2368 root 1.214 cf::write_runtime; # external watchdog should not bark
2369 root 1.183
2370 root 1.212 warn "syncing database to disk";
2371     BDB::db_env_txn_checkpoint $DB_ENV;
2372 root 1.106
2373     # if anything goes wrong in here, we should simply crash as we already saved
2374 root 1.65
2375 root 1.183 warn "cancelling all WF_AUTOCANCEL watchers";
2376 root 1.87 for (Event::all_watchers) {
2377     $_->cancel if $_->data & WF_AUTOCANCEL;
2378     }
2379 root 1.65
2380 root 1.183 warn "flushing outstanding aio requests";
2381     for (;;) {
2382 root 1.208 BDB::flush;
2383 root 1.183 IO::AIO::flush;
2384     Coro::cede;
2385 root 1.208 last unless IO::AIO::nreqs || BDB::nreqs;
2386 root 1.183 warn "iterate...";
2387     }
2388    
2389     warn "cancelling all extension coros";
2390 root 1.103 $_->cancel for values %EXT_CORO;
2391     %EXT_CORO = ();
2392    
2393 root 1.183 warn "removing commands";
2394 root 1.159 %COMMAND = ();
2395    
2396 root 1.183 warn "removing ext commands";
2397 root 1.159 %EXTCMD = ();
2398    
2399 root 1.183 warn "unloading/nuking all extensions";
2400 root 1.159 for my $pkg (@EXTS) {
2401 root 1.160 warn "... unloading $pkg";
2402 root 1.159
2403     if (my $cb = $pkg->can ("unload")) {
2404     eval {
2405     $cb->($pkg);
2406     1
2407     } or warn "$pkg unloaded, but with errors: $@";
2408     }
2409    
2410 root 1.160 warn "... nuking $pkg";
2411 root 1.159 Symbol::delete_package $pkg;
2412 root 1.65 }
2413    
2414 root 1.183 warn "unloading all perl modules loaded from $LIBDIR";
2415 root 1.65 while (my ($k, $v) = each %INC) {
2416     next unless $v =~ /^\Q$LIBDIR\E\/.*\.pm$/;
2417    
2418 root 1.183 warn "... unloading $k";
2419 root 1.65 delete $INC{$k};
2420    
2421     $k =~ s/\.pm$//;
2422     $k =~ s/\//::/g;
2423    
2424     if (my $cb = $k->can ("unload_module")) {
2425     $cb->();
2426     }
2427    
2428     Symbol::delete_package $k;
2429     }
2430    
2431 root 1.183 warn "getting rid of safe::, as good as possible";
2432 root 1.65 Symbol::delete_package "safe::$_"
2433 root 1.103 for qw(cf::attachable cf::object cf::object::player cf::client cf::player cf::map cf::party cf::region);
2434 root 1.65
2435 root 1.183 warn "unloading cf.pm \"a bit\"";
2436 root 1.65 delete $INC{"cf.pm"};
2437    
2438     # don't, removes xs symbols, too,
2439     # and global variables created in xs
2440     #Symbol::delete_package __PACKAGE__;
2441    
2442 root 1.183 warn "unload completed, starting to reload now";
2443    
2444 root 1.103 warn "reloading cf.pm";
2445 root 1.65 require cf;
2446 root 1.100 cf::_connect_to_perl; # nominally unnecessary, but cannot hurt
2447    
2448 root 1.183 warn "loading config and database again";
2449 root 1.73 cf::cfg_load;
2450 root 1.65
2451 root 1.183 warn "loading extensions";
2452 root 1.65 cf::load_extensions;
2453    
2454 root 1.183 warn "reattaching attachments to objects/players";
2455 root 1.65 _global_reattach;
2456 root 1.183 warn "reattaching attachments to maps";
2457 root 1.144 reattach $_ for values %MAP;
2458 root 1.183
2459 root 1.203 warn "loading reloadable resources";
2460 root 1.217 init_resources;
2461 root 1.203
2462 root 1.212 warn "leaving sync_job";
2463 root 1.183
2464 root 1.212 1
2465     } or do {
2466 root 1.106 warn $@;
2467     warn "error while reloading, exiting.";
2468     exit 1;
2469 root 1.212 };
2470 root 1.106
2471 root 1.159 warn "reloaded";
2472 root 1.65 };
2473    
2474 root 1.175 our $RELOAD_WATCHER; # used only during reload
2475    
2476 root 1.111 register_command "reload" => sub {
2477 root 1.65 my ($who, $arg) = @_;
2478    
2479     if ($who->flag (FLAG_WIZ)) {
2480 root 1.175 $who->message ("reloading server.");
2481    
2482     # doing reload synchronously and two reloads happen back-to-back,
2483     # coro crashes during coro_state_free->destroy here.
2484    
2485 root 1.189 $RELOAD_WATCHER ||= Event->timer (
2486     reentrant => 0,
2487     after => 0,
2488     data => WF_AUTOCANCEL,
2489     cb => sub {
2490     reload;
2491     undef $RELOAD_WATCHER;
2492     },
2493     );
2494 root 1.65 }
2495     };
2496    
2497 root 1.27 unshift @INC, $LIBDIR;
2498 root 1.17
2499 root 1.183 my $bug_warning = 0;
2500    
2501 root 1.35 $TICK_WATCHER = Event->timer (
2502 root 1.104 reentrant => 0,
2503 root 1.183 parked => 1,
2504 root 1.191 prio => 0,
2505 root 1.104 at => $NEXT_TICK || $TICK,
2506     data => WF_AUTOCANCEL,
2507     cb => sub {
2508 root 1.183 if ($Coro::current != $Coro::main) {
2509     Carp::cluck "major BUG: server tick called outside of main coro, skipping it"
2510     unless ++$bug_warning > 10;
2511     return;
2512     }
2513    
2514 root 1.163 $NOW = Event::time;
2515    
2516 root 1.133 cf::server_tick; # one server iteration
2517     $RUNTIME += $TICK;
2518 root 1.35 $NEXT_TICK += $TICK;
2519    
2520 root 1.214 if ($NOW >= $NEXT_RUNTIME_WRITE) {
2521     $NEXT_RUNTIME_WRITE = $NOW + 10;
2522     Coro::async_pool {
2523     write_runtime
2524     or warn "ERROR: unable to write runtime file: $!";
2525     };
2526     }
2527    
2528 root 1.155 $WAIT_FOR_TICK->broadcast;
2529     $WAIT_FOR_TICK_ONE->send if $WAIT_FOR_TICK_ONE->awaited;
2530    
2531 root 1.191 # my $AFTER = Event::time;
2532     # warn $AFTER - $NOW;#d#
2533 root 1.190
2534 root 1.78 # if we are delayed by four ticks or more, skip them all
2535 root 1.103 $NEXT_TICK = Event::time if Event::time >= $NEXT_TICK + $TICK * 4;
2536 root 1.35
2537     $TICK_WATCHER->at ($NEXT_TICK);
2538     $TICK_WATCHER->start;
2539     },
2540     );
2541    
2542 root 1.206 {
2543     BDB::max_poll_time $TICK * 0.1;
2544     $BDB_POLL_WATCHER = Event->io (
2545     reentrant => 0,
2546     fd => BDB::poll_fileno,
2547     poll => 'r',
2548     prio => 0,
2549     data => WF_AUTOCANCEL,
2550     cb => \&BDB::poll_cb,
2551     );
2552     BDB::min_parallel 8;
2553    
2554     BDB::set_sync_prepare {
2555     my $status;
2556     my $current = $Coro::current;
2557     (
2558     sub {
2559     $status = $!;
2560     $current->ready; undef $current;
2561     },
2562     sub {
2563     Coro::schedule while defined $current;
2564     $! = $status;
2565     },
2566     )
2567     };
2568 root 1.77
2569 root 1.206 unless ($DB_ENV) {
2570     $DB_ENV = BDB::db_env_create;
2571    
2572     cf::sync_job {
2573 root 1.208 eval {
2574     BDB::db_env_open
2575     $DB_ENV,
2576     $BDB_ENV_DIR,
2577     BDB::INIT_LOCK | BDB::INIT_LOG | BDB::INIT_MPOOL | BDB::INIT_TXN
2578     | BDB::RECOVER | BDB::REGISTER | BDB::USE_ENVIRON | BDB::CREATE,
2579     0666;
2580    
2581     cf::cleanup "db_env_open($BDB_ENV_DIR): $!" if $!;
2582    
2583     $DB_ENV->set_flags (BDB::AUTO_COMMIT | BDB::REGION_INIT | BDB::TXN_NOSYNC, 1);
2584     $DB_ENV->set_lk_detect;
2585     };
2586    
2587     cf::cleanup "db_env_open(db): $@" if $@;
2588 root 1.206 };
2589     }
2590     }
2591    
2592     {
2593     IO::AIO::min_parallel 8;
2594    
2595     undef $Coro::AIO::WATCHER;
2596     IO::AIO::max_poll_time $TICK * 0.1;
2597     $AIO_POLL_WATCHER = Event->io (
2598     reentrant => 0,
2599 root 1.214 data => WF_AUTOCANCEL,
2600 root 1.206 fd => IO::AIO::poll_fileno,
2601     poll => 'r',
2602     prio => 6,
2603     cb => \&IO::AIO::poll_cb,
2604     );
2605     }
2606 root 1.108
2607 root 1.125 END { cf::emergency_save }
2608    
2609 root 1.1 1
2610