ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/lib/cf.pm
Revision: 1.195
Committed: Fri Jan 26 20:59:57 2007 UTC (17 years, 4 months ago) by root
Branch: MAIN
Changes since 1.194: +11 -6 lines
Log Message:
- tame the map/map-world.ext a bit to avoid potential memleaks for now
- object refcounting was borked, fixed, again :)
- add cf::attacahble::mortals_size
- disable reset-after-load, this is unsafe due to locking issues, so don't do it
- make map-scheduler configurable
- improve emergency swap mode
- prepare_random_map must be a sync job for now :(
- do not keep object reference in enter_exit, the object might have been gone already.
- nuke cf::object::mortals.

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.193 use Coro 3.5 ();
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.154 use Data::Dumper;
21 root 1.108 use Digest::MD5;
22 root 1.105 use Fcntl;
23 root 1.145 use IO::AIO 2.32 ();
24 root 1.72 use YAML::Syck ();
25 root 1.32 use Time::HiRes;
26 root 1.96
27     use Event; $Event::Eval = 1; # no idea why this is required, but it is
28 root 1.1
29 root 1.155 sub WF_AUTOCANCEL () { 1 } # automatically cancel this watcher on reload
30    
31 root 1.72 # work around bug in YAML::Syck - bad news for perl6, will it be as broken wrt. unicode?
32     $YAML::Syck::ImplicitUnicode = 1;
33    
34 root 1.139 $Coro::main->prio (Coro::PRIO_MAX); # run main coroutine ("the server") with very high priority
35 root 1.1
36 root 1.85 our %COMMAND = ();
37     our %COMMAND_TIME = ();
38 root 1.159
39     our @EXTS = (); # list of extension package names
40 root 1.85 our %EXTCMD = ();
41 root 1.159 our %EXT_CORO = (); # coroutines bound to extensions
42 root 1.161 our %EXT_MAP = (); # pluggable maps
43 root 1.85
44 root 1.1 our @EVENT;
45 root 1.88 our $LIBDIR = datadir . "/ext";
46 root 1.1
47 root 1.35 our $TICK = MAX_TIME * 1e-6;
48     our $TICK_WATCHER;
49 root 1.168 our $AIO_POLL_WATCHER;
50     our $WRITE_RUNTIME_WATCHER;
51 root 1.35 our $NEXT_TICK;
52 root 1.103 our $NOW;
53 root 1.35
54 root 1.70 our %CFG;
55    
56 root 1.84 our $UPTIME; $UPTIME ||= time;
57 root 1.103 our $RUNTIME;
58    
59 root 1.143 our %PLAYER; # all users
60     our %MAP; # all maps
61 root 1.166 our $LINK_MAP; # the special {link} map, which is always available
62 root 1.108 our $RANDOM_MAPS = cf::localdir . "/random";
63 root 1.103
64 root 1.155 our $WAIT_FOR_TICK; $WAIT_FOR_TICK ||= new Coro::Signal;
65     our $WAIT_FOR_TICK_ONE; $WAIT_FOR_TICK_ONE ||= new Coro::Signal;
66    
67 root 1.166 # used to convert map paths into valid unix filenames by replacing / by ∕
68     our $PATH_SEP = "∕"; # U+2215, chosen purely for visual reasons
69    
70 root 1.103 binmode STDOUT;
71     binmode STDERR;
72    
73     # read virtual server time, if available
74     unless ($RUNTIME || !-e cf::localdir . "/runtime") {
75     open my $fh, "<", cf::localdir . "/runtime"
76     or die "unable to read runtime file: $!";
77     $RUNTIME = <$fh> + 0.;
78     }
79    
80     mkdir cf::localdir;
81     mkdir cf::localdir . "/" . cf::playerdir;
82     mkdir cf::localdir . "/" . cf::tmpdir;
83     mkdir cf::localdir . "/" . cf::uniquedir;
84 root 1.108 mkdir $RANDOM_MAPS;
85 root 1.103
86 root 1.131 our $EMERGENCY_POSITION;
87 root 1.110
88 root 1.70 #############################################################################
89    
90     =head2 GLOBAL VARIABLES
91    
92     =over 4
93    
94 root 1.83 =item $cf::UPTIME
95    
96     The timestamp of the server start (so not actually an uptime).
97    
98 root 1.103 =item $cf::RUNTIME
99    
100     The time this server has run, starts at 0 and is increased by $cf::TICK on
101     every server tick.
102    
103 root 1.70 =item $cf::LIBDIR
104    
105     The perl library directory, where extensions and cf-specific modules can
106     be found. It will be added to C<@INC> automatically.
107    
108 root 1.103 =item $cf::NOW
109    
110     The time of the last (current) server tick.
111    
112 root 1.70 =item $cf::TICK
113    
114     The interval between server ticks, in seconds.
115    
116     =item %cf::CFG
117    
118     Configuration for the server, loaded from C</etc/crossfire/config>, or
119     from wherever your confdir points to.
120    
121 root 1.155 =item $cf::WAIT_FOR_TICK, $cf::WAIT_FOR_TICK_ONE
122    
123     These are Coro::Signal objects that are C<< ->broadcast >> (WAIT_FOR_TICK)
124     or C<< ->send >> (WAIT_FOR_TICK_ONE) on after normal server tick
125     processing has been done. Call C<< ->wait >> on them to maximise the
126     window of cpu time available, or simply to synchronise to the server tick.
127    
128 root 1.70 =back
129    
130     =cut
131    
132 root 1.1 BEGIN {
133     *CORE::GLOBAL::warn = sub {
134     my $msg = join "", @_;
135 root 1.103 utf8::encode $msg;
136    
137 root 1.1 $msg .= "\n"
138     unless $msg =~ /\n$/;
139    
140 root 1.146 LOG llevError, $msg;
141 root 1.1 };
142     }
143    
144 root 1.93 @safe::cf::global::ISA = @cf::global::ISA = 'cf::attachable';
145     @safe::cf::object::ISA = @cf::object::ISA = 'cf::attachable';
146     @safe::cf::player::ISA = @cf::player::ISA = 'cf::attachable';
147     @safe::cf::client::ISA = @cf::client::ISA = 'cf::attachable';
148     @safe::cf::map::ISA = @cf::map::ISA = 'cf::attachable';
149 root 1.41 @safe::cf::object::player::ISA = @cf::object::player::ISA = 'cf::object';
150 root 1.25
151 root 1.41 # we bless all objects into (empty) derived classes to force a method lookup
152 root 1.25 # within the Safe compartment.
153 root 1.86 for my $pkg (qw(
154 root 1.100 cf::global cf::attachable
155 root 1.86 cf::object cf::object::player
156 root 1.89 cf::client cf::player
157 root 1.86 cf::arch cf::living
158     cf::map cf::party cf::region
159     )) {
160 root 1.25 no strict 'refs';
161 root 1.41 @{"safe::$pkg\::wrap::ISA"} = @{"$pkg\::wrap::ISA"} = $pkg;
162 root 1.25 }
163 root 1.1
164 root 1.18 $Event::DIED = sub {
165     warn "error in event callback: @_";
166     };
167    
168 root 1.70 =head2 UTILITY FUNCTIONS
169    
170     =over 4
171    
172 root 1.154 =item dumpval $ref
173    
174 root 1.70 =cut
175 root 1.44
176 root 1.154 sub dumpval {
177     eval {
178     local $SIG{__DIE__};
179     my $d;
180     if (1) {
181     $d = new Data::Dumper([$_[0]], ["*var"]);
182     $d->Terse(1);
183     $d->Indent(2);
184     $d->Quotekeys(0);
185     $d->Useqq(1);
186     #$d->Bless(...);
187     $d->Seen($_[1]) if @_ > 1;
188     $d = $d->Dump();
189     }
190     $d =~ s/([\x00-\x07\x09\x0b\x0c\x0e-\x1f])/sprintf "\\x%02x", ord($1)/ge;
191     $d
192     } || "[unable to dump $_[0]: '$@']";
193     }
194    
195 root 1.45 use JSON::Syck (); # TODO# replace by JSON::PC once working
196 root 1.44
197 root 1.70 =item $ref = cf::from_json $json
198    
199     Converts a JSON string into the corresponding perl data structure.
200    
201     =cut
202    
203 root 1.45 sub from_json($) {
204     $JSON::Syck::ImplicitUnicode = 1; # work around JSON::Syck bugs
205     JSON::Syck::Load $_[0]
206 root 1.44 }
207    
208 root 1.70 =item $json = cf::to_json $ref
209    
210     Converts a perl data structure into its JSON representation.
211    
212     =cut
213    
214 root 1.45 sub to_json($) {
215     $JSON::Syck::ImplicitUnicode = 0; # work around JSON::Syck bugs
216     JSON::Syck::Dump $_[0]
217 root 1.44 }
218    
219 root 1.120 =item cf::lock_wait $string
220    
221     Wait until the given lock is available. See cf::lock_acquire.
222    
223     =item my $lock = cf::lock_acquire $string
224    
225     Wait until the given lock is available and then acquires it and returns
226 root 1.135 a Coro::guard object. If the guard object gets destroyed (goes out of scope,
227 root 1.120 for example when the coroutine gets canceled), the lock is automatically
228     returned.
229    
230 root 1.133 Lock names should begin with a unique identifier (for example, cf::map::find
231     uses map_find and cf::map::load uses map_load).
232 root 1.120
233     =cut
234    
235     our %LOCK;
236    
237     sub lock_wait($) {
238     my ($key) = @_;
239    
240     # wait for lock, if any
241     while ($LOCK{$key}) {
242     push @{ $LOCK{$key} }, $Coro::current;
243     Coro::schedule;
244     }
245     }
246    
247     sub lock_acquire($) {
248     my ($key) = @_;
249    
250     # wait, to be sure we are not locked
251     lock_wait $key;
252    
253     $LOCK{$key} = [];
254    
255 root 1.135 Coro::guard {
256 root 1.120 # wake up all waiters, to be on the safe side
257     $_->ready for @{ delete $LOCK{$key} };
258     }
259     }
260    
261 root 1.133 sub freeze_mainloop {
262     return unless $TICK_WATCHER->is_active;
263    
264 root 1.168 my $guard = Coro::guard {
265     $TICK_WATCHER->start;
266     $WRITE_RUNTIME_WATCHER->start;
267     };
268     $WRITE_RUNTIME_WATCHER->stop;
269 root 1.133 $TICK_WATCHER->stop;
270     $guard
271     }
272    
273 root 1.140 =item cf::async { BLOCK }
274    
275     Currently the same as Coro::async_pool, meaning you cannot use
276     C<on_destroy>, C<join> or other gimmicks on these coroutines. The only
277     thing you are allowed to do is call C<prio> on it.
278    
279     =cut
280    
281     BEGIN { *async = \&Coro::async_pool }
282    
283 root 1.106 =item cf::sync_job { BLOCK }
284    
285     The design of crossfire+ requires that the main coro ($Coro::main) is
286     always able to handle events or runnable, as crossfire+ is only partly
287     reentrant. Thus "blocking" it by e.g. waiting for I/O is not acceptable.
288    
289     If it must be done, put the blocking parts into C<sync_job>. This will run
290     the given BLOCK in another coroutine while waiting for the result. The
291     server will be frozen during this time, so the block should either finish
292     fast or be very important.
293    
294     =cut
295    
296 root 1.105 sub sync_job(&) {
297     my ($job) = @_;
298    
299     if ($Coro::current == $Coro::main) {
300 root 1.112 # this is the main coro, too bad, we have to block
301     # till the operation succeeds, freezing the server :/
302    
303 root 1.110 # TODO: use suspend/resume instead
304 root 1.112 # (but this is cancel-safe)
305 root 1.133 my $freeze_guard = freeze_mainloop;
306 root 1.112
307     my $busy = 1;
308     my @res;
309    
310 root 1.140 (async {
311 root 1.112 @res = eval { $job->() };
312     warn $@ if $@;
313     undef $busy;
314     })->prio (Coro::PRIO_MAX);
315    
316 root 1.105 while ($busy) {
317 root 1.141 Coro::cede or Event::one_event;
318 root 1.105 }
319 root 1.112
320     wantarray ? @res : $res[0]
321 root 1.105 } else {
322 root 1.112 # we are in another coroutine, how wonderful, everything just works
323    
324     $job->()
325 root 1.105 }
326     }
327    
328 root 1.140 =item $coro = cf::async_ext { BLOCK }
329 root 1.103
330 root 1.159 Like async, but this coro is automatically being canceled when the
331 root 1.140 extension calling this is being unloaded.
332 root 1.103
333     =cut
334    
335 root 1.140 sub async_ext(&) {
336 root 1.103 my $cb = shift;
337    
338 root 1.140 my $coro = &Coro::async ($cb);
339 root 1.103
340     $coro->on_destroy (sub {
341     delete $EXT_CORO{$coro+0};
342     });
343     $EXT_CORO{$coro+0} = $coro;
344    
345     $coro
346     }
347    
348 root 1.108 sub write_runtime {
349     my $runtime = cf::localdir . "/runtime";
350    
351     my $fh = aio_open "$runtime~", O_WRONLY | O_CREAT, 0644
352     or return;
353    
354 root 1.186 my $value = $cf::RUNTIME + 90 + 10;
355     # 10 is the runtime save interval, for a monotonic clock
356     # 60 allows for the watchdog to kill the server.
357    
358 root 1.108 (aio_write $fh, 0, (length $value), $value, 0) <= 0
359     and return;
360    
361     aio_fsync $fh
362     and return;
363    
364     close $fh
365     or return;
366    
367     aio_rename "$runtime~", $runtime
368     and return;
369    
370     1
371     }
372    
373 root 1.70 =back
374    
375 root 1.71 =cut
376    
377 root 1.44 #############################################################################
378 root 1.39
379 root 1.93 =head2 ATTACHABLE OBJECTS
380    
381 root 1.94 Many objects in crossfire are so-called attachable objects. That means you can
382     attach callbacks/event handlers (a collection of which is called an "attachment")
383     to it. All such attachable objects support the following methods.
384    
385     In the following description, CLASS can be any of C<global>, C<object>
386     C<player>, C<client> or C<map> (i.e. the attachable objects in
387     crossfire+).
388 root 1.55
389     =over 4
390    
391 root 1.94 =item $attachable->attach ($attachment, key => $value...)
392    
393     =item $attachable->detach ($attachment)
394    
395     Attach/detach a pre-registered attachment to a specific object and give it
396     the specified key/value pairs as arguments.
397    
398     Example, attach a minesweeper attachment to the given object, making it a
399     10x10 minesweeper game:
400 root 1.46
401 root 1.94 $obj->attach (minesweeper => width => 10, height => 10);
402 root 1.53
403 root 1.93 =item $bool = $attachable->attached ($name)
404 root 1.46
405 root 1.93 Checks wether the named attachment is currently attached to the object.
406 root 1.46
407 root 1.94 =item cf::CLASS->attach ...
408 root 1.46
409 root 1.94 =item cf::CLASS->detach ...
410 root 1.92
411 root 1.94 Define an anonymous attachment and attach it to all objects of the given
412     CLASS. See the next function for an explanation of its arguments.
413 root 1.92
414 root 1.93 You can attach to global events by using the C<cf::global> class.
415 root 1.92
416 root 1.94 Example, log all player logins:
417    
418     cf::player->attach (
419     on_login => sub {
420     my ($pl) = @_;
421     ...
422     },
423     );
424    
425     Example, attach to the jeweler skill:
426    
427     cf::object->attach (
428     type => cf::SKILL,
429     subtype => cf::SK_JEWELER,
430     on_use_skill => sub {
431     my ($sk, $ob, $part, $dir, $msg) = @_;
432     ...
433     },
434     );
435    
436     =item cf::CLASS::attachment $name, ...
437    
438     Register an attachment by C<$name> through which attachable objects of the
439     given CLASS can refer to this attachment.
440    
441     Some classes such as crossfire maps and objects can specify attachments
442     that are attached at load/instantiate time, thus the need for a name.
443    
444     These calls expect any number of the following handler/hook descriptions:
445 root 1.46
446     =over 4
447    
448     =item prio => $number
449    
450     Set the priority for all following handlers/hooks (unless overwritten
451     by another C<prio> setting). Lower priority handlers get executed
452     earlier. The default priority is C<0>, and many built-in handlers are
453     registered at priority C<-1000>, so lower priorities should not be used
454     unless you know what you are doing.
455    
456 root 1.93 =item type => $type
457    
458     (Only for C<< cf::object->attach >> calls), limits the attachment to the
459     given type of objects only (the additional parameter C<subtype> can be
460     used to further limit to the given subtype).
461    
462 root 1.46 =item on_I<event> => \&cb
463    
464     Call the given code reference whenever the named event happens (event is
465     something like C<instantiate>, C<apply>, C<use_skill> and so on, and which
466     handlers are recognised generally depends on the type of object these
467     handlers attach to).
468    
469     See F<include/eventinc.h> for the full list of events supported, and their
470     class.
471    
472     =item package => package::
473    
474     Look for sub functions of the name C<< on_I<event> >> in the given
475     package and register them. Only handlers for eevents supported by the
476     object/class are recognised.
477    
478     =back
479    
480 root 1.94 Example, define an attachment called "sockpuppet" that calls the given
481     event handler when a monster attacks:
482    
483     cf::object::attachment sockpuppet =>
484     on_skill_attack => sub {
485     my ($self, $victim) = @_;
486     ...
487     }
488     }
489    
490 root 1.96 =item $attachable->valid
491    
492     Just because you have a perl object does not mean that the corresponding
493     C-level object still exists. If you try to access an object that has no
494     valid C counterpart anymore you get an exception at runtime. This method
495     can be used to test for existence of the C object part without causing an
496     exception.
497    
498 root 1.39 =cut
499    
500 root 1.40 # the following variables are defined in .xs and must not be re-created
501 root 1.100 our @CB_GLOBAL = (); # registry for all global events
502     our @CB_ATTACHABLE = (); # registry for all attachables
503     our @CB_OBJECT = (); # all objects (should not be used except in emergency)
504     our @CB_PLAYER = ();
505     our @CB_CLIENT = ();
506     our @CB_TYPE = (); # registry for type (cf-object class) based events
507     our @CB_MAP = ();
508 root 1.39
509 root 1.45 my %attachment;
510    
511 root 1.170 sub cf::attachable::thawer_merge {
512     # simply override everything except _meta
513     local $_[0]{_meta};
514     %{$_[0]} = %{$_[1]};
515     }
516    
517 root 1.93 sub _attach_cb($$$$) {
518     my ($registry, $event, $prio, $cb) = @_;
519 root 1.39
520     use sort 'stable';
521    
522     $cb = [$prio, $cb];
523    
524     @{$registry->[$event]} = sort
525     { $a->[0] cmp $b->[0] }
526     @{$registry->[$event] || []}, $cb;
527     }
528    
529 root 1.100 # hack
530     my %attachable_klass = map +($_ => 1), KLASS_OBJECT, KLASS_CLIENT, KLASS_PLAYER, KLASS_MAP;
531    
532 root 1.39 # attach handles attaching event callbacks
533     # the only thing the caller has to do is pass the correct
534     # registry (== where the callback attaches to).
535 root 1.93 sub _attach {
536 root 1.45 my ($registry, $klass, @arg) = @_;
537 root 1.39
538 root 1.93 my $object_type;
539 root 1.39 my $prio = 0;
540     my %cb_id = map +("on_" . lc $EVENT[$_][0], $_) , grep $EVENT[$_][1] == $klass, 0 .. $#EVENT;
541    
542 root 1.100 #TODO: get rid of this hack
543     if ($attachable_klass{$klass}) {
544     %cb_id = (%cb_id, map +("on_" . lc $EVENT[$_][0], $_) , grep $EVENT[$_][1] == KLASS_ATTACHABLE, 0 .. $#EVENT);
545     }
546    
547 root 1.45 while (@arg) {
548     my $type = shift @arg;
549 root 1.39
550     if ($type eq "prio") {
551 root 1.45 $prio = shift @arg;
552 root 1.39
553 root 1.93 } elsif ($type eq "type") {
554     $object_type = shift @arg;
555     $registry = $CB_TYPE[$object_type] ||= [];
556    
557     } elsif ($type eq "subtype") {
558     defined $object_type or Carp::croak "subtype specified without type";
559     my $object_subtype = shift @arg;
560     $registry = $CB_TYPE[$object_type + $object_subtype * NUM_SUBTYPES] ||= [];
561    
562 root 1.39 } elsif ($type eq "package") {
563 root 1.45 my $pkg = shift @arg;
564 root 1.39
565     while (my ($name, $id) = each %cb_id) {
566     if (my $cb = $pkg->can ($name)) {
567 root 1.93 _attach_cb $registry, $id, $prio, $cb;
568 root 1.39 }
569     }
570    
571     } elsif (exists $cb_id{$type}) {
572 root 1.93 _attach_cb $registry, $cb_id{$type}, $prio, shift @arg;
573 root 1.39
574     } elsif (ref $type) {
575     warn "attaching objects not supported, ignoring.\n";
576    
577     } else {
578 root 1.45 shift @arg;
579 root 1.39 warn "attach argument '$type' not supported, ignoring.\n";
580     }
581     }
582     }
583    
584 root 1.93 sub _object_attach {
585 root 1.48 my ($obj, $name, %arg) = @_;
586 root 1.46
587 root 1.55 return if exists $obj->{_attachment}{$name};
588    
589 root 1.46 if (my $attach = $attachment{$name}) {
590     my $registry = $obj->registry;
591    
592 root 1.47 for (@$attach) {
593     my ($klass, @attach) = @$_;
594 root 1.93 _attach $registry, $klass, @attach;
595 root 1.47 }
596 root 1.46
597 root 1.48 $obj->{$name} = \%arg;
598 root 1.46 } else {
599     warn "object uses attachment '$name' that is not available, postponing.\n";
600     }
601    
602 root 1.50 $obj->{_attachment}{$name} = undef;
603 root 1.46 }
604    
605 root 1.93 sub cf::attachable::attach {
606     if (ref $_[0]) {
607     _object_attach @_;
608     } else {
609     _attach shift->_attach_registry, @_;
610     }
611 root 1.55 };
612 root 1.46
613 root 1.54 # all those should be optimised
614 root 1.93 sub cf::attachable::detach {
615 root 1.54 my ($obj, $name) = @_;
616 root 1.46
617 root 1.93 if (ref $obj) {
618     delete $obj->{_attachment}{$name};
619     reattach ($obj);
620     } else {
621     Carp::croak "cannot, currently, detach class attachments";
622     }
623 root 1.55 };
624    
625 root 1.93 sub cf::attachable::attached {
626 root 1.55 my ($obj, $name) = @_;
627    
628     exists $obj->{_attachment}{$name}
629 root 1.39 }
630    
631 root 1.100 for my $klass (qw(ATTACHABLE GLOBAL OBJECT PLAYER CLIENT MAP)) {
632 root 1.93 eval "#line " . __LINE__ . " 'cf.pm'
633     sub cf::\L$klass\E::_attach_registry {
634     (\\\@CB_$klass, KLASS_$klass)
635     }
636 root 1.45
637 root 1.93 sub cf::\L$klass\E::attachment {
638     my \$name = shift;
639 root 1.39
640 root 1.93 \$attachment{\$name} = [[KLASS_$klass, \@_]];
641     }
642     ";
643     die if $@;
644 root 1.52 }
645    
646 root 1.39 our $override;
647 root 1.45 our @invoke_results = (); # referenced from .xs code. TODO: play tricks with reify and mortals?
648 root 1.39
649 root 1.45 sub override {
650     $override = 1;
651     @invoke_results = ();
652 root 1.39 }
653    
654 root 1.45 sub do_invoke {
655 root 1.39 my $event = shift;
656 root 1.40 my $callbacks = shift;
657 root 1.39
658 root 1.45 @invoke_results = ();
659    
660 root 1.39 local $override;
661    
662 root 1.40 for (@$callbacks) {
663 root 1.39 eval { &{$_->[1]} };
664    
665     if ($@) {
666     warn "$@";
667 root 1.64 warn "... while processing $EVENT[$event][0](@_) event, skipping processing altogether.\n";
668 root 1.39 override;
669     }
670    
671     return 1 if $override;
672     }
673    
674     0
675     }
676    
677 root 1.96 =item $bool = cf::global::invoke (EVENT_CLASS_XXX, ...)
678 root 1.55
679 root 1.96 =item $bool = $attachable->invoke (EVENT_CLASS_XXX, ...)
680 root 1.55
681 root 1.96 Generate an object-specific event with the given arguments.
682 root 1.55
683 root 1.96 This API is preliminary (most likely, the EVENT_CLASS_xxx prefix will be
684 root 1.55 removed in future versions), and there is no public API to access override
685     results (if you must, access C<@cf::invoke_results> directly).
686    
687     =back
688    
689 root 1.71 =cut
690    
691 root 1.70 #############################################################################
692 root 1.45 # object support
693    
694 root 1.102 sub reattach {
695     # basically do the same as instantiate, without calling instantiate
696     my ($obj) = @_;
697    
698 root 1.169 bless $obj, ref $obj; # re-bless in case extensions have been reloaded
699    
700 root 1.102 my $registry = $obj->registry;
701    
702     @$registry = ();
703    
704     delete $obj->{_attachment} unless scalar keys %{ $obj->{_attachment} || {} };
705    
706     for my $name (keys %{ $obj->{_attachment} || {} }) {
707     if (my $attach = $attachment{$name}) {
708     for (@$attach) {
709     my ($klass, @attach) = @$_;
710     _attach $registry, $klass, @attach;
711     }
712     } else {
713     warn "object uses attachment '$name' that is not available, postponing.\n";
714     }
715     }
716     }
717    
718 root 1.100 cf::attachable->attach (
719     prio => -1000000,
720     on_instantiate => sub {
721     my ($obj, $data) = @_;
722 root 1.45
723 root 1.100 $data = from_json $data;
724 root 1.45
725 root 1.100 for (@$data) {
726     my ($name, $args) = @$_;
727 root 1.49
728 root 1.100 $obj->attach ($name, %{$args || {} });
729     }
730     },
731 root 1.102 on_reattach => \&reattach,
732 root 1.100 on_clone => sub {
733     my ($src, $dst) = @_;
734    
735     @{$dst->registry} = @{$src->registry};
736    
737     %$dst = %$src;
738    
739     %{$dst->{_attachment}} = %{$src->{_attachment}}
740     if exists $src->{_attachment};
741     },
742     );
743 root 1.45
744 root 1.46 sub object_freezer_save {
745 root 1.59 my ($filename, $rdata, $objs) = @_;
746 root 1.46
747 root 1.105 sync_job {
748     if (length $$rdata) {
749     warn sprintf "saving %s (%d,%d)\n",
750     $filename, length $$rdata, scalar @$objs;
751 root 1.60
752 root 1.105 if (my $fh = aio_open "$filename~", O_WRONLY | O_CREAT, 0600) {
753 root 1.60 chmod SAVE_MODE, $fh;
754 root 1.105 aio_write $fh, 0, (length $$rdata), $$rdata, 0;
755     aio_fsync $fh;
756 root 1.60 close $fh;
757 root 1.105
758     if (@$objs) {
759     if (my $fh = aio_open "$filename.pst~", O_WRONLY | O_CREAT, 0600) {
760     chmod SAVE_MODE, $fh;
761     my $data = Storable::nfreeze { version => 1, objs => $objs };
762     aio_write $fh, 0, (length $data), $data, 0;
763     aio_fsync $fh;
764     close $fh;
765     aio_rename "$filename.pst~", "$filename.pst";
766     }
767     } else {
768     aio_unlink "$filename.pst";
769     }
770    
771     aio_rename "$filename~", $filename;
772 root 1.60 } else {
773 root 1.105 warn "FATAL: $filename~: $!\n";
774 root 1.60 }
775 root 1.59 } else {
776 root 1.105 aio_unlink $filename;
777     aio_unlink "$filename.pst";
778 root 1.59 }
779 root 1.45 }
780     }
781    
782 root 1.80 sub object_freezer_as_string {
783     my ($rdata, $objs) = @_;
784    
785     use Data::Dumper;
786    
787 root 1.81 $$rdata . Dumper $objs
788 root 1.80 }
789    
790 root 1.46 sub object_thawer_load {
791     my ($filename) = @_;
792    
793 root 1.105 my ($data, $av);
794 root 1.61
795 root 1.105 (aio_load $filename, $data) >= 0
796     or return;
797 root 1.61
798 root 1.105 unless (aio_stat "$filename.pst") {
799     (aio_load "$filename.pst", $av) >= 0
800     or return;
801 root 1.113 $av = eval { (Storable::thaw $av)->{objs} };
802 root 1.61 }
803 root 1.45
804 root 1.118 warn sprintf "loading %s (%d)\n",
805     $filename, length $data, scalar @{$av || []};#d#
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 root 1.159 $EXTCMD{$name} = $cb;
841 root 1.16 }
842    
843 root 1.93 cf::player->attach (
844 root 1.85 on_command => sub {
845     my ($pl, $name, $params) = @_;
846    
847     my $cb = $COMMAND{$name}
848     or return;
849    
850     for my $cmd (@$cb) {
851     $cmd->[1]->($pl->ob, $params);
852     }
853    
854     cf::override;
855     },
856     on_extcmd => sub {
857     my ($pl, $buf) = @_;
858    
859     my $msg = eval { from_json $buf };
860    
861     if (ref $msg) {
862     if (my $cb = $EXTCMD{$msg->{msgtype}}) {
863 root 1.159 if (my %reply = $cb->($pl, $msg)) {
864 root 1.85 $pl->ext_reply ($msg->{msgid}, %reply);
865     }
866     }
867     } else {
868     warn "player " . ($pl->ob->name) . " sent unparseable ext message: <$buf>\n";
869     }
870    
871     cf::override;
872     },
873 root 1.93 );
874 root 1.85
875 root 1.1 sub load_extension {
876     my ($path) = @_;
877    
878     $path =~ /([^\/\\]+)\.ext$/ or die "$path";
879 root 1.5 my $base = $1;
880 root 1.1 my $pkg = $1;
881     $pkg =~ s/[^[:word:]]/_/g;
882 root 1.41 $pkg = "ext::$pkg";
883 root 1.1
884 root 1.160 warn "... loading '$path' into '$pkg'\n";
885 root 1.1
886     open my $fh, "<:utf8", $path
887     or die "$path: $!";
888    
889     my $source =
890     "package $pkg; use strict; use utf8;\n"
891     . "#line 1 \"$path\"\n{\n"
892     . (do { local $/; <$fh> })
893     . "\n};\n1";
894    
895 root 1.166 unless (eval $source) {
896     my $msg = $@ ? "$path: $@\n"
897     : "extension disabled.\n";
898     if ($source =~ /^#!.*perl.*#.*MANDATORY/m) { # ugly match
899     warn $@;
900     warn "mandatory extension failed to load, exiting.\n";
901     exit 1;
902     }
903     die $@;
904     }
905 root 1.1
906 root 1.159 push @EXTS, $pkg;
907 root 1.1 }
908    
909     sub load_extensions {
910     for my $ext (<$LIBDIR/*.ext>) {
911 root 1.3 next unless -r $ext;
912 root 1.2 eval {
913     load_extension $ext;
914     1
915     } or warn "$ext not loaded: $@";
916 root 1.1 }
917     }
918    
919 root 1.8 #############################################################################
920 root 1.70
921     =head2 CORE EXTENSIONS
922    
923     Functions and methods that extend core crossfire objects.
924    
925 root 1.143 =cut
926    
927     package cf::player;
928    
929 root 1.154 use Coro::AIO;
930    
931 root 1.95 =head3 cf::player
932    
933 root 1.70 =over 4
934 root 1.22
935 root 1.143 =item cf::player::find $login
936 root 1.23
937 root 1.143 Returns the given player object, loading it if necessary (might block).
938 root 1.23
939     =cut
940    
941 root 1.145 sub playerdir($) {
942     cf::localdir
943     . "/"
944     . cf::playerdir
945     . "/"
946     . (ref $_[0] ? $_[0]->ob->name : $_[0])
947     }
948    
949 root 1.143 sub path($) {
950 root 1.145 my $login = ref $_[0] ? $_[0]->ob->name : $_[0];
951    
952     (playerdir $login) . "/$login.pl"
953 root 1.143 }
954    
955     sub find_active($) {
956     $cf::PLAYER{$_[0]}
957     and $cf::PLAYER{$_[0]}->active
958     and $cf::PLAYER{$_[0]}
959     }
960    
961     sub exists($) {
962     my ($login) = @_;
963    
964     $cf::PLAYER{$login}
965 root 1.180 or cf::sync_job { !aio_stat path $login }
966 root 1.143 }
967    
968     sub find($) {
969     return $cf::PLAYER{$_[0]} || do {
970     my $login = $_[0];
971    
972     my $guard = cf::lock_acquire "user_find:$login";
973    
974 root 1.151 $cf::PLAYER{$_[0]} || do {
975     my $pl = load_pl path $login
976     or return;
977     $cf::PLAYER{$login} = $pl
978     }
979     }
980 root 1.143 }
981    
982     sub save($) {
983     my ($pl) = @_;
984    
985     return if $pl->{deny_save};
986    
987     my $path = path $pl;
988     my $guard = cf::lock_acquire "user_save:$path";
989    
990     return if $pl->{deny_save};
991 root 1.146
992 root 1.154 aio_mkdir playerdir $pl, 0770;
993 root 1.143 $pl->{last_save} = $cf::RUNTIME;
994    
995     $pl->save_pl ($path);
996     Coro::cede;
997     }
998    
999     sub new($) {
1000     my ($login) = @_;
1001    
1002     my $self = create;
1003    
1004     $self->ob->name ($login);
1005     $self->{deny_save} = 1;
1006    
1007     $cf::PLAYER{$login} = $self;
1008    
1009     $self
1010 root 1.23 }
1011    
1012 root 1.154 =item $pl->quit_character
1013    
1014     Nukes the player without looking back. If logged in, the connection will
1015     be destroyed. May block for a long time.
1016    
1017     =cut
1018    
1019 root 1.145 sub quit_character {
1020     my ($pl) = @_;
1021    
1022     $pl->{deny_save} = 1;
1023     $pl->password ("*"); # this should lock out the player until we nuked the dir
1024    
1025     $pl->invoke (cf::EVENT_PLAYER_LOGOUT, 1) if $pl->active;
1026     $pl->deactivate;
1027     $pl->invoke (cf::EVENT_PLAYER_QUIT);
1028     $pl->ns->destroy if $pl->ns;
1029    
1030     my $path = playerdir $pl;
1031     my $temp = "$path~$cf::RUNTIME~deleting~";
1032 root 1.154 aio_rename $path, $temp;
1033 root 1.150 delete $cf::PLAYER{$pl->ob->name};
1034     $pl->destroy;
1035     IO::AIO::aio_rmtree $temp;
1036 root 1.145 }
1037    
1038 root 1.154 =item cf::player::list_logins
1039    
1040     Returns am arrayref of all valid playernames in the system, can take a
1041     while and may block, so not sync_job-capable, ever.
1042    
1043     =cut
1044    
1045     sub list_logins {
1046     my $dirs = aio_readdir cf::localdir . "/" . cf::playerdir
1047     or return [];
1048    
1049     my @logins;
1050    
1051     for my $login (@$dirs) {
1052     my $fh = aio_open path $login, Fcntl::O_RDONLY, 0 or next;
1053     aio_read $fh, 0, 512, my $buf, 0 or next;
1054 root 1.155 $buf !~ /^password -------------$/m or next; # official not-valid tag
1055 root 1.154
1056     utf8::decode $login;
1057     push @logins, $login;
1058     }
1059    
1060     \@logins
1061     }
1062    
1063     =item $player->maps
1064    
1065 root 1.166 Returns an arrayref of map paths that are private for this
1066 root 1.154 player. May block.
1067    
1068     =cut
1069    
1070     sub maps($) {
1071     my ($pl) = @_;
1072    
1073     my $files = aio_readdir playerdir $pl
1074     or return;
1075    
1076     my @paths;
1077    
1078     for (@$files) {
1079     utf8::decode $_;
1080     next if /\.(?:pl|pst)$/;
1081 root 1.158 next unless /^$PATH_SEP/o;
1082 root 1.154
1083 root 1.167 s/\.map$//;
1084 root 1.166 push @paths, "~" . $pl->ob->name . "/" . $_;
1085 root 1.154 }
1086    
1087     \@paths
1088     }
1089    
1090 root 1.95 =item $player->ext_reply ($msgid, $msgtype, %msg)
1091    
1092     Sends an ext reply to the player.
1093    
1094     =cut
1095    
1096 root 1.143 sub ext_reply($$$%) {
1097 root 1.95 my ($self, $id, %msg) = @_;
1098    
1099     $msg{msgid} = $id;
1100    
1101 root 1.143 $self->send ("ext " . cf::to_json \%msg);
1102 root 1.95 }
1103    
1104 root 1.143 package cf;
1105    
1106 root 1.95 =back
1107    
1108 root 1.110
1109     =head3 cf::map
1110    
1111     =over 4
1112    
1113     =cut
1114    
1115     package cf::map;
1116    
1117     use Fcntl;
1118     use Coro::AIO;
1119    
1120 root 1.166 use overload
1121 root 1.173 '""' => \&as_string,
1122     fallback => 1;
1123 root 1.166
1124 root 1.133 our $MAX_RESET = 3600;
1125     our $DEFAULT_RESET = 3000;
1126 root 1.110
1127     sub generate_random_map {
1128 root 1.166 my ($self, $rmp) = @_;
1129 root 1.110 # mit "rum" bekleckern, nicht
1130 root 1.166 $self->_create_random_map (
1131 root 1.110 $rmp->{wallstyle}, $rmp->{wall_name}, $rmp->{floorstyle}, $rmp->{monsterstyle},
1132     $rmp->{treasurestyle}, $rmp->{layoutstyle}, $rmp->{doorstyle}, $rmp->{decorstyle},
1133     $rmp->{origin_map}, $rmp->{final_map}, $rmp->{exitstyle}, $rmp->{this_map},
1134     $rmp->{exit_on_final_map},
1135     $rmp->{xsize}, $rmp->{ysize},
1136     $rmp->{expand2x}, $rmp->{layoutoptions1}, $rmp->{layoutoptions2}, $rmp->{layoutoptions3},
1137     $rmp->{symmetry}, $rmp->{difficulty}, $rmp->{difficulty_given}, $rmp->{difficulty_increase},
1138     $rmp->{dungeon_level}, $rmp->{dungeon_depth}, $rmp->{decoroptions}, $rmp->{orientation},
1139     $rmp->{origin_y}, $rmp->{origin_x}, $rmp->{random_seed}, $rmp->{total_map_hp},
1140     $rmp->{map_layout_style}, $rmp->{treasureoptions}, $rmp->{symmetry_used},
1141 root 1.162 (cf::region::find $rmp->{region}), $rmp->{custom}
1142     )
1143 root 1.110 }
1144    
1145 root 1.187 =item cf::map->register ($regex, $prio)
1146    
1147     Register a handler for the map path matching the given regex at the
1148     givne priority (higher is better, built-in handlers have priority 0, the
1149     default).
1150    
1151     =cut
1152    
1153 root 1.166 sub register {
1154 root 1.187 my (undef, $regex, $prio) = @_;
1155 root 1.166 my $pkg = caller;
1156    
1157     no strict;
1158     push @{"$pkg\::ISA"}, __PACKAGE__;
1159    
1160 root 1.187 $EXT_MAP{$pkg} = [$prio, qr<$regex>];
1161 root 1.166 }
1162    
1163     # also paths starting with '/'
1164 root 1.187 $EXT_MAP{"cf::map"} = [0, qr{^(?=/)}];
1165 root 1.166
1166 root 1.170 sub thawer_merge {
1167 root 1.172 my ($self, $merge) = @_;
1168    
1169 root 1.170 # we have to keep some variables in memory intact
1170 root 1.172 local $self->{path};
1171     local $self->{load_path};
1172     local $self->{deny_save};
1173     local $self->{deny_reset};
1174 root 1.170
1175 root 1.172 $self->SUPER::thawer_merge ($merge);
1176 root 1.170 }
1177    
1178 root 1.166 sub normalise {
1179     my ($path, $base) = @_;
1180    
1181 root 1.192 $path = "$path"; # make sure its a string
1182    
1183 root 1.166 # map plan:
1184     #
1185     # /! non-realised random map exit (special hack!)
1186     # {... are special paths that are not being touched
1187     # ?xxx/... are special absolute paths
1188     # ?random/... random maps
1189     # /... normal maps
1190     # ~user/... per-player map of a specific user
1191    
1192     $path =~ s/$PATH_SEP/\//go;
1193    
1194     # treat it as relative path if it starts with
1195     # something that looks reasonable
1196     if ($path =~ m{^(?:\./|\.\./|\w)}) {
1197     $base or Carp::carp "normalise called with relative path and no base: '$path'";
1198    
1199     $base =~ s{[^/]+/?$}{};
1200     $path = "$base/$path";
1201     }
1202    
1203     for ($path) {
1204     redo if s{//}{/};
1205     redo if s{/\.?/}{/};
1206     redo if s{/[^/]+/\.\./}{/};
1207     }
1208    
1209     $path
1210     }
1211    
1212     sub new_from_path {
1213     my (undef, $path, $base) = @_;
1214    
1215     return $path if UNIVERSAL::isa $path, "cf::map"; # already a map object
1216    
1217     $path = normalise $path, $base;
1218    
1219 root 1.187 for my $pkg (sort { $EXT_MAP{$b}[0] <=> $EXT_MAP{$a}[0] } keys %EXT_MAP) {
1220     if ($path =~ $EXT_MAP{$pkg}[1]) {
1221 root 1.166 my $self = bless cf::map::new, $pkg;
1222     $self->{path} = $path; $self->path ($path);
1223     $self->init; # pass $1 etc.
1224     return $self;
1225     }
1226     }
1227    
1228 root 1.192 Carp::carp "unable to resolve path '$path' (base '$base').";
1229 root 1.166 ()
1230     }
1231    
1232     sub init {
1233     my ($self) = @_;
1234    
1235     $self
1236     }
1237    
1238     sub as_string {
1239     my ($self) = @_;
1240    
1241     "$self->{path}"
1242     }
1243    
1244     # the displayed name, this is a one way mapping
1245     sub visible_name {
1246     &as_string
1247     }
1248    
1249     # the original (read-only) location
1250     sub load_path {
1251     my ($self) = @_;
1252    
1253     sprintf "%s/%s/%s", cf::datadir, cf::mapdir, $self->{path}
1254     }
1255    
1256     # the temporary/swap location
1257     sub save_path {
1258     my ($self) = @_;
1259    
1260 root 1.167 (my $path = $_[0]{path}) =~ s/\//$PATH_SEP/g;
1261     sprintf "%s/%s/%s", cf::localdir, cf::tmpdir, $path
1262 root 1.166 }
1263    
1264     # the unique path, undef == no special unique path
1265     sub uniq_path {
1266     my ($self) = @_;
1267    
1268 root 1.167 (my $path = $_[0]{path}) =~ s/\//$PATH_SEP/g;
1269     sprintf "%s/%s/%s", cf::localdir, cf::uniquedir, $path
1270 root 1.166 }
1271    
1272 root 1.110 # and all this just because we cannot iterate over
1273     # all maps in C++...
1274     sub change_all_map_light {
1275     my ($change) = @_;
1276    
1277 root 1.122 $_->change_map_light ($change)
1278     for grep $_->outdoor, values %cf::MAP;
1279 root 1.110 }
1280    
1281 root 1.166 sub unlink_save {
1282     my ($self) = @_;
1283    
1284     utf8::encode (my $save = $self->save_path);
1285 root 1.170 IO::AIO::aioreq_pri 4; Coro::AIO::aio_unlink $save;
1286     IO::AIO::aioreq_pri 4; Coro::AIO::aio_unlink "$save.pst";
1287 root 1.166 }
1288    
1289     sub load_header_from($) {
1290     my ($self, $path) = @_;
1291 root 1.110
1292     utf8::encode $path;
1293     aio_open $path, O_RDONLY, 0
1294     or return;
1295    
1296 root 1.166 $self->_load_header ($path)
1297 root 1.110 or return;
1298    
1299 root 1.166 $self->{load_path} = $path;
1300 root 1.135
1301 root 1.166 1
1302     }
1303 root 1.110
1304 root 1.188 sub load_header_orig {
1305 root 1.166 my ($self) = @_;
1306 root 1.110
1307 root 1.166 $self->load_header_from ($self->load_path)
1308 root 1.110 }
1309    
1310 root 1.188 sub load_header_temp {
1311 root 1.166 my ($self) = @_;
1312 root 1.110
1313 root 1.166 $self->load_header_from ($self->save_path)
1314     }
1315 root 1.110
1316 root 1.188 sub prepare_temp {
1317     my ($self) = @_;
1318    
1319     $self->last_access ((delete $self->{last_access})
1320     || $cf::RUNTIME); #d#
1321     # safety
1322     $self->{instantiate_time} = $cf::RUNTIME
1323     if $self->{instantiate_time} > $cf::RUNTIME;
1324     }
1325    
1326     sub prepare_orig {
1327     my ($self) = @_;
1328    
1329     $self->{load_original} = 1;
1330     $self->{instantiate_time} = $cf::RUNTIME;
1331     $self->last_access ($cf::RUNTIME);
1332     $self->instantiate;
1333     }
1334    
1335 root 1.166 sub load_header {
1336     my ($self) = @_;
1337 root 1.110
1338 root 1.188 if ($self->load_header_temp) {
1339     $self->prepare_temp;
1340 root 1.166 } else {
1341 root 1.188 $self->load_header_orig
1342 root 1.166 or return;
1343 root 1.188 $self->prepare_orig;
1344 root 1.166 }
1345 root 1.120
1346 root 1.166 1
1347     }
1348 root 1.110
1349 root 1.166 sub find;
1350     sub find {
1351     my ($path, $origin) = @_;
1352 root 1.134
1353 root 1.166 $path = normalise $path, $origin && $origin->path;
1354 root 1.110
1355 root 1.166 cf::lock_wait "map_find:$path";
1356 root 1.110
1357 root 1.166 $cf::MAP{$path} || do {
1358     my $guard = cf::lock_acquire "map_find:$path";
1359     my $map = new_from_path cf::map $path
1360     or return;
1361 root 1.110
1362 root 1.116 $map->{last_save} = $cf::RUNTIME;
1363 root 1.110
1364 root 1.166 $map->load_header
1365     or return;
1366 root 1.134
1367 root 1.195 if ($map->should_reset && 0) {#d#TODO# disabled, crashy (locking issue?)
1368 root 1.185 # doing this can freeze the server in a sync job, obviously
1369     #$cf::WAIT_FOR_TICK->wait;
1370 root 1.112 $map->reset;
1371 root 1.123 undef $guard;
1372 root 1.192 return find $path;
1373 root 1.112 }
1374 root 1.110
1375 root 1.166 $cf::MAP{$path} = $map
1376 root 1.110 }
1377     }
1378    
1379 root 1.188 sub pre_load { }
1380     sub post_load { }
1381    
1382 root 1.110 sub load {
1383     my ($self) = @_;
1384    
1385 root 1.120 my $path = $self->{path};
1386 root 1.166 my $guard = cf::lock_acquire "map_load:$path";
1387 root 1.120
1388 root 1.110 return if $self->in_memory != cf::MAP_SWAPPED;
1389    
1390     $self->in_memory (cf::MAP_LOADING);
1391    
1392     $self->alloc;
1393 root 1.188
1394     $self->pre_load;
1395    
1396 root 1.166 $self->_load_objects ($self->{load_path}, 1)
1397 root 1.110 or return;
1398    
1399 root 1.112 $self->set_object_flag (cf::FLAG_OBJ_ORIGINAL, 1)
1400     if delete $self->{load_original};
1401 root 1.111
1402 root 1.166 if (my $uniq = $self->uniq_path) {
1403 root 1.110 utf8::encode $uniq;
1404     if (aio_open $uniq, O_RDONLY, 0) {
1405     $self->clear_unique_items;
1406 root 1.166 $self->_load_objects ($uniq, 0);
1407 root 1.110 }
1408     }
1409    
1410 root 1.134 Coro::cede;
1411    
1412 root 1.110 # now do the right thing for maps
1413     $self->link_multipart_objects;
1414    
1415 root 1.166 unless ($self->{deny_activate}) {
1416 root 1.164 $self->decay_objects;
1417 root 1.110 $self->fix_auto_apply;
1418     $self->update_buttons;
1419 root 1.166 Coro::cede;
1420 root 1.110 $self->set_darkness_map;
1421     $self->difficulty ($self->estimate_difficulty)
1422     unless $self->difficulty;
1423 root 1.166 Coro::cede;
1424 root 1.110 $self->activate;
1425     }
1426    
1427 root 1.188 $self->post_load;
1428    
1429 root 1.166 $self->in_memory (cf::MAP_IN_MEMORY);
1430     }
1431    
1432     sub customise_for {
1433     my ($self, $ob) = @_;
1434    
1435     return find "~" . $ob->name . "/" . $self->{path}
1436     if $self->per_player;
1437 root 1.134
1438 root 1.166 $self
1439 root 1.110 }
1440    
1441 root 1.157 # find and load all maps in the 3x3 area around a map
1442     sub load_diag {
1443     my ($map) = @_;
1444    
1445     my @diag; # diagonal neighbours
1446    
1447     for (0 .. 3) {
1448     my $neigh = $map->tile_path ($_)
1449     or next;
1450     $neigh = find $neigh, $map
1451     or next;
1452     $neigh->load;
1453    
1454     push @diag, [$neigh->tile_path (($_ + 3) % 4), $neigh],
1455     [$neigh->tile_path (($_ + 1) % 4), $neigh];
1456     }
1457    
1458     for (@diag) {
1459     my $neigh = find @$_
1460     or next;
1461     $neigh->load;
1462     }
1463     }
1464    
1465 root 1.133 sub find_sync {
1466 root 1.110 my ($path, $origin) = @_;
1467    
1468 root 1.157 cf::sync_job { find $path, $origin }
1469 root 1.133 }
1470    
1471     sub do_load_sync {
1472     my ($map) = @_;
1473 root 1.110
1474 root 1.133 cf::sync_job { $map->load };
1475 root 1.110 }
1476    
1477 root 1.157 our %MAP_PREFETCH;
1478 root 1.183 our $MAP_PREFETCHER = undef;
1479 root 1.157
1480     sub find_async {
1481     my ($path, $origin) = @_;
1482    
1483 root 1.166 $path = normalise $path, $origin && $origin->{path};
1484 root 1.157
1485 root 1.166 if (my $map = $cf::MAP{$path}) {
1486 root 1.157 return $map if $map->in_memory == cf::MAP_IN_MEMORY;
1487     }
1488    
1489 root 1.183 undef $MAP_PREFETCH{$path};
1490     $MAP_PREFETCHER ||= cf::async {
1491     while (%MAP_PREFETCH) {
1492     for my $path (keys %MAP_PREFETCH) {
1493     my $map = find $path
1494     or next;
1495     $map->load;
1496    
1497     delete $MAP_PREFETCH{$path};
1498     }
1499     }
1500     undef $MAP_PREFETCHER;
1501     };
1502 root 1.189 $MAP_PREFETCHER->prio (6);
1503 root 1.157
1504     ()
1505     }
1506    
1507 root 1.110 sub save {
1508     my ($self) = @_;
1509    
1510 root 1.137 my $lock = cf::lock_acquire "map_data:" . $self->path;
1511    
1512 root 1.110 $self->{last_save} = $cf::RUNTIME;
1513    
1514     return unless $self->dirty;
1515    
1516 root 1.166 my $save = $self->save_path; utf8::encode $save;
1517     my $uniq = $self->uniq_path; utf8::encode $uniq;
1518 root 1.117
1519 root 1.110 $self->{load_path} = $save;
1520    
1521     return if $self->{deny_save};
1522    
1523 root 1.132 local $self->{last_access} = $self->last_access;#d#
1524    
1525 root 1.143 cf::async {
1526     $_->contr->save for $self->players;
1527     };
1528    
1529 root 1.110 if ($uniq) {
1530 root 1.166 $self->_save_objects ($save, cf::IO_HEADER | cf::IO_OBJECTS);
1531     $self->_save_objects ($uniq, cf::IO_UNIQUES);
1532 root 1.110 } else {
1533 root 1.166 $self->_save_objects ($save, cf::IO_HEADER | cf::IO_OBJECTS | cf::IO_UNIQUES);
1534 root 1.110 }
1535     }
1536    
1537     sub swap_out {
1538     my ($self) = @_;
1539    
1540 root 1.130 # save first because save cedes
1541     $self->save;
1542    
1543 root 1.137 my $lock = cf::lock_acquire "map_data:" . $self->path;
1544    
1545 root 1.110 return if $self->players;
1546     return if $self->in_memory != cf::MAP_IN_MEMORY;
1547     return if $self->{deny_save};
1548    
1549     $self->clear;
1550     $self->in_memory (cf::MAP_SWAPPED);
1551     }
1552    
1553 root 1.112 sub reset_at {
1554     my ($self) = @_;
1555 root 1.110
1556     # TODO: safety, remove and allow resettable per-player maps
1557 root 1.169 return 1e99 if $self->isa ("ext::map_per_player");#d#
1558 root 1.114 return 1e99 if $self->{deny_reset};
1559 root 1.110
1560 root 1.112 my $time = $self->fixed_resettime ? $self->{instantiate_time} : $self->last_access;
1561 root 1.114 my $to = List::Util::min $MAX_RESET, $self->reset_timeout || $DEFAULT_RESET;
1562 root 1.110
1563 root 1.112 $time + $to
1564     }
1565    
1566     sub should_reset {
1567     my ($self) = @_;
1568    
1569     $self->reset_at <= $cf::RUNTIME
1570 root 1.111 }
1571    
1572 root 1.110 sub reset {
1573     my ($self) = @_;
1574    
1575 root 1.167 my $lock = cf::lock_acquire "map_data:$self->{path}";
1576 root 1.137
1577 root 1.110 return if $self->players;
1578 root 1.166 return if $self->isa ("ext::map_per_player");#d#
1579 root 1.110
1580     warn "resetting map ", $self->path;#d#
1581    
1582 root 1.111 delete $cf::MAP{$self->path};
1583 root 1.110
1584 root 1.167 $self->in_memory (cf::MAP_SWAPPED);
1585     $self->clear;
1586    
1587 root 1.110 $_->clear_links_to ($self) for values %cf::MAP;
1588    
1589 root 1.166 $self->unlink_save;
1590 root 1.111 $self->destroy;
1591 root 1.110 }
1592    
1593 root 1.114 my $nuke_counter = "aaaa";
1594    
1595     sub nuke {
1596     my ($self) = @_;
1597    
1598 root 1.174 delete $cf::MAP{$self->path};
1599    
1600     $self->unlink_save;
1601    
1602     bless $self, "cf::map";
1603     delete $self->{deny_reset};
1604 root 1.114 $self->{deny_save} = 1;
1605     $self->reset_timeout (1);
1606 root 1.174 $self->path ($self->{path} = "{nuke}/" . ($nuke_counter++));
1607    
1608     $cf::MAP{$self->path} = $self;
1609    
1610 root 1.114 $self->reset; # polite request, might not happen
1611     }
1612    
1613 root 1.158 =item cf::map::unique_maps
1614    
1615 root 1.166 Returns an arrayref of paths of all shared maps that have
1616 root 1.158 instantiated unique items. May block.
1617    
1618     =cut
1619    
1620     sub unique_maps() {
1621     my $files = aio_readdir cf::localdir . "/" . cf::uniquedir
1622     or return;
1623    
1624     my @paths;
1625    
1626     for (@$files) {
1627     utf8::decode $_;
1628     next if /\.pst$/;
1629     next unless /^$PATH_SEP/o;
1630    
1631 root 1.167 s/\.map$//;
1632 root 1.166 push @paths, $_;
1633 root 1.158 }
1634    
1635     \@paths
1636     }
1637    
1638 root 1.155 package cf;
1639    
1640     =back
1641    
1642     =head3 cf::object
1643    
1644     =cut
1645    
1646     package cf::object;
1647    
1648     =over 4
1649    
1650     =item $ob->inv_recursive
1651 root 1.110
1652 root 1.155 Returns the inventory of the object _and_ their inventories, recursively.
1653 root 1.110
1654 root 1.155 =cut
1655 root 1.144
1656 root 1.155 sub inv_recursive_;
1657     sub inv_recursive_ {
1658     map { $_, inv_recursive_ $_->inv } @_
1659     }
1660 root 1.110
1661 root 1.155 sub inv_recursive {
1662     inv_recursive_ inv $_[0]
1663 root 1.110 }
1664    
1665     package cf;
1666    
1667     =back
1668    
1669 root 1.95 =head3 cf::object::player
1670    
1671     =over 4
1672    
1673 root 1.79 =item $player_object->reply ($npc, $msg[, $flags])
1674 root 1.28
1675     Sends a message to the player, as if the npc C<$npc> replied. C<$npc>
1676     can be C<undef>. Does the right thing when the player is currently in a
1677     dialogue with the given NPC character.
1678    
1679     =cut
1680    
1681 root 1.22 # rough implementation of a future "reply" method that works
1682     # with dialog boxes.
1683 root 1.95 #TODO: the first argument must go, split into a $npc->reply_to ( method
1684 root 1.23 sub cf::object::player::reply($$$;$) {
1685     my ($self, $npc, $msg, $flags) = @_;
1686    
1687     $flags = cf::NDI_BROWN | cf::NDI_UNIQUE unless @_ >= 4;
1688 root 1.22
1689 root 1.24 if ($self->{record_replies}) {
1690     push @{ $self->{record_replies} }, [$npc, $msg, $flags];
1691     } else {
1692     $msg = $npc->name . " says: $msg" if $npc;
1693     $self->message ($msg, $flags);
1694     }
1695 root 1.22 }
1696    
1697 root 1.79 =item $player_object->may ("access")
1698    
1699     Returns wether the given player is authorized to access resource "access"
1700     (e.g. "command_wizcast").
1701    
1702     =cut
1703    
1704     sub cf::object::player::may {
1705     my ($self, $access) = @_;
1706    
1707     $self->flag (cf::FLAG_WIZ) ||
1708     (ref $cf::CFG{"may_$access"}
1709     ? scalar grep $self->name eq $_, @{$cf::CFG{"may_$access"}}
1710     : $cf::CFG{"may_$access"})
1711     }
1712 root 1.70
1713 root 1.115 =item $player_object->enter_link
1714    
1715     Freezes the player and moves him/her to a special map (C<{link}>).
1716    
1717 root 1.166 The player should be reasonably safe there for short amounts of time. You
1718 root 1.115 I<MUST> call C<leave_link> as soon as possible, though.
1719    
1720 root 1.166 Will never block.
1721    
1722 root 1.115 =item $player_object->leave_link ($map, $x, $y)
1723    
1724 root 1.166 Moves the player out of the special C<{link}> map onto the specified
1725     map. If the map is not valid (or omitted), the player will be moved back
1726     to the location he/she was before the call to C<enter_link>, or, if that
1727     fails, to the emergency map position.
1728 root 1.115
1729     Might block.
1730    
1731     =cut
1732    
1733 root 1.166 sub link_map {
1734     unless ($LINK_MAP) {
1735     $LINK_MAP = cf::map::find "{link}"
1736     or do { warn "FATAL: unable to provide {link} map, exiting."; exit 1 };
1737     $LINK_MAP->load;
1738     }
1739    
1740     $LINK_MAP
1741     }
1742    
1743 root 1.110 sub cf::object::player::enter_link {
1744     my ($self) = @_;
1745    
1746 root 1.120 $self->deactivate_recursive;
1747    
1748 root 1.166 return if UNIVERSAL::isa $self->map, "ext::map_link";
1749 root 1.110
1750 root 1.120 $self->{_link_pos} ||= [$self->map->{path}, $self->x, $self->y]
1751 root 1.110 if $self->map;
1752    
1753 root 1.194 $self->enter_map ($LINK_MAP || link_map, 10, 10);
1754 root 1.110 }
1755    
1756     sub cf::object::player::leave_link {
1757     my ($self, $map, $x, $y) = @_;
1758    
1759     my $link_pos = delete $self->{_link_pos};
1760    
1761     unless ($map) {
1762     # restore original map position
1763     ($map, $x, $y) = @{ $link_pos || [] };
1764 root 1.133 $map = cf::map::find $map;
1765 root 1.110
1766     unless ($map) {
1767     ($map, $x, $y) = @$EMERGENCY_POSITION;
1768 root 1.133 $map = cf::map::find $map
1769 root 1.110 or die "FATAL: cannot load emergency map\n";
1770     }
1771     }
1772    
1773     ($x, $y) = (-1, -1)
1774     unless (defined $x) && (defined $y);
1775    
1776     # use -1 or undef as default coordinates, not 0, 0
1777     ($x, $y) = ($map->enter_x, $map->enter_y)
1778     if $x <=0 && $y <= 0;
1779    
1780     $map->load;
1781 root 1.157 $map->load_diag;
1782 root 1.110
1783 root 1.143 return unless $self->contr->active;
1784 root 1.110 $self->activate_recursive;
1785     $self->enter_map ($map, $x, $y);
1786     }
1787    
1788 root 1.120 cf::player->attach (
1789     on_logout => sub {
1790     my ($pl) = @_;
1791    
1792     # abort map switching before logout
1793     if ($pl->ob->{_link_pos}) {
1794     cf::sync_job {
1795     $pl->ob->leave_link
1796     };
1797     }
1798     },
1799     on_login => sub {
1800     my ($pl) = @_;
1801    
1802     # try to abort aborted map switching on player login :)
1803     # should happen only on crashes
1804     if ($pl->ob->{_link_pos}) {
1805     $pl->ob->enter_link;
1806 root 1.140 (async {
1807 root 1.120 # we need this sleep as the login has a concurrent enter_exit running
1808     # and this sleep increases chances of the player not ending up in scorn
1809 root 1.140 $pl->ob->reply (undef,
1810     "There was an internal problem at your last logout, "
1811     . "the server will try to bring you to your intended destination in a second.",
1812     cf::NDI_RED);
1813 root 1.120 Coro::Timer::sleep 1;
1814     $pl->ob->leave_link;
1815 root 1.139 })->prio (2);
1816 root 1.120 }
1817     },
1818     );
1819    
1820 root 1.136 =item $player_object->goto ($path, $x, $y)
1821 root 1.110
1822     =cut
1823    
1824 root 1.136 sub cf::object::player::goto {
1825 root 1.110 my ($self, $path, $x, $y) = @_;
1826    
1827     $self->enter_link;
1828    
1829 root 1.140 (async {
1830 root 1.166 my $map = cf::map::find $path;
1831     $map = $map->customise_for ($self) if $map;
1832 root 1.110
1833 root 1.119 # warn "entering ", $map->path, " at ($x, $y)\n"
1834     # if $map;
1835 root 1.110
1836 root 1.149 $map or $self->message ("The exit to '" . ($path->visible_name) . "' is closed", cf::NDI_UNIQUE | cf::NDI_RED);
1837 root 1.115
1838 root 1.110 $self->leave_link ($map, $x, $y);
1839     })->prio (1);
1840     }
1841    
1842     =item $player_object->enter_exit ($exit_object)
1843    
1844     =cut
1845    
1846     sub parse_random_map_params {
1847     my ($spec) = @_;
1848    
1849     my $rmp = { # defaults
1850 root 1.181 xsize => (cf::rndm 15, 40),
1851     ysize => (cf::rndm 15, 40),
1852     symmetry => (cf::rndm 1, cf::SYMMETRY_XY),
1853 root 1.182 #layout => string,
1854 root 1.110 };
1855    
1856     for (split /\n/, $spec) {
1857     my ($k, $v) = split /\s+/, $_, 2;
1858    
1859     $rmp->{lc $k} = $v if (length $k) && (length $v);
1860     }
1861    
1862     $rmp
1863     }
1864    
1865     sub prepare_random_map {
1866     my ($exit) = @_;
1867    
1868 root 1.179 my $guard = cf::lock_acquire "exit_prepare:$exit";
1869    
1870 root 1.110 # all this does is basically replace the /! path by
1871     # a new random map path (?random/...) with a seed
1872     # that depends on the exit object
1873    
1874     my $rmp = parse_random_map_params $exit->msg;
1875    
1876     if ($exit->map) {
1877     $rmp->{region} = $exit->map->region_name;
1878     $rmp->{origin_map} = $exit->map->path;
1879     $rmp->{origin_x} = $exit->x;
1880     $rmp->{origin_y} = $exit->y;
1881     }
1882    
1883     $rmp->{random_seed} ||= $exit->random_seed;
1884    
1885     my $data = cf::to_json $rmp;
1886     my $md5 = Digest::MD5::md5_hex $data;
1887 root 1.177 my $meta = "$cf::RANDOM_MAPS/$md5.meta";
1888 root 1.110
1889 root 1.177 if (my $fh = aio_open "$meta~", O_WRONLY | O_CREAT, 0666) {
1890 root 1.110 aio_write $fh, 0, (length $data), $data, 0;
1891 root 1.177 undef $fh;
1892     aio_rename "$meta~", $meta;
1893 root 1.110
1894     $exit->slaying ("?random/$md5");
1895     $exit->msg (undef);
1896     }
1897     }
1898    
1899     sub cf::object::player::enter_exit {
1900     my ($self, $exit) = @_;
1901    
1902     return unless $self->type == cf::PLAYER;
1903    
1904 root 1.195 if ($exit->slaying eq "/!") {
1905     #TODO: this should de-fi-ni-te-ly not be a sync-job
1906     cf::sync_job { prepare_random_map $exit };
1907     }
1908    
1909     my $slaying = cf::map::normalise $exit->slaying, $exit->map && $exit->map->path;
1910     my $hp = $exit->stats->hp;
1911     my $sp = $exit->stats->sp;
1912    
1913 root 1.110 $self->enter_link;
1914    
1915 root 1.140 (async {
1916 root 1.133 $self->deactivate_recursive; # just to be sure
1917 root 1.110 unless (eval {
1918 root 1.195 $self->goto ($slaying, $hp, $sp);
1919 root 1.110
1920     1;
1921     }) {
1922     $self->message ("Something went wrong deep within the crossfire server. "
1923     . "I'll try to bring you back to the map you were before. "
1924 root 1.158 . "Please report this to the dungeon master!",
1925 root 1.110 cf::NDI_UNIQUE | cf::NDI_RED);
1926    
1927     warn "ERROR in enter_exit: $@";
1928     $self->leave_link;
1929     }
1930     })->prio (1);
1931     }
1932    
1933 root 1.95 =head3 cf::client
1934    
1935     =over 4
1936    
1937     =item $client->send_drawinfo ($text, $flags)
1938    
1939     Sends a drawinfo packet to the client. Circumvents output buffering so
1940     should not be used under normal circumstances.
1941    
1942 root 1.70 =cut
1943    
1944 root 1.95 sub cf::client::send_drawinfo {
1945     my ($self, $text, $flags) = @_;
1946    
1947     utf8::encode $text;
1948     $self->send_packet (sprintf "drawinfo %d %s", $flags, $text);
1949     }
1950    
1951    
1952     =item $success = $client->query ($flags, "text", \&cb)
1953    
1954     Queues a query to the client, calling the given callback with
1955     the reply text on a reply. flags can be C<cf::CS_QUERY_YESNO>,
1956     C<cf::CS_QUERY_SINGLECHAR> or C<cf::CS_QUERY_HIDEINPUT> or C<0>.
1957    
1958     Queries can fail, so check the return code. Or don't, as queries will become
1959     reliable at some point in the future.
1960    
1961     =cut
1962    
1963     sub cf::client::query {
1964     my ($self, $flags, $text, $cb) = @_;
1965    
1966     return unless $self->state == ST_PLAYING
1967     || $self->state == ST_SETUP
1968     || $self->state == ST_CUSTOM;
1969    
1970     $self->state (ST_CUSTOM);
1971    
1972     utf8::encode $text;
1973     push @{ $self->{query_queue} }, [(sprintf "query %d %s", $flags, $text), $cb];
1974    
1975     $self->send_packet ($self->{query_queue}[0][0])
1976     if @{ $self->{query_queue} } == 1;
1977     }
1978    
1979     cf::client->attach (
1980     on_reply => sub {
1981     my ($ns, $msg) = @_;
1982    
1983     # this weird shuffling is so that direct followup queries
1984     # get handled first
1985 root 1.128 my $queue = delete $ns->{query_queue}
1986 root 1.129 or return; # be conservative, not sure how that can happen, but we saw a crash here
1987 root 1.95
1988     (shift @$queue)->[1]->($msg);
1989    
1990     push @{ $ns->{query_queue} }, @$queue;
1991    
1992     if (@{ $ns->{query_queue} } == @$queue) {
1993     if (@$queue) {
1994     $ns->send_packet ($ns->{query_queue}[0][0]);
1995     } else {
1996 root 1.98 $ns->state (ST_PLAYING) if $ns->state == ST_CUSTOM;
1997 root 1.95 }
1998     }
1999     },
2000     );
2001    
2002 root 1.140 =item $client->async (\&cb)
2003 root 1.96
2004     Create a new coroutine, running the specified callback. The coroutine will
2005     be automatically cancelled when the client gets destroyed (e.g. on logout,
2006     or loss of connection).
2007    
2008     =cut
2009    
2010 root 1.140 sub cf::client::async {
2011 root 1.96 my ($self, $cb) = @_;
2012    
2013 root 1.140 my $coro = &Coro::async ($cb);
2014 root 1.103
2015     $coro->on_destroy (sub {
2016 root 1.96 delete $self->{_coro}{$coro+0};
2017 root 1.103 });
2018 root 1.96
2019     $self->{_coro}{$coro+0} = $coro;
2020 root 1.103
2021     $coro
2022 root 1.96 }
2023    
2024     cf::client->attach (
2025     on_destroy => sub {
2026     my ($ns) = @_;
2027    
2028 root 1.97 $_->cancel for values %{ (delete $ns->{_coro}) || {} };
2029 root 1.96 },
2030     );
2031    
2032 root 1.95 =back
2033    
2034 root 1.70
2035     =head2 SAFE SCRIPTING
2036    
2037     Functions that provide a safe environment to compile and execute
2038     snippets of perl code without them endangering the safety of the server
2039     itself. Looping constructs, I/O operators and other built-in functionality
2040     is not available in the safe scripting environment, and the number of
2041 root 1.79 functions and methods that can be called is greatly reduced.
2042 root 1.70
2043     =cut
2044 root 1.23
2045 root 1.42 our $safe = new Safe "safe";
2046 root 1.23 our $safe_hole = new Safe::Hole;
2047    
2048     $SIG{FPE} = 'IGNORE';
2049    
2050     $safe->permit_only (Opcode::opset qw(:base_core :base_mem :base_orig :base_math sort time));
2051    
2052 root 1.25 # here we export the classes and methods available to script code
2053    
2054 root 1.70 =pod
2055    
2056     The following fucntions and emthods are available within a safe environment:
2057    
2058 elmex 1.91 cf::object contr pay_amount pay_player map
2059 root 1.70 cf::object::player player
2060     cf::player peaceful
2061 elmex 1.91 cf::map trigger
2062 root 1.70
2063     =cut
2064    
2065 root 1.25 for (
2066 elmex 1.91 ["cf::object" => qw(contr pay_amount pay_player map)],
2067 root 1.25 ["cf::object::player" => qw(player)],
2068     ["cf::player" => qw(peaceful)],
2069 elmex 1.91 ["cf::map" => qw(trigger)],
2070 root 1.25 ) {
2071     no strict 'refs';
2072     my ($pkg, @funs) = @$_;
2073 root 1.41 *{"safe::$pkg\::$_"} = $safe_hole->wrap (\&{"$pkg\::$_"})
2074 root 1.25 for @funs;
2075     }
2076 root 1.23
2077 root 1.70 =over 4
2078    
2079     =item @retval = safe_eval $code, [var => value, ...]
2080    
2081     Compiled and executes the given perl code snippet. additional var/value
2082     pairs result in temporary local (my) scalar variables of the given name
2083     that are available in the code snippet. Example:
2084    
2085     my $five = safe_eval '$first + $second', first => 1, second => 4;
2086    
2087     =cut
2088    
2089 root 1.23 sub safe_eval($;@) {
2090     my ($code, %vars) = @_;
2091    
2092     my $qcode = $code;
2093     $qcode =~ s/"/‟/g; # not allowed in #line filenames
2094     $qcode =~ s/\n/\\n/g;
2095    
2096     local $_;
2097 root 1.41 local @safe::cf::_safe_eval_args = values %vars;
2098 root 1.23
2099 root 1.42 my $eval =
2100 root 1.23 "do {\n"
2101     . "my (" . (join ",", map "\$$_", keys %vars) . ") = \@cf::_safe_eval_args;\n"
2102     . "#line 0 \"{$qcode}\"\n"
2103     . $code
2104     . "\n}"
2105 root 1.25 ;
2106    
2107     sub_generation_inc;
2108 root 1.42 my @res = wantarray ? $safe->reval ($eval) : scalar $safe->reval ($eval);
2109 root 1.25 sub_generation_inc;
2110    
2111 root 1.42 if ($@) {
2112     warn "$@";
2113     warn "while executing safe code '$code'\n";
2114     warn "with arguments " . (join " ", %vars) . "\n";
2115     }
2116    
2117 root 1.25 wantarray ? @res : $res[0]
2118 root 1.23 }
2119    
2120 root 1.69 =item cf::register_script_function $function => $cb
2121    
2122     Register a function that can be called from within map/npc scripts. The
2123     function should be reasonably secure and should be put into a package name
2124     like the extension.
2125    
2126     Example: register a function that gets called whenever a map script calls
2127     C<rent::overview>, as used by the C<rent> extension.
2128    
2129     cf::register_script_function "rent::overview" => sub {
2130     ...
2131     };
2132    
2133     =cut
2134    
2135 root 1.23 sub register_script_function {
2136     my ($fun, $cb) = @_;
2137    
2138     no strict 'refs';
2139 root 1.41 *{"safe::$fun"} = $safe_hole->wrap ($cb);
2140 root 1.23 }
2141    
2142 root 1.70 =back
2143    
2144 root 1.71 =cut
2145    
2146 root 1.23 #############################################################################
2147 root 1.65
2148     =head2 EXTENSION DATABASE SUPPORT
2149    
2150     Crossfire maintains a very simple database for extension use. It can
2151     currently store anything that can be serialised using Storable, which
2152     excludes objects.
2153    
2154     The parameter C<$family> should best start with the name of the extension
2155     using it, it should be unique.
2156    
2157     =over 4
2158    
2159     =item $hashref = cf::db_get $family
2160    
2161     Return a hashref for use by the extension C<$family>, which can be
2162     modified. After modifications, you have to call C<cf::db_dirty> or
2163     C<cf::db_sync>.
2164    
2165     =item $value = cf::db_get $family => $key
2166    
2167     Returns a single value from the database
2168    
2169     =item cf::db_put $family => $hashref
2170    
2171     Stores the given family hashref into the database. Updates are delayed, if
2172     you want the data to be synced to disk immediately, use C<cf::db_sync>.
2173    
2174     =item cf::db_put $family => $key => $value
2175    
2176     Stores the given C<$value> in the family hash. Updates are delayed, if you
2177     want the data to be synced to disk immediately, use C<cf::db_sync>.
2178    
2179     =item cf::db_dirty
2180    
2181     Marks the database as dirty, to be updated at a later time.
2182    
2183     =item cf::db_sync
2184    
2185     Immediately write the database to disk I<if it is dirty>.
2186    
2187     =cut
2188    
2189 root 1.78 our $DB;
2190    
2191 root 1.65 {
2192 root 1.66 my $path = cf::localdir . "/database.pst";
2193 root 1.65
2194     sub db_load() {
2195 root 1.78 $DB = stat $path ? Storable::retrieve $path : { };
2196 root 1.65 }
2197    
2198     my $pid;
2199    
2200     sub db_save() {
2201     waitpid $pid, 0 if $pid;
2202 root 1.67 if (0 == ($pid = fork)) {
2203 root 1.78 $DB->{_meta}{version} = 1;
2204     Storable::nstore $DB, "$path~";
2205 root 1.65 rename "$path~", $path;
2206     cf::_exit 0 if defined $pid;
2207     }
2208     }
2209    
2210     my $dirty;
2211    
2212     sub db_sync() {
2213     db_save if $dirty;
2214     undef $dirty;
2215     }
2216    
2217 root 1.189 my $idle = Event->idle (
2218     reentrant => 0,
2219     min => 10,
2220     max => 20,
2221     repeat => 0,
2222     data => WF_AUTOCANCEL,
2223     cb => \&db_sync,
2224     );
2225 root 1.65
2226     sub db_dirty() {
2227     $dirty = 1;
2228     $idle->start;
2229     }
2230    
2231     sub db_get($;$) {
2232     @_ >= 2
2233 root 1.78 ? $DB->{$_[0]}{$_[1]}
2234     : ($DB->{$_[0]} ||= { })
2235 root 1.65 }
2236    
2237     sub db_put($$;$) {
2238     if (@_ >= 3) {
2239 root 1.78 $DB->{$_[0]}{$_[1]} = $_[2];
2240 root 1.65 } else {
2241 root 1.78 $DB->{$_[0]} = $_[1];
2242 root 1.65 }
2243     db_dirty;
2244     }
2245 root 1.67
2246 root 1.93 cf::global->attach (
2247     prio => 10000,
2248 root 1.67 on_cleanup => sub {
2249     db_sync;
2250     },
2251 root 1.93 );
2252 root 1.65 }
2253    
2254     #############################################################################
2255 root 1.34 # the server's main()
2256    
2257 root 1.73 sub cfg_load {
2258 root 1.72 open my $fh, "<:utf8", cf::confdir . "/config"
2259     or return;
2260    
2261     local $/;
2262     *CFG = YAML::Syck::Load <$fh>;
2263 root 1.131
2264     $EMERGENCY_POSITION = $CFG{emergency_position} || ["/world/world_105_115", 5, 37];
2265    
2266 root 1.139 $cf::map::MAX_RESET = $CFG{map_max_reset} if exists $CFG{map_max_reset};
2267     $cf::map::DEFAULT_RESET = $CFG{map_default_reset} if exists $CFG{map_default_reset};
2268    
2269 root 1.131 if (exists $CFG{mlockall}) {
2270     eval {
2271 root 1.147 $CFG{mlockall} ? eval "mlockall()" : eval "munlockall()"
2272 root 1.131 and die "WARNING: m(un)lockall failed: $!\n";
2273     };
2274     warn $@ if $@;
2275     }
2276 root 1.72 }
2277    
2278 root 1.39 sub main {
2279 root 1.108 # we must not ever block the main coroutine
2280     local $Coro::idle = sub {
2281 root 1.115 Carp::cluck "FATAL: Coro::idle was called, major BUG, use cf::sync_job!\n";#d#
2282 root 1.175 (async {
2283     Event::one_event;
2284     })->prio (Coro::PRIO_MAX);
2285 root 1.108 };
2286    
2287 root 1.73 cfg_load;
2288 root 1.65 db_load;
2289 root 1.61 load_extensions;
2290 root 1.183
2291     $TICK_WATCHER->start;
2292 root 1.34 Event::loop;
2293     }
2294    
2295     #############################################################################
2296 root 1.155 # initialisation and cleanup
2297    
2298     # install some emergency cleanup handlers
2299     BEGIN {
2300     for my $signal (qw(INT HUP TERM)) {
2301     Event->signal (
2302 root 1.189 reentrant => 0,
2303     data => WF_AUTOCANCEL,
2304     signal => $signal,
2305 root 1.191 prio => 0,
2306 root 1.189 cb => sub {
2307 root 1.155 cf::cleanup "SIG$signal";
2308     },
2309     );
2310     }
2311     }
2312    
2313 root 1.156 sub emergency_save() {
2314 root 1.155 my $freeze_guard = cf::freeze_mainloop;
2315    
2316     warn "enter emergency perl save\n";
2317    
2318     cf::sync_job {
2319     # use a peculiar iteration method to avoid tripping on perl
2320     # refcount bugs in for. also avoids problems with players
2321 root 1.167 # and maps saved/destroyed asynchronously.
2322 root 1.155 warn "begin emergency player save\n";
2323     for my $login (keys %cf::PLAYER) {
2324     my $pl = $cf::PLAYER{$login} or next;
2325     $pl->valid or next;
2326     $pl->save;
2327     }
2328     warn "end emergency player save\n";
2329    
2330     warn "begin emergency map save\n";
2331     for my $path (keys %cf::MAP) {
2332     my $map = $cf::MAP{$path} or next;
2333     $map->valid or next;
2334     $map->save;
2335     }
2336     warn "end emergency map save\n";
2337     };
2338    
2339     warn "leave emergency perl save\n";
2340     }
2341 root 1.22
2342 root 1.111 sub reload() {
2343 root 1.106 # can/must only be called in main
2344     if ($Coro::current != $Coro::main) {
2345 root 1.183 warn "can only reload from main coroutine";
2346 root 1.106 return;
2347     }
2348    
2349 root 1.103 warn "reloading...";
2350    
2351 root 1.183 warn "cancelling server ticker";
2352     $TICK_WATCHER->cancel;
2353    
2354 root 1.106 cf::emergency_save;
2355    
2356 root 1.103 eval {
2357 root 1.106 # if anything goes wrong in here, we should simply crash as we already saved
2358 root 1.65
2359 root 1.183 warn "syncing database to disk";
2360     cf::db_sync;
2361    
2362     warn "cancelling all WF_AUTOCANCEL watchers";
2363 root 1.87 for (Event::all_watchers) {
2364     $_->cancel if $_->data & WF_AUTOCANCEL;
2365     }
2366 root 1.65
2367 root 1.183 warn "flushing outstanding aio requests";
2368     for (;;) {
2369     IO::AIO::flush;
2370     Coro::cede;
2371     last unless IO::AIO::nreqs;
2372     warn "iterate...";
2373     }
2374    
2375     warn "cancelling all extension coros";
2376 root 1.103 $_->cancel for values %EXT_CORO;
2377     %EXT_CORO = ();
2378    
2379 root 1.183 warn "removing commands";
2380 root 1.159 %COMMAND = ();
2381    
2382 root 1.183 warn "removing ext commands";
2383 root 1.159 %EXTCMD = ();
2384    
2385 root 1.183 warn "unloading/nuking all extensions";
2386 root 1.159 for my $pkg (@EXTS) {
2387 root 1.160 warn "... unloading $pkg";
2388 root 1.159
2389     if (my $cb = $pkg->can ("unload")) {
2390     eval {
2391     $cb->($pkg);
2392     1
2393     } or warn "$pkg unloaded, but with errors: $@";
2394     }
2395    
2396 root 1.160 warn "... nuking $pkg";
2397 root 1.159 Symbol::delete_package $pkg;
2398 root 1.65 }
2399    
2400 root 1.183 warn "unloading all perl modules loaded from $LIBDIR";
2401 root 1.65 while (my ($k, $v) = each %INC) {
2402     next unless $v =~ /^\Q$LIBDIR\E\/.*\.pm$/;
2403    
2404 root 1.183 warn "... unloading $k";
2405 root 1.65 delete $INC{$k};
2406    
2407     $k =~ s/\.pm$//;
2408     $k =~ s/\//::/g;
2409    
2410     if (my $cb = $k->can ("unload_module")) {
2411     $cb->();
2412     }
2413    
2414     Symbol::delete_package $k;
2415     }
2416    
2417 root 1.183 warn "getting rid of safe::, as good as possible";
2418 root 1.65 Symbol::delete_package "safe::$_"
2419 root 1.103 for qw(cf::attachable cf::object cf::object::player cf::client cf::player cf::map cf::party cf::region);
2420 root 1.65
2421 root 1.183 warn "unloading cf.pm \"a bit\"";
2422 root 1.65 delete $INC{"cf.pm"};
2423    
2424     # don't, removes xs symbols, too,
2425     # and global variables created in xs
2426     #Symbol::delete_package __PACKAGE__;
2427    
2428 root 1.183 warn "unload completed, starting to reload now";
2429    
2430 root 1.103 warn "reloading cf.pm";
2431 root 1.65 require cf;
2432 root 1.100 cf::_connect_to_perl; # nominally unnecessary, but cannot hurt
2433    
2434 root 1.183 warn "loading config and database again";
2435 root 1.73 cf::cfg_load;
2436 root 1.65 cf::db_load;
2437    
2438 root 1.183 warn "loading extensions";
2439 root 1.65 cf::load_extensions;
2440    
2441 root 1.183 warn "reattaching attachments to objects/players";
2442 root 1.65 _global_reattach;
2443 root 1.183 warn "reattaching attachments to maps";
2444 root 1.144 reattach $_ for values %MAP;
2445 root 1.183
2446     warn "restarting server ticker";
2447    
2448     $TICK_WATCHER->start;
2449 root 1.65 };
2450    
2451 root 1.106 if ($@) {
2452     warn $@;
2453     warn "error while reloading, exiting.";
2454     exit 1;
2455     }
2456    
2457 root 1.159 warn "reloaded";
2458 root 1.65 };
2459    
2460 root 1.175 our $RELOAD_WATCHER; # used only during reload
2461    
2462 root 1.111 register_command "reload" => sub {
2463 root 1.65 my ($who, $arg) = @_;
2464    
2465     if ($who->flag (FLAG_WIZ)) {
2466 root 1.175 $who->message ("reloading server.");
2467    
2468     # doing reload synchronously and two reloads happen back-to-back,
2469     # coro crashes during coro_state_free->destroy here.
2470    
2471 root 1.189 $RELOAD_WATCHER ||= Event->timer (
2472     reentrant => 0,
2473     after => 0,
2474     data => WF_AUTOCANCEL,
2475     cb => sub {
2476     reload;
2477     undef $RELOAD_WATCHER;
2478     },
2479     );
2480 root 1.65 }
2481     };
2482    
2483 root 1.27 unshift @INC, $LIBDIR;
2484 root 1.17
2485 root 1.183 my $bug_warning = 0;
2486    
2487 root 1.35 $TICK_WATCHER = Event->timer (
2488 root 1.104 reentrant => 0,
2489 root 1.183 parked => 1,
2490 root 1.191 prio => 0,
2491 root 1.104 at => $NEXT_TICK || $TICK,
2492     data => WF_AUTOCANCEL,
2493     cb => sub {
2494 root 1.183 if ($Coro::current != $Coro::main) {
2495     Carp::cluck "major BUG: server tick called outside of main coro, skipping it"
2496     unless ++$bug_warning > 10;
2497     return;
2498     }
2499    
2500 root 1.163 $NOW = Event::time;
2501    
2502 root 1.133 cf::server_tick; # one server iteration
2503     $RUNTIME += $TICK;
2504 root 1.35 $NEXT_TICK += $TICK;
2505    
2506 root 1.155 $WAIT_FOR_TICK->broadcast;
2507     $WAIT_FOR_TICK_ONE->send if $WAIT_FOR_TICK_ONE->awaited;
2508    
2509 root 1.191 Event::sweep;
2510     Coro::cede_notself;
2511    
2512     # my $AFTER = Event::time;
2513     # warn $AFTER - $NOW;#d#
2514 root 1.190
2515 root 1.78 # if we are delayed by four ticks or more, skip them all
2516 root 1.103 $NEXT_TICK = Event::time if Event::time >= $NEXT_TICK + $TICK * 4;
2517 root 1.35
2518     $TICK_WATCHER->at ($NEXT_TICK);
2519     $TICK_WATCHER->start;
2520     },
2521     );
2522    
2523 root 1.191 IO::AIO::max_poll_time $TICK * 0.1;
2524 root 1.77
2525 root 1.189 undef $Coro::AIO::WATCHER;
2526 root 1.168 $AIO_POLL_WATCHER = Event->io (
2527 root 1.189 reentrant => 0,
2528     fd => IO::AIO::poll_fileno,
2529     poll => 'r',
2530     prio => 6,
2531     data => WF_AUTOCANCEL,
2532     cb => \&IO::AIO::poll_cb,
2533 root 1.108 );
2534    
2535 root 1.168 $WRITE_RUNTIME_WATCHER = Event->timer (
2536 root 1.189 reentrant => 0,
2537     data => WF_AUTOCANCEL,
2538     after => 1,
2539     interval => 10,
2540     prio => 6, # keep it lowest so it acts like a watchdog
2541     cb => Coro::unblock_sub {
2542 root 1.183 write_runtime
2543     or warn "ERROR: unable to write runtime file: $!";
2544 root 1.108 },
2545     );
2546 root 1.103
2547 root 1.125 END { cf::emergency_save }
2548    
2549 root 1.1 1
2550