ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/lib/cf.pm
Revision: 1.167
Committed: Sat Jan 13 23:32:43 2007 UTC (17 years, 4 months ago) by root
Branch: MAIN
Changes since 1.166: +11 -25 lines
Log Message:
fixes, starting to look good again

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