ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/lib/cf.pm
Revision: 1.112
Committed: Mon Jan 1 13:31:47 2007 UTC (17 years, 4 months ago) by root
Branch: MAIN
Changes since 1.111: +40 -30 lines
Log Message:
this is close to working

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