ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/lib/cf.pm
Revision: 1.113
Committed: Mon Jan 1 15:32:40 2007 UTC (17 years, 4 months ago) by root
Branch: MAIN
Changes since 1.112: +14 -1 lines
Log Message:
in my stupidity i broke the loader

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