ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/lib/cf.pm
Revision: 1.199
Committed: Mon Jan 29 14:46:01 2007 UTC (17 years, 4 months ago) by root
Branch: MAIN
Changes since 1.198: +6 -4 lines
Log Message:
partial region cleanup

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