ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/lib/cf.pm
Revision: 1.203
Committed: Thu Feb 1 19:40:42 2007 UTC (17 years, 3 months ago) by root
Branch: MAIN
Changes since 1.202: +13 -1 lines
Log Message:
load regions from perl, reload on, well, reload

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