ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/lib/cf.pm
Revision: 1.200
Committed: Mon Jan 29 17:57:22 2007 UTC (17 years, 3 months ago) by root
Branch: MAIN
Changes since 1.199: +18 -4 lines
Log Message:
support maps with and without .map extension, rename to .map on save

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