ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/lib/cf.pm
Revision: 1.117
Committed: Mon Jan 1 17:50:26 2007 UTC (17 years, 4 months ago) by root
Branch: MAIN
Changes since 1.116: +3 -3 lines
Log Message:
move nimbus to /, simplifies upgrading

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 root 1.116 $map->{last_save} = $cf::RUNTIME;
1149 root 1.110 $map->last_access ($cf::RUNTIME);
1150    
1151 root 1.112 if ($map->should_reset) {
1152     $map->reset;
1153     $map = find_map $path;
1154     }
1155 root 1.110
1156     $cf::MAP{$key} = $map
1157     }
1158     }
1159    
1160     sub load {
1161     my ($self) = @_;
1162    
1163     return if $self->in_memory != cf::MAP_SWAPPED;
1164    
1165     $self->in_memory (cf::MAP_LOADING);
1166    
1167     my $path = $self->{path};
1168    
1169     $self->alloc;
1170     $self->load_objects ($self->{load_path}, 1)
1171     or return;
1172    
1173 root 1.112 $self->set_object_flag (cf::FLAG_OBJ_ORIGINAL, 1)
1174     if delete $self->{load_original};
1175 root 1.111
1176 root 1.110 if (my $uniq = $path->uniq_path) {
1177     utf8::encode $uniq;
1178     if (aio_open $uniq, O_RDONLY, 0) {
1179     $self->clear_unique_items;
1180     $self->load_objects ($uniq, 0);
1181     }
1182     }
1183    
1184     # now do the right thing for maps
1185     $self->link_multipart_objects;
1186    
1187     if ($self->{path}->is_style_map) {
1188     $self->{deny_save} = 1;
1189     $self->{deny_reset} = 1;
1190     } else {
1191     $self->fix_auto_apply;
1192     $self->decay_objects;
1193     $self->update_buttons;
1194     $self->set_darkness_map;
1195     $self->difficulty ($self->estimate_difficulty)
1196     unless $self->difficulty;
1197     $self->activate;
1198     }
1199    
1200     $self->in_memory (cf::MAP_IN_MEMORY);
1201     }
1202    
1203     sub load_map_sync {
1204     my ($path, $origin) = @_;
1205    
1206     #warn "load_map_sync<$path, $origin>\n";#d#
1207    
1208     cf::sync_job {
1209     my $map = cf::map::find_map $path, $origin
1210     or return;
1211     $map->load;
1212     $map
1213     }
1214     }
1215    
1216     sub save {
1217     my ($self) = @_;
1218    
1219     $self->{last_save} = $cf::RUNTIME;
1220    
1221     return unless $self->dirty;
1222    
1223 root 1.117 my $save = $self->{path}->save_path; utf8::encode $save;
1224     my $uniq = $self->{path}->uniq_path; utf8::encode $uniq;
1225    
1226 root 1.110 $self->{load_path} = $save;
1227    
1228     return if $self->{deny_save};
1229    
1230     if ($uniq) {
1231     $self->save_objects ($save, cf::IO_HEADER | cf::IO_OBJECTS);
1232     $self->save_objects ($uniq, cf::IO_UNIQUES);
1233     } else {
1234     $self->save_objects ($save, cf::IO_HEADER | cf::IO_OBJECTS | cf::IO_UNIQUES);
1235     }
1236     }
1237    
1238     sub swap_out {
1239     my ($self) = @_;
1240    
1241     return if $self->players;
1242     return if $self->in_memory != cf::MAP_IN_MEMORY;
1243     return if $self->{deny_save};
1244    
1245     $self->save;
1246     $self->clear;
1247     $self->in_memory (cf::MAP_SWAPPED);
1248     }
1249    
1250 root 1.112 sub reset_at {
1251     my ($self) = @_;
1252 root 1.110
1253     # TODO: safety, remove and allow resettable per-player maps
1254 root 1.114 return 1e99 if $self->{path}{user_rel};
1255     return 1e99 if $self->{deny_reset};
1256 root 1.110
1257 root 1.112 my $time = $self->fixed_resettime ? $self->{instantiate_time} : $self->last_access;
1258 root 1.114 my $to = List::Util::min $MAX_RESET, $self->reset_timeout || $DEFAULT_RESET;
1259 root 1.110
1260 root 1.112 $time + $to
1261     }
1262    
1263     sub should_reset {
1264     my ($self) = @_;
1265    
1266     $self->reset_at <= $cf::RUNTIME
1267 root 1.111 }
1268    
1269     sub unlink_save {
1270     my ($self) = @_;
1271    
1272     utf8::encode (my $save = $self->{path}->save_path);
1273     aioreq_pri 3; IO::AIO::aio_unlink $save;
1274     aioreq_pri 3; IO::AIO::aio_unlink "$save.pst";
1275 root 1.110 }
1276    
1277 root 1.113 sub rename {
1278     my ($self, $new_path) = @_;
1279    
1280     $self->unlink_save;
1281    
1282     delete $cf::MAP{$self->path};
1283     $self->{path} = new cf::path $new_path;
1284 root 1.114 $self->path ($self->{path}->as_string);
1285 root 1.113 $cf::MAP{$self->path} = $self;
1286    
1287     $self->save;
1288     }
1289    
1290 root 1.110 sub reset {
1291     my ($self) = @_;
1292    
1293     return if $self->players;
1294     return if $self->{path}{user_rel};#d#
1295    
1296     warn "resetting map ", $self->path;#d#
1297    
1298 root 1.111 delete $cf::MAP{$self->path};
1299 root 1.110
1300     $_->clear_links_to ($self) for values %cf::MAP;
1301    
1302 root 1.111 $self->unlink_save;
1303     $self->destroy;
1304 root 1.110 }
1305    
1306 root 1.114 my $nuke_counter = "aaaa";
1307    
1308     sub nuke {
1309     my ($self) = @_;
1310    
1311     $self->{deny_save} = 1;
1312     $self->reset_timeout (1);
1313     $self->rename ("{nuke}/" . ($nuke_counter++));
1314     $self->reset; # polite request, might not happen
1315     }
1316    
1317 root 1.110 sub customise_for {
1318     my ($map, $ob) = @_;
1319    
1320     if ($map->per_player) {
1321     return cf::map::find_map "~" . $ob->name . "/" . $map->{path}{path};
1322     }
1323    
1324     $map
1325     }
1326    
1327     sub emergency_save {
1328     local $cf::FREEZE = 1;
1329    
1330     warn "enter emergency map save\n";
1331    
1332     cf::sync_job {
1333     warn "begin emergency map save\n";
1334     $_->save for values %cf::MAP;
1335     };
1336    
1337     warn "end emergency map save\n";
1338     }
1339    
1340     package cf;
1341    
1342     =back
1343    
1344    
1345 root 1.95 =head3 cf::object::player
1346    
1347     =over 4
1348    
1349 root 1.79 =item $player_object->reply ($npc, $msg[, $flags])
1350 root 1.28
1351     Sends a message to the player, as if the npc C<$npc> replied. C<$npc>
1352     can be C<undef>. Does the right thing when the player is currently in a
1353     dialogue with the given NPC character.
1354    
1355     =cut
1356    
1357 root 1.22 # rough implementation of a future "reply" method that works
1358     # with dialog boxes.
1359 root 1.95 #TODO: the first argument must go, split into a $npc->reply_to ( method
1360 root 1.23 sub cf::object::player::reply($$$;$) {
1361     my ($self, $npc, $msg, $flags) = @_;
1362    
1363     $flags = cf::NDI_BROWN | cf::NDI_UNIQUE unless @_ >= 4;
1364 root 1.22
1365 root 1.24 if ($self->{record_replies}) {
1366     push @{ $self->{record_replies} }, [$npc, $msg, $flags];
1367     } else {
1368     $msg = $npc->name . " says: $msg" if $npc;
1369     $self->message ($msg, $flags);
1370     }
1371 root 1.22 }
1372    
1373 root 1.79 =item $player_object->may ("access")
1374    
1375     Returns wether the given player is authorized to access resource "access"
1376     (e.g. "command_wizcast").
1377    
1378     =cut
1379    
1380     sub cf::object::player::may {
1381     my ($self, $access) = @_;
1382    
1383     $self->flag (cf::FLAG_WIZ) ||
1384     (ref $cf::CFG{"may_$access"}
1385     ? scalar grep $self->name eq $_, @{$cf::CFG{"may_$access"}}
1386     : $cf::CFG{"may_$access"})
1387     }
1388 root 1.70
1389 root 1.115 =item $player_object->enter_link
1390    
1391     Freezes the player and moves him/her to a special map (C<{link}>).
1392    
1393     The player should be reaosnably safe there for short amounts of time. You
1394     I<MUST> call C<leave_link> as soon as possible, though.
1395    
1396     =item $player_object->leave_link ($map, $x, $y)
1397    
1398     Moves the player out of the specila link map onto the given map. If the
1399     map is not valid (or omitted), the player will be moved back to the
1400     location he/she was before the call to C<enter_link>, or, if that fails,
1401     to the emergency map position.
1402    
1403     Might block.
1404    
1405     =cut
1406    
1407 root 1.110 sub cf::object::player::enter_link {
1408     my ($self) = @_;
1409    
1410     return if $self->map == $LINK_MAP;
1411    
1412     $self->{_link_pos} = [$self->map->{path}, $self->x, $self->y]
1413     if $self->map;
1414    
1415     $self->enter_map ($LINK_MAP, 20, 20);
1416     $self->deactivate_recursive;
1417     }
1418    
1419     sub cf::object::player::leave_link {
1420     my ($self, $map, $x, $y) = @_;
1421    
1422     my $link_pos = delete $self->{_link_pos};
1423    
1424     unless ($map) {
1425     # restore original map position
1426     ($map, $x, $y) = @{ $link_pos || [] };
1427     $map = cf::map::find_map $map;
1428    
1429     unless ($map) {
1430     ($map, $x, $y) = @$EMERGENCY_POSITION;
1431     $map = cf::map::find_map $map
1432     or die "FATAL: cannot load emergency map\n";
1433     }
1434     }
1435    
1436     ($x, $y) = (-1, -1)
1437     unless (defined $x) && (defined $y);
1438    
1439     # use -1 or undef as default coordinates, not 0, 0
1440     ($x, $y) = ($map->enter_x, $map->enter_y)
1441     if $x <=0 && $y <= 0;
1442    
1443     $map->load;
1444    
1445     $self->activate_recursive;
1446     $self->enter_map ($map, $x, $y);
1447     }
1448    
1449     =item $player_object->goto_map ($map, $x, $y)
1450    
1451     =cut
1452    
1453     sub cf::object::player::goto_map {
1454     my ($self, $path, $x, $y) = @_;
1455    
1456     $self->enter_link;
1457    
1458     (Coro::async {
1459     $path = new cf::path $path;
1460    
1461     my $map = cf::map::find_map $path->as_string;
1462     $map = $map->customise_for ($self) if $map;
1463    
1464     warn "entering ", $map->path, " at ($x, $y)\n"
1465     if $map;
1466    
1467 root 1.115 $map or $self->message ("The exit is closed", cf::NDI_UNIQUE | cf::NDI_RED);
1468    
1469 root 1.110 $self->leave_link ($map, $x, $y);
1470     })->prio (1);
1471     }
1472    
1473     =item $player_object->enter_exit ($exit_object)
1474    
1475     =cut
1476    
1477     sub parse_random_map_params {
1478     my ($spec) = @_;
1479    
1480     my $rmp = { # defaults
1481     xsize => 10,
1482     ysize => 10,
1483     };
1484    
1485     for (split /\n/, $spec) {
1486     my ($k, $v) = split /\s+/, $_, 2;
1487    
1488     $rmp->{lc $k} = $v if (length $k) && (length $v);
1489     }
1490    
1491     $rmp
1492     }
1493    
1494     sub prepare_random_map {
1495     my ($exit) = @_;
1496    
1497     # all this does is basically replace the /! path by
1498     # a new random map path (?random/...) with a seed
1499     # that depends on the exit object
1500    
1501     my $rmp = parse_random_map_params $exit->msg;
1502    
1503     if ($exit->map) {
1504     $rmp->{region} = $exit->map->region_name;
1505     $rmp->{origin_map} = $exit->map->path;
1506     $rmp->{origin_x} = $exit->x;
1507     $rmp->{origin_y} = $exit->y;
1508     }
1509    
1510     $rmp->{random_seed} ||= $exit->random_seed;
1511    
1512     my $data = cf::to_json $rmp;
1513     my $md5 = Digest::MD5::md5_hex $data;
1514    
1515     if (my $fh = aio_open "$cf::RANDOM_MAPS/$md5.meta", O_WRONLY | O_CREAT, 0666) {
1516     aio_write $fh, 0, (length $data), $data, 0;
1517    
1518     $exit->slaying ("?random/$md5");
1519     $exit->msg (undef);
1520     }
1521     }
1522    
1523     sub cf::object::player::enter_exit {
1524     my ($self, $exit) = @_;
1525    
1526     return unless $self->type == cf::PLAYER;
1527    
1528     $self->enter_link;
1529    
1530     (Coro::async {
1531     unless (eval {
1532    
1533     prepare_random_map $exit
1534     if $exit->slaying eq "/!";
1535    
1536     my $path = new cf::path $exit->slaying, $exit->map && $exit->map->path;
1537     $self->goto_map ($path, $exit->stats->hp, $exit->stats->sp);
1538    
1539     1;
1540     }) {
1541     $self->message ("Something went wrong deep within the crossfire server. "
1542     . "I'll try to bring you back to the map you were before. "
1543     . "Please report this to the dungeon master",
1544     cf::NDI_UNIQUE | cf::NDI_RED);
1545    
1546     warn "ERROR in enter_exit: $@";
1547     $self->leave_link;
1548     }
1549     })->prio (1);
1550     }
1551    
1552 root 1.95 =head3 cf::client
1553    
1554     =over 4
1555    
1556     =item $client->send_drawinfo ($text, $flags)
1557    
1558     Sends a drawinfo packet to the client. Circumvents output buffering so
1559     should not be used under normal circumstances.
1560    
1561 root 1.70 =cut
1562    
1563 root 1.95 sub cf::client::send_drawinfo {
1564     my ($self, $text, $flags) = @_;
1565    
1566     utf8::encode $text;
1567     $self->send_packet (sprintf "drawinfo %d %s", $flags, $text);
1568     }
1569    
1570    
1571     =item $success = $client->query ($flags, "text", \&cb)
1572    
1573     Queues a query to the client, calling the given callback with
1574     the reply text on a reply. flags can be C<cf::CS_QUERY_YESNO>,
1575     C<cf::CS_QUERY_SINGLECHAR> or C<cf::CS_QUERY_HIDEINPUT> or C<0>.
1576    
1577     Queries can fail, so check the return code. Or don't, as queries will become
1578     reliable at some point in the future.
1579    
1580     =cut
1581    
1582     sub cf::client::query {
1583     my ($self, $flags, $text, $cb) = @_;
1584    
1585     return unless $self->state == ST_PLAYING
1586     || $self->state == ST_SETUP
1587     || $self->state == ST_CUSTOM;
1588    
1589     $self->state (ST_CUSTOM);
1590    
1591     utf8::encode $text;
1592     push @{ $self->{query_queue} }, [(sprintf "query %d %s", $flags, $text), $cb];
1593    
1594     $self->send_packet ($self->{query_queue}[0][0])
1595     if @{ $self->{query_queue} } == 1;
1596     }
1597    
1598     cf::client->attach (
1599     on_reply => sub {
1600     my ($ns, $msg) = @_;
1601    
1602     # this weird shuffling is so that direct followup queries
1603     # get handled first
1604     my $queue = delete $ns->{query_queue};
1605    
1606     (shift @$queue)->[1]->($msg);
1607    
1608     push @{ $ns->{query_queue} }, @$queue;
1609    
1610     if (@{ $ns->{query_queue} } == @$queue) {
1611     if (@$queue) {
1612     $ns->send_packet ($ns->{query_queue}[0][0]);
1613     } else {
1614 root 1.98 $ns->state (ST_PLAYING) if $ns->state == ST_CUSTOM;
1615 root 1.95 }
1616     }
1617     },
1618     );
1619    
1620 root 1.96 =item $client->coro (\&cb)
1621    
1622     Create a new coroutine, running the specified callback. The coroutine will
1623     be automatically cancelled when the client gets destroyed (e.g. on logout,
1624     or loss of connection).
1625    
1626     =cut
1627    
1628     sub cf::client::coro {
1629     my ($self, $cb) = @_;
1630    
1631     my $coro; $coro = async {
1632     eval {
1633     $cb->();
1634     };
1635     warn $@ if $@;
1636 root 1.103 };
1637    
1638     $coro->on_destroy (sub {
1639 root 1.96 delete $self->{_coro}{$coro+0};
1640 root 1.103 });
1641 root 1.96
1642     $self->{_coro}{$coro+0} = $coro;
1643 root 1.103
1644     $coro
1645 root 1.96 }
1646    
1647     cf::client->attach (
1648     on_destroy => sub {
1649     my ($ns) = @_;
1650    
1651 root 1.97 $_->cancel for values %{ (delete $ns->{_coro}) || {} };
1652 root 1.96 },
1653     );
1654    
1655 root 1.95 =back
1656    
1657 root 1.70
1658     =head2 SAFE SCRIPTING
1659    
1660     Functions that provide a safe environment to compile and execute
1661     snippets of perl code without them endangering the safety of the server
1662     itself. Looping constructs, I/O operators and other built-in functionality
1663     is not available in the safe scripting environment, and the number of
1664 root 1.79 functions and methods that can be called is greatly reduced.
1665 root 1.70
1666     =cut
1667 root 1.23
1668 root 1.42 our $safe = new Safe "safe";
1669 root 1.23 our $safe_hole = new Safe::Hole;
1670    
1671     $SIG{FPE} = 'IGNORE';
1672    
1673     $safe->permit_only (Opcode::opset qw(:base_core :base_mem :base_orig :base_math sort time));
1674    
1675 root 1.25 # here we export the classes and methods available to script code
1676    
1677 root 1.70 =pod
1678    
1679     The following fucntions and emthods are available within a safe environment:
1680    
1681 elmex 1.91 cf::object contr pay_amount pay_player map
1682 root 1.70 cf::object::player player
1683     cf::player peaceful
1684 elmex 1.91 cf::map trigger
1685 root 1.70
1686     =cut
1687    
1688 root 1.25 for (
1689 elmex 1.91 ["cf::object" => qw(contr pay_amount pay_player map)],
1690 root 1.25 ["cf::object::player" => qw(player)],
1691     ["cf::player" => qw(peaceful)],
1692 elmex 1.91 ["cf::map" => qw(trigger)],
1693 root 1.25 ) {
1694     no strict 'refs';
1695     my ($pkg, @funs) = @$_;
1696 root 1.41 *{"safe::$pkg\::$_"} = $safe_hole->wrap (\&{"$pkg\::$_"})
1697 root 1.25 for @funs;
1698     }
1699 root 1.23
1700 root 1.70 =over 4
1701    
1702     =item @retval = safe_eval $code, [var => value, ...]
1703    
1704     Compiled and executes the given perl code snippet. additional var/value
1705     pairs result in temporary local (my) scalar variables of the given name
1706     that are available in the code snippet. Example:
1707    
1708     my $five = safe_eval '$first + $second', first => 1, second => 4;
1709    
1710     =cut
1711    
1712 root 1.23 sub safe_eval($;@) {
1713     my ($code, %vars) = @_;
1714    
1715     my $qcode = $code;
1716     $qcode =~ s/"/‟/g; # not allowed in #line filenames
1717     $qcode =~ s/\n/\\n/g;
1718    
1719     local $_;
1720 root 1.41 local @safe::cf::_safe_eval_args = values %vars;
1721 root 1.23
1722 root 1.42 my $eval =
1723 root 1.23 "do {\n"
1724     . "my (" . (join ",", map "\$$_", keys %vars) . ") = \@cf::_safe_eval_args;\n"
1725     . "#line 0 \"{$qcode}\"\n"
1726     . $code
1727     . "\n}"
1728 root 1.25 ;
1729    
1730     sub_generation_inc;
1731 root 1.42 my @res = wantarray ? $safe->reval ($eval) : scalar $safe->reval ($eval);
1732 root 1.25 sub_generation_inc;
1733    
1734 root 1.42 if ($@) {
1735     warn "$@";
1736     warn "while executing safe code '$code'\n";
1737     warn "with arguments " . (join " ", %vars) . "\n";
1738     }
1739    
1740 root 1.25 wantarray ? @res : $res[0]
1741 root 1.23 }
1742    
1743 root 1.69 =item cf::register_script_function $function => $cb
1744    
1745     Register a function that can be called from within map/npc scripts. The
1746     function should be reasonably secure and should be put into a package name
1747     like the extension.
1748    
1749     Example: register a function that gets called whenever a map script calls
1750     C<rent::overview>, as used by the C<rent> extension.
1751    
1752     cf::register_script_function "rent::overview" => sub {
1753     ...
1754     };
1755    
1756     =cut
1757    
1758 root 1.23 sub register_script_function {
1759     my ($fun, $cb) = @_;
1760    
1761     no strict 'refs';
1762 root 1.41 *{"safe::$fun"} = $safe_hole->wrap ($cb);
1763 root 1.23 }
1764    
1765 root 1.70 =back
1766    
1767 root 1.71 =cut
1768    
1769 root 1.23 #############################################################################
1770 root 1.65
1771     =head2 EXTENSION DATABASE SUPPORT
1772    
1773     Crossfire maintains a very simple database for extension use. It can
1774     currently store anything that can be serialised using Storable, which
1775     excludes objects.
1776    
1777     The parameter C<$family> should best start with the name of the extension
1778     using it, it should be unique.
1779    
1780     =over 4
1781    
1782     =item $hashref = cf::db_get $family
1783    
1784     Return a hashref for use by the extension C<$family>, which can be
1785     modified. After modifications, you have to call C<cf::db_dirty> or
1786     C<cf::db_sync>.
1787    
1788     =item $value = cf::db_get $family => $key
1789    
1790     Returns a single value from the database
1791    
1792     =item cf::db_put $family => $hashref
1793    
1794     Stores the given family hashref into the database. Updates are delayed, if
1795     you want the data to be synced to disk immediately, use C<cf::db_sync>.
1796    
1797     =item cf::db_put $family => $key => $value
1798    
1799     Stores the given C<$value> in the family hash. Updates are delayed, if you
1800     want the data to be synced to disk immediately, use C<cf::db_sync>.
1801    
1802     =item cf::db_dirty
1803    
1804     Marks the database as dirty, to be updated at a later time.
1805    
1806     =item cf::db_sync
1807    
1808     Immediately write the database to disk I<if it is dirty>.
1809    
1810     =cut
1811    
1812 root 1.78 our $DB;
1813    
1814 root 1.65 {
1815 root 1.66 my $path = cf::localdir . "/database.pst";
1816 root 1.65
1817     sub db_load() {
1818     warn "loading database $path\n";#d# remove later
1819 root 1.78 $DB = stat $path ? Storable::retrieve $path : { };
1820 root 1.65 }
1821    
1822     my $pid;
1823    
1824     sub db_save() {
1825     warn "saving database $path\n";#d# remove later
1826     waitpid $pid, 0 if $pid;
1827 root 1.67 if (0 == ($pid = fork)) {
1828 root 1.78 $DB->{_meta}{version} = 1;
1829     Storable::nstore $DB, "$path~";
1830 root 1.65 rename "$path~", $path;
1831     cf::_exit 0 if defined $pid;
1832     }
1833     }
1834    
1835     my $dirty;
1836    
1837     sub db_sync() {
1838     db_save if $dirty;
1839     undef $dirty;
1840     }
1841    
1842 root 1.87 my $idle = Event->idle (min => $TICK * 2.8, max => 10, repeat => 0, data => WF_AUTOCANCEL, cb => sub {
1843 root 1.65 db_sync;
1844     });
1845    
1846     sub db_dirty() {
1847     $dirty = 1;
1848     $idle->start;
1849     }
1850    
1851     sub db_get($;$) {
1852     @_ >= 2
1853 root 1.78 ? $DB->{$_[0]}{$_[1]}
1854     : ($DB->{$_[0]} ||= { })
1855 root 1.65 }
1856    
1857     sub db_put($$;$) {
1858     if (@_ >= 3) {
1859 root 1.78 $DB->{$_[0]}{$_[1]} = $_[2];
1860 root 1.65 } else {
1861 root 1.78 $DB->{$_[0]} = $_[1];
1862 root 1.65 }
1863     db_dirty;
1864     }
1865 root 1.67
1866 root 1.93 cf::global->attach (
1867     prio => 10000,
1868 root 1.67 on_cleanup => sub {
1869     db_sync;
1870     },
1871 root 1.93 );
1872 root 1.65 }
1873    
1874     #############################################################################
1875 root 1.34 # the server's main()
1876    
1877 root 1.73 sub cfg_load {
1878 root 1.72 open my $fh, "<:utf8", cf::confdir . "/config"
1879     or return;
1880    
1881     local $/;
1882     *CFG = YAML::Syck::Load <$fh>;
1883     }
1884    
1885 root 1.39 sub main {
1886 root 1.108 # we must not ever block the main coroutine
1887     local $Coro::idle = sub {
1888 root 1.115 Carp::cluck "FATAL: Coro::idle was called, major BUG, use cf::sync_job!\n";#d#
1889 root 1.108 (Coro::unblock_sub {
1890     Event::one_event;
1891     })->();
1892     };
1893    
1894 root 1.73 cfg_load;
1895 root 1.65 db_load;
1896 root 1.61 load_extensions;
1897 root 1.34 Event::loop;
1898     }
1899    
1900     #############################################################################
1901 root 1.22 # initialisation
1902    
1903 root 1.111 sub reload() {
1904 root 1.106 # can/must only be called in main
1905     if ($Coro::current != $Coro::main) {
1906     warn "can only reload from main coroutine\n";
1907     return;
1908     }
1909    
1910 root 1.103 warn "reloading...";
1911    
1912 root 1.106 local $FREEZE = 1;
1913     cf::emergency_save;
1914    
1915 root 1.103 eval {
1916 root 1.106 # if anything goes wrong in here, we should simply crash as we already saved
1917 root 1.65
1918     # cancel all watchers
1919 root 1.87 for (Event::all_watchers) {
1920     $_->cancel if $_->data & WF_AUTOCANCEL;
1921     }
1922 root 1.65
1923 root 1.103 # cancel all extension coros
1924     $_->cancel for values %EXT_CORO;
1925     %EXT_CORO = ();
1926    
1927 root 1.65 # unload all extensions
1928     for (@exts) {
1929 root 1.103 warn "unloading <$_>";
1930 root 1.65 unload_extension $_;
1931     }
1932    
1933     # unload all modules loaded from $LIBDIR
1934     while (my ($k, $v) = each %INC) {
1935     next unless $v =~ /^\Q$LIBDIR\E\/.*\.pm$/;
1936    
1937 root 1.103 warn "removing <$k>";
1938 root 1.65 delete $INC{$k};
1939    
1940     $k =~ s/\.pm$//;
1941     $k =~ s/\//::/g;
1942    
1943     if (my $cb = $k->can ("unload_module")) {
1944     $cb->();
1945     }
1946    
1947     Symbol::delete_package $k;
1948     }
1949    
1950     # sync database to disk
1951     cf::db_sync;
1952 root 1.103 IO::AIO::flush;
1953 root 1.65
1954     # get rid of safe::, as good as possible
1955     Symbol::delete_package "safe::$_"
1956 root 1.103 for qw(cf::attachable cf::object cf::object::player cf::client cf::player cf::map cf::party cf::region);
1957 root 1.65
1958     # remove register_script_function callbacks
1959     # TODO
1960    
1961     # unload cf.pm "a bit"
1962     delete $INC{"cf.pm"};
1963    
1964     # don't, removes xs symbols, too,
1965     # and global variables created in xs
1966     #Symbol::delete_package __PACKAGE__;
1967    
1968     # reload cf.pm
1969 root 1.103 warn "reloading cf.pm";
1970 root 1.65 require cf;
1971 root 1.100 cf::_connect_to_perl; # nominally unnecessary, but cannot hurt
1972    
1973 root 1.73 # load config and database again
1974     cf::cfg_load;
1975 root 1.65 cf::db_load;
1976    
1977     # load extensions
1978 root 1.103 warn "load extensions";
1979 root 1.65 cf::load_extensions;
1980    
1981     # reattach attachments to objects
1982 root 1.103 warn "reattach";
1983 root 1.65 _global_reattach;
1984     };
1985    
1986 root 1.106 if ($@) {
1987     warn $@;
1988     warn "error while reloading, exiting.";
1989     exit 1;
1990     }
1991    
1992     warn "reloaded successfully";
1993 root 1.65 };
1994    
1995 root 1.108 #############################################################################
1996    
1997     unless ($LINK_MAP) {
1998     $LINK_MAP = cf::map::new;
1999    
2000     $LINK_MAP->width (41);
2001     $LINK_MAP->height (41);
2002     $LINK_MAP->alloc;
2003     $LINK_MAP->path ("{link}");
2004     $LINK_MAP->{path} = bless { path => "{link}" }, "cf::path";
2005     $LINK_MAP->in_memory (MAP_IN_MEMORY);
2006 root 1.110
2007     # dirty hack because... archetypes are not yet loaded
2008     Event->timer (
2009     after => 2,
2010     cb => sub {
2011     $_[0]->w->cancel;
2012    
2013     # provide some exits "home"
2014     my $exit = cf::object::new "exit";
2015    
2016     $exit->slaying ($EMERGENCY_POSITION->[0]);
2017     $exit->stats->hp ($EMERGENCY_POSITION->[1]);
2018     $exit->stats->sp ($EMERGENCY_POSITION->[2]);
2019    
2020     $LINK_MAP->insert ($exit->clone, 19, 19);
2021     $LINK_MAP->insert ($exit->clone, 19, 20);
2022     $LINK_MAP->insert ($exit->clone, 19, 21);
2023     $LINK_MAP->insert ($exit->clone, 20, 19);
2024     $LINK_MAP->insert ($exit->clone, 20, 21);
2025     $LINK_MAP->insert ($exit->clone, 21, 19);
2026     $LINK_MAP->insert ($exit->clone, 21, 20);
2027     $LINK_MAP->insert ($exit->clone, 21, 21);
2028    
2029     $exit->destroy;
2030     });
2031    
2032     $LINK_MAP->{deny_save} = 1;
2033     $LINK_MAP->{deny_reset} = 1;
2034    
2035     $cf::MAP{$LINK_MAP->path} = $LINK_MAP;
2036 root 1.108 }
2037    
2038 root 1.85 register "<global>", __PACKAGE__;
2039    
2040 root 1.111 register_command "reload" => sub {
2041 root 1.65 my ($who, $arg) = @_;
2042    
2043     if ($who->flag (FLAG_WIZ)) {
2044 root 1.107 $who->message ("start of reload.");
2045 root 1.111 reload;
2046 root 1.107 $who->message ("end of reload.");
2047 root 1.65 }
2048     };
2049    
2050 root 1.27 unshift @INC, $LIBDIR;
2051 root 1.17
2052 root 1.35 $TICK_WATCHER = Event->timer (
2053 root 1.104 reentrant => 0,
2054     prio => 0,
2055     at => $NEXT_TICK || $TICK,
2056     data => WF_AUTOCANCEL,
2057     cb => sub {
2058 root 1.103 unless ($FREEZE) {
2059     cf::server_tick; # one server iteration
2060     $RUNTIME += $TICK;
2061     }
2062 root 1.35
2063     $NEXT_TICK += $TICK;
2064    
2065 root 1.78 # if we are delayed by four ticks or more, skip them all
2066 root 1.103 $NEXT_TICK = Event::time if Event::time >= $NEXT_TICK + $TICK * 4;
2067 root 1.35
2068     $TICK_WATCHER->at ($NEXT_TICK);
2069     $TICK_WATCHER->start;
2070     },
2071     );
2072    
2073 root 1.80 IO::AIO::max_poll_time $TICK * 0.2;
2074 root 1.77
2075 root 1.108 Event->io (
2076     fd => IO::AIO::poll_fileno,
2077     poll => 'r',
2078     prio => 5,
2079     data => WF_AUTOCANCEL,
2080     cb => \&IO::AIO::poll_cb,
2081     );
2082    
2083     Event->timer (
2084     data => WF_AUTOCANCEL,
2085     after => 0,
2086     interval => 10,
2087     cb => sub {
2088     (Coro::unblock_sub {
2089     write_runtime
2090     or warn "ERROR: unable to write runtime file: $!";
2091     })->();
2092     },
2093     );
2094 root 1.103
2095 root 1.1 1
2096