ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/lib/cf.pm
Revision: 1.114
Committed: Mon Jan 1 16:00:10 2007 UTC (17 years, 5 months ago) by root
Branch: MAIN
Changes since 1.113: +26 -6 lines
Log Message:
nimbus seems to work again

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.103 use Coro 3.3;
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.108 use Digest::MD5;
21 root 1.105 use Fcntl;
22     use IO::AIO 2.31 ();
23 root 1.72 use YAML::Syck ();
24 root 1.32 use Time::HiRes;
25 root 1.96
26     use Event; $Event::Eval = 1; # no idea why this is required, but it is
27 root 1.1
28 root 1.72 # work around bug in YAML::Syck - bad news for perl6, will it be as broken wrt. unicode?
29     $YAML::Syck::ImplicitUnicode = 1;
30    
31 root 1.103 $Coro::main->prio (2); # run main coroutine ("the server") with very high priority
32 root 1.1
33 root 1.87 sub WF_AUTOCANCEL () { 1 } # automatically cancel this watcher on reload
34    
35 root 1.85 our %COMMAND = ();
36     our %COMMAND_TIME = ();
37     our %EXTCMD = ();
38    
39 root 1.1 our @EVENT;
40 root 1.88 our $LIBDIR = datadir . "/ext";
41 root 1.1
42 root 1.35 our $TICK = MAX_TIME * 1e-6;
43     our $TICK_WATCHER;
44     our $NEXT_TICK;
45 root 1.103 our $NOW;
46 root 1.35
47 root 1.70 our %CFG;
48    
49 root 1.84 our $UPTIME; $UPTIME ||= time;
50 root 1.103 our $RUNTIME;
51    
52     our %MAP; # all maps
53     our $LINK_MAP; # the special {link} map
54     our $FREEZE;
55 root 1.108 our $RANDOM_MAPS = cf::localdir . "/random";
56     our %EXT_CORO;
57 root 1.103
58     binmode STDOUT;
59     binmode STDERR;
60    
61     # read virtual server time, if available
62     unless ($RUNTIME || !-e cf::localdir . "/runtime") {
63     open my $fh, "<", cf::localdir . "/runtime"
64     or die "unable to read runtime file: $!";
65     $RUNTIME = <$fh> + 0.;
66     }
67    
68     mkdir cf::localdir;
69     mkdir cf::localdir . "/" . cf::playerdir;
70     mkdir cf::localdir . "/" . cf::tmpdir;
71     mkdir cf::localdir . "/" . cf::uniquedir;
72 root 1.108 mkdir $RANDOM_MAPS;
73 root 1.103
74 root 1.108 # a special map that is always available
75     our $LINK_MAP;
76 root 1.76
77 root 1.110 our $EMERGENCY_POSITION = $cf::CFG{emergency_position} || ["/world/world_105_115", 5, 37];
78    
79 root 1.70 #############################################################################
80    
81     =head2 GLOBAL VARIABLES
82    
83     =over 4
84    
85 root 1.83 =item $cf::UPTIME
86    
87     The timestamp of the server start (so not actually an uptime).
88    
89 root 1.103 =item $cf::RUNTIME
90    
91     The time this server has run, starts at 0 and is increased by $cf::TICK on
92     every server tick.
93    
94 root 1.70 =item $cf::LIBDIR
95    
96     The perl library directory, where extensions and cf-specific modules can
97     be found. It will be added to C<@INC> automatically.
98    
99 root 1.103 =item $cf::NOW
100    
101     The time of the last (current) server tick.
102    
103 root 1.70 =item $cf::TICK
104    
105     The interval between server ticks, in seconds.
106    
107     =item %cf::CFG
108    
109     Configuration for the server, loaded from C</etc/crossfire/config>, or
110     from wherever your confdir points to.
111    
112     =back
113    
114     =cut
115    
116 root 1.1 BEGIN {
117     *CORE::GLOBAL::warn = sub {
118     my $msg = join "", @_;
119 root 1.103 utf8::encode $msg;
120    
121 root 1.1 $msg .= "\n"
122     unless $msg =~ /\n$/;
123    
124     LOG llevError, "cfperl: $msg";
125     };
126     }
127    
128 root 1.93 @safe::cf::global::ISA = @cf::global::ISA = 'cf::attachable';
129     @safe::cf::object::ISA = @cf::object::ISA = 'cf::attachable';
130     @safe::cf::player::ISA = @cf::player::ISA = 'cf::attachable';
131     @safe::cf::client::ISA = @cf::client::ISA = 'cf::attachable';
132     @safe::cf::map::ISA = @cf::map::ISA = 'cf::attachable';
133 root 1.41 @safe::cf::object::player::ISA = @cf::object::player::ISA = 'cf::object';
134 root 1.25
135 root 1.41 # we bless all objects into (empty) derived classes to force a method lookup
136 root 1.25 # within the Safe compartment.
137 root 1.86 for my $pkg (qw(
138 root 1.100 cf::global cf::attachable
139 root 1.86 cf::object cf::object::player
140 root 1.89 cf::client cf::player
141 root 1.86 cf::arch cf::living
142     cf::map cf::party cf::region
143     )) {
144 root 1.25 no strict 'refs';
145 root 1.41 @{"safe::$pkg\::wrap::ISA"} = @{"$pkg\::wrap::ISA"} = $pkg;
146 root 1.25 }
147 root 1.1
148 root 1.18 $Event::DIED = sub {
149     warn "error in event callback: @_";
150     };
151    
152 root 1.5 my %ext_pkg;
153 root 1.1 my @exts;
154     my @hook;
155    
156 root 1.70 =head2 UTILITY FUNCTIONS
157    
158     =over 4
159    
160     =cut
161 root 1.44
162 root 1.45 use JSON::Syck (); # TODO# replace by JSON::PC once working
163 root 1.44
164 root 1.70 =item $ref = cf::from_json $json
165    
166     Converts a JSON string into the corresponding perl data structure.
167    
168     =cut
169    
170 root 1.45 sub from_json($) {
171     $JSON::Syck::ImplicitUnicode = 1; # work around JSON::Syck bugs
172     JSON::Syck::Load $_[0]
173 root 1.44 }
174    
175 root 1.70 =item $json = cf::to_json $ref
176    
177     Converts a perl data structure into its JSON representation.
178    
179     =cut
180    
181 root 1.45 sub to_json($) {
182     $JSON::Syck::ImplicitUnicode = 0; # work around JSON::Syck bugs
183     JSON::Syck::Dump $_[0]
184 root 1.44 }
185    
186 root 1.106 =item cf::sync_job { BLOCK }
187    
188     The design of crossfire+ requires that the main coro ($Coro::main) is
189     always able to handle events or runnable, as crossfire+ is only partly
190     reentrant. Thus "blocking" it by e.g. waiting for I/O is not acceptable.
191    
192     If it must be done, put the blocking parts into C<sync_job>. This will run
193     the given BLOCK in another coroutine while waiting for the result. The
194     server will be frozen during this time, so the block should either finish
195     fast or be very important.
196    
197     =cut
198    
199 root 1.105 sub sync_job(&) {
200     my ($job) = @_;
201    
202     if ($Coro::current == $Coro::main) {
203 root 1.112 # this is the main coro, too bad, we have to block
204     # till the operation succeeds, freezing the server :/
205    
206 root 1.110 # TODO: use suspend/resume instead
207 root 1.112 # (but this is cancel-safe)
208 root 1.110 local $FREEZE = 1;
209 root 1.112
210     my $busy = 1;
211     my @res;
212    
213     (Coro::async {
214     @res = eval { $job->() };
215     warn $@ if $@;
216     undef $busy;
217     })->prio (Coro::PRIO_MAX);
218    
219 root 1.105 while ($busy) {
220     Coro::cede_notself;
221     Event::one_event unless Coro::nready;
222     }
223 root 1.112
224     wantarray ? @res : $res[0]
225 root 1.105 } else {
226 root 1.112 # we are in another coroutine, how wonderful, everything just works
227    
228     $job->()
229 root 1.105 }
230     }
231    
232 root 1.103 =item $coro = cf::coro { BLOCK }
233    
234     Creates and returns a new coro. This coro is automcatially being canceled
235     when the extension calling this is being unloaded.
236    
237     =cut
238    
239     sub coro(&) {
240     my $cb = shift;
241    
242     my $coro; $coro = async {
243     eval {
244     $cb->();
245     };
246     warn $@ if $@;
247     };
248    
249     $coro->on_destroy (sub {
250     delete $EXT_CORO{$coro+0};
251     });
252     $EXT_CORO{$coro+0} = $coro;
253    
254     $coro
255     }
256    
257 root 1.108 sub write_runtime {
258     my $runtime = cf::localdir . "/runtime";
259    
260     my $fh = aio_open "$runtime~", O_WRONLY | O_CREAT, 0644
261     or return;
262    
263 root 1.112 my $value = $cf::RUNTIME + 1 + 10; # 10 is the runtime save interval, for a monotonic clock
264 root 1.108 (aio_write $fh, 0, (length $value), $value, 0) <= 0
265     and return;
266    
267     aio_fsync $fh
268     and return;
269    
270     close $fh
271     or return;
272    
273     aio_rename "$runtime~", $runtime
274     and return;
275    
276     1
277     }
278    
279 root 1.70 =back
280    
281 root 1.71 =cut
282    
283 root 1.44 #############################################################################
284 root 1.39
285 root 1.108 package cf::path;
286    
287     sub new {
288     my ($class, $path, $base) = @_;
289    
290 root 1.110 $path = $path->as_string if ref $path;
291    
292 root 1.108 my $self = bless { }, $class;
293    
294 root 1.114 # {... are special paths that are not touched
295     # ?xxx/... are special absolute paths
296     # ?random/... random maps
297     # /! non-realised random map exit
298     # /... normal maps
299     # ~/... per-player maps without a specific player (DO NOT USE)
300     # ~user/... per-player map of a specific user
301    
302     if ($path =~ /^{/) {
303     # fine as it is
304     } elsif ($path =~ s{^\?random/}{}) {
305 root 1.109 Coro::AIO::aio_load "$cf::RANDOM_MAPS/$path.meta", my $data;
306     $self->{random} = cf::from_json $data;
307 root 1.108 } else {
308     if ($path =~ s{^~([^/]+)?}{}) {
309     $self->{user_rel} = 1;
310    
311     if (defined $1) {
312     $self->{user} = $1;
313     } elsif ($base =~ m{^~([^/]+)/}) {
314     $self->{user} = $1;
315     } else {
316     warn "cannot resolve user-relative path without user <$path,$base>\n";
317     }
318     } elsif ($path =~ /^\//) {
319     # already absolute
320     } else {
321     $base =~ s{[^/]+/?$}{};
322     return $class->new ("$base/$path");
323     }
324    
325     for ($path) {
326     redo if s{/\.?/}{/};
327     redo if s{/[^/]+/\.\./}{/};
328     }
329     }
330    
331     $self->{path} = $path;
332    
333     $self
334     }
335    
336     # the name / primary key / in-game path
337     sub as_string {
338     my ($self) = @_;
339    
340     $self->{user_rel} ? "~$self->{user}$self->{path}"
341     : $self->{random} ? "?random/$self->{path}"
342     : $self->{path}
343     }
344    
345     # the displayed name, this is a one way mapping
346     sub visible_name {
347     my ($self) = @_;
348    
349 root 1.109 # if (my $rmp = $self->{random}) {
350     # # todo: be more intelligent about this
351     # "?random/$rmp->{origin_map}+$rmp->{origin_x}+$rmp->{origin_y}/$rmp->{dungeon_level}"
352     # } else {
353     $self->as_string
354     # }
355 root 1.108 }
356    
357     # escape the /'s in the path
358     sub _escaped_path {
359     # ∕ is U+2215
360     (my $path = $_[0]{path}) =~ s/\//∕/g;
361     $path
362     }
363    
364     # the original (read-only) location
365     sub load_path {
366     my ($self) = @_;
367    
368     sprintf "%s/%s/%s", cf::datadir, cf::mapdir, $self->{path}
369     }
370    
371     # the temporary/swap location
372     sub save_path {
373     my ($self) = @_;
374    
375     $self->{user_rel} ? sprintf "%s/%s/%s/%s", cf::localdir, cf::playerdir, $self->{user}, $self->_escaped_path
376 root 1.109 : $self->{random} ? sprintf "%s/%s", $RANDOM_MAPS, $self->{path}
377 root 1.108 : sprintf "%s/%s/%s", cf::localdir, cf::tmpdir, $self->_escaped_path
378     }
379    
380     # the unique path, might be eq to save_path
381     sub uniq_path {
382     my ($self) = @_;
383    
384     $self->{user_rel} || $self->{random}
385     ? undef
386     : sprintf "%s/%s/%s", cf::localdir, cf::uniquedir, $self->_escaped_path
387     }
388    
389     # return random map parameters, or undef
390     sub random_map_params {
391     my ($self) = @_;
392    
393     $self->{random}
394     }
395    
396     # this is somewhat ugly, but style maps do need special treatment
397     sub is_style_map {
398     $_[0]{path} =~ m{^/styles/}
399     }
400    
401     package cf;
402    
403     #############################################################################
404    
405 root 1.93 =head2 ATTACHABLE OBJECTS
406    
407 root 1.94 Many objects in crossfire are so-called attachable objects. That means you can
408     attach callbacks/event handlers (a collection of which is called an "attachment")
409     to it. All such attachable objects support the following methods.
410    
411     In the following description, CLASS can be any of C<global>, C<object>
412     C<player>, C<client> or C<map> (i.e. the attachable objects in
413     crossfire+).
414 root 1.55
415     =over 4
416    
417 root 1.94 =item $attachable->attach ($attachment, key => $value...)
418    
419     =item $attachable->detach ($attachment)
420    
421     Attach/detach a pre-registered attachment to a specific object and give it
422     the specified key/value pairs as arguments.
423    
424     Example, attach a minesweeper attachment to the given object, making it a
425     10x10 minesweeper game:
426 root 1.46
427 root 1.94 $obj->attach (minesweeper => width => 10, height => 10);
428 root 1.53
429 root 1.93 =item $bool = $attachable->attached ($name)
430 root 1.46
431 root 1.93 Checks wether the named attachment is currently attached to the object.
432 root 1.46
433 root 1.94 =item cf::CLASS->attach ...
434 root 1.46
435 root 1.94 =item cf::CLASS->detach ...
436 root 1.92
437 root 1.94 Define an anonymous attachment and attach it to all objects of the given
438     CLASS. See the next function for an explanation of its arguments.
439 root 1.92
440 root 1.93 You can attach to global events by using the C<cf::global> class.
441 root 1.92
442 root 1.94 Example, log all player logins:
443    
444     cf::player->attach (
445     on_login => sub {
446     my ($pl) = @_;
447     ...
448     },
449     );
450    
451     Example, attach to the jeweler skill:
452    
453     cf::object->attach (
454     type => cf::SKILL,
455     subtype => cf::SK_JEWELER,
456     on_use_skill => sub {
457     my ($sk, $ob, $part, $dir, $msg) = @_;
458     ...
459     },
460     );
461    
462     =item cf::CLASS::attachment $name, ...
463    
464     Register an attachment by C<$name> through which attachable objects of the
465     given CLASS can refer to this attachment.
466    
467     Some classes such as crossfire maps and objects can specify attachments
468     that are attached at load/instantiate time, thus the need for a name.
469    
470     These calls expect any number of the following handler/hook descriptions:
471 root 1.46
472     =over 4
473    
474     =item prio => $number
475    
476     Set the priority for all following handlers/hooks (unless overwritten
477     by another C<prio> setting). Lower priority handlers get executed
478     earlier. The default priority is C<0>, and many built-in handlers are
479     registered at priority C<-1000>, so lower priorities should not be used
480     unless you know what you are doing.
481    
482 root 1.93 =item type => $type
483    
484     (Only for C<< cf::object->attach >> calls), limits the attachment to the
485     given type of objects only (the additional parameter C<subtype> can be
486     used to further limit to the given subtype).
487    
488 root 1.46 =item on_I<event> => \&cb
489    
490     Call the given code reference whenever the named event happens (event is
491     something like C<instantiate>, C<apply>, C<use_skill> and so on, and which
492     handlers are recognised generally depends on the type of object these
493     handlers attach to).
494    
495     See F<include/eventinc.h> for the full list of events supported, and their
496     class.
497    
498     =item package => package::
499    
500     Look for sub functions of the name C<< on_I<event> >> in the given
501     package and register them. Only handlers for eevents supported by the
502     object/class are recognised.
503    
504     =back
505    
506 root 1.94 Example, define an attachment called "sockpuppet" that calls the given
507     event handler when a monster attacks:
508    
509     cf::object::attachment sockpuppet =>
510     on_skill_attack => sub {
511     my ($self, $victim) = @_;
512     ...
513     }
514     }
515    
516 root 1.96 =item $attachable->valid
517    
518     Just because you have a perl object does not mean that the corresponding
519     C-level object still exists. If you try to access an object that has no
520     valid C counterpart anymore you get an exception at runtime. This method
521     can be used to test for existence of the C object part without causing an
522     exception.
523    
524 root 1.39 =cut
525    
526 root 1.40 # the following variables are defined in .xs and must not be re-created
527 root 1.100 our @CB_GLOBAL = (); # registry for all global events
528     our @CB_ATTACHABLE = (); # registry for all attachables
529     our @CB_OBJECT = (); # all objects (should not be used except in emergency)
530     our @CB_PLAYER = ();
531     our @CB_CLIENT = ();
532     our @CB_TYPE = (); # registry for type (cf-object class) based events
533     our @CB_MAP = ();
534 root 1.39
535 root 1.45 my %attachment;
536    
537 root 1.93 sub _attach_cb($$$$) {
538     my ($registry, $event, $prio, $cb) = @_;
539 root 1.39
540     use sort 'stable';
541    
542     $cb = [$prio, $cb];
543    
544     @{$registry->[$event]} = sort
545     { $a->[0] cmp $b->[0] }
546     @{$registry->[$event] || []}, $cb;
547     }
548    
549 root 1.100 # hack
550     my %attachable_klass = map +($_ => 1), KLASS_OBJECT, KLASS_CLIENT, KLASS_PLAYER, KLASS_MAP;
551    
552 root 1.39 # attach handles attaching event callbacks
553     # the only thing the caller has to do is pass the correct
554     # registry (== where the callback attaches to).
555 root 1.93 sub _attach {
556 root 1.45 my ($registry, $klass, @arg) = @_;
557 root 1.39
558 root 1.93 my $object_type;
559 root 1.39 my $prio = 0;
560     my %cb_id = map +("on_" . lc $EVENT[$_][0], $_) , grep $EVENT[$_][1] == $klass, 0 .. $#EVENT;
561    
562 root 1.100 #TODO: get rid of this hack
563     if ($attachable_klass{$klass}) {
564     %cb_id = (%cb_id, map +("on_" . lc $EVENT[$_][0], $_) , grep $EVENT[$_][1] == KLASS_ATTACHABLE, 0 .. $#EVENT);
565     }
566    
567 root 1.45 while (@arg) {
568     my $type = shift @arg;
569 root 1.39
570     if ($type eq "prio") {
571 root 1.45 $prio = shift @arg;
572 root 1.39
573 root 1.93 } elsif ($type eq "type") {
574     $object_type = shift @arg;
575     $registry = $CB_TYPE[$object_type] ||= [];
576    
577     } elsif ($type eq "subtype") {
578     defined $object_type or Carp::croak "subtype specified without type";
579     my $object_subtype = shift @arg;
580     $registry = $CB_TYPE[$object_type + $object_subtype * NUM_SUBTYPES] ||= [];
581    
582 root 1.39 } elsif ($type eq "package") {
583 root 1.45 my $pkg = shift @arg;
584 root 1.39
585     while (my ($name, $id) = each %cb_id) {
586     if (my $cb = $pkg->can ($name)) {
587 root 1.93 _attach_cb $registry, $id, $prio, $cb;
588 root 1.39 }
589     }
590    
591     } elsif (exists $cb_id{$type}) {
592 root 1.93 _attach_cb $registry, $cb_id{$type}, $prio, shift @arg;
593 root 1.39
594     } elsif (ref $type) {
595     warn "attaching objects not supported, ignoring.\n";
596    
597     } else {
598 root 1.45 shift @arg;
599 root 1.39 warn "attach argument '$type' not supported, ignoring.\n";
600     }
601     }
602     }
603    
604 root 1.93 sub _object_attach {
605 root 1.48 my ($obj, $name, %arg) = @_;
606 root 1.46
607 root 1.55 return if exists $obj->{_attachment}{$name};
608    
609 root 1.46 if (my $attach = $attachment{$name}) {
610     my $registry = $obj->registry;
611    
612 root 1.47 for (@$attach) {
613     my ($klass, @attach) = @$_;
614 root 1.93 _attach $registry, $klass, @attach;
615 root 1.47 }
616 root 1.46
617 root 1.48 $obj->{$name} = \%arg;
618 root 1.46 } else {
619     warn "object uses attachment '$name' that is not available, postponing.\n";
620     }
621    
622 root 1.50 $obj->{_attachment}{$name} = undef;
623 root 1.46 }
624    
625 root 1.93 sub cf::attachable::attach {
626     if (ref $_[0]) {
627     _object_attach @_;
628     } else {
629     _attach shift->_attach_registry, @_;
630     }
631 root 1.55 };
632 root 1.46
633 root 1.54 # all those should be optimised
634 root 1.93 sub cf::attachable::detach {
635 root 1.54 my ($obj, $name) = @_;
636 root 1.46
637 root 1.93 if (ref $obj) {
638     delete $obj->{_attachment}{$name};
639     reattach ($obj);
640     } else {
641     Carp::croak "cannot, currently, detach class attachments";
642     }
643 root 1.55 };
644    
645 root 1.93 sub cf::attachable::attached {
646 root 1.55 my ($obj, $name) = @_;
647    
648     exists $obj->{_attachment}{$name}
649 root 1.39 }
650    
651 root 1.100 for my $klass (qw(ATTACHABLE GLOBAL OBJECT PLAYER CLIENT MAP)) {
652 root 1.93 eval "#line " . __LINE__ . " 'cf.pm'
653     sub cf::\L$klass\E::_attach_registry {
654     (\\\@CB_$klass, KLASS_$klass)
655     }
656 root 1.45
657 root 1.93 sub cf::\L$klass\E::attachment {
658     my \$name = shift;
659 root 1.39
660 root 1.93 \$attachment{\$name} = [[KLASS_$klass, \@_]];
661     }
662     ";
663     die if $@;
664 root 1.52 }
665    
666 root 1.39 our $override;
667 root 1.45 our @invoke_results = (); # referenced from .xs code. TODO: play tricks with reify and mortals?
668 root 1.39
669 root 1.45 sub override {
670     $override = 1;
671     @invoke_results = ();
672 root 1.39 }
673    
674 root 1.45 sub do_invoke {
675 root 1.39 my $event = shift;
676 root 1.40 my $callbacks = shift;
677 root 1.39
678 root 1.45 @invoke_results = ();
679    
680 root 1.39 local $override;
681    
682 root 1.40 for (@$callbacks) {
683 root 1.39 eval { &{$_->[1]} };
684    
685     if ($@) {
686     warn "$@";
687 root 1.64 warn "... while processing $EVENT[$event][0](@_) event, skipping processing altogether.\n";
688 root 1.39 override;
689     }
690    
691     return 1 if $override;
692     }
693    
694     0
695     }
696    
697 root 1.96 =item $bool = cf::global::invoke (EVENT_CLASS_XXX, ...)
698 root 1.55
699 root 1.96 =item $bool = $attachable->invoke (EVENT_CLASS_XXX, ...)
700 root 1.55
701 root 1.96 Generate an object-specific event with the given arguments.
702 root 1.55
703 root 1.96 This API is preliminary (most likely, the EVENT_CLASS_xxx prefix will be
704 root 1.55 removed in future versions), and there is no public API to access override
705     results (if you must, access C<@cf::invoke_results> directly).
706    
707     =back
708    
709 root 1.71 =cut
710    
711 root 1.70 #############################################################################
712 root 1.45 # object support
713    
714 root 1.102 sub reattach {
715     # basically do the same as instantiate, without calling instantiate
716     my ($obj) = @_;
717    
718     my $registry = $obj->registry;
719    
720     @$registry = ();
721    
722     delete $obj->{_attachment} unless scalar keys %{ $obj->{_attachment} || {} };
723    
724     for my $name (keys %{ $obj->{_attachment} || {} }) {
725     if (my $attach = $attachment{$name}) {
726     for (@$attach) {
727     my ($klass, @attach) = @$_;
728     _attach $registry, $klass, @attach;
729     }
730     } else {
731     warn "object uses attachment '$name' that is not available, postponing.\n";
732     }
733     }
734     }
735    
736 root 1.100 cf::attachable->attach (
737     prio => -1000000,
738     on_instantiate => sub {
739     my ($obj, $data) = @_;
740 root 1.45
741 root 1.100 $data = from_json $data;
742 root 1.45
743 root 1.100 for (@$data) {
744     my ($name, $args) = @$_;
745 root 1.49
746 root 1.100 $obj->attach ($name, %{$args || {} });
747     }
748     },
749 root 1.102 on_reattach => \&reattach,
750 root 1.100 on_clone => sub {
751     my ($src, $dst) = @_;
752    
753     @{$dst->registry} = @{$src->registry};
754    
755     %$dst = %$src;
756    
757     %{$dst->{_attachment}} = %{$src->{_attachment}}
758     if exists $src->{_attachment};
759     },
760     );
761 root 1.45
762 root 1.46 sub object_freezer_save {
763 root 1.59 my ($filename, $rdata, $objs) = @_;
764 root 1.46
765 root 1.105 sync_job {
766     if (length $$rdata) {
767     warn sprintf "saving %s (%d,%d)\n",
768     $filename, length $$rdata, scalar @$objs;
769 root 1.60
770 root 1.105 if (my $fh = aio_open "$filename~", O_WRONLY | O_CREAT, 0600) {
771 root 1.60 chmod SAVE_MODE, $fh;
772 root 1.105 aio_write $fh, 0, (length $$rdata), $$rdata, 0;
773     aio_fsync $fh;
774 root 1.60 close $fh;
775 root 1.105
776     if (@$objs) {
777     if (my $fh = aio_open "$filename.pst~", O_WRONLY | O_CREAT, 0600) {
778     chmod SAVE_MODE, $fh;
779     my $data = Storable::nfreeze { version => 1, objs => $objs };
780     aio_write $fh, 0, (length $data), $data, 0;
781     aio_fsync $fh;
782     close $fh;
783     aio_rename "$filename.pst~", "$filename.pst";
784     }
785     } else {
786     aio_unlink "$filename.pst";
787     }
788    
789     aio_rename "$filename~", $filename;
790 root 1.60 } else {
791 root 1.105 warn "FATAL: $filename~: $!\n";
792 root 1.60 }
793 root 1.59 } else {
794 root 1.105 aio_unlink $filename;
795     aio_unlink "$filename.pst";
796 root 1.59 }
797 root 1.45 }
798     }
799    
800 root 1.80 sub object_freezer_as_string {
801     my ($rdata, $objs) = @_;
802    
803     use Data::Dumper;
804    
805 root 1.81 $$rdata . Dumper $objs
806 root 1.80 }
807    
808 root 1.46 sub object_thawer_load {
809     my ($filename) = @_;
810    
811 root 1.105 my ($data, $av);
812 root 1.61
813 root 1.105 (aio_load $filename, $data) >= 0
814     or return;
815 root 1.61
816 root 1.105 unless (aio_stat "$filename.pst") {
817     (aio_load "$filename.pst", $av) >= 0
818     or return;
819 root 1.113 $av = eval { (Storable::thaw $av)->{objs} };
820 root 1.61 }
821 root 1.45
822 root 1.105 return ($data, $av);
823 root 1.45 }
824    
825     #############################################################################
826 root 1.85 # command handling &c
827 root 1.39
828 root 1.85 =item cf::register_command $name => \&callback($ob,$args);
829 root 1.1
830 root 1.85 Register a callback for execution when the client sends the user command
831     $name.
832 root 1.5
833 root 1.85 =cut
834 root 1.5
835 root 1.85 sub register_command {
836     my ($name, $cb) = @_;
837 root 1.5
838 root 1.85 my $caller = caller;
839     #warn "registering command '$name/$time' to '$caller'";
840 root 1.1
841 root 1.85 push @{ $COMMAND{$name} }, [$caller, $cb];
842 root 1.1 }
843    
844 root 1.85 =item cf::register_extcmd $name => \&callback($pl,$packet);
845 root 1.1
846 root 1.85 Register a callbackf ro execution when the client sends an extcmd packet.
847 root 1.1
848 root 1.85 If the callback returns something, it is sent back as if reply was being
849     called.
850 root 1.1
851 root 1.85 =cut
852 root 1.1
853 root 1.16 sub register_extcmd {
854     my ($name, $cb) = @_;
855    
856     my $caller = caller;
857     #warn "registering extcmd '$name' to '$caller'";
858    
859 root 1.85 $EXTCMD{$name} = [$cb, $caller];
860 root 1.16 }
861    
862 root 1.93 cf::player->attach (
863 root 1.85 on_command => sub {
864     my ($pl, $name, $params) = @_;
865    
866     my $cb = $COMMAND{$name}
867     or return;
868    
869     for my $cmd (@$cb) {
870     $cmd->[1]->($pl->ob, $params);
871     }
872    
873     cf::override;
874     },
875     on_extcmd => sub {
876     my ($pl, $buf) = @_;
877    
878     my $msg = eval { from_json $buf };
879    
880     if (ref $msg) {
881     if (my $cb = $EXTCMD{$msg->{msgtype}}) {
882     if (my %reply = $cb->[0]->($pl, $msg)) {
883     $pl->ext_reply ($msg->{msgid}, %reply);
884     }
885     }
886     } else {
887     warn "player " . ($pl->ob->name) . " sent unparseable ext message: <$buf>\n";
888     }
889    
890     cf::override;
891     },
892 root 1.93 );
893 root 1.85
894 root 1.6 sub register {
895     my ($base, $pkg) = @_;
896    
897 root 1.45 #TODO
898 root 1.6 }
899    
900 root 1.1 sub load_extension {
901     my ($path) = @_;
902    
903     $path =~ /([^\/\\]+)\.ext$/ or die "$path";
904 root 1.5 my $base = $1;
905 root 1.1 my $pkg = $1;
906     $pkg =~ s/[^[:word:]]/_/g;
907 root 1.41 $pkg = "ext::$pkg";
908 root 1.1
909     warn "loading '$path' into '$pkg'\n";
910    
911     open my $fh, "<:utf8", $path
912     or die "$path: $!";
913    
914     my $source =
915     "package $pkg; use strict; use utf8;\n"
916     . "#line 1 \"$path\"\n{\n"
917     . (do { local $/; <$fh> })
918     . "\n};\n1";
919    
920     eval $source
921 root 1.82 or die $@ ? "$path: $@\n"
922     : "extension disabled.\n";
923 root 1.1
924     push @exts, $pkg;
925 root 1.5 $ext_pkg{$base} = $pkg;
926 root 1.1
927 root 1.6 # no strict 'refs';
928 root 1.23 # @{"$pkg\::ISA"} = ext::;
929 root 1.1
930 root 1.6 register $base, $pkg;
931 root 1.1 }
932    
933     sub unload_extension {
934     my ($pkg) = @_;
935    
936     warn "removing extension $pkg\n";
937    
938     # remove hooks
939 root 1.45 #TODO
940     # for my $idx (0 .. $#PLUGIN_EVENT) {
941     # delete $hook[$idx]{$pkg};
942     # }
943 root 1.1
944     # remove commands
945 root 1.85 for my $name (keys %COMMAND) {
946     my @cb = grep $_->[0] ne $pkg, @{ $COMMAND{$name} };
947 root 1.1
948     if (@cb) {
949 root 1.85 $COMMAND{$name} = \@cb;
950 root 1.1 } else {
951 root 1.85 delete $COMMAND{$name};
952 root 1.1 }
953     }
954    
955 root 1.15 # remove extcmds
956 root 1.85 for my $name (grep $EXTCMD{$_}[1] eq $pkg, keys %EXTCMD) {
957     delete $EXTCMD{$name};
958 root 1.15 }
959    
960 root 1.43 if (my $cb = $pkg->can ("unload")) {
961 elmex 1.31 eval {
962     $cb->($pkg);
963     1
964     } or warn "$pkg unloaded, but with errors: $@";
965     }
966    
967 root 1.1 Symbol::delete_package $pkg;
968     }
969    
970     sub load_extensions {
971     for my $ext (<$LIBDIR/*.ext>) {
972 root 1.3 next unless -r $ext;
973 root 1.2 eval {
974     load_extension $ext;
975     1
976     } or warn "$ext not loaded: $@";
977 root 1.1 }
978     }
979    
980 root 1.8 #############################################################################
981     # load/save/clean perl data associated with a map
982    
983 root 1.39 *cf::mapsupport::on_clean = sub {
984 root 1.13 my ($map) = @_;
985 root 1.7
986     my $path = $map->tmpname;
987     defined $path or return;
988    
989 root 1.46 unlink "$path.pst";
990 root 1.7 };
991    
992 root 1.93 cf::map->attach (prio => -10000, package => cf::mapsupport::);
993 root 1.39
994 root 1.8 #############################################################################
995     # load/save perl data associated with player->ob objects
996    
997 root 1.33 sub all_objects(@) {
998     @_, map all_objects ($_->inv), @_
999     }
1000    
1001 root 1.60 # TODO: compatibility cruft, remove when no longer needed
1002 root 1.93 cf::player->attach (
1003 root 1.39 on_load => sub {
1004     my ($pl, $path) = @_;
1005    
1006     for my $o (all_objects $pl->ob) {
1007     if (my $value = $o->get_ob_key_value ("_perl_data")) {
1008     $o->set_ob_key_value ("_perl_data");
1009 root 1.8
1010 root 1.39 %$o = %{ Storable::thaw pack "H*", $value };
1011     }
1012 root 1.11 }
1013 root 1.39 },
1014 root 1.93 );
1015 root 1.6
1016 root 1.22 #############################################################################
1017 root 1.70
1018     =head2 CORE EXTENSIONS
1019    
1020     Functions and methods that extend core crossfire objects.
1021    
1022 root 1.95 =head3 cf::player
1023    
1024 root 1.70 =over 4
1025 root 1.22
1026 root 1.23 =item cf::player::exists $login
1027    
1028     Returns true when the given account exists.
1029    
1030     =cut
1031    
1032     sub cf::player::exists($) {
1033     cf::player::find $_[0]
1034     or -f sprintf "%s/%s/%s/%s.pl", cf::localdir, cf::playerdir, ($_[0]) x 2;
1035     }
1036    
1037 root 1.95 =item $player->ext_reply ($msgid, $msgtype, %msg)
1038    
1039     Sends an ext reply to the player.
1040    
1041     =cut
1042    
1043     sub cf::player::ext_reply($$$%) {
1044     my ($self, $id, %msg) = @_;
1045    
1046     $msg{msgid} = $id;
1047    
1048     $self->send ("ext " . to_json \%msg);
1049     }
1050    
1051     =back
1052    
1053 root 1.110
1054     =head3 cf::map
1055    
1056     =over 4
1057    
1058     =cut
1059    
1060     package cf::map;
1061    
1062     use Fcntl;
1063     use Coro::AIO;
1064    
1065     our $MAX_RESET = 7200;
1066     our $DEFAULT_RESET = 3600;
1067    
1068     sub generate_random_map {
1069     my ($path, $rmp) = @_;
1070    
1071     # mit "rum" bekleckern, nicht
1072     cf::map::_create_random_map
1073     $path,
1074     $rmp->{wallstyle}, $rmp->{wall_name}, $rmp->{floorstyle}, $rmp->{monsterstyle},
1075     $rmp->{treasurestyle}, $rmp->{layoutstyle}, $rmp->{doorstyle}, $rmp->{decorstyle},
1076     $rmp->{origin_map}, $rmp->{final_map}, $rmp->{exitstyle}, $rmp->{this_map},
1077     $rmp->{exit_on_final_map},
1078     $rmp->{xsize}, $rmp->{ysize},
1079     $rmp->{expand2x}, $rmp->{layoutoptions1}, $rmp->{layoutoptions2}, $rmp->{layoutoptions3},
1080     $rmp->{symmetry}, $rmp->{difficulty}, $rmp->{difficulty_given}, $rmp->{difficulty_increase},
1081     $rmp->{dungeon_level}, $rmp->{dungeon_depth}, $rmp->{decoroptions}, $rmp->{orientation},
1082     $rmp->{origin_y}, $rmp->{origin_x}, $rmp->{random_seed}, $rmp->{total_map_hp},
1083     $rmp->{map_layout_style}, $rmp->{treasureoptions}, $rmp->{symmetry_used},
1084     (cf::region::find $rmp->{region})
1085     }
1086    
1087     # and all this just because we cannot iterate over
1088     # all maps in C++...
1089     sub change_all_map_light {
1090     my ($change) = @_;
1091    
1092     $_->change_map_light ($change) for values %cf::MAP;
1093     }
1094    
1095     sub try_load_header($) {
1096     my ($path) = @_;
1097    
1098     utf8::encode $path;
1099     aio_open $path, O_RDONLY, 0
1100     or return;
1101    
1102     my $map = cf::map::new
1103     or return;
1104    
1105     $map->load_header ($path)
1106     or return;
1107    
1108     $map->{load_path} = $path;
1109    
1110     $map
1111     }
1112    
1113     sub find_map {
1114     my ($path, $origin) = @_;
1115    
1116     #warn "find_map<$path,$origin>\n";#d#
1117    
1118 root 1.112 $path = new cf::path $path, $origin && $origin->path;
1119 root 1.110 my $key = $path->as_string;
1120    
1121     $cf::MAP{$key} || do {
1122     # do it the slow way
1123     my $map = try_load_header $path->save_path;
1124    
1125     if ($map) {
1126     # safety
1127     $map->{instantiate_time} = $cf::RUNTIME
1128     if $map->{instantiate_time} > $cf::RUNTIME;
1129     } else {
1130     if (my $rmp = $path->random_map_params) {
1131     $map = generate_random_map $key, $rmp;
1132     } else {
1133     $map = try_load_header $path->load_path;
1134     }
1135    
1136     $map or return;
1137    
1138 root 1.111 $map->{load_original} = 1;
1139 root 1.110 $map->{instantiate_time} = $cf::RUNTIME;
1140     $map->instantiate;
1141    
1142     # per-player maps become, after loading, normal maps
1143     $map->per_player (0) if $path->{user_rel};
1144     }
1145    
1146     $map->path ($key);
1147     $map->{path} = $path;
1148     $map->last_access ($cf::RUNTIME);
1149    
1150 root 1.112 if ($map->should_reset) {
1151     $map->reset;
1152     $map = find_map $path;
1153     }
1154 root 1.110
1155     $cf::MAP{$key} = $map
1156     }
1157     }
1158    
1159     sub load {
1160     my ($self) = @_;
1161    
1162     return if $self->in_memory != cf::MAP_SWAPPED;
1163    
1164     $self->in_memory (cf::MAP_LOADING);
1165    
1166     my $path = $self->{path};
1167    
1168     $self->alloc;
1169     $self->load_objects ($self->{load_path}, 1)
1170     or return;
1171    
1172 root 1.112 $self->set_object_flag (cf::FLAG_OBJ_ORIGINAL, 1)
1173     if delete $self->{load_original};
1174 root 1.111
1175 root 1.110 if (my $uniq = $path->uniq_path) {
1176     utf8::encode $uniq;
1177     if (aio_open $uniq, O_RDONLY, 0) {
1178     $self->clear_unique_items;
1179     $self->load_objects ($uniq, 0);
1180     }
1181     }
1182    
1183     # now do the right thing for maps
1184     $self->link_multipart_objects;
1185    
1186     if ($self->{path}->is_style_map) {
1187     $self->{deny_save} = 1;
1188     $self->{deny_reset} = 1;
1189     } else {
1190     $self->fix_auto_apply;
1191     $self->decay_objects;
1192     $self->update_buttons;
1193     $self->set_darkness_map;
1194     $self->difficulty ($self->estimate_difficulty)
1195     unless $self->difficulty;
1196     $self->activate;
1197     }
1198    
1199     $self->in_memory (cf::MAP_IN_MEMORY);
1200     }
1201    
1202     sub load_map_sync {
1203     my ($path, $origin) = @_;
1204    
1205     #warn "load_map_sync<$path, $origin>\n";#d#
1206    
1207     cf::sync_job {
1208     my $map = cf::map::find_map $path, $origin
1209     or return;
1210     $map->load;
1211     $map
1212     }
1213     }
1214    
1215     sub save {
1216     my ($self) = @_;
1217    
1218     my $save = $self->{path}->save_path; utf8::encode $save;
1219     my $uniq = $self->{path}->uniq_path; utf8::encode $uniq;
1220    
1221     $self->{last_save} = $cf::RUNTIME;
1222    
1223     return unless $self->dirty;
1224    
1225     $self->{load_path} = $save;
1226    
1227     return if $self->{deny_save};
1228    
1229     if ($uniq) {
1230     $self->save_objects ($save, cf::IO_HEADER | cf::IO_OBJECTS);
1231     $self->save_objects ($uniq, cf::IO_UNIQUES);
1232     } else {
1233     $self->save_objects ($save, cf::IO_HEADER | cf::IO_OBJECTS | cf::IO_UNIQUES);
1234     }
1235     }
1236    
1237     sub swap_out {
1238     my ($self) = @_;
1239    
1240     return if $self->players;
1241     return if $self->in_memory != cf::MAP_IN_MEMORY;
1242     return if $self->{deny_save};
1243    
1244     $self->save;
1245     $self->clear;
1246     $self->in_memory (cf::MAP_SWAPPED);
1247     }
1248    
1249 root 1.112 sub reset_at {
1250     my ($self) = @_;
1251 root 1.110
1252     # TODO: safety, remove and allow resettable per-player maps
1253 root 1.114 return 1e99 if $self->{path}{user_rel};
1254     return 1e99 if $self->{deny_reset};
1255 root 1.110
1256 root 1.112 my $time = $self->fixed_resettime ? $self->{instantiate_time} : $self->last_access;
1257 root 1.114 my $to = List::Util::min $MAX_RESET, $self->reset_timeout || $DEFAULT_RESET;
1258 root 1.110
1259 root 1.112 $time + $to
1260     }
1261    
1262     sub should_reset {
1263     my ($self) = @_;
1264    
1265     $self->reset_at <= $cf::RUNTIME
1266 root 1.111 }
1267    
1268     sub unlink_save {
1269     my ($self) = @_;
1270    
1271     utf8::encode (my $save = $self->{path}->save_path);
1272     aioreq_pri 3; IO::AIO::aio_unlink $save;
1273     aioreq_pri 3; IO::AIO::aio_unlink "$save.pst";
1274 root 1.110 }
1275    
1276 root 1.113 sub rename {
1277     my ($self, $new_path) = @_;
1278    
1279     $self->unlink_save;
1280    
1281     delete $cf::MAP{$self->path};
1282     $self->{path} = new cf::path $new_path;
1283 root 1.114 $self->path ($self->{path}->as_string);
1284 root 1.113 $cf::MAP{$self->path} = $self;
1285    
1286     $self->save;
1287     }
1288    
1289 root 1.110 sub reset {
1290     my ($self) = @_;
1291    
1292     return if $self->players;
1293     return if $self->{path}{user_rel};#d#
1294    
1295     warn "resetting map ", $self->path;#d#
1296    
1297 root 1.111 delete $cf::MAP{$self->path};
1298 root 1.110
1299     $_->clear_links_to ($self) for values %cf::MAP;
1300    
1301 root 1.111 $self->unlink_save;
1302     $self->destroy;
1303 root 1.110 }
1304    
1305 root 1.114 my $nuke_counter = "aaaa";
1306    
1307     sub nuke {
1308     my ($self) = @_;
1309    
1310     $self->{deny_save} = 1;
1311     $self->reset_timeout (1);
1312     $self->rename ("{nuke}/" . ($nuke_counter++));
1313     $self->reset; # polite request, might not happen
1314     }
1315    
1316 root 1.110 sub customise_for {
1317     my ($map, $ob) = @_;
1318    
1319     if ($map->per_player) {
1320     return cf::map::find_map "~" . $ob->name . "/" . $map->{path}{path};
1321     }
1322    
1323     $map
1324     }
1325    
1326     sub emergency_save {
1327     local $cf::FREEZE = 1;
1328    
1329     warn "enter emergency map save\n";
1330    
1331     cf::sync_job {
1332     warn "begin emergency map save\n";
1333     $_->save for values %cf::MAP;
1334     };
1335    
1336     warn "end emergency map save\n";
1337     }
1338    
1339     package cf;
1340    
1341     =back
1342    
1343    
1344 root 1.95 =head3 cf::object::player
1345    
1346     =over 4
1347    
1348 root 1.79 =item $player_object->reply ($npc, $msg[, $flags])
1349 root 1.28
1350     Sends a message to the player, as if the npc C<$npc> replied. C<$npc>
1351     can be C<undef>. Does the right thing when the player is currently in a
1352     dialogue with the given NPC character.
1353    
1354     =cut
1355    
1356 root 1.22 # rough implementation of a future "reply" method that works
1357     # with dialog boxes.
1358 root 1.95 #TODO: the first argument must go, split into a $npc->reply_to ( method
1359 root 1.23 sub cf::object::player::reply($$$;$) {
1360     my ($self, $npc, $msg, $flags) = @_;
1361    
1362     $flags = cf::NDI_BROWN | cf::NDI_UNIQUE unless @_ >= 4;
1363 root 1.22
1364 root 1.24 if ($self->{record_replies}) {
1365     push @{ $self->{record_replies} }, [$npc, $msg, $flags];
1366     } else {
1367     $msg = $npc->name . " says: $msg" if $npc;
1368     $self->message ($msg, $flags);
1369     }
1370 root 1.22 }
1371    
1372 root 1.79 =item $player_object->may ("access")
1373    
1374     Returns wether the given player is authorized to access resource "access"
1375     (e.g. "command_wizcast").
1376    
1377     =cut
1378    
1379     sub cf::object::player::may {
1380     my ($self, $access) = @_;
1381    
1382     $self->flag (cf::FLAG_WIZ) ||
1383     (ref $cf::CFG{"may_$access"}
1384     ? scalar grep $self->name eq $_, @{$cf::CFG{"may_$access"}}
1385     : $cf::CFG{"may_$access"})
1386     }
1387 root 1.70
1388 root 1.110 sub cf::object::player::enter_link {
1389     my ($self) = @_;
1390    
1391     return if $self->map == $LINK_MAP;
1392    
1393     $self->{_link_pos} = [$self->map->{path}, $self->x, $self->y]
1394     if $self->map;
1395    
1396     $self->enter_map ($LINK_MAP, 20, 20);
1397     $self->deactivate_recursive;
1398     }
1399    
1400     sub cf::object::player::leave_link {
1401     my ($self, $map, $x, $y) = @_;
1402    
1403     my $link_pos = delete $self->{_link_pos};
1404    
1405     unless ($map) {
1406     $self->message ("The exit is closed", cf::NDI_UNIQUE | cf::NDI_RED);
1407    
1408     # restore original map position
1409     ($map, $x, $y) = @{ $link_pos || [] };
1410     $map = cf::map::find_map $map;
1411    
1412     unless ($map) {
1413     ($map, $x, $y) = @$EMERGENCY_POSITION;
1414     $map = cf::map::find_map $map
1415     or die "FATAL: cannot load emergency map\n";
1416     }
1417     }
1418    
1419     ($x, $y) = (-1, -1)
1420     unless (defined $x) && (defined $y);
1421    
1422     # use -1 or undef as default coordinates, not 0, 0
1423     ($x, $y) = ($map->enter_x, $map->enter_y)
1424     if $x <=0 && $y <= 0;
1425    
1426     $map->load;
1427    
1428     $self->activate_recursive;
1429     $self->enter_map ($map, $x, $y);
1430     }
1431    
1432     =item $player_object->goto_map ($map, $x, $y)
1433    
1434     =cut
1435    
1436     sub cf::object::player::goto_map {
1437     my ($self, $path, $x, $y) = @_;
1438    
1439     $self->enter_link;
1440    
1441     (Coro::async {
1442     $path = new cf::path $path;
1443    
1444     my $map = cf::map::find_map $path->as_string;
1445     $map = $map->customise_for ($self) if $map;
1446    
1447     warn "entering ", $map->path, " at ($x, $y)\n"
1448     if $map;
1449    
1450     $self->leave_link ($map, $x, $y);
1451     })->prio (1);
1452     }
1453    
1454     =item $player_object->enter_exit ($exit_object)
1455    
1456     =cut
1457    
1458     sub parse_random_map_params {
1459     my ($spec) = @_;
1460    
1461     my $rmp = { # defaults
1462     xsize => 10,
1463     ysize => 10,
1464     };
1465    
1466     for (split /\n/, $spec) {
1467     my ($k, $v) = split /\s+/, $_, 2;
1468    
1469     $rmp->{lc $k} = $v if (length $k) && (length $v);
1470     }
1471    
1472     $rmp
1473     }
1474    
1475     sub prepare_random_map {
1476     my ($exit) = @_;
1477    
1478     # all this does is basically replace the /! path by
1479     # a new random map path (?random/...) with a seed
1480     # that depends on the exit object
1481    
1482     my $rmp = parse_random_map_params $exit->msg;
1483    
1484     if ($exit->map) {
1485     $rmp->{region} = $exit->map->region_name;
1486     $rmp->{origin_map} = $exit->map->path;
1487     $rmp->{origin_x} = $exit->x;
1488     $rmp->{origin_y} = $exit->y;
1489     }
1490    
1491     $rmp->{random_seed} ||= $exit->random_seed;
1492    
1493     my $data = cf::to_json $rmp;
1494     my $md5 = Digest::MD5::md5_hex $data;
1495    
1496     if (my $fh = aio_open "$cf::RANDOM_MAPS/$md5.meta", O_WRONLY | O_CREAT, 0666) {
1497     aio_write $fh, 0, (length $data), $data, 0;
1498    
1499     $exit->slaying ("?random/$md5");
1500     $exit->msg (undef);
1501     }
1502     }
1503    
1504     sub cf::object::player::enter_exit {
1505     my ($self, $exit) = @_;
1506    
1507     return unless $self->type == cf::PLAYER;
1508    
1509     $self->enter_link;
1510    
1511     (Coro::async {
1512     unless (eval {
1513    
1514     prepare_random_map $exit
1515     if $exit->slaying eq "/!";
1516    
1517     my $path = new cf::path $exit->slaying, $exit->map && $exit->map->path;
1518     $self->goto_map ($path, $exit->stats->hp, $exit->stats->sp);
1519    
1520     1;
1521     }) {
1522     $self->message ("Something went wrong deep within the crossfire server. "
1523     . "I'll try to bring you back to the map you were before. "
1524     . "Please report this to the dungeon master",
1525     cf::NDI_UNIQUE | cf::NDI_RED);
1526    
1527     warn "ERROR in enter_exit: $@";
1528     $self->leave_link;
1529     }
1530     })->prio (1);
1531     }
1532    
1533 root 1.95 =head3 cf::client
1534    
1535     =over 4
1536    
1537     =item $client->send_drawinfo ($text, $flags)
1538    
1539     Sends a drawinfo packet to the client. Circumvents output buffering so
1540     should not be used under normal circumstances.
1541    
1542 root 1.70 =cut
1543    
1544 root 1.95 sub cf::client::send_drawinfo {
1545     my ($self, $text, $flags) = @_;
1546    
1547     utf8::encode $text;
1548     $self->send_packet (sprintf "drawinfo %d %s", $flags, $text);
1549     }
1550    
1551    
1552     =item $success = $client->query ($flags, "text", \&cb)
1553    
1554     Queues a query to the client, calling the given callback with
1555     the reply text on a reply. flags can be C<cf::CS_QUERY_YESNO>,
1556     C<cf::CS_QUERY_SINGLECHAR> or C<cf::CS_QUERY_HIDEINPUT> or C<0>.
1557    
1558     Queries can fail, so check the return code. Or don't, as queries will become
1559     reliable at some point in the future.
1560    
1561     =cut
1562    
1563     sub cf::client::query {
1564     my ($self, $flags, $text, $cb) = @_;
1565    
1566     return unless $self->state == ST_PLAYING
1567     || $self->state == ST_SETUP
1568     || $self->state == ST_CUSTOM;
1569    
1570     $self->state (ST_CUSTOM);
1571    
1572     utf8::encode $text;
1573     push @{ $self->{query_queue} }, [(sprintf "query %d %s", $flags, $text), $cb];
1574    
1575     $self->send_packet ($self->{query_queue}[0][0])
1576     if @{ $self->{query_queue} } == 1;
1577     }
1578    
1579     cf::client->attach (
1580     on_reply => sub {
1581     my ($ns, $msg) = @_;
1582    
1583     # this weird shuffling is so that direct followup queries
1584     # get handled first
1585     my $queue = delete $ns->{query_queue};
1586    
1587     (shift @$queue)->[1]->($msg);
1588    
1589     push @{ $ns->{query_queue} }, @$queue;
1590    
1591     if (@{ $ns->{query_queue} } == @$queue) {
1592     if (@$queue) {
1593     $ns->send_packet ($ns->{query_queue}[0][0]);
1594     } else {
1595 root 1.98 $ns->state (ST_PLAYING) if $ns->state == ST_CUSTOM;
1596 root 1.95 }
1597     }
1598     },
1599     );
1600    
1601 root 1.96 =item $client->coro (\&cb)
1602    
1603     Create a new coroutine, running the specified callback. The coroutine will
1604     be automatically cancelled when the client gets destroyed (e.g. on logout,
1605     or loss of connection).
1606    
1607     =cut
1608    
1609     sub cf::client::coro {
1610     my ($self, $cb) = @_;
1611    
1612     my $coro; $coro = async {
1613     eval {
1614     $cb->();
1615     };
1616     warn $@ if $@;
1617 root 1.103 };
1618    
1619     $coro->on_destroy (sub {
1620 root 1.96 delete $self->{_coro}{$coro+0};
1621 root 1.103 });
1622 root 1.96
1623     $self->{_coro}{$coro+0} = $coro;
1624 root 1.103
1625     $coro
1626 root 1.96 }
1627    
1628     cf::client->attach (
1629     on_destroy => sub {
1630     my ($ns) = @_;
1631    
1632 root 1.97 $_->cancel for values %{ (delete $ns->{_coro}) || {} };
1633 root 1.96 },
1634     );
1635    
1636 root 1.95 =back
1637    
1638 root 1.70
1639     =head2 SAFE SCRIPTING
1640    
1641     Functions that provide a safe environment to compile and execute
1642     snippets of perl code without them endangering the safety of the server
1643     itself. Looping constructs, I/O operators and other built-in functionality
1644     is not available in the safe scripting environment, and the number of
1645 root 1.79 functions and methods that can be called is greatly reduced.
1646 root 1.70
1647     =cut
1648 root 1.23
1649 root 1.42 our $safe = new Safe "safe";
1650 root 1.23 our $safe_hole = new Safe::Hole;
1651    
1652     $SIG{FPE} = 'IGNORE';
1653    
1654     $safe->permit_only (Opcode::opset qw(:base_core :base_mem :base_orig :base_math sort time));
1655    
1656 root 1.25 # here we export the classes and methods available to script code
1657    
1658 root 1.70 =pod
1659    
1660     The following fucntions and emthods are available within a safe environment:
1661    
1662 elmex 1.91 cf::object contr pay_amount pay_player map
1663 root 1.70 cf::object::player player
1664     cf::player peaceful
1665 elmex 1.91 cf::map trigger
1666 root 1.70
1667     =cut
1668    
1669 root 1.25 for (
1670 elmex 1.91 ["cf::object" => qw(contr pay_amount pay_player map)],
1671 root 1.25 ["cf::object::player" => qw(player)],
1672     ["cf::player" => qw(peaceful)],
1673 elmex 1.91 ["cf::map" => qw(trigger)],
1674 root 1.25 ) {
1675     no strict 'refs';
1676     my ($pkg, @funs) = @$_;
1677 root 1.41 *{"safe::$pkg\::$_"} = $safe_hole->wrap (\&{"$pkg\::$_"})
1678 root 1.25 for @funs;
1679     }
1680 root 1.23
1681 root 1.70 =over 4
1682    
1683     =item @retval = safe_eval $code, [var => value, ...]
1684    
1685     Compiled and executes the given perl code snippet. additional var/value
1686     pairs result in temporary local (my) scalar variables of the given name
1687     that are available in the code snippet. Example:
1688    
1689     my $five = safe_eval '$first + $second', first => 1, second => 4;
1690    
1691     =cut
1692    
1693 root 1.23 sub safe_eval($;@) {
1694     my ($code, %vars) = @_;
1695    
1696     my $qcode = $code;
1697     $qcode =~ s/"/‟/g; # not allowed in #line filenames
1698     $qcode =~ s/\n/\\n/g;
1699    
1700     local $_;
1701 root 1.41 local @safe::cf::_safe_eval_args = values %vars;
1702 root 1.23
1703 root 1.42 my $eval =
1704 root 1.23 "do {\n"
1705     . "my (" . (join ",", map "\$$_", keys %vars) . ") = \@cf::_safe_eval_args;\n"
1706     . "#line 0 \"{$qcode}\"\n"
1707     . $code
1708     . "\n}"
1709 root 1.25 ;
1710    
1711     sub_generation_inc;
1712 root 1.42 my @res = wantarray ? $safe->reval ($eval) : scalar $safe->reval ($eval);
1713 root 1.25 sub_generation_inc;
1714    
1715 root 1.42 if ($@) {
1716     warn "$@";
1717     warn "while executing safe code '$code'\n";
1718     warn "with arguments " . (join " ", %vars) . "\n";
1719     }
1720    
1721 root 1.25 wantarray ? @res : $res[0]
1722 root 1.23 }
1723    
1724 root 1.69 =item cf::register_script_function $function => $cb
1725    
1726     Register a function that can be called from within map/npc scripts. The
1727     function should be reasonably secure and should be put into a package name
1728     like the extension.
1729    
1730     Example: register a function that gets called whenever a map script calls
1731     C<rent::overview>, as used by the C<rent> extension.
1732    
1733     cf::register_script_function "rent::overview" => sub {
1734     ...
1735     };
1736    
1737     =cut
1738    
1739 root 1.23 sub register_script_function {
1740     my ($fun, $cb) = @_;
1741    
1742     no strict 'refs';
1743 root 1.41 *{"safe::$fun"} = $safe_hole->wrap ($cb);
1744 root 1.23 }
1745    
1746 root 1.70 =back
1747    
1748 root 1.71 =cut
1749    
1750 root 1.23 #############################################################################
1751 root 1.65
1752     =head2 EXTENSION DATABASE SUPPORT
1753    
1754     Crossfire maintains a very simple database for extension use. It can
1755     currently store anything that can be serialised using Storable, which
1756     excludes objects.
1757    
1758     The parameter C<$family> should best start with the name of the extension
1759     using it, it should be unique.
1760    
1761     =over 4
1762    
1763     =item $hashref = cf::db_get $family
1764    
1765     Return a hashref for use by the extension C<$family>, which can be
1766     modified. After modifications, you have to call C<cf::db_dirty> or
1767     C<cf::db_sync>.
1768    
1769     =item $value = cf::db_get $family => $key
1770    
1771     Returns a single value from the database
1772    
1773     =item cf::db_put $family => $hashref
1774    
1775     Stores the given family hashref into the database. Updates are delayed, if
1776     you want the data to be synced to disk immediately, use C<cf::db_sync>.
1777    
1778     =item cf::db_put $family => $key => $value
1779    
1780     Stores the given C<$value> in the family hash. Updates are delayed, if you
1781     want the data to be synced to disk immediately, use C<cf::db_sync>.
1782    
1783     =item cf::db_dirty
1784    
1785     Marks the database as dirty, to be updated at a later time.
1786    
1787     =item cf::db_sync
1788    
1789     Immediately write the database to disk I<if it is dirty>.
1790    
1791     =cut
1792    
1793 root 1.78 our $DB;
1794    
1795 root 1.65 {
1796 root 1.66 my $path = cf::localdir . "/database.pst";
1797 root 1.65
1798     sub db_load() {
1799     warn "loading database $path\n";#d# remove later
1800 root 1.78 $DB = stat $path ? Storable::retrieve $path : { };
1801 root 1.65 }
1802    
1803     my $pid;
1804    
1805     sub db_save() {
1806     warn "saving database $path\n";#d# remove later
1807     waitpid $pid, 0 if $pid;
1808 root 1.67 if (0 == ($pid = fork)) {
1809 root 1.78 $DB->{_meta}{version} = 1;
1810     Storable::nstore $DB, "$path~";
1811 root 1.65 rename "$path~", $path;
1812     cf::_exit 0 if defined $pid;
1813     }
1814     }
1815    
1816     my $dirty;
1817    
1818     sub db_sync() {
1819     db_save if $dirty;
1820     undef $dirty;
1821     }
1822    
1823 root 1.87 my $idle = Event->idle (min => $TICK * 2.8, max => 10, repeat => 0, data => WF_AUTOCANCEL, cb => sub {
1824 root 1.65 db_sync;
1825     });
1826    
1827     sub db_dirty() {
1828     $dirty = 1;
1829     $idle->start;
1830     }
1831    
1832     sub db_get($;$) {
1833     @_ >= 2
1834 root 1.78 ? $DB->{$_[0]}{$_[1]}
1835     : ($DB->{$_[0]} ||= { })
1836 root 1.65 }
1837    
1838     sub db_put($$;$) {
1839     if (@_ >= 3) {
1840 root 1.78 $DB->{$_[0]}{$_[1]} = $_[2];
1841 root 1.65 } else {
1842 root 1.78 $DB->{$_[0]} = $_[1];
1843 root 1.65 }
1844     db_dirty;
1845     }
1846 root 1.67
1847 root 1.93 cf::global->attach (
1848     prio => 10000,
1849 root 1.67 on_cleanup => sub {
1850     db_sync;
1851     },
1852 root 1.93 );
1853 root 1.65 }
1854    
1855     #############################################################################
1856 root 1.34 # the server's main()
1857    
1858 root 1.73 sub cfg_load {
1859 root 1.72 open my $fh, "<:utf8", cf::confdir . "/config"
1860     or return;
1861    
1862     local $/;
1863     *CFG = YAML::Syck::Load <$fh>;
1864     }
1865    
1866 root 1.39 sub main {
1867 root 1.108 # we must not ever block the main coroutine
1868     local $Coro::idle = sub {
1869     Carp::cluck "FATAL: Coro::idle was called, major BUG\n";#d#
1870     (Coro::unblock_sub {
1871     Event::one_event;
1872     })->();
1873     };
1874    
1875 root 1.73 cfg_load;
1876 root 1.65 db_load;
1877 root 1.61 load_extensions;
1878 root 1.34 Event::loop;
1879     }
1880    
1881     #############################################################################
1882 root 1.22 # initialisation
1883    
1884 root 1.111 sub reload() {
1885 root 1.106 # can/must only be called in main
1886     if ($Coro::current != $Coro::main) {
1887     warn "can only reload from main coroutine\n";
1888     return;
1889     }
1890    
1891 root 1.103 warn "reloading...";
1892    
1893 root 1.106 local $FREEZE = 1;
1894     cf::emergency_save;
1895    
1896 root 1.103 eval {
1897 root 1.106 # if anything goes wrong in here, we should simply crash as we already saved
1898 root 1.65
1899     # cancel all watchers
1900 root 1.87 for (Event::all_watchers) {
1901     $_->cancel if $_->data & WF_AUTOCANCEL;
1902     }
1903 root 1.65
1904 root 1.103 # cancel all extension coros
1905     $_->cancel for values %EXT_CORO;
1906     %EXT_CORO = ();
1907    
1908 root 1.65 # unload all extensions
1909     for (@exts) {
1910 root 1.103 warn "unloading <$_>";
1911 root 1.65 unload_extension $_;
1912     }
1913    
1914     # unload all modules loaded from $LIBDIR
1915     while (my ($k, $v) = each %INC) {
1916     next unless $v =~ /^\Q$LIBDIR\E\/.*\.pm$/;
1917    
1918 root 1.103 warn "removing <$k>";
1919 root 1.65 delete $INC{$k};
1920    
1921     $k =~ s/\.pm$//;
1922     $k =~ s/\//::/g;
1923    
1924     if (my $cb = $k->can ("unload_module")) {
1925     $cb->();
1926     }
1927    
1928     Symbol::delete_package $k;
1929     }
1930    
1931     # sync database to disk
1932     cf::db_sync;
1933 root 1.103 IO::AIO::flush;
1934 root 1.65
1935     # get rid of safe::, as good as possible
1936     Symbol::delete_package "safe::$_"
1937 root 1.103 for qw(cf::attachable cf::object cf::object::player cf::client cf::player cf::map cf::party cf::region);
1938 root 1.65
1939     # remove register_script_function callbacks
1940     # TODO
1941    
1942     # unload cf.pm "a bit"
1943     delete $INC{"cf.pm"};
1944    
1945     # don't, removes xs symbols, too,
1946     # and global variables created in xs
1947     #Symbol::delete_package __PACKAGE__;
1948    
1949     # reload cf.pm
1950 root 1.103 warn "reloading cf.pm";
1951 root 1.65 require cf;
1952 root 1.100 cf::_connect_to_perl; # nominally unnecessary, but cannot hurt
1953    
1954 root 1.73 # load config and database again
1955     cf::cfg_load;
1956 root 1.65 cf::db_load;
1957    
1958     # load extensions
1959 root 1.103 warn "load extensions";
1960 root 1.65 cf::load_extensions;
1961    
1962     # reattach attachments to objects
1963 root 1.103 warn "reattach";
1964 root 1.65 _global_reattach;
1965     };
1966    
1967 root 1.106 if ($@) {
1968     warn $@;
1969     warn "error while reloading, exiting.";
1970     exit 1;
1971     }
1972    
1973     warn "reloaded successfully";
1974 root 1.65 };
1975    
1976 root 1.108 #############################################################################
1977    
1978     unless ($LINK_MAP) {
1979     $LINK_MAP = cf::map::new;
1980    
1981     $LINK_MAP->width (41);
1982     $LINK_MAP->height (41);
1983     $LINK_MAP->alloc;
1984     $LINK_MAP->path ("{link}");
1985     $LINK_MAP->{path} = bless { path => "{link}" }, "cf::path";
1986     $LINK_MAP->in_memory (MAP_IN_MEMORY);
1987 root 1.110
1988     # dirty hack because... archetypes are not yet loaded
1989     Event->timer (
1990     after => 2,
1991     cb => sub {
1992     $_[0]->w->cancel;
1993    
1994     # provide some exits "home"
1995     my $exit = cf::object::new "exit";
1996    
1997     $exit->slaying ($EMERGENCY_POSITION->[0]);
1998     $exit->stats->hp ($EMERGENCY_POSITION->[1]);
1999     $exit->stats->sp ($EMERGENCY_POSITION->[2]);
2000    
2001     $LINK_MAP->insert ($exit->clone, 19, 19);
2002     $LINK_MAP->insert ($exit->clone, 19, 20);
2003     $LINK_MAP->insert ($exit->clone, 19, 21);
2004     $LINK_MAP->insert ($exit->clone, 20, 19);
2005     $LINK_MAP->insert ($exit->clone, 20, 21);
2006     $LINK_MAP->insert ($exit->clone, 21, 19);
2007     $LINK_MAP->insert ($exit->clone, 21, 20);
2008     $LINK_MAP->insert ($exit->clone, 21, 21);
2009    
2010     $exit->destroy;
2011     });
2012    
2013     $LINK_MAP->{deny_save} = 1;
2014     $LINK_MAP->{deny_reset} = 1;
2015    
2016     $cf::MAP{$LINK_MAP->path} = $LINK_MAP;
2017 root 1.108 }
2018    
2019 root 1.85 register "<global>", __PACKAGE__;
2020    
2021 root 1.111 register_command "reload" => sub {
2022 root 1.65 my ($who, $arg) = @_;
2023    
2024     if ($who->flag (FLAG_WIZ)) {
2025 root 1.107 $who->message ("start of reload.");
2026 root 1.111 reload;
2027 root 1.107 $who->message ("end of reload.");
2028 root 1.65 }
2029     };
2030    
2031 root 1.27 unshift @INC, $LIBDIR;
2032 root 1.17
2033 root 1.35 $TICK_WATCHER = Event->timer (
2034 root 1.104 reentrant => 0,
2035     prio => 0,
2036     at => $NEXT_TICK || $TICK,
2037     data => WF_AUTOCANCEL,
2038     cb => sub {
2039 root 1.103 unless ($FREEZE) {
2040     cf::server_tick; # one server iteration
2041     $RUNTIME += $TICK;
2042     }
2043 root 1.35
2044     $NEXT_TICK += $TICK;
2045    
2046 root 1.78 # if we are delayed by four ticks or more, skip them all
2047 root 1.103 $NEXT_TICK = Event::time if Event::time >= $NEXT_TICK + $TICK * 4;
2048 root 1.35
2049     $TICK_WATCHER->at ($NEXT_TICK);
2050     $TICK_WATCHER->start;
2051     },
2052     );
2053    
2054 root 1.80 IO::AIO::max_poll_time $TICK * 0.2;
2055 root 1.77
2056 root 1.108 Event->io (
2057     fd => IO::AIO::poll_fileno,
2058     poll => 'r',
2059     prio => 5,
2060     data => WF_AUTOCANCEL,
2061     cb => \&IO::AIO::poll_cb,
2062     );
2063    
2064     Event->timer (
2065     data => WF_AUTOCANCEL,
2066     after => 0,
2067     interval => 10,
2068     cb => sub {
2069     (Coro::unblock_sub {
2070     write_runtime
2071     or warn "ERROR: unable to write runtime file: $!";
2072     })->();
2073     },
2074     );
2075 root 1.103
2076 root 1.1 1
2077