ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/lib/cf.pm
Revision: 1.111
Committed: Mon Jan 1 12:28:47 2007 UTC (17 years, 4 months ago) by root
Branch: MAIN
Changes since 1.110: +20 -10 lines
Log Message:
set original flag so decay object doesn't go wild

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