ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/lib/cf.pm
Revision: 1.306
Committed: Sat Jul 14 14:33:30 2007 UTC (16 years, 10 months ago) by root
Branch: MAIN
Changes since 1.305: +6 -3 lines
Log Message:
some goofing around

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.250 use Socket;
9 root 1.6 use Storable;
10 root 1.224 use Event;
11 root 1.23 use Opcode;
12     use Safe;
13     use Safe::Hole;
14 root 1.19
15 root 1.244 use Coro 3.61 ();
16 root 1.224 use Coro::State;
17 root 1.250 use Coro::Handle;
18 root 1.96 use Coro::Event;
19     use Coro::Timer;
20     use Coro::Signal;
21     use Coro::Semaphore;
22 root 1.105 use Coro::AIO;
23 root 1.237 use Coro::Storable;
24 root 1.96
25 root 1.288 use JSON::XS 1.4 ();
26 root 1.206 use BDB ();
27 root 1.154 use Data::Dumper;
28 root 1.108 use Digest::MD5;
29 root 1.105 use Fcntl;
30 root 1.227 use YAML::Syck ();
31 root 1.145 use IO::AIO 2.32 ();
32 root 1.32 use Time::HiRes;
33 root 1.208 use Compress::LZF;
34 root 1.302 use Digest::MD5 ();
35 root 1.208
36 root 1.227 # configure various modules to our taste
37     #
38 root 1.237 $Storable::canonical = 1; # reduce rsync transfers
39 root 1.224 Coro::State::cctx_stacksize 256000; # 1-2MB stack, for deep recursions in maze generator
40 root 1.208 Compress::LZF::sfreeze_cr { }; # prime Compress::LZF so it does not use require later
41 root 1.227
42 root 1.224 $Event::Eval = 1; # no idea why this is required, but it is
43 root 1.1
44 root 1.72 # work around bug in YAML::Syck - bad news for perl6, will it be as broken wrt. unicode?
45     $YAML::Syck::ImplicitUnicode = 1;
46    
47 root 1.139 $Coro::main->prio (Coro::PRIO_MAX); # run main coroutine ("the server") with very high priority
48 root 1.1
49 root 1.227 sub WF_AUTOCANCEL () { 1 } # automatically cancel this watcher on reload
50    
51 root 1.85 our %COMMAND = ();
52     our %COMMAND_TIME = ();
53 root 1.159
54     our @EXTS = (); # list of extension package names
55 root 1.85 our %EXTCMD = ();
56 root 1.287 our %EXTICMD = ();
57 root 1.159 our %EXT_CORO = (); # coroutines bound to extensions
58 root 1.161 our %EXT_MAP = (); # pluggable maps
59 root 1.85
60 root 1.223 our $RELOAD; # number of reloads so far
61 root 1.1 our @EVENT;
62 root 1.253
63     our $CONFDIR = confdir;
64     our $DATADIR = datadir;
65     our $LIBDIR = "$DATADIR/ext";
66     our $PODDIR = "$DATADIR/pod";
67     our $MAPDIR = "$DATADIR/" . mapdir;
68     our $LOCALDIR = localdir;
69     our $TMPDIR = "$LOCALDIR/" . tmpdir;
70     our $UNIQUEDIR = "$LOCALDIR/" . uniquedir;
71     our $PLAYERDIR = "$LOCALDIR/" . playerdir;
72     our $RANDOMDIR = "$LOCALDIR/random";
73     our $BDBDIR = "$LOCALDIR/db";
74 root 1.1
75 root 1.245 our $TICK = MAX_TIME * 1e-6; # this is a CONSTANT(!)
76 root 1.35 our $TICK_WATCHER;
77 root 1.168 our $AIO_POLL_WATCHER;
78 root 1.214 our $NEXT_RUNTIME_WRITE; # when should the runtime file be written
79 root 1.35 our $NEXT_TICK;
80 root 1.103 our $NOW;
81 root 1.205 our $USE_FSYNC = 1; # use fsync to write maps - default off
82 root 1.35
83 root 1.206 our $BDB_POLL_WATCHER;
84     our $DB_ENV;
85    
86 root 1.70 our %CFG;
87    
88 root 1.84 our $UPTIME; $UPTIME ||= time;
89 root 1.103 our $RUNTIME;
90    
91 root 1.143 our %PLAYER; # all users
92     our %MAP; # all maps
93 root 1.166 our $LINK_MAP; # the special {link} map, which is always available
94 root 1.103
95 root 1.166 # used to convert map paths into valid unix filenames by replacing / by ∕
96     our $PATH_SEP = "∕"; # U+2215, chosen purely for visual reasons
97    
98 root 1.265 our $LOAD; # a number between 0 (idle) and 1 (too many objects)
99     our $LOADAVG; # same thing, but with alpha-smoothing
100     our $tick_start; # for load detecting purposes
101    
102 root 1.103 binmode STDOUT;
103     binmode STDERR;
104    
105     # read virtual server time, if available
106 root 1.253 unless ($RUNTIME || !-e "$LOCALDIR/runtime") {
107     open my $fh, "<", "$LOCALDIR/runtime"
108 root 1.103 or die "unable to read runtime file: $!";
109     $RUNTIME = <$fh> + 0.;
110     }
111    
112 root 1.253 mkdir $_
113     for $LOCALDIR, $TMPDIR, $UNIQUEDIR, $PLAYERDIR, $RANDOMDIR, $BDBDIR;
114 root 1.103
115 root 1.131 our $EMERGENCY_POSITION;
116 root 1.110
117 root 1.199 sub cf::map::normalise;
118    
119 root 1.70 #############################################################################
120    
121     =head2 GLOBAL VARIABLES
122    
123     =over 4
124    
125 root 1.83 =item $cf::UPTIME
126    
127     The timestamp of the server start (so not actually an uptime).
128    
129 root 1.103 =item $cf::RUNTIME
130    
131     The time this server has run, starts at 0 and is increased by $cf::TICK on
132     every server tick.
133    
134 root 1.253 =item $cf::CONFDIR $cf::DATADIR $cf::LIBDIR $cf::PODDIR
135     $cf::MAPDIR $cf::LOCALDIR $cf::TMPDIR $cf::UNIQUEDIR
136     $cf::PLAYERDIR $cf::RANDOMDIR $cf::BDBDIR
137    
138     Various directories - "/etc", read-only install directory, perl-library
139     directory, pod-directory, read-only maps directory, "/var", "/var/tmp",
140     unique-items directory, player file directory, random maps directory and
141     database environment.
142 root 1.70
143 root 1.103 =item $cf::NOW
144    
145     The time of the last (current) server tick.
146    
147 root 1.70 =item $cf::TICK
148    
149     The interval between server ticks, in seconds.
150    
151 root 1.265 =item $cf::LOADAVG
152    
153     The current CPU load on the server (alpha-smoothed), as a value between 0
154     (none) and 1 (overloaded), indicating how much time is spent on processing
155     objects per tick. Healthy values are < 0.5.
156    
157     =item $cf::LOAD
158    
159     The raw value load value from the last tick.
160    
161 root 1.70 =item %cf::CFG
162    
163     Configuration for the server, loaded from C</etc/crossfire/config>, or
164     from wherever your confdir points to.
165    
166 root 1.239 =item cf::wait_for_tick, cf::wait_for_tick_begin
167 root 1.155
168 root 1.239 These are functions that inhibit the current coroutine one tick. cf::wait_for_tick_begin only
169     returns directly I<after> the tick processing (and consequently, can only wake one process
170     per tick), while cf::wait_for_tick wakes up all waiters after tick processing.
171 root 1.155
172 root 1.70 =back
173    
174     =cut
175    
176 root 1.1 BEGIN {
177     *CORE::GLOBAL::warn = sub {
178     my $msg = join "", @_;
179 root 1.103
180 root 1.1 $msg .= "\n"
181     unless $msg =~ /\n$/;
182    
183 root 1.255 $msg =~ s/([\x00-\x08\x0b-\x1f])/sprintf "\\x%02x", ord $1/ge;
184 root 1.250
185     utf8::encode $msg;
186 root 1.146 LOG llevError, $msg;
187 root 1.1 };
188     }
189    
190 root 1.93 @safe::cf::global::ISA = @cf::global::ISA = 'cf::attachable';
191     @safe::cf::object::ISA = @cf::object::ISA = 'cf::attachable';
192     @safe::cf::player::ISA = @cf::player::ISA = 'cf::attachable';
193     @safe::cf::client::ISA = @cf::client::ISA = 'cf::attachable';
194     @safe::cf::map::ISA = @cf::map::ISA = 'cf::attachable';
195 root 1.273 @safe::cf::arch::ISA = @cf::arch::ISA = 'cf::object';
196     @safe::cf::object::player::ISA = @cf::object::player::ISA = 'cf::object'; # not really true (yet)
197 root 1.25
198 root 1.41 # we bless all objects into (empty) derived classes to force a method lookup
199 root 1.25 # within the Safe compartment.
200 root 1.86 for my $pkg (qw(
201 root 1.100 cf::global cf::attachable
202 root 1.86 cf::object cf::object::player
203 root 1.89 cf::client cf::player
204 root 1.86 cf::arch cf::living
205     cf::map cf::party cf::region
206     )) {
207 root 1.25 no strict 'refs';
208 root 1.41 @{"safe::$pkg\::wrap::ISA"} = @{"$pkg\::wrap::ISA"} = $pkg;
209 root 1.25 }
210 root 1.1
211 root 1.18 $Event::DIED = sub {
212     warn "error in event callback: @_";
213     };
214    
215 root 1.281 #############################################################################
216    
217 root 1.70 =head2 UTILITY FUNCTIONS
218    
219     =over 4
220    
221 root 1.154 =item dumpval $ref
222    
223 root 1.70 =cut
224 root 1.44
225 root 1.154 sub dumpval {
226     eval {
227     local $SIG{__DIE__};
228     my $d;
229     if (1) {
230     $d = new Data::Dumper([$_[0]], ["*var"]);
231     $d->Terse(1);
232     $d->Indent(2);
233     $d->Quotekeys(0);
234     $d->Useqq(1);
235     #$d->Bless(...);
236     $d->Seen($_[1]) if @_ > 1;
237     $d = $d->Dump();
238     }
239     $d =~ s/([\x00-\x07\x09\x0b\x0c\x0e-\x1f])/sprintf "\\x%02x", ord($1)/ge;
240     $d
241     } || "[unable to dump $_[0]: '$@']";
242     }
243    
244 root 1.70 =item $ref = cf::from_json $json
245    
246     Converts a JSON string into the corresponding perl data structure.
247    
248     =item $json = cf::to_json $ref
249    
250     Converts a perl data structure into its JSON representation.
251    
252 root 1.287 =cut
253    
254 root 1.290 our $json_coder = JSON::XS->new->utf8->max_size (1e6); # accept ~1mb max
255 root 1.287
256     sub to_json ($) { $json_coder->encode ($_[0]) }
257     sub from_json ($) { $json_coder->decode ($_[0]) }
258    
259 root 1.120 =item cf::lock_wait $string
260    
261     Wait until the given lock is available. See cf::lock_acquire.
262    
263     =item my $lock = cf::lock_acquire $string
264    
265     Wait until the given lock is available and then acquires it and returns
266 root 1.135 a Coro::guard object. If the guard object gets destroyed (goes out of scope,
267 root 1.120 for example when the coroutine gets canceled), the lock is automatically
268     returned.
269    
270 root 1.133 Lock names should begin with a unique identifier (for example, cf::map::find
271     uses map_find and cf::map::load uses map_load).
272 root 1.120
273 root 1.253 =item $locked = cf::lock_active $string
274    
275     Return true if the lock is currently active, i.e. somebody has locked it.
276    
277 root 1.120 =cut
278    
279     our %LOCK;
280    
281     sub lock_wait($) {
282     my ($key) = @_;
283    
284     # wait for lock, if any
285     while ($LOCK{$key}) {
286     push @{ $LOCK{$key} }, $Coro::current;
287     Coro::schedule;
288     }
289     }
290    
291     sub lock_acquire($) {
292     my ($key) = @_;
293    
294     # wait, to be sure we are not locked
295     lock_wait $key;
296    
297     $LOCK{$key} = [];
298    
299 root 1.135 Coro::guard {
300 root 1.120 # wake up all waiters, to be on the safe side
301     $_->ready for @{ delete $LOCK{$key} };
302     }
303     }
304    
305 root 1.253 sub lock_active($) {
306     my ($key) = @_;
307    
308     ! ! $LOCK{$key}
309     }
310    
311 root 1.133 sub freeze_mainloop {
312     return unless $TICK_WATCHER->is_active;
313    
314 root 1.168 my $guard = Coro::guard {
315     $TICK_WATCHER->start;
316     };
317 root 1.133 $TICK_WATCHER->stop;
318     $guard
319     }
320    
321 root 1.140 =item cf::async { BLOCK }
322    
323     Currently the same as Coro::async_pool, meaning you cannot use
324     C<on_destroy>, C<join> or other gimmicks on these coroutines. The only
325     thing you are allowed to do is call C<prio> on it.
326    
327     =cut
328    
329     BEGIN { *async = \&Coro::async_pool }
330    
331 root 1.106 =item cf::sync_job { BLOCK }
332    
333 root 1.281 The design of Crossfire TRT requires that the main coroutine ($Coro::main)
334     is always able to handle events or runnable, as Crossfire TRT is only
335     partly reentrant. Thus "blocking" it by e.g. waiting for I/O is not
336     acceptable.
337 root 1.106
338     If it must be done, put the blocking parts into C<sync_job>. This will run
339     the given BLOCK in another coroutine while waiting for the result. The
340     server will be frozen during this time, so the block should either finish
341     fast or be very important.
342    
343     =cut
344    
345 root 1.105 sub sync_job(&) {
346     my ($job) = @_;
347    
348     if ($Coro::current == $Coro::main) {
349 root 1.265 my $time = Event::time;
350    
351 root 1.112 # this is the main coro, too bad, we have to block
352     # till the operation succeeds, freezing the server :/
353    
354 root 1.110 # TODO: use suspend/resume instead
355 root 1.112 # (but this is cancel-safe)
356 root 1.133 my $freeze_guard = freeze_mainloop;
357 root 1.112
358     my $busy = 1;
359     my @res;
360    
361 root 1.140 (async {
362 root 1.112 @res = eval { $job->() };
363     warn $@ if $@;
364     undef $busy;
365     })->prio (Coro::PRIO_MAX);
366    
367 root 1.105 while ($busy) {
368 root 1.141 Coro::cede or Event::one_event;
369 root 1.105 }
370 root 1.112
371 root 1.265 $time = Event::time - $time;
372    
373 root 1.266 LOG llevError | logBacktrace, Carp::longmess "long sync job"
374     if $time > $TICK * 0.5 && $TICK_WATCHER->is_active;
375 root 1.265
376     $tick_start += $time; # do not account sync jobs to server load
377    
378 root 1.112 wantarray ? @res : $res[0]
379 root 1.105 } else {
380 root 1.112 # we are in another coroutine, how wonderful, everything just works
381    
382     $job->()
383 root 1.105 }
384     }
385    
386 root 1.140 =item $coro = cf::async_ext { BLOCK }
387 root 1.103
388 root 1.159 Like async, but this coro is automatically being canceled when the
389 root 1.140 extension calling this is being unloaded.
390 root 1.103
391     =cut
392    
393 root 1.140 sub async_ext(&) {
394 root 1.103 my $cb = shift;
395    
396 root 1.140 my $coro = &Coro::async ($cb);
397 root 1.103
398     $coro->on_destroy (sub {
399     delete $EXT_CORO{$coro+0};
400     });
401     $EXT_CORO{$coro+0} = $coro;
402    
403     $coro
404     }
405    
406 root 1.281 =item fork_call { }, $args
407    
408     Executes the given code block with the given arguments in a seperate
409     process, returning the results. Everything must be serialisable with
410     Coro::Storable. May, of course, block. Note that the executed sub may
411     never block itself or use any form of Event handling.
412    
413     =cut
414    
415 root 1.299 sub _store_scalar {
416     open my $fh, ">", \my $buf
417     or die "fork_call: cannot open fh-to-buf in child : $!";
418     Storable::store_fd $_[0], $fh;
419     close $fh;
420    
421     $buf
422     }
423    
424 root 1.281 sub fork_call(&@) {
425     my ($cb, @args) = @_;
426    
427     # socketpair my $fh1, my $fh2, Socket::AF_UNIX, Socket::SOCK_STREAM, Socket::PF_UNSPEC
428     # or die "socketpair: $!";
429     pipe my $fh1, my $fh2
430     or die "pipe: $!";
431    
432     if (my $pid = fork) {
433     close $fh2;
434    
435     my $res = (Coro::Handle::unblock $fh1)->readline (undef);
436 root 1.298 warn "pst<$res>" unless $res =~ /^pst/;
437 root 1.281 $res = Coro::Storable::thaw $res;
438    
439     waitpid $pid, 0; # should not block anymore, we expect the child to simply behave
440    
441 root 1.298 Carp::confess $$res unless "ARRAY" eq ref $res;
442 root 1.281
443     return wantarray ? @$res : $res->[-1];
444     } else {
445     reset_signals;
446     local $SIG{__WARN__};
447     local $SIG{__DIE__};
448 root 1.299 # just in case, this hack effectively disables event
449     # in the child. cleaner and slower would be canceling all watchers,
450     # but this works for the time being.
451 root 1.298 local $Coro::idle;
452     $Coro::current->prio (Coro::PRIO_MAX);
453 root 1.299
454 root 1.281 eval {
455     close $fh1;
456    
457     my @res = eval { $cb->(@args) };
458 root 1.298
459 root 1.299 syswrite $fh2, _store_scalar $@ ? \"$@" : \@res;
460 root 1.298 close $fh2;
461 root 1.281 };
462    
463     warn $@ if $@;
464     _exit 0;
465     }
466     }
467    
468     =item $value = cf::db_get $family => $key
469    
470     Returns a single value from the environment database.
471    
472     =item cf::db_put $family => $key => $value
473    
474     Stores the given C<$value> in the family. It can currently store binary
475     data only (use Compress::LZF::sfreeze_cr/sthaw to convert to/from binary).
476    
477     =cut
478    
479     our $DB;
480    
481     sub db_init {
482     unless ($DB) {
483     $DB = BDB::db_create $DB_ENV;
484    
485     cf::sync_job {
486     eval {
487     $DB->set_flags (BDB::CHKSUM);
488    
489     BDB::db_open $DB, undef, "db", undef, BDB::BTREE,
490     BDB::CREATE | BDB::AUTO_COMMIT, 0666;
491     cf::cleanup "db_open(db): $!" if $!;
492     };
493     cf::cleanup "db_open(db): $@" if $@;
494     };
495     }
496     }
497    
498     sub db_get($$) {
499     my $key = "$_[0]/$_[1]";
500    
501     cf::sync_job {
502     BDB::db_get $DB, undef, $key, my $data;
503    
504     $! ? ()
505     : $data
506     }
507     }
508    
509     sub db_put($$$) {
510     BDB::dbreq_pri 4;
511     BDB::db_put $DB, undef, "$_[0]/$_[1]", $_[2], 0, sub { };
512     }
513    
514     =item cf::cache $id => [$paths...], $processversion => $process
515    
516     Generic caching function that returns the value of the resource $id,
517     caching and regenerating as required.
518    
519     This function can block.
520    
521     =cut
522    
523     sub cache {
524     my ($id, $src, $processversion, $process) = @_;
525    
526     my $meta =
527     join "\x00",
528     $processversion,
529     map {
530     aio_stat $_
531     and Carp::croak "$_: $!";
532 root 1.264
533 root 1.281 ($_, (stat _)[7,9])
534     } @$src;
535 root 1.264
536 root 1.281 my $dbmeta = db_get cache => "$id/meta";
537     if ($dbmeta ne $meta) {
538     # changed, we may need to process
539 root 1.264
540 root 1.281 my @data;
541     my $md5;
542 root 1.219
543 root 1.281 for (0 .. $#$src) {
544     0 <= aio_load $src->[$_], $data[$_]
545     or Carp::croak "$src->[$_]: $!";
546     }
547 root 1.108
548 root 1.281 # if processing is expensive, check
549     # checksum first
550     if (1) {
551     $md5 =
552     join "\x00",
553     $processversion,
554     map {
555     Coro::cede;
556     ($src->[$_], Digest::MD5::md5_hex $data[$_])
557     } 0.. $#$src;
558    
559 root 1.186
560 root 1.281 my $dbmd5 = db_get cache => "$id/md5";
561     if ($dbmd5 eq $md5) {
562     db_put cache => "$id/meta", $meta;
563 root 1.108
564 root 1.281 return db_get cache => "$id/data";
565     }
566     }
567 root 1.108
568 root 1.281 my $t1 = Time::HiRes::time;
569     my $data = $process->(\@data);
570     my $t2 = Time::HiRes::time;
571 root 1.264
572 root 1.281 warn "cache: '$id' processed in ", $t2 - $t1, "s\n";
573 root 1.108
574 root 1.281 db_put cache => "$id/data", $data;
575     db_put cache => "$id/md5" , $md5;
576     db_put cache => "$id/meta", $meta;
577 root 1.108
578 root 1.281 return $data;
579     }
580 root 1.263
581 root 1.281 db_get cache => "$id/data"
582 root 1.108 }
583    
584 root 1.230 =item cf::datalog type => key => value, ...
585    
586     Log a datalog packet of the given type with the given key-value pairs.
587    
588     =cut
589    
590     sub datalog($@) {
591     my ($type, %kv) = @_;
592     warn "DATALOG ", JSON::XS->new->ascii->encode ({ %kv, type => $type });
593     }
594    
595 root 1.70 =back
596    
597 root 1.71 =cut
598    
599 root 1.44 #############################################################################
600 root 1.39
601 root 1.93 =head2 ATTACHABLE OBJECTS
602    
603 root 1.94 Many objects in crossfire are so-called attachable objects. That means you can
604     attach callbacks/event handlers (a collection of which is called an "attachment")
605     to it. All such attachable objects support the following methods.
606    
607     In the following description, CLASS can be any of C<global>, C<object>
608     C<player>, C<client> or C<map> (i.e. the attachable objects in
609 root 1.281 Crossfire TRT).
610 root 1.55
611     =over 4
612    
613 root 1.94 =item $attachable->attach ($attachment, key => $value...)
614    
615     =item $attachable->detach ($attachment)
616    
617     Attach/detach a pre-registered attachment to a specific object and give it
618     the specified key/value pairs as arguments.
619    
620     Example, attach a minesweeper attachment to the given object, making it a
621     10x10 minesweeper game:
622 root 1.46
623 root 1.94 $obj->attach (minesweeper => width => 10, height => 10);
624 root 1.53
625 root 1.93 =item $bool = $attachable->attached ($name)
626 root 1.46
627 root 1.93 Checks wether the named attachment is currently attached to the object.
628 root 1.46
629 root 1.94 =item cf::CLASS->attach ...
630 root 1.46
631 root 1.94 =item cf::CLASS->detach ...
632 root 1.92
633 root 1.94 Define an anonymous attachment and attach it to all objects of the given
634     CLASS. See the next function for an explanation of its arguments.
635 root 1.92
636 root 1.93 You can attach to global events by using the C<cf::global> class.
637 root 1.92
638 root 1.94 Example, log all player logins:
639    
640     cf::player->attach (
641     on_login => sub {
642     my ($pl) = @_;
643     ...
644     },
645     );
646    
647     Example, attach to the jeweler skill:
648    
649     cf::object->attach (
650     type => cf::SKILL,
651     subtype => cf::SK_JEWELER,
652     on_use_skill => sub {
653     my ($sk, $ob, $part, $dir, $msg) = @_;
654     ...
655     },
656     );
657    
658     =item cf::CLASS::attachment $name, ...
659    
660     Register an attachment by C<$name> through which attachable objects of the
661     given CLASS can refer to this attachment.
662    
663     Some classes such as crossfire maps and objects can specify attachments
664     that are attached at load/instantiate time, thus the need for a name.
665    
666     These calls expect any number of the following handler/hook descriptions:
667 root 1.46
668     =over 4
669    
670     =item prio => $number
671    
672     Set the priority for all following handlers/hooks (unless overwritten
673     by another C<prio> setting). Lower priority handlers get executed
674     earlier. The default priority is C<0>, and many built-in handlers are
675     registered at priority C<-1000>, so lower priorities should not be used
676     unless you know what you are doing.
677    
678 root 1.93 =item type => $type
679    
680     (Only for C<< cf::object->attach >> calls), limits the attachment to the
681     given type of objects only (the additional parameter C<subtype> can be
682     used to further limit to the given subtype).
683    
684 root 1.46 =item on_I<event> => \&cb
685    
686     Call the given code reference whenever the named event happens (event is
687     something like C<instantiate>, C<apply>, C<use_skill> and so on, and which
688     handlers are recognised generally depends on the type of object these
689     handlers attach to).
690    
691     See F<include/eventinc.h> for the full list of events supported, and their
692     class.
693    
694     =item package => package::
695    
696     Look for sub functions of the name C<< on_I<event> >> in the given
697     package and register them. Only handlers for eevents supported by the
698     object/class are recognised.
699    
700     =back
701    
702 root 1.94 Example, define an attachment called "sockpuppet" that calls the given
703     event handler when a monster attacks:
704    
705     cf::object::attachment sockpuppet =>
706     on_skill_attack => sub {
707     my ($self, $victim) = @_;
708     ...
709     }
710     }
711    
712 root 1.96 =item $attachable->valid
713    
714     Just because you have a perl object does not mean that the corresponding
715     C-level object still exists. If you try to access an object that has no
716     valid C counterpart anymore you get an exception at runtime. This method
717     can be used to test for existence of the C object part without causing an
718     exception.
719    
720 root 1.39 =cut
721    
722 root 1.40 # the following variables are defined in .xs and must not be re-created
723 root 1.100 our @CB_GLOBAL = (); # registry for all global events
724     our @CB_ATTACHABLE = (); # registry for all attachables
725     our @CB_OBJECT = (); # all objects (should not be used except in emergency)
726     our @CB_PLAYER = ();
727     our @CB_CLIENT = ();
728     our @CB_TYPE = (); # registry for type (cf-object class) based events
729     our @CB_MAP = ();
730 root 1.39
731 root 1.45 my %attachment;
732    
733 root 1.170 sub cf::attachable::thawer_merge {
734     # simply override everything except _meta
735     local $_[0]{_meta};
736     %{$_[0]} = %{$_[1]};
737     }
738    
739 root 1.93 sub _attach_cb($$$$) {
740     my ($registry, $event, $prio, $cb) = @_;
741 root 1.39
742     use sort 'stable';
743    
744     $cb = [$prio, $cb];
745    
746     @{$registry->[$event]} = sort
747     { $a->[0] cmp $b->[0] }
748     @{$registry->[$event] || []}, $cb;
749     }
750    
751 root 1.100 # hack
752     my %attachable_klass = map +($_ => 1), KLASS_OBJECT, KLASS_CLIENT, KLASS_PLAYER, KLASS_MAP;
753    
754 root 1.39 # attach handles attaching event callbacks
755     # the only thing the caller has to do is pass the correct
756     # registry (== where the callback attaches to).
757 root 1.93 sub _attach {
758 root 1.45 my ($registry, $klass, @arg) = @_;
759 root 1.39
760 root 1.93 my $object_type;
761 root 1.39 my $prio = 0;
762     my %cb_id = map +("on_" . lc $EVENT[$_][0], $_) , grep $EVENT[$_][1] == $klass, 0 .. $#EVENT;
763    
764 root 1.100 #TODO: get rid of this hack
765     if ($attachable_klass{$klass}) {
766     %cb_id = (%cb_id, map +("on_" . lc $EVENT[$_][0], $_) , grep $EVENT[$_][1] == KLASS_ATTACHABLE, 0 .. $#EVENT);
767     }
768    
769 root 1.45 while (@arg) {
770     my $type = shift @arg;
771 root 1.39
772     if ($type eq "prio") {
773 root 1.45 $prio = shift @arg;
774 root 1.39
775 root 1.93 } elsif ($type eq "type") {
776     $object_type = shift @arg;
777     $registry = $CB_TYPE[$object_type] ||= [];
778    
779     } elsif ($type eq "subtype") {
780     defined $object_type or Carp::croak "subtype specified without type";
781     my $object_subtype = shift @arg;
782 root 1.267 $registry = $CB_TYPE[$object_type + $object_subtype * NUM_TYPES] ||= [];
783 root 1.93
784 root 1.39 } elsif ($type eq "package") {
785 root 1.45 my $pkg = shift @arg;
786 root 1.39
787     while (my ($name, $id) = each %cb_id) {
788     if (my $cb = $pkg->can ($name)) {
789 root 1.93 _attach_cb $registry, $id, $prio, $cb;
790 root 1.39 }
791     }
792    
793     } elsif (exists $cb_id{$type}) {
794 root 1.93 _attach_cb $registry, $cb_id{$type}, $prio, shift @arg;
795 root 1.39
796     } elsif (ref $type) {
797     warn "attaching objects not supported, ignoring.\n";
798    
799     } else {
800 root 1.45 shift @arg;
801 root 1.39 warn "attach argument '$type' not supported, ignoring.\n";
802     }
803     }
804     }
805    
806 root 1.93 sub _object_attach {
807 root 1.48 my ($obj, $name, %arg) = @_;
808 root 1.46
809 root 1.55 return if exists $obj->{_attachment}{$name};
810    
811 root 1.46 if (my $attach = $attachment{$name}) {
812     my $registry = $obj->registry;
813    
814 root 1.47 for (@$attach) {
815     my ($klass, @attach) = @$_;
816 root 1.93 _attach $registry, $klass, @attach;
817 root 1.47 }
818 root 1.46
819 root 1.48 $obj->{$name} = \%arg;
820 root 1.46 } else {
821 root 1.280 warn "object uses attachment '$name' which is not available, postponing.\n";
822 root 1.46 }
823    
824 root 1.50 $obj->{_attachment}{$name} = undef;
825 root 1.46 }
826    
827 root 1.93 sub cf::attachable::attach {
828     if (ref $_[0]) {
829     _object_attach @_;
830     } else {
831     _attach shift->_attach_registry, @_;
832     }
833 root 1.267 _recalc_want;
834 root 1.55 };
835 root 1.46
836 root 1.54 # all those should be optimised
837 root 1.93 sub cf::attachable::detach {
838 root 1.54 my ($obj, $name) = @_;
839 root 1.46
840 root 1.93 if (ref $obj) {
841     delete $obj->{_attachment}{$name};
842     reattach ($obj);
843     } else {
844     Carp::croak "cannot, currently, detach class attachments";
845     }
846 root 1.267 _recalc_want;
847 root 1.55 };
848    
849 root 1.93 sub cf::attachable::attached {
850 root 1.55 my ($obj, $name) = @_;
851    
852     exists $obj->{_attachment}{$name}
853 root 1.39 }
854    
855 root 1.100 for my $klass (qw(ATTACHABLE GLOBAL OBJECT PLAYER CLIENT MAP)) {
856 root 1.93 eval "#line " . __LINE__ . " 'cf.pm'
857     sub cf::\L$klass\E::_attach_registry {
858     (\\\@CB_$klass, KLASS_$klass)
859     }
860 root 1.45
861 root 1.93 sub cf::\L$klass\E::attachment {
862     my \$name = shift;
863 root 1.39
864 root 1.93 \$attachment{\$name} = [[KLASS_$klass, \@_]];
865     }
866     ";
867     die if $@;
868 root 1.52 }
869    
870 root 1.39 our $override;
871 root 1.45 our @invoke_results = (); # referenced from .xs code. TODO: play tricks with reify and mortals?
872 root 1.39
873 root 1.45 sub override {
874     $override = 1;
875     @invoke_results = ();
876 root 1.39 }
877    
878 root 1.45 sub do_invoke {
879 root 1.39 my $event = shift;
880 root 1.40 my $callbacks = shift;
881 root 1.39
882 root 1.45 @invoke_results = ();
883    
884 root 1.39 local $override;
885    
886 root 1.40 for (@$callbacks) {
887 root 1.39 eval { &{$_->[1]} };
888    
889     if ($@) {
890     warn "$@";
891 root 1.64 warn "... while processing $EVENT[$event][0](@_) event, skipping processing altogether.\n";
892 root 1.39 override;
893     }
894    
895     return 1 if $override;
896     }
897    
898     0
899     }
900    
901 root 1.96 =item $bool = cf::global::invoke (EVENT_CLASS_XXX, ...)
902 root 1.55
903 root 1.96 =item $bool = $attachable->invoke (EVENT_CLASS_XXX, ...)
904 root 1.55
905 root 1.96 Generate an object-specific event with the given arguments.
906 root 1.55
907 root 1.96 This API is preliminary (most likely, the EVENT_CLASS_xxx prefix will be
908 root 1.55 removed in future versions), and there is no public API to access override
909     results (if you must, access C<@cf::invoke_results> directly).
910    
911     =back
912    
913 root 1.71 =cut
914    
915 root 1.70 #############################################################################
916 root 1.45 # object support
917    
918 root 1.102 sub reattach {
919     # basically do the same as instantiate, without calling instantiate
920     my ($obj) = @_;
921    
922 root 1.169 bless $obj, ref $obj; # re-bless in case extensions have been reloaded
923    
924 root 1.102 my $registry = $obj->registry;
925    
926     @$registry = ();
927    
928     delete $obj->{_attachment} unless scalar keys %{ $obj->{_attachment} || {} };
929    
930     for my $name (keys %{ $obj->{_attachment} || {} }) {
931     if (my $attach = $attachment{$name}) {
932     for (@$attach) {
933     my ($klass, @attach) = @$_;
934     _attach $registry, $klass, @attach;
935     }
936     } else {
937     warn "object uses attachment '$name' that is not available, postponing.\n";
938     }
939     }
940     }
941    
942 root 1.100 cf::attachable->attach (
943     prio => -1000000,
944     on_instantiate => sub {
945     my ($obj, $data) = @_;
946 root 1.45
947 root 1.100 $data = from_json $data;
948 root 1.45
949 root 1.100 for (@$data) {
950     my ($name, $args) = @$_;
951 root 1.49
952 root 1.100 $obj->attach ($name, %{$args || {} });
953     }
954     },
955 root 1.102 on_reattach => \&reattach,
956 root 1.100 on_clone => sub {
957     my ($src, $dst) = @_;
958    
959     @{$dst->registry} = @{$src->registry};
960    
961     %$dst = %$src;
962    
963     %{$dst->{_attachment}} = %{$src->{_attachment}}
964     if exists $src->{_attachment};
965     },
966     );
967 root 1.45
968 root 1.46 sub object_freezer_save {
969 root 1.59 my ($filename, $rdata, $objs) = @_;
970 root 1.46
971 root 1.105 sync_job {
972     if (length $$rdata) {
973     warn sprintf "saving %s (%d,%d)\n",
974     $filename, length $$rdata, scalar @$objs;
975 root 1.60
976 root 1.105 if (my $fh = aio_open "$filename~", O_WRONLY | O_CREAT, 0600) {
977 root 1.60 chmod SAVE_MODE, $fh;
978 root 1.105 aio_write $fh, 0, (length $$rdata), $$rdata, 0;
979 root 1.204 aio_fsync $fh if $cf::USE_FSYNC;
980 root 1.60 close $fh;
981 root 1.105
982     if (@$objs) {
983     if (my $fh = aio_open "$filename.pst~", O_WRONLY | O_CREAT, 0600) {
984     chmod SAVE_MODE, $fh;
985     my $data = Storable::nfreeze { version => 1, objs => $objs };
986     aio_write $fh, 0, (length $data), $data, 0;
987 root 1.204 aio_fsync $fh if $cf::USE_FSYNC;
988 root 1.105 close $fh;
989     aio_rename "$filename.pst~", "$filename.pst";
990     }
991     } else {
992     aio_unlink "$filename.pst";
993     }
994    
995     aio_rename "$filename~", $filename;
996 root 1.60 } else {
997 root 1.105 warn "FATAL: $filename~: $!\n";
998 root 1.60 }
999 root 1.59 } else {
1000 root 1.105 aio_unlink $filename;
1001     aio_unlink "$filename.pst";
1002 root 1.59 }
1003 root 1.45 }
1004     }
1005    
1006 root 1.80 sub object_freezer_as_string {
1007     my ($rdata, $objs) = @_;
1008    
1009     use Data::Dumper;
1010    
1011 root 1.81 $$rdata . Dumper $objs
1012 root 1.80 }
1013    
1014 root 1.46 sub object_thawer_load {
1015     my ($filename) = @_;
1016    
1017 root 1.105 my ($data, $av);
1018 root 1.61
1019 root 1.105 (aio_load $filename, $data) >= 0
1020     or return;
1021 root 1.61
1022 root 1.105 unless (aio_stat "$filename.pst") {
1023     (aio_load "$filename.pst", $av) >= 0
1024     or return;
1025 root 1.113 $av = eval { (Storable::thaw $av)->{objs} };
1026 root 1.61 }
1027 root 1.45
1028 root 1.118 warn sprintf "loading %s (%d)\n",
1029 root 1.274 $filename, length $data, scalar @{$av || []};
1030 root 1.105 return ($data, $av);
1031 root 1.45 }
1032    
1033 root 1.281 =head2 COMMAND CALLBACKS
1034    
1035     =over 4
1036    
1037     =cut
1038    
1039 root 1.45 #############################################################################
1040 root 1.85 # command handling &c
1041 root 1.39
1042 root 1.85 =item cf::register_command $name => \&callback($ob,$args);
1043 root 1.1
1044 root 1.85 Register a callback for execution when the client sends the user command
1045     $name.
1046 root 1.5
1047 root 1.85 =cut
1048 root 1.5
1049 root 1.85 sub register_command {
1050     my ($name, $cb) = @_;
1051 root 1.5
1052 root 1.85 my $caller = caller;
1053     #warn "registering command '$name/$time' to '$caller'";
1054 root 1.1
1055 root 1.85 push @{ $COMMAND{$name} }, [$caller, $cb];
1056 root 1.1 }
1057    
1058 root 1.85 =item cf::register_extcmd $name => \&callback($pl,$packet);
1059 root 1.1
1060 root 1.287 Register a callback for execution when the client sends an (synchronous)
1061     extcmd packet. Ext commands will be processed in the order they are
1062     received by the server, like other user commands. The first argument is
1063     the logged-in player. Ext commands can only be processed after a player
1064     has logged in successfully.
1065    
1066     If the callback returns something, it is sent back as if reply was being
1067     called.
1068    
1069     =item cf::register_exticmd $name => \&callback($ns,$packet);
1070    
1071     Register a callback for execution when the client sends an (asynchronous)
1072     exticmd packet. Exti commands are processed by the server as soon as they
1073     are received, i.e. out of order w.r.t. other commands. The first argument
1074     is a client socket. Exti commands can be received anytime, even before
1075     log-in.
1076 root 1.1
1077 root 1.85 If the callback returns something, it is sent back as if reply was being
1078     called.
1079 root 1.1
1080 root 1.85 =cut
1081 root 1.1
1082 root 1.16 sub register_extcmd {
1083     my ($name, $cb) = @_;
1084    
1085 root 1.159 $EXTCMD{$name} = $cb;
1086 root 1.16 }
1087    
1088 root 1.287 sub register_exticmd {
1089     my ($name, $cb) = @_;
1090    
1091     $EXTICMD{$name} = $cb;
1092     }
1093    
1094 root 1.93 cf::player->attach (
1095 root 1.85 on_command => sub {
1096     my ($pl, $name, $params) = @_;
1097    
1098     my $cb = $COMMAND{$name}
1099     or return;
1100    
1101     for my $cmd (@$cb) {
1102     $cmd->[1]->($pl->ob, $params);
1103     }
1104    
1105     cf::override;
1106     },
1107     on_extcmd => sub {
1108     my ($pl, $buf) = @_;
1109    
1110 root 1.290 my $msg = eval { $pl->ns->{json_coder}->decode ($buf) };
1111 root 1.85
1112     if (ref $msg) {
1113     if (my $cb = $EXTCMD{$msg->{msgtype}}) {
1114 root 1.159 if (my %reply = $cb->($pl, $msg)) {
1115 root 1.85 $pl->ext_reply ($msg->{msgid}, %reply);
1116     }
1117     }
1118     } else {
1119     warn "player " . ($pl->ob->name) . " sent unparseable ext message: <$buf>\n";
1120     }
1121    
1122     cf::override;
1123     },
1124 root 1.93 );
1125 root 1.85
1126 root 1.278 sub load_extensions {
1127     cf::sync_job {
1128     my %todo;
1129    
1130     for my $path (<$LIBDIR/*.ext>) {
1131     next unless -r $path;
1132    
1133     $path =~ /([^\/\\]+)\.ext$/ or die "$path";
1134     my $base = $1;
1135     my $pkg = $1;
1136     $pkg =~ s/[^[:word:]]/_/g;
1137     $pkg = "ext::$pkg";
1138    
1139     open my $fh, "<:utf8", $path
1140     or die "$path: $!";
1141    
1142     my $source = do { local $/; <$fh> };
1143 root 1.1
1144 root 1.278 my %ext = (
1145     path => $path,
1146     base => $base,
1147     pkg => $pkg,
1148     );
1149 root 1.1
1150 root 1.279 $ext{meta} = { map { (split /=/, $_, 2)[0, 1] } split /\s+/, $1 }
1151     if $source =~ /\A#!.*?perl.*?#\s*(.*)$/m;
1152 root 1.1
1153 root 1.278 $ext{source} =
1154     "package $pkg; use strict; use utf8;\n"
1155     . "#line 1 \"$path\"\n{\n"
1156     . $source
1157     . "\n};\n1";
1158 root 1.1
1159 root 1.278 $todo{$base} = \%ext;
1160 root 1.166 }
1161 root 1.1
1162 root 1.278 my %done;
1163     while (%todo) {
1164     my $progress;
1165    
1166     while (my ($k, $v) = each %todo) {
1167 root 1.279 for (split /,\s*/, $v->{meta}{depends}) {
1168 root 1.278 goto skip
1169     unless exists $done{$_};
1170     }
1171    
1172     warn "... loading '$k' into '$v->{pkg}'\n";
1173    
1174     unless (eval $v->{source}) {
1175     my $msg = $@ ? "$v->{path}: $@\n"
1176 root 1.279 : "$v->{base}: extension inactive.\n";
1177 root 1.278
1178     if (exists $v->{meta}{mandatory}) {
1179     warn $msg;
1180     warn "mandatory extension failed to load, exiting.\n";
1181     exit 1;
1182     }
1183    
1184 root 1.279 warn $msg;
1185 root 1.278 }
1186    
1187     $done{$k} = delete $todo{$k};
1188     push @EXTS, $v->{pkg};
1189 root 1.279 $progress = 1;
1190 root 1.278 }
1191 root 1.1
1192 root 1.278 skip:
1193     die "cannot load " . (join ", ", keys %todo) . ": unable to resolve dependencies\n"
1194     unless $progress;
1195     }
1196     };
1197 root 1.1 }
1198    
1199 root 1.8 #############################################################################
1200 root 1.70
1201 root 1.281 =back
1202    
1203 root 1.70 =head2 CORE EXTENSIONS
1204    
1205     Functions and methods that extend core crossfire objects.
1206    
1207 root 1.143 =cut
1208    
1209     package cf::player;
1210    
1211 root 1.154 use Coro::AIO;
1212    
1213 root 1.95 =head3 cf::player
1214    
1215 root 1.70 =over 4
1216 root 1.22
1217 root 1.143 =item cf::player::find $login
1218 root 1.23
1219 root 1.143 Returns the given player object, loading it if necessary (might block).
1220 root 1.23
1221     =cut
1222    
1223 root 1.145 sub playerdir($) {
1224 root 1.253 "$PLAYERDIR/"
1225 root 1.145 . (ref $_[0] ? $_[0]->ob->name : $_[0])
1226     }
1227    
1228 root 1.143 sub path($) {
1229 root 1.145 my $login = ref $_[0] ? $_[0]->ob->name : $_[0];
1230    
1231 root 1.234 (playerdir $login) . "/playerdata"
1232 root 1.143 }
1233    
1234     sub find_active($) {
1235     $cf::PLAYER{$_[0]}
1236     and $cf::PLAYER{$_[0]}->active
1237     and $cf::PLAYER{$_[0]}
1238     }
1239    
1240     sub exists($) {
1241     my ($login) = @_;
1242    
1243     $cf::PLAYER{$login}
1244 root 1.180 or cf::sync_job { !aio_stat path $login }
1245 root 1.143 }
1246    
1247     sub find($) {
1248     return $cf::PLAYER{$_[0]} || do {
1249     my $login = $_[0];
1250    
1251     my $guard = cf::lock_acquire "user_find:$login";
1252    
1253 root 1.151 $cf::PLAYER{$_[0]} || do {
1254 root 1.234 # rename old playerfiles to new ones
1255     #TODO: remove when no longer required
1256     aio_link +(playerdir $login) . "/$login.pl.pst", (playerdir $login) . "/playerdata.pst";
1257     aio_link +(playerdir $login) . "/$login.pl" , (playerdir $login) . "/playerdata";
1258     aio_unlink +(playerdir $login) . "/$login.pl.pst";
1259     aio_unlink +(playerdir $login) . "/$login.pl";
1260    
1261 root 1.151 my $pl = load_pl path $login
1262     or return;
1263     $cf::PLAYER{$login} = $pl
1264     }
1265     }
1266 root 1.143 }
1267    
1268     sub save($) {
1269     my ($pl) = @_;
1270    
1271     return if $pl->{deny_save};
1272    
1273     my $path = path $pl;
1274     my $guard = cf::lock_acquire "user_save:$path";
1275    
1276     return if $pl->{deny_save};
1277 root 1.146
1278 root 1.154 aio_mkdir playerdir $pl, 0770;
1279 root 1.143 $pl->{last_save} = $cf::RUNTIME;
1280    
1281     $pl->save_pl ($path);
1282     Coro::cede;
1283     }
1284    
1285     sub new($) {
1286     my ($login) = @_;
1287    
1288     my $self = create;
1289    
1290     $self->ob->name ($login);
1291     $self->{deny_save} = 1;
1292    
1293     $cf::PLAYER{$login} = $self;
1294    
1295     $self
1296 root 1.23 }
1297    
1298 root 1.154 =item $pl->quit_character
1299    
1300     Nukes the player without looking back. If logged in, the connection will
1301     be destroyed. May block for a long time.
1302    
1303     =cut
1304    
1305 root 1.145 sub quit_character {
1306     my ($pl) = @_;
1307    
1308 root 1.220 my $name = $pl->ob->name;
1309    
1310 root 1.145 $pl->{deny_save} = 1;
1311     $pl->password ("*"); # this should lock out the player until we nuked the dir
1312    
1313     $pl->invoke (cf::EVENT_PLAYER_LOGOUT, 1) if $pl->active;
1314     $pl->deactivate;
1315     $pl->invoke (cf::EVENT_PLAYER_QUIT);
1316     $pl->ns->destroy if $pl->ns;
1317    
1318     my $path = playerdir $pl;
1319     my $temp = "$path~$cf::RUNTIME~deleting~";
1320 root 1.154 aio_rename $path, $temp;
1321 root 1.150 delete $cf::PLAYER{$pl->ob->name};
1322     $pl->destroy;
1323 root 1.220
1324     my $prefix = qr<^~\Q$name\E/>;
1325    
1326     # nuke player maps
1327     $cf::MAP{$_}->nuke for grep /$prefix/, keys %cf::MAP;
1328    
1329 root 1.150 IO::AIO::aio_rmtree $temp;
1330 root 1.145 }
1331    
1332 pippijn 1.221 =item $pl->kick
1333    
1334     Kicks a player out of the game. This destroys the connection.
1335    
1336     =cut
1337    
1338     sub kick {
1339     my ($pl, $kicker) = @_;
1340    
1341     $pl->invoke (cf::EVENT_PLAYER_KICK, $kicker);
1342     $pl->killer ("kicked");
1343     $pl->ns->destroy;
1344     }
1345    
1346 root 1.154 =item cf::player::list_logins
1347    
1348     Returns am arrayref of all valid playernames in the system, can take a
1349     while and may block, so not sync_job-capable, ever.
1350    
1351     =cut
1352    
1353     sub list_logins {
1354 root 1.253 my $dirs = aio_readdir $PLAYERDIR
1355 root 1.154 or return [];
1356    
1357     my @logins;
1358    
1359     for my $login (@$dirs) {
1360     my $fh = aio_open path $login, Fcntl::O_RDONLY, 0 or next;
1361     aio_read $fh, 0, 512, my $buf, 0 or next;
1362 root 1.155 $buf !~ /^password -------------$/m or next; # official not-valid tag
1363 root 1.154
1364     utf8::decode $login;
1365     push @logins, $login;
1366     }
1367    
1368     \@logins
1369     }
1370    
1371     =item $player->maps
1372    
1373 root 1.166 Returns an arrayref of map paths that are private for this
1374 root 1.154 player. May block.
1375    
1376     =cut
1377    
1378     sub maps($) {
1379     my ($pl) = @_;
1380    
1381 root 1.201 $pl = ref $pl ? $pl->ob->name : $pl;
1382    
1383 root 1.154 my $files = aio_readdir playerdir $pl
1384     or return;
1385    
1386     my @paths;
1387    
1388     for (@$files) {
1389     utf8::decode $_;
1390     next if /\.(?:pl|pst)$/;
1391 root 1.158 next unless /^$PATH_SEP/o;
1392 root 1.154
1393 root 1.201 push @paths, cf::map::normalise "~$pl/$_";
1394 root 1.154 }
1395    
1396     \@paths
1397     }
1398    
1399 root 1.283 =item $protocol_xml = $player->expand_cfpod ($crossfire_pod)
1400    
1401     Expand crossfire pod fragments into protocol xml.
1402    
1403     =cut
1404    
1405     sub expand_cfpod {
1406     ((my $self), (local $_)) = @_;
1407    
1408     # escape & and <
1409     s/&/&amp;/g;
1410     s/(?<![BIUGH])</&lt;/g;
1411    
1412     # this is buggy, it needs to properly take care of nested <'s
1413    
1414     1 while
1415     # replace B<>, I<>, U<> etc.
1416     s/B<([^\>]*)>/<b>$1<\/b>/
1417     || s/I<([^\>]*)>/<i>$1<\/i>/
1418     || s/U<([^\>]*)>/<u>$1<\/u>/
1419     # replace G<male|female> tags
1420     || s{G<([^>|]*)\|([^>]*)>}{
1421     $self->gender ? $2 : $1
1422     }ge
1423     # replace H<hint text>
1424 root 1.291 || s{H<([^\>]*)>}
1425     {
1426     ("<fg name=\"lightblue\">[$1 (Use hintmode to suppress hints)]</fg>",
1427     "<fg name=\"lightblue\">[Hint suppressed, see hintmode]</fg>",
1428     "")
1429     [$self->{hintmode}]
1430     }ge;
1431 root 1.283
1432     # create single paragraphs (very hackish)
1433     s/(?<=\S)\n(?=\w)/ /g;
1434    
1435 root 1.291 # compress some whitespace
1436 root 1.295 s/\s+\n/\n/g; # ws line-ends
1437     s/\n\n+/\n/g; # double lines
1438     s/^\n+//; # beginning lines
1439     s/\n+$//; # ending lines
1440 root 1.293
1441 root 1.283 $_
1442     }
1443    
1444 root 1.291 sub hintmode {
1445     $_[0]{hintmode} = $_[1] if @_ > 1;
1446     $_[0]{hintmode}
1447     }
1448    
1449 root 1.231 =item $player->ext_reply ($msgid, %msg)
1450 root 1.95
1451     Sends an ext reply to the player.
1452    
1453     =cut
1454    
1455 root 1.231 sub ext_reply($$%) {
1456 root 1.95 my ($self, $id, %msg) = @_;
1457    
1458     $msg{msgid} = $id;
1459 root 1.290 $self->send ("ext " . $self->ns->{json_coder}->encode (\%msg));
1460 root 1.95 }
1461    
1462 root 1.231 =item $player->ext_event ($type, %msg)
1463    
1464     Sends an ext event to the client.
1465    
1466     =cut
1467    
1468     sub ext_event($$%) {
1469     my ($self, $type, %msg) = @_;
1470    
1471 root 1.232 $self->ns->ext_event ($type, %msg);
1472 root 1.231 }
1473    
1474 root 1.238 =head3 cf::region
1475    
1476     =over 4
1477    
1478     =cut
1479    
1480     package cf::region;
1481    
1482     =item cf::region::find_by_path $path
1483    
1484 root 1.281 Tries to decuce the likely region for a map knowing only its path.
1485 root 1.238
1486     =cut
1487    
1488     sub find_by_path($) {
1489     my ($path) = @_;
1490    
1491     my ($match, $specificity);
1492    
1493     for my $region (list) {
1494 root 1.304 if ($region->{match} && $path =~ $region->{match}) {
1495 root 1.238 ($match, $specificity) = ($region, $region->specificity)
1496     if $region->specificity > $specificity;
1497     }
1498     }
1499    
1500     $match
1501     }
1502 root 1.143
1503 root 1.95 =back
1504    
1505 root 1.110 =head3 cf::map
1506    
1507     =over 4
1508    
1509     =cut
1510    
1511     package cf::map;
1512    
1513     use Fcntl;
1514     use Coro::AIO;
1515    
1516 root 1.166 use overload
1517 root 1.173 '""' => \&as_string,
1518     fallback => 1;
1519 root 1.166
1520 root 1.133 our $MAX_RESET = 3600;
1521     our $DEFAULT_RESET = 3000;
1522 root 1.110
1523     sub generate_random_map {
1524 root 1.166 my ($self, $rmp) = @_;
1525 root 1.110 # mit "rum" bekleckern, nicht
1526 root 1.166 $self->_create_random_map (
1527 root 1.110 $rmp->{wallstyle}, $rmp->{wall_name}, $rmp->{floorstyle}, $rmp->{monsterstyle},
1528     $rmp->{treasurestyle}, $rmp->{layoutstyle}, $rmp->{doorstyle}, $rmp->{decorstyle},
1529     $rmp->{origin_map}, $rmp->{final_map}, $rmp->{exitstyle}, $rmp->{this_map},
1530     $rmp->{exit_on_final_map},
1531     $rmp->{xsize}, $rmp->{ysize},
1532     $rmp->{expand2x}, $rmp->{layoutoptions1}, $rmp->{layoutoptions2}, $rmp->{layoutoptions3},
1533     $rmp->{symmetry}, $rmp->{difficulty}, $rmp->{difficulty_given}, $rmp->{difficulty_increase},
1534     $rmp->{dungeon_level}, $rmp->{dungeon_depth}, $rmp->{decoroptions}, $rmp->{orientation},
1535     $rmp->{origin_y}, $rmp->{origin_x}, $rmp->{random_seed}, $rmp->{total_map_hp},
1536     $rmp->{map_layout_style}, $rmp->{treasureoptions}, $rmp->{symmetry_used},
1537 root 1.162 (cf::region::find $rmp->{region}), $rmp->{custom}
1538     )
1539 root 1.110 }
1540    
1541 root 1.187 =item cf::map->register ($regex, $prio)
1542    
1543     Register a handler for the map path matching the given regex at the
1544     givne priority (higher is better, built-in handlers have priority 0, the
1545     default).
1546    
1547     =cut
1548    
1549 root 1.166 sub register {
1550 root 1.187 my (undef, $regex, $prio) = @_;
1551 root 1.166 my $pkg = caller;
1552    
1553     no strict;
1554     push @{"$pkg\::ISA"}, __PACKAGE__;
1555    
1556 root 1.187 $EXT_MAP{$pkg} = [$prio, qr<$regex>];
1557 root 1.166 }
1558    
1559     # also paths starting with '/'
1560 root 1.187 $EXT_MAP{"cf::map"} = [0, qr{^(?=/)}];
1561 root 1.166
1562 root 1.170 sub thawer_merge {
1563 root 1.172 my ($self, $merge) = @_;
1564    
1565 root 1.170 # we have to keep some variables in memory intact
1566 root 1.172 local $self->{path};
1567     local $self->{load_path};
1568 root 1.170
1569 root 1.172 $self->SUPER::thawer_merge ($merge);
1570 root 1.170 }
1571    
1572 root 1.166 sub normalise {
1573     my ($path, $base) = @_;
1574    
1575 root 1.192 $path = "$path"; # make sure its a string
1576    
1577 root 1.199 $path =~ s/\.map$//;
1578    
1579 root 1.166 # map plan:
1580     #
1581     # /! non-realised random map exit (special hack!)
1582     # {... are special paths that are not being touched
1583     # ?xxx/... are special absolute paths
1584     # ?random/... random maps
1585     # /... normal maps
1586     # ~user/... per-player map of a specific user
1587    
1588     $path =~ s/$PATH_SEP/\//go;
1589    
1590     # treat it as relative path if it starts with
1591     # something that looks reasonable
1592     if ($path =~ m{^(?:\./|\.\./|\w)}) {
1593     $base or Carp::carp "normalise called with relative path and no base: '$path'";
1594    
1595     $base =~ s{[^/]+/?$}{};
1596     $path = "$base/$path";
1597     }
1598    
1599     for ($path) {
1600     redo if s{//}{/};
1601     redo if s{/\.?/}{/};
1602     redo if s{/[^/]+/\.\./}{/};
1603     }
1604    
1605     $path
1606     }
1607    
1608     sub new_from_path {
1609     my (undef, $path, $base) = @_;
1610    
1611     return $path if UNIVERSAL::isa $path, "cf::map"; # already a map object
1612    
1613     $path = normalise $path, $base;
1614    
1615 root 1.187 for my $pkg (sort { $EXT_MAP{$b}[0] <=> $EXT_MAP{$a}[0] } keys %EXT_MAP) {
1616     if ($path =~ $EXT_MAP{$pkg}[1]) {
1617 root 1.166 my $self = bless cf::map::new, $pkg;
1618     $self->{path} = $path; $self->path ($path);
1619     $self->init; # pass $1 etc.
1620     return $self;
1621     }
1622     }
1623    
1624 root 1.192 Carp::carp "unable to resolve path '$path' (base '$base').";
1625 root 1.166 ()
1626     }
1627    
1628     sub init {
1629     my ($self) = @_;
1630    
1631     $self
1632     }
1633    
1634     sub as_string {
1635     my ($self) = @_;
1636    
1637     "$self->{path}"
1638     }
1639    
1640     # the displayed name, this is a one way mapping
1641     sub visible_name {
1642     &as_string
1643     }
1644    
1645     # the original (read-only) location
1646     sub load_path {
1647     my ($self) = @_;
1648    
1649 root 1.254 "$MAPDIR/$self->{path}.map"
1650 root 1.166 }
1651    
1652     # the temporary/swap location
1653     sub save_path {
1654     my ($self) = @_;
1655    
1656 root 1.167 (my $path = $_[0]{path}) =~ s/\//$PATH_SEP/g;
1657 root 1.254 "$TMPDIR/$path.map"
1658 root 1.166 }
1659    
1660     # the unique path, undef == no special unique path
1661     sub uniq_path {
1662     my ($self) = @_;
1663    
1664 root 1.167 (my $path = $_[0]{path}) =~ s/\//$PATH_SEP/g;
1665 root 1.253 "$UNIQUEDIR/$path"
1666 root 1.166 }
1667    
1668 root 1.110 # and all this just because we cannot iterate over
1669     # all maps in C++...
1670     sub change_all_map_light {
1671     my ($change) = @_;
1672    
1673 root 1.122 $_->change_map_light ($change)
1674     for grep $_->outdoor, values %cf::MAP;
1675 root 1.110 }
1676    
1677 root 1.275 sub decay_objects {
1678     my ($self) = @_;
1679    
1680     return if $self->{deny_reset};
1681    
1682     $self->do_decay_objects;
1683     }
1684    
1685 root 1.166 sub unlink_save {
1686     my ($self) = @_;
1687    
1688     utf8::encode (my $save = $self->save_path);
1689 root 1.170 IO::AIO::aioreq_pri 4; Coro::AIO::aio_unlink $save;
1690     IO::AIO::aioreq_pri 4; Coro::AIO::aio_unlink "$save.pst";
1691 root 1.166 }
1692    
1693     sub load_header_from($) {
1694     my ($self, $path) = @_;
1695 root 1.110
1696     utf8::encode $path;
1697 root 1.200 #aio_open $path, O_RDONLY, 0
1698     # or return;
1699 root 1.110
1700 root 1.166 $self->_load_header ($path)
1701 root 1.110 or return;
1702    
1703 root 1.166 $self->{load_path} = $path;
1704 root 1.135
1705 root 1.166 1
1706     }
1707 root 1.110
1708 root 1.188 sub load_header_orig {
1709 root 1.166 my ($self) = @_;
1710 root 1.110
1711 root 1.166 $self->load_header_from ($self->load_path)
1712 root 1.110 }
1713    
1714 root 1.188 sub load_header_temp {
1715 root 1.166 my ($self) = @_;
1716 root 1.110
1717 root 1.166 $self->load_header_from ($self->save_path)
1718     }
1719 root 1.110
1720 root 1.188 sub prepare_temp {
1721     my ($self) = @_;
1722    
1723     $self->last_access ((delete $self->{last_access})
1724     || $cf::RUNTIME); #d#
1725     # safety
1726     $self->{instantiate_time} = $cf::RUNTIME
1727     if $self->{instantiate_time} > $cf::RUNTIME;
1728     }
1729    
1730     sub prepare_orig {
1731     my ($self) = @_;
1732    
1733     $self->{load_original} = 1;
1734     $self->{instantiate_time} = $cf::RUNTIME;
1735     $self->last_access ($cf::RUNTIME);
1736     $self->instantiate;
1737     }
1738    
1739 root 1.166 sub load_header {
1740     my ($self) = @_;
1741 root 1.110
1742 root 1.188 if ($self->load_header_temp) {
1743     $self->prepare_temp;
1744 root 1.166 } else {
1745 root 1.188 $self->load_header_orig
1746 root 1.166 or return;
1747 root 1.188 $self->prepare_orig;
1748 root 1.166 }
1749 root 1.120
1750 root 1.275 $self->{deny_reset} = 1
1751     if $self->no_reset;
1752    
1753 root 1.238 $self->default_region (cf::region::find_by_path $self->{path})
1754     unless $self->default_region;
1755    
1756 root 1.166 1
1757     }
1758 root 1.110
1759 root 1.166 sub find;
1760     sub find {
1761     my ($path, $origin) = @_;
1762 root 1.134
1763 root 1.166 $path = normalise $path, $origin && $origin->path;
1764 root 1.110
1765 root 1.166 cf::lock_wait "map_find:$path";
1766 root 1.110
1767 root 1.166 $cf::MAP{$path} || do {
1768     my $guard = cf::lock_acquire "map_find:$path";
1769     my $map = new_from_path cf::map $path
1770     or return;
1771 root 1.110
1772 root 1.116 $map->{last_save} = $cf::RUNTIME;
1773 root 1.110
1774 root 1.166 $map->load_header
1775     or return;
1776 root 1.134
1777 root 1.275 if ($map->should_reset) {#d#TODO# disabled, crashy (locking issue?)
1778 root 1.185 # doing this can freeze the server in a sync job, obviously
1779     #$cf::WAIT_FOR_TICK->wait;
1780 root 1.112 $map->reset;
1781 root 1.123 undef $guard;
1782 root 1.192 return find $path;
1783 root 1.112 }
1784 root 1.110
1785 root 1.166 $cf::MAP{$path} = $map
1786 root 1.110 }
1787     }
1788    
1789 root 1.188 sub pre_load { }
1790     sub post_load { }
1791    
1792 root 1.110 sub load {
1793     my ($self) = @_;
1794    
1795 root 1.196 local $self->{deny_reset} = 1; # loading can take a long time
1796    
1797 root 1.120 my $path = $self->{path};
1798    
1799 root 1.256 {
1800     my $guard = cf::lock_acquire "map_load:$path";
1801    
1802     return if $self->in_memory != cf::MAP_SWAPPED;
1803 root 1.110
1804 root 1.256 $self->in_memory (cf::MAP_LOADING);
1805 root 1.110
1806 root 1.256 $self->alloc;
1807 root 1.188
1808 root 1.256 $self->pre_load;
1809     Coro::cede;
1810 root 1.188
1811 root 1.256 $self->_load_objects ($self->{load_path}, 1)
1812     or return;
1813 root 1.110
1814 root 1.256 $self->set_object_flag (cf::FLAG_OBJ_ORIGINAL, 1)
1815     if delete $self->{load_original};
1816 root 1.111
1817 root 1.256 if (my $uniq = $self->uniq_path) {
1818     utf8::encode $uniq;
1819     if (aio_open $uniq, O_RDONLY, 0) {
1820     $self->clear_unique_items;
1821     $self->_load_objects ($uniq, 0);
1822     }
1823 root 1.110 }
1824    
1825 root 1.166 Coro::cede;
1826 root 1.256 # now do the right thing for maps
1827     $self->link_multipart_objects;
1828 root 1.110 $self->difficulty ($self->estimate_difficulty)
1829     unless $self->difficulty;
1830 root 1.166 Coro::cede;
1831 root 1.256
1832     unless ($self->{deny_activate}) {
1833     $self->decay_objects;
1834     $self->fix_auto_apply;
1835     $self->update_buttons;
1836     Coro::cede;
1837     $self->set_darkness_map;
1838     Coro::cede;
1839     $self->activate;
1840     }
1841    
1842     $self->in_memory (cf::MAP_IN_MEMORY);
1843 root 1.110 }
1844    
1845 root 1.188 $self->post_load;
1846 root 1.166 }
1847    
1848     sub customise_for {
1849     my ($self, $ob) = @_;
1850    
1851     return find "~" . $ob->name . "/" . $self->{path}
1852     if $self->per_player;
1853 root 1.134
1854 root 1.275 # return find "?party/" . $ob->name . "/" . $self->{path}
1855     # if $self->per_party;
1856    
1857 root 1.166 $self
1858 root 1.110 }
1859    
1860 root 1.157 # find and load all maps in the 3x3 area around a map
1861     sub load_diag {
1862     my ($map) = @_;
1863    
1864     my @diag; # diagonal neighbours
1865    
1866     for (0 .. 3) {
1867     my $neigh = $map->tile_path ($_)
1868     or next;
1869     $neigh = find $neigh, $map
1870     or next;
1871     $neigh->load;
1872    
1873     push @diag, [$neigh->tile_path (($_ + 3) % 4), $neigh],
1874     [$neigh->tile_path (($_ + 1) % 4), $neigh];
1875     }
1876    
1877     for (@diag) {
1878     my $neigh = find @$_
1879     or next;
1880     $neigh->load;
1881     }
1882     }
1883    
1884 root 1.133 sub find_sync {
1885 root 1.110 my ($path, $origin) = @_;
1886    
1887 root 1.157 cf::sync_job { find $path, $origin }
1888 root 1.133 }
1889    
1890     sub do_load_sync {
1891     my ($map) = @_;
1892 root 1.110
1893 root 1.133 cf::sync_job { $map->load };
1894 root 1.110 }
1895    
1896 root 1.157 our %MAP_PREFETCH;
1897 root 1.183 our $MAP_PREFETCHER = undef;
1898 root 1.157
1899     sub find_async {
1900     my ($path, $origin) = @_;
1901    
1902 root 1.166 $path = normalise $path, $origin && $origin->{path};
1903 root 1.157
1904 root 1.166 if (my $map = $cf::MAP{$path}) {
1905 root 1.157 return $map if $map->in_memory == cf::MAP_IN_MEMORY;
1906     }
1907    
1908 root 1.183 undef $MAP_PREFETCH{$path};
1909     $MAP_PREFETCHER ||= cf::async {
1910     while (%MAP_PREFETCH) {
1911     for my $path (keys %MAP_PREFETCH) {
1912     my $map = find $path
1913     or next;
1914     $map->load;
1915    
1916     delete $MAP_PREFETCH{$path};
1917     }
1918     }
1919     undef $MAP_PREFETCHER;
1920     };
1921 root 1.189 $MAP_PREFETCHER->prio (6);
1922 root 1.157
1923     ()
1924     }
1925    
1926 root 1.110 sub save {
1927     my ($self) = @_;
1928    
1929 root 1.137 my $lock = cf::lock_acquire "map_data:" . $self->path;
1930    
1931 root 1.110 $self->{last_save} = $cf::RUNTIME;
1932    
1933     return unless $self->dirty;
1934    
1935 root 1.166 my $save = $self->save_path; utf8::encode $save;
1936     my $uniq = $self->uniq_path; utf8::encode $uniq;
1937 root 1.117
1938 root 1.110 $self->{load_path} = $save;
1939    
1940     return if $self->{deny_save};
1941    
1942 root 1.132 local $self->{last_access} = $self->last_access;#d#
1943    
1944 root 1.143 cf::async {
1945     $_->contr->save for $self->players;
1946     };
1947    
1948 root 1.110 if ($uniq) {
1949 root 1.166 $self->_save_objects ($save, cf::IO_HEADER | cf::IO_OBJECTS);
1950     $self->_save_objects ($uniq, cf::IO_UNIQUES);
1951 root 1.110 } else {
1952 root 1.166 $self->_save_objects ($save, cf::IO_HEADER | cf::IO_OBJECTS | cf::IO_UNIQUES);
1953 root 1.110 }
1954     }
1955    
1956     sub swap_out {
1957     my ($self) = @_;
1958    
1959 root 1.130 # save first because save cedes
1960     $self->save;
1961    
1962 root 1.137 my $lock = cf::lock_acquire "map_data:" . $self->path;
1963    
1964 root 1.110 return if $self->players;
1965     return if $self->in_memory != cf::MAP_IN_MEMORY;
1966     return if $self->{deny_save};
1967    
1968     $self->clear;
1969     $self->in_memory (cf::MAP_SWAPPED);
1970     }
1971    
1972 root 1.112 sub reset_at {
1973     my ($self) = @_;
1974 root 1.110
1975     # TODO: safety, remove and allow resettable per-player maps
1976 root 1.114 return 1e99 if $self->{deny_reset};
1977 root 1.110
1978 root 1.112 my $time = $self->fixed_resettime ? $self->{instantiate_time} : $self->last_access;
1979 root 1.114 my $to = List::Util::min $MAX_RESET, $self->reset_timeout || $DEFAULT_RESET;
1980 root 1.110
1981 root 1.112 $time + $to
1982     }
1983    
1984     sub should_reset {
1985     my ($self) = @_;
1986    
1987     $self->reset_at <= $cf::RUNTIME
1988 root 1.111 }
1989    
1990 root 1.110 sub reset {
1991     my ($self) = @_;
1992    
1993 root 1.167 my $lock = cf::lock_acquire "map_data:$self->{path}";
1994 root 1.137
1995 root 1.110 return if $self->players;
1996    
1997 root 1.274 warn "resetting map ", $self->path;
1998 root 1.110
1999 root 1.210 $self->in_memory (cf::MAP_SWAPPED);
2000    
2001     # need to save uniques path
2002     unless ($self->{deny_save}) {
2003     my $uniq = $self->uniq_path; utf8::encode $uniq;
2004    
2005     $self->_save_objects ($uniq, cf::IO_UNIQUES)
2006     if $uniq;
2007     }
2008    
2009 root 1.111 delete $cf::MAP{$self->path};
2010 root 1.110
2011 root 1.167 $self->clear;
2012    
2013 root 1.110 $_->clear_links_to ($self) for values %cf::MAP;
2014    
2015 root 1.166 $self->unlink_save;
2016 root 1.111 $self->destroy;
2017 root 1.110 }
2018    
2019 root 1.114 my $nuke_counter = "aaaa";
2020    
2021     sub nuke {
2022     my ($self) = @_;
2023    
2024 root 1.174 delete $cf::MAP{$self->path};
2025    
2026     $self->unlink_save;
2027    
2028     bless $self, "cf::map";
2029     delete $self->{deny_reset};
2030 root 1.114 $self->{deny_save} = 1;
2031     $self->reset_timeout (1);
2032 root 1.174 $self->path ($self->{path} = "{nuke}/" . ($nuke_counter++));
2033    
2034     $cf::MAP{$self->path} = $self;
2035    
2036 root 1.114 $self->reset; # polite request, might not happen
2037     }
2038    
2039 root 1.276 =item $maps = cf::map::tmp_maps
2040    
2041     Returns an arrayref with all map paths of currently instantiated and saved
2042 root 1.277 maps. May block.
2043 root 1.276
2044     =cut
2045    
2046     sub tmp_maps() {
2047     [
2048     map {
2049     utf8::decode $_;
2050 root 1.277 /\.map$/
2051 root 1.276 ? normalise $_
2052     : ()
2053     } @{ aio_readdir $TMPDIR or [] }
2054     ]
2055     }
2056    
2057 root 1.277 =item $maps = cf::map::random_maps
2058    
2059     Returns an arrayref with all map paths of currently instantiated and saved
2060     random maps. May block.
2061    
2062     =cut
2063    
2064     sub random_maps() {
2065     [
2066     map {
2067     utf8::decode $_;
2068     /\.map$/
2069     ? normalise "?random/$_"
2070     : ()
2071     } @{ aio_readdir $RANDOMDIR or [] }
2072     ]
2073     }
2074    
2075 root 1.158 =item cf::map::unique_maps
2076    
2077 root 1.166 Returns an arrayref of paths of all shared maps that have
2078 root 1.158 instantiated unique items. May block.
2079    
2080     =cut
2081    
2082     sub unique_maps() {
2083 root 1.276 [
2084     map {
2085     utf8::decode $_;
2086 root 1.277 /\.map$/
2087 root 1.276 ? normalise $_
2088     : ()
2089     } @{ aio_readdir $UNIQUEDIR or [] }
2090     ]
2091 root 1.158 }
2092    
2093 root 1.155 package cf;
2094    
2095     =back
2096    
2097     =head3 cf::object
2098    
2099     =cut
2100    
2101     package cf::object;
2102    
2103     =over 4
2104    
2105     =item $ob->inv_recursive
2106 root 1.110
2107 root 1.155 Returns the inventory of the object _and_ their inventories, recursively.
2108 root 1.110
2109 root 1.155 =cut
2110 root 1.144
2111 root 1.155 sub inv_recursive_;
2112     sub inv_recursive_ {
2113     map { $_, inv_recursive_ $_->inv } @_
2114     }
2115 root 1.110
2116 root 1.155 sub inv_recursive {
2117     inv_recursive_ inv $_[0]
2118 root 1.110 }
2119    
2120     package cf;
2121    
2122     =back
2123    
2124 root 1.95 =head3 cf::object::player
2125    
2126     =over 4
2127    
2128 root 1.79 =item $player_object->reply ($npc, $msg[, $flags])
2129 root 1.28
2130     Sends a message to the player, as if the npc C<$npc> replied. C<$npc>
2131     can be C<undef>. Does the right thing when the player is currently in a
2132     dialogue with the given NPC character.
2133    
2134     =cut
2135    
2136 root 1.22 # rough implementation of a future "reply" method that works
2137     # with dialog boxes.
2138 root 1.95 #TODO: the first argument must go, split into a $npc->reply_to ( method
2139 root 1.23 sub cf::object::player::reply($$$;$) {
2140     my ($self, $npc, $msg, $flags) = @_;
2141    
2142     $flags = cf::NDI_BROWN | cf::NDI_UNIQUE unless @_ >= 4;
2143 root 1.22
2144 root 1.24 if ($self->{record_replies}) {
2145     push @{ $self->{record_replies} }, [$npc, $msg, $flags];
2146 elmex 1.282
2147 root 1.24 } else {
2148 elmex 1.282 my $pl = $self->contr;
2149    
2150     if ($pl->{npc_dialog} && $pl->{npc_dialog}->{id}) {
2151     my $diag = $pl->{npc_dialog};
2152     $diag->{pl}->ext_reply (
2153 root 1.283 $diag->{id},
2154     msgtype => "reply",
2155     msg => $diag->{pl}->expand_cfpod ($msg),
2156     add_topics => []
2157 elmex 1.282 );
2158    
2159     } else {
2160     $msg = $npc->name . " says: $msg" if $npc;
2161     $self->message ($msg, $flags);
2162     }
2163 root 1.24 }
2164 root 1.22 }
2165    
2166 root 1.79 =item $player_object->may ("access")
2167    
2168     Returns wether the given player is authorized to access resource "access"
2169     (e.g. "command_wizcast").
2170    
2171     =cut
2172    
2173     sub cf::object::player::may {
2174     my ($self, $access) = @_;
2175    
2176     $self->flag (cf::FLAG_WIZ) ||
2177     (ref $cf::CFG{"may_$access"}
2178     ? scalar grep $self->name eq $_, @{$cf::CFG{"may_$access"}}
2179     : $cf::CFG{"may_$access"})
2180     }
2181 root 1.70
2182 root 1.115 =item $player_object->enter_link
2183    
2184     Freezes the player and moves him/her to a special map (C<{link}>).
2185    
2186 root 1.166 The player should be reasonably safe there for short amounts of time. You
2187 root 1.115 I<MUST> call C<leave_link> as soon as possible, though.
2188    
2189 root 1.166 Will never block.
2190    
2191 root 1.115 =item $player_object->leave_link ($map, $x, $y)
2192    
2193 root 1.166 Moves the player out of the special C<{link}> map onto the specified
2194     map. If the map is not valid (or omitted), the player will be moved back
2195     to the location he/she was before the call to C<enter_link>, or, if that
2196     fails, to the emergency map position.
2197 root 1.115
2198     Might block.
2199    
2200     =cut
2201    
2202 root 1.166 sub link_map {
2203     unless ($LINK_MAP) {
2204     $LINK_MAP = cf::map::find "{link}"
2205 root 1.196 or cf::cleanup "FATAL: unable to provide {link} map, exiting.";
2206 root 1.166 $LINK_MAP->load;
2207     }
2208    
2209     $LINK_MAP
2210     }
2211    
2212 root 1.110 sub cf::object::player::enter_link {
2213     my ($self) = @_;
2214    
2215 root 1.259 $self->deactivate_recursive;
2216 root 1.258
2217 root 1.166 return if UNIVERSAL::isa $self->map, "ext::map_link";
2218 root 1.110
2219 root 1.120 $self->{_link_pos} ||= [$self->map->{path}, $self->x, $self->y]
2220 root 1.270 if $self->map && $self->map->{path} ne "{link}";
2221 root 1.110
2222 root 1.194 $self->enter_map ($LINK_MAP || link_map, 10, 10);
2223 root 1.110 }
2224    
2225     sub cf::object::player::leave_link {
2226     my ($self, $map, $x, $y) = @_;
2227    
2228 root 1.270 return unless $self->contr->active;
2229    
2230 root 1.110 my $link_pos = delete $self->{_link_pos};
2231    
2232     unless ($map) {
2233     # restore original map position
2234     ($map, $x, $y) = @{ $link_pos || [] };
2235 root 1.133 $map = cf::map::find $map;
2236 root 1.110
2237     unless ($map) {
2238     ($map, $x, $y) = @$EMERGENCY_POSITION;
2239 root 1.133 $map = cf::map::find $map
2240 root 1.110 or die "FATAL: cannot load emergency map\n";
2241     }
2242     }
2243    
2244     ($x, $y) = (-1, -1)
2245     unless (defined $x) && (defined $y);
2246    
2247     # use -1 or undef as default coordinates, not 0, 0
2248     ($x, $y) = ($map->enter_x, $map->enter_y)
2249     if $x <=0 && $y <= 0;
2250    
2251     $map->load;
2252 root 1.157 $map->load_diag;
2253 root 1.110
2254 root 1.143 return unless $self->contr->active;
2255 root 1.110 $self->activate_recursive;
2256 root 1.215
2257     local $self->{_prev_pos} = $link_pos; # ugly hack for rent.ext
2258 root 1.110 $self->enter_map ($map, $x, $y);
2259     }
2260    
2261 root 1.306 =item $player_object->goto ($path, $x, $y[, $check->($map)[, $done->()]])
2262 root 1.268
2263     Moves the player to the given map-path and coordinates by first freezing
2264     her, loading and preparing them map, calling the provided $check callback
2265     that has to return the map if sucecssful, and then unfreezes the player on
2266 root 1.306 the new (success) or old (failed) map position. In either case, $done will
2267     be called at the end of this process.
2268 root 1.110
2269     =cut
2270    
2271 root 1.270 our $GOTOGEN;
2272    
2273 root 1.136 sub cf::object::player::goto {
2274 root 1.306 my ($self, $path, $x, $y, $check, $done) = @_;
2275 root 1.268
2276 root 1.270 # do generation counting so two concurrent goto's will be executed in-order
2277     my $gen = $self->{_goto_generation} = ++$GOTOGEN;
2278    
2279 root 1.110 $self->enter_link;
2280    
2281 root 1.140 (async {
2282 root 1.197 my $map = eval {
2283     my $map = cf::map::find $path;
2284 root 1.268
2285     if ($map) {
2286     $map = $map->customise_for ($self);
2287     $map = $check->($map) if $check && $map;
2288     } else {
2289     $self->message ("The exit to '$path' is closed", cf::NDI_UNIQUE | cf::NDI_RED);
2290     }
2291    
2292 root 1.197 $map
2293 root 1.268 };
2294    
2295     if ($@) {
2296     $self->message ("Something went wrong within the server, please report this incident!", cf::NDI_UNIQUE | cf::NDI_RED);
2297     LOG llevError | logBacktrace, Carp::longmess $@;
2298     }
2299 root 1.115
2300 root 1.270 if ($gen == $self->{_goto_generation}) {
2301     delete $self->{_goto_generation};
2302     $self->leave_link ($map, $x, $y);
2303     }
2304 root 1.306
2305     $done->() if $done;
2306 root 1.110 })->prio (1);
2307     }
2308    
2309     =item $player_object->enter_exit ($exit_object)
2310    
2311     =cut
2312    
2313     sub parse_random_map_params {
2314     my ($spec) = @_;
2315    
2316     my $rmp = { # defaults
2317 root 1.181 xsize => (cf::rndm 15, 40),
2318     ysize => (cf::rndm 15, 40),
2319     symmetry => (cf::rndm 1, cf::SYMMETRY_XY),
2320 root 1.182 #layout => string,
2321 root 1.110 };
2322    
2323     for (split /\n/, $spec) {
2324     my ($k, $v) = split /\s+/, $_, 2;
2325    
2326     $rmp->{lc $k} = $v if (length $k) && (length $v);
2327     }
2328    
2329     $rmp
2330     }
2331    
2332     sub prepare_random_map {
2333     my ($exit) = @_;
2334    
2335 root 1.179 my $guard = cf::lock_acquire "exit_prepare:$exit";
2336    
2337 root 1.110 # all this does is basically replace the /! path by
2338     # a new random map path (?random/...) with a seed
2339     # that depends on the exit object
2340    
2341     my $rmp = parse_random_map_params $exit->msg;
2342    
2343     if ($exit->map) {
2344 root 1.198 $rmp->{region} = $exit->region->name;
2345 root 1.110 $rmp->{origin_map} = $exit->map->path;
2346     $rmp->{origin_x} = $exit->x;
2347     $rmp->{origin_y} = $exit->y;
2348     }
2349    
2350     $rmp->{random_seed} ||= $exit->random_seed;
2351    
2352     my $data = cf::to_json $rmp;
2353     my $md5 = Digest::MD5::md5_hex $data;
2354 root 1.253 my $meta = "$RANDOMDIR/$md5.meta";
2355 root 1.110
2356 root 1.177 if (my $fh = aio_open "$meta~", O_WRONLY | O_CREAT, 0666) {
2357 root 1.110 aio_write $fh, 0, (length $data), $data, 0;
2358 root 1.177 undef $fh;
2359     aio_rename "$meta~", $meta;
2360 root 1.110
2361     $exit->slaying ("?random/$md5");
2362     $exit->msg (undef);
2363     }
2364     }
2365    
2366     sub cf::object::player::enter_exit {
2367     my ($self, $exit) = @_;
2368    
2369     return unless $self->type == cf::PLAYER;
2370    
2371 root 1.195 if ($exit->slaying eq "/!") {
2372     #TODO: this should de-fi-ni-te-ly not be a sync-job
2373 root 1.233 # the problem is that $exit might not survive long enough
2374     # so it needs to be done right now, right here
2375 root 1.195 cf::sync_job { prepare_random_map $exit };
2376     }
2377    
2378     my $slaying = cf::map::normalise $exit->slaying, $exit->map && $exit->map->path;
2379     my $hp = $exit->stats->hp;
2380     my $sp = $exit->stats->sp;
2381    
2382 root 1.110 $self->enter_link;
2383    
2384 root 1.296 # if exit is damned, update players death & WoR home-position
2385     $self->contr->savebed ($slaying, $hp, $sp)
2386     if $exit->flag (FLAG_DAMNED);
2387    
2388 root 1.140 (async {
2389 root 1.133 $self->deactivate_recursive; # just to be sure
2390 root 1.110 unless (eval {
2391 root 1.195 $self->goto ($slaying, $hp, $sp);
2392 root 1.110
2393     1;
2394     }) {
2395     $self->message ("Something went wrong deep within the crossfire server. "
2396 root 1.233 . "I'll try to bring you back to the map you were before. "
2397     . "Please report this to the dungeon master!",
2398     cf::NDI_UNIQUE | cf::NDI_RED);
2399 root 1.110
2400     warn "ERROR in enter_exit: $@";
2401     $self->leave_link;
2402     }
2403     })->prio (1);
2404     }
2405    
2406 root 1.95 =head3 cf::client
2407    
2408     =over 4
2409    
2410     =item $client->send_drawinfo ($text, $flags)
2411    
2412     Sends a drawinfo packet to the client. Circumvents output buffering so
2413     should not be used under normal circumstances.
2414    
2415 root 1.70 =cut
2416    
2417 root 1.95 sub cf::client::send_drawinfo {
2418     my ($self, $text, $flags) = @_;
2419    
2420     utf8::encode $text;
2421 root 1.225 $self->send_packet (sprintf "drawinfo %d %s", $flags || cf::NDI_BLACK, $text);
2422 root 1.95 }
2423    
2424 root 1.283 =item $client->send_msg ($color, $type, $msg, [extra...])
2425    
2426     Send a drawinfo or msg packet to the client, formatting the msg for the
2427     client if neccessary. C<$type> should be a string identifying the type of
2428     the message, with C<log> being the default. If C<$color> is negative, suppress
2429     the message unless the client supports the msg packet.
2430    
2431     =cut
2432    
2433     sub cf::client::send_msg {
2434     my ($self, $color, $type, $msg, @extra) = @_;
2435    
2436     $msg = $self->pl->expand_cfpod ($msg);
2437    
2438 root 1.294 return unless @extra || length $msg;
2439    
2440 root 1.283 if ($self->can_msg) {
2441 root 1.290 $self->send_packet ("msg " . $self->{json_coder}->encode ([$color, $type, $msg, @extra]));
2442 root 1.283 } else {
2443     # replace some tags by gcfclient-compatible ones
2444     for ($msg) {
2445     1 while
2446     s/<b>([^<]*)<\/b>/[b]${1}[\/b]/
2447     || s/<i>([^<]*)<\/i>/[i]${1}[\/i]/
2448     || s/<u>([^<]*)<\/u>/[ul]${1}[\/ul]/
2449     || s/<tt>([^<]*)<\/tt>/[fixed]${1}[\/fixed]/
2450 root 1.285 || s/<fg name=\"([^"]+)\">([^<]*)<\/fg>/[color=$1]${2}[\/color]/;
2451 root 1.283 }
2452    
2453     if ($color >= 0) {
2454 root 1.284 if (0 && $msg =~ /\[/) {
2455 root 1.283 $self->send_packet ("drawextinfo $color 4 0 $msg")
2456     } else {
2457 root 1.286 $msg =~ s/\[\/?(?:b|i|u|fixed|color)[^\]]*\]//g;
2458 root 1.283 $self->send_packet ("drawinfo $color $msg")
2459     }
2460     }
2461     }
2462     }
2463    
2464 root 1.232 =item $client->ext_event ($type, %msg)
2465    
2466 root 1.287 Sends an ext event to the client.
2467 root 1.232
2468     =cut
2469    
2470     sub cf::client::ext_event($$%) {
2471     my ($self, $type, %msg) = @_;
2472    
2473 root 1.305 return unless $self->extcmd;
2474    
2475 root 1.232 $msg{msgtype} = "event_$type";
2476 root 1.290 $self->send_packet ("ext " . $self->{json_coder}->encode (\%msg));
2477 root 1.232 }
2478 root 1.95
2479     =item $success = $client->query ($flags, "text", \&cb)
2480    
2481     Queues a query to the client, calling the given callback with
2482     the reply text on a reply. flags can be C<cf::CS_QUERY_YESNO>,
2483     C<cf::CS_QUERY_SINGLECHAR> or C<cf::CS_QUERY_HIDEINPUT> or C<0>.
2484    
2485 root 1.287 Queries can fail, so check the return code. Or don't, as queries will
2486     become reliable at some point in the future.
2487 root 1.95
2488     =cut
2489    
2490     sub cf::client::query {
2491     my ($self, $flags, $text, $cb) = @_;
2492    
2493     return unless $self->state == ST_PLAYING
2494     || $self->state == ST_SETUP
2495     || $self->state == ST_CUSTOM;
2496    
2497     $self->state (ST_CUSTOM);
2498    
2499     utf8::encode $text;
2500     push @{ $self->{query_queue} }, [(sprintf "query %d %s", $flags, $text), $cb];
2501    
2502     $self->send_packet ($self->{query_queue}[0][0])
2503     if @{ $self->{query_queue} } == 1;
2504 root 1.287
2505     1
2506 root 1.95 }
2507    
2508     cf::client->attach (
2509 root 1.290 on_connect => sub {
2510     my ($ns) = @_;
2511    
2512     $ns->{json_coder} = JSON::XS->new->utf8->max_size (1e6)->convert_blessed;
2513     },
2514 root 1.95 on_reply => sub {
2515     my ($ns, $msg) = @_;
2516    
2517     # this weird shuffling is so that direct followup queries
2518     # get handled first
2519 root 1.128 my $queue = delete $ns->{query_queue}
2520 root 1.129 or return; # be conservative, not sure how that can happen, but we saw a crash here
2521 root 1.95
2522     (shift @$queue)->[1]->($msg);
2523 root 1.202 return unless $ns->valid; # temporary(?) workaround for callback destroying socket
2524 root 1.95
2525     push @{ $ns->{query_queue} }, @$queue;
2526    
2527     if (@{ $ns->{query_queue} } == @$queue) {
2528     if (@$queue) {
2529     $ns->send_packet ($ns->{query_queue}[0][0]);
2530     } else {
2531 root 1.98 $ns->state (ST_PLAYING) if $ns->state == ST_CUSTOM;
2532 root 1.95 }
2533     }
2534     },
2535 root 1.287 on_exticmd => sub {
2536     my ($ns, $buf) = @_;
2537    
2538 root 1.290 my $msg = eval { $ns->{json_coder}->decode ($buf) };
2539 root 1.287
2540     if (ref $msg) {
2541     if (my $cb = $EXTICMD{$msg->{msgtype}}) {
2542     if (my %reply = $cb->($ns, $msg)) {
2543     $reply{msgid} = $msg->{msgid};
2544 root 1.290 $ns->send ("ext " . $ns->{json_coder}->encode (\%reply));
2545 root 1.287 }
2546     }
2547     } else {
2548     warn "client " . ($ns->pl ? $ns->pl->ob->name : $ns->host) . " sent unparseable exti message: <$buf>\n";
2549     }
2550    
2551     cf::override;
2552     },
2553 root 1.95 );
2554    
2555 root 1.140 =item $client->async (\&cb)
2556 root 1.96
2557     Create a new coroutine, running the specified callback. The coroutine will
2558     be automatically cancelled when the client gets destroyed (e.g. on logout,
2559     or loss of connection).
2560    
2561     =cut
2562    
2563 root 1.140 sub cf::client::async {
2564 root 1.96 my ($self, $cb) = @_;
2565    
2566 root 1.140 my $coro = &Coro::async ($cb);
2567 root 1.103
2568     $coro->on_destroy (sub {
2569 root 1.96 delete $self->{_coro}{$coro+0};
2570 root 1.103 });
2571 root 1.96
2572     $self->{_coro}{$coro+0} = $coro;
2573 root 1.103
2574     $coro
2575 root 1.96 }
2576    
2577     cf::client->attach (
2578     on_destroy => sub {
2579     my ($ns) = @_;
2580    
2581 root 1.97 $_->cancel for values %{ (delete $ns->{_coro}) || {} };
2582 root 1.96 },
2583     );
2584    
2585 root 1.95 =back
2586    
2587 root 1.70
2588     =head2 SAFE SCRIPTING
2589    
2590     Functions that provide a safe environment to compile and execute
2591     snippets of perl code without them endangering the safety of the server
2592     itself. Looping constructs, I/O operators and other built-in functionality
2593     is not available in the safe scripting environment, and the number of
2594 root 1.79 functions and methods that can be called is greatly reduced.
2595 root 1.70
2596     =cut
2597 root 1.23
2598 root 1.42 our $safe = new Safe "safe";
2599 root 1.23 our $safe_hole = new Safe::Hole;
2600    
2601     $SIG{FPE} = 'IGNORE';
2602    
2603     $safe->permit_only (Opcode::opset qw(:base_core :base_mem :base_orig :base_math sort time));
2604    
2605 root 1.25 # here we export the classes and methods available to script code
2606    
2607 root 1.70 =pod
2608    
2609 root 1.228 The following functions and methods are available within a safe environment:
2610 root 1.70
2611 root 1.297 cf::object
2612     contr pay_amount pay_player map x y force_find force_add
2613     insert remove
2614    
2615     cf::object::player
2616     player
2617    
2618     cf::player
2619     peaceful
2620    
2621     cf::map
2622     trigger
2623 root 1.70
2624     =cut
2625    
2626 root 1.25 for (
2627 root 1.297 ["cf::object" => qw(contr pay_amount pay_player map force_find force_add x y
2628     insert remove)],
2629 root 1.25 ["cf::object::player" => qw(player)],
2630     ["cf::player" => qw(peaceful)],
2631 elmex 1.91 ["cf::map" => qw(trigger)],
2632 root 1.25 ) {
2633     no strict 'refs';
2634     my ($pkg, @funs) = @$_;
2635 root 1.41 *{"safe::$pkg\::$_"} = $safe_hole->wrap (\&{"$pkg\::$_"})
2636 root 1.25 for @funs;
2637     }
2638 root 1.23
2639 root 1.70 =over 4
2640    
2641     =item @retval = safe_eval $code, [var => value, ...]
2642    
2643     Compiled and executes the given perl code snippet. additional var/value
2644     pairs result in temporary local (my) scalar variables of the given name
2645     that are available in the code snippet. Example:
2646    
2647     my $five = safe_eval '$first + $second', first => 1, second => 4;
2648    
2649     =cut
2650    
2651 root 1.23 sub safe_eval($;@) {
2652     my ($code, %vars) = @_;
2653    
2654     my $qcode = $code;
2655     $qcode =~ s/"/‟/g; # not allowed in #line filenames
2656     $qcode =~ s/\n/\\n/g;
2657    
2658     local $_;
2659 root 1.41 local @safe::cf::_safe_eval_args = values %vars;
2660 root 1.23
2661 root 1.42 my $eval =
2662 root 1.23 "do {\n"
2663     . "my (" . (join ",", map "\$$_", keys %vars) . ") = \@cf::_safe_eval_args;\n"
2664     . "#line 0 \"{$qcode}\"\n"
2665     . $code
2666     . "\n}"
2667 root 1.25 ;
2668    
2669     sub_generation_inc;
2670 root 1.42 my @res = wantarray ? $safe->reval ($eval) : scalar $safe->reval ($eval);
2671 root 1.25 sub_generation_inc;
2672    
2673 root 1.42 if ($@) {
2674     warn "$@";
2675     warn "while executing safe code '$code'\n";
2676     warn "with arguments " . (join " ", %vars) . "\n";
2677     }
2678    
2679 root 1.25 wantarray ? @res : $res[0]
2680 root 1.23 }
2681    
2682 root 1.69 =item cf::register_script_function $function => $cb
2683    
2684     Register a function that can be called from within map/npc scripts. The
2685     function should be reasonably secure and should be put into a package name
2686     like the extension.
2687    
2688     Example: register a function that gets called whenever a map script calls
2689     C<rent::overview>, as used by the C<rent> extension.
2690    
2691     cf::register_script_function "rent::overview" => sub {
2692     ...
2693     };
2694    
2695     =cut
2696    
2697 root 1.23 sub register_script_function {
2698     my ($fun, $cb) = @_;
2699    
2700     no strict 'refs';
2701 root 1.41 *{"safe::$fun"} = $safe_hole->wrap ($cb);
2702 root 1.23 }
2703    
2704 root 1.70 =back
2705    
2706 root 1.71 =cut
2707    
2708 root 1.23 #############################################################################
2709 root 1.203 # the server's init and main functions
2710    
2711 root 1.246 sub load_facedata($) {
2712     my ($path) = @_;
2713 root 1.223
2714 root 1.229 warn "loading facedata from $path\n";
2715 root 1.223
2716 root 1.236 my $facedata;
2717     0 < aio_load $path, $facedata
2718 root 1.223 or die "$path: $!";
2719    
2720 root 1.237 $facedata = Coro::Storable::thaw $facedata;
2721 root 1.223
2722 root 1.236 $facedata->{version} == 2
2723 root 1.226 or cf::cleanup "$path: version mismatch, cannot proceed.";
2724    
2725 root 1.236 {
2726     my $faces = $facedata->{faceinfo};
2727    
2728     while (my ($face, $info) = each %$faces) {
2729     my $idx = (cf::face::find $face) || cf::face::alloc $face;
2730 root 1.302 cf::face::set_visibility $idx, $info->{visibility};
2731     cf::face::set_magicmap $idx, $info->{magicmap};
2732 root 1.236 cf::face::set_data $idx, 0, $info->{data32}, $info->{chksum32};
2733     cf::face::set_data $idx, 1, $info->{data64}, $info->{chksum64};
2734 root 1.302
2735     cf::cede_to_tick;
2736 root 1.236 }
2737    
2738     while (my ($face, $info) = each %$faces) {
2739     next unless $info->{smooth};
2740     my $idx = cf::face::find $face
2741     or next;
2742     if (my $smooth = cf::face::find $info->{smooth}) {
2743 root 1.302 cf::face::set_smooth $idx, $smooth;
2744     cf::face::set_smoothlevel $idx, $info->{smoothlevel};
2745 root 1.236 } else {
2746     warn "smooth face '$info->{smooth}' not found for face '$face'";
2747     }
2748 root 1.302
2749     cf::cede_to_tick;
2750 root 1.236 }
2751 root 1.223 }
2752    
2753 root 1.236 {
2754     my $anims = $facedata->{animinfo};
2755    
2756     while (my ($anim, $info) = each %$anims) {
2757     cf::anim::set $anim, $info->{frames}, $info->{facings};
2758 root 1.302 cf::cede_to_tick;
2759 root 1.225 }
2760 root 1.236
2761     cf::anim::invalidate_all; # d'oh
2762 root 1.225 }
2763    
2764 root 1.302 {
2765     # TODO: for gcfclient pleasure, we should give resources
2766     # that gcfclient doesn't grok a >10000 face index.
2767     my $res = $facedata->{resource};
2768     my $enc = JSON::XS->new->utf8->canonical;
2769    
2770     while (my ($name, $info) = each %$res) {
2771     my $meta = $enc->encode ({
2772     name => $name,
2773     type => $info->{type},
2774 root 1.303 copyright => $info->{copyright}, #TODO#
2775 root 1.302 });
2776     my $data = pack "(w/a*)*", $meta, $info->{data};
2777     my $chk = Digest::MD5::md5 "$info->{chksum},$meta"; # mangle data checksum and metadata
2778    
2779     my $idx = (cf::face::find $name) || cf::face::alloc $name;
2780     cf::face::set_type $idx, 1;
2781     cf::face::set_data $idx, 0, $data, $chk;
2782    
2783     cf::cede_to_tick;
2784     }
2785     }
2786    
2787 root 1.223 1
2788     }
2789    
2790 root 1.253 sub reload_regions {
2791     load_resource_file "$MAPDIR/regions"
2792     or die "unable to load regions file\n";
2793 root 1.304
2794     for (cf::region::list) {
2795     $_->{match} = qr/$_->{match}/
2796     if exists $_->{match};
2797     }
2798 root 1.253 }
2799    
2800 root 1.246 sub reload_facedata {
2801 root 1.253 load_facedata "$DATADIR/facedata"
2802 root 1.246 or die "unable to load facedata\n";
2803     }
2804    
2805     sub reload_archetypes {
2806 root 1.253 load_resource_file "$DATADIR/archetypes"
2807 root 1.246 or die "unable to load archetypes\n";
2808 root 1.289 #d# NEED to laod twice to resolve forward references
2809     # this really needs to be done in an extra post-pass
2810     # (which needs to be synchronous, so solve it differently)
2811     load_resource_file "$DATADIR/archetypes"
2812     or die "unable to load archetypes\n";
2813 root 1.241 }
2814    
2815 root 1.246 sub reload_treasures {
2816 root 1.253 load_resource_file "$DATADIR/treasures"
2817 root 1.246 or die "unable to load treasurelists\n";
2818 root 1.241 }
2819    
2820 root 1.223 sub reload_resources {
2821 root 1.245 warn "reloading resource files...\n";
2822    
2823 root 1.246 reload_regions;
2824     reload_facedata;
2825 root 1.274 #reload_archetypes;#d#
2826 root 1.246 reload_archetypes;
2827     reload_treasures;
2828 root 1.245
2829     warn "finished reloading resource files\n";
2830 root 1.223 }
2831    
2832     sub init {
2833     reload_resources;
2834 root 1.203 }
2835 root 1.34
2836 root 1.73 sub cfg_load {
2837 root 1.253 open my $fh, "<:utf8", "$CONFDIR/config"
2838 root 1.72 or return;
2839    
2840     local $/;
2841     *CFG = YAML::Syck::Load <$fh>;
2842 root 1.131
2843     $EMERGENCY_POSITION = $CFG{emergency_position} || ["/world/world_105_115", 5, 37];
2844    
2845 root 1.139 $cf::map::MAX_RESET = $CFG{map_max_reset} if exists $CFG{map_max_reset};
2846     $cf::map::DEFAULT_RESET = $CFG{map_default_reset} if exists $CFG{map_default_reset};
2847    
2848 root 1.131 if (exists $CFG{mlockall}) {
2849     eval {
2850 root 1.147 $CFG{mlockall} ? eval "mlockall()" : eval "munlockall()"
2851 root 1.131 and die "WARNING: m(un)lockall failed: $!\n";
2852     };
2853     warn $@ if $@;
2854     }
2855 root 1.72 }
2856    
2857 root 1.39 sub main {
2858 root 1.108 # we must not ever block the main coroutine
2859     local $Coro::idle = sub {
2860 root 1.115 Carp::cluck "FATAL: Coro::idle was called, major BUG, use cf::sync_job!\n";#d#
2861 root 1.175 (async {
2862     Event::one_event;
2863     })->prio (Coro::PRIO_MAX);
2864 root 1.108 };
2865    
2866 root 1.73 cfg_load;
2867 root 1.210 db_init;
2868 root 1.61 load_extensions;
2869 root 1.183
2870     $TICK_WATCHER->start;
2871 root 1.34 Event::loop;
2872     }
2873    
2874     #############################################################################
2875 root 1.155 # initialisation and cleanup
2876    
2877     # install some emergency cleanup handlers
2878     BEGIN {
2879     for my $signal (qw(INT HUP TERM)) {
2880     Event->signal (
2881 root 1.189 reentrant => 0,
2882     data => WF_AUTOCANCEL,
2883     signal => $signal,
2884 root 1.191 prio => 0,
2885 root 1.189 cb => sub {
2886 root 1.155 cf::cleanup "SIG$signal";
2887     },
2888     );
2889     }
2890     }
2891    
2892 root 1.281 sub write_runtime {
2893     my $runtime = "$LOCALDIR/runtime";
2894    
2895     # first touch the runtime file to show we are still running:
2896     # the fsync below can take a very very long time.
2897    
2898     IO::AIO::aio_utime $runtime, undef, undef;
2899    
2900     my $guard = cf::lock_acquire "write_runtime";
2901    
2902     my $fh = aio_open "$runtime~", O_WRONLY | O_CREAT, 0644
2903     or return;
2904    
2905     my $value = $cf::RUNTIME + 90 + 10;
2906     # 10 is the runtime save interval, for a monotonic clock
2907     # 60 allows for the watchdog to kill the server.
2908    
2909     (aio_write $fh, 0, (length $value), $value, 0) <= 0
2910     and return;
2911    
2912     # always fsync - this file is important
2913     aio_fsync $fh
2914     and return;
2915    
2916     # touch it again to show we are up-to-date
2917     aio_utime $fh, undef, undef;
2918    
2919     close $fh
2920     or return;
2921    
2922     aio_rename "$runtime~", $runtime
2923     and return;
2924    
2925     warn "runtime file written.\n";
2926    
2927     1
2928     }
2929    
2930 root 1.156 sub emergency_save() {
2931 root 1.155 my $freeze_guard = cf::freeze_mainloop;
2932    
2933     warn "enter emergency perl save\n";
2934    
2935     cf::sync_job {
2936     # use a peculiar iteration method to avoid tripping on perl
2937     # refcount bugs in for. also avoids problems with players
2938 root 1.167 # and maps saved/destroyed asynchronously.
2939 root 1.155 warn "begin emergency player save\n";
2940     for my $login (keys %cf::PLAYER) {
2941     my $pl = $cf::PLAYER{$login} or next;
2942     $pl->valid or next;
2943     $pl->save;
2944     }
2945     warn "end emergency player save\n";
2946    
2947     warn "begin emergency map save\n";
2948     for my $path (keys %cf::MAP) {
2949     my $map = $cf::MAP{$path} or next;
2950     $map->valid or next;
2951     $map->save;
2952     }
2953     warn "end emergency map save\n";
2954 root 1.208
2955     warn "begin emergency database checkpoint\n";
2956     BDB::db_env_txn_checkpoint $DB_ENV;
2957     warn "end emergency database checkpoint\n";
2958 root 1.155 };
2959    
2960     warn "leave emergency perl save\n";
2961     }
2962 root 1.22
2963 root 1.211 sub post_cleanup {
2964     my ($make_core) = @_;
2965    
2966     warn Carp::longmess "post_cleanup backtrace"
2967     if $make_core;
2968     }
2969    
2970 root 1.246 sub do_reload_perl() {
2971 root 1.106 # can/must only be called in main
2972     if ($Coro::current != $Coro::main) {
2973 root 1.183 warn "can only reload from main coroutine";
2974 root 1.106 return;
2975     }
2976    
2977 root 1.103 warn "reloading...";
2978    
2979 root 1.212 warn "entering sync_job";
2980    
2981 root 1.213 cf::sync_job {
2982 root 1.214 cf::write_runtime; # external watchdog should not bark
2983 root 1.212 cf::emergency_save;
2984 root 1.214 cf::write_runtime; # external watchdog should not bark
2985 root 1.183
2986 root 1.212 warn "syncing database to disk";
2987     BDB::db_env_txn_checkpoint $DB_ENV;
2988 root 1.106
2989     # if anything goes wrong in here, we should simply crash as we already saved
2990 root 1.65
2991 root 1.183 warn "cancelling all WF_AUTOCANCEL watchers";
2992 root 1.87 for (Event::all_watchers) {
2993     $_->cancel if $_->data & WF_AUTOCANCEL;
2994     }
2995 root 1.65
2996 root 1.183 warn "flushing outstanding aio requests";
2997     for (;;) {
2998 root 1.208 BDB::flush;
2999 root 1.183 IO::AIO::flush;
3000     Coro::cede;
3001 root 1.208 last unless IO::AIO::nreqs || BDB::nreqs;
3002 root 1.183 warn "iterate...";
3003     }
3004    
3005 root 1.223 ++$RELOAD;
3006    
3007 root 1.183 warn "cancelling all extension coros";
3008 root 1.103 $_->cancel for values %EXT_CORO;
3009     %EXT_CORO = ();
3010    
3011 root 1.183 warn "removing commands";
3012 root 1.159 %COMMAND = ();
3013    
3014 root 1.287 warn "removing ext/exti commands";
3015     %EXTCMD = ();
3016     %EXTICMD = ();
3017 root 1.159
3018 root 1.183 warn "unloading/nuking all extensions";
3019 root 1.159 for my $pkg (@EXTS) {
3020 root 1.160 warn "... unloading $pkg";
3021 root 1.159
3022     if (my $cb = $pkg->can ("unload")) {
3023     eval {
3024     $cb->($pkg);
3025     1
3026     } or warn "$pkg unloaded, but with errors: $@";
3027     }
3028    
3029 root 1.160 warn "... nuking $pkg";
3030 root 1.159 Symbol::delete_package $pkg;
3031 root 1.65 }
3032    
3033 root 1.183 warn "unloading all perl modules loaded from $LIBDIR";
3034 root 1.65 while (my ($k, $v) = each %INC) {
3035     next unless $v =~ /^\Q$LIBDIR\E\/.*\.pm$/;
3036    
3037 root 1.183 warn "... unloading $k";
3038 root 1.65 delete $INC{$k};
3039    
3040     $k =~ s/\.pm$//;
3041     $k =~ s/\//::/g;
3042    
3043     if (my $cb = $k->can ("unload_module")) {
3044     $cb->();
3045     }
3046    
3047     Symbol::delete_package $k;
3048     }
3049    
3050 root 1.183 warn "getting rid of safe::, as good as possible";
3051 root 1.65 Symbol::delete_package "safe::$_"
3052 root 1.103 for qw(cf::attachable cf::object cf::object::player cf::client cf::player cf::map cf::party cf::region);
3053 root 1.65
3054 root 1.183 warn "unloading cf.pm \"a bit\"";
3055 root 1.65 delete $INC{"cf.pm"};
3056 root 1.252 delete $INC{"cf/pod.pm"};
3057 root 1.65
3058     # don't, removes xs symbols, too,
3059     # and global variables created in xs
3060     #Symbol::delete_package __PACKAGE__;
3061    
3062 root 1.183 warn "unload completed, starting to reload now";
3063    
3064 root 1.103 warn "reloading cf.pm";
3065 root 1.65 require cf;
3066 root 1.100 cf::_connect_to_perl; # nominally unnecessary, but cannot hurt
3067    
3068 root 1.183 warn "loading config and database again";
3069 root 1.73 cf::cfg_load;
3070 root 1.65
3071 root 1.183 warn "loading extensions";
3072 root 1.65 cf::load_extensions;
3073    
3074 root 1.183 warn "reattaching attachments to objects/players";
3075 root 1.222 _global_reattach; # objects, sockets
3076 root 1.183 warn "reattaching attachments to maps";
3077 root 1.144 reattach $_ for values %MAP;
3078 root 1.222 warn "reattaching attachments to players";
3079     reattach $_ for values %PLAYER;
3080 root 1.183
3081 root 1.212 warn "leaving sync_job";
3082 root 1.183
3083 root 1.212 1
3084     } or do {
3085 root 1.106 warn $@;
3086     warn "error while reloading, exiting.";
3087     exit 1;
3088 root 1.212 };
3089 root 1.106
3090 root 1.159 warn "reloaded";
3091 root 1.65 };
3092    
3093 root 1.175 our $RELOAD_WATCHER; # used only during reload
3094    
3095 root 1.246 sub reload_perl() {
3096     # doing reload synchronously and two reloads happen back-to-back,
3097     # coro crashes during coro_state_free->destroy here.
3098    
3099     $RELOAD_WATCHER ||= Event->timer (
3100     reentrant => 0,
3101     after => 0,
3102     data => WF_AUTOCANCEL,
3103     cb => sub {
3104     do_reload_perl;
3105     undef $RELOAD_WATCHER;
3106     },
3107     );
3108     }
3109    
3110 root 1.111 register_command "reload" => sub {
3111 root 1.65 my ($who, $arg) = @_;
3112    
3113     if ($who->flag (FLAG_WIZ)) {
3114 root 1.175 $who->message ("reloading server.");
3115 root 1.246 async { reload_perl };
3116 root 1.65 }
3117     };
3118    
3119 root 1.27 unshift @INC, $LIBDIR;
3120 root 1.17
3121 root 1.183 my $bug_warning = 0;
3122    
3123 root 1.239 our @WAIT_FOR_TICK;
3124     our @WAIT_FOR_TICK_BEGIN;
3125    
3126     sub wait_for_tick {
3127 root 1.240 return unless $TICK_WATCHER->is_active;
3128 root 1.241 return if $Coro::current == $Coro::main;
3129    
3130 root 1.239 my $signal = new Coro::Signal;
3131     push @WAIT_FOR_TICK, $signal;
3132     $signal->wait;
3133     }
3134    
3135     sub wait_for_tick_begin {
3136 root 1.240 return unless $TICK_WATCHER->is_active;
3137 root 1.241 return if $Coro::current == $Coro::main;
3138    
3139 root 1.239 my $signal = new Coro::Signal;
3140     push @WAIT_FOR_TICK_BEGIN, $signal;
3141     $signal->wait;
3142     }
3143    
3144 root 1.268 my $min = 1e6;#d#
3145     my $avg = 10;
3146 root 1.35 $TICK_WATCHER = Event->timer (
3147 root 1.104 reentrant => 0,
3148 root 1.183 parked => 1,
3149 root 1.191 prio => 0,
3150 root 1.104 at => $NEXT_TICK || $TICK,
3151     data => WF_AUTOCANCEL,
3152     cb => sub {
3153 root 1.183 if ($Coro::current != $Coro::main) {
3154     Carp::cluck "major BUG: server tick called outside of main coro, skipping it"
3155     unless ++$bug_warning > 10;
3156     return;
3157     }
3158    
3159 root 1.265 $NOW = $tick_start = Event::time;
3160 root 1.163
3161 root 1.133 cf::server_tick; # one server iteration
3162 root 1.245
3163 root 1.268 0 && sync_job {#d#
3164     for(1..10) {
3165     my $t = Event::time;
3166     my $map = my $map = new_from_path cf::map "/tmp/x.map"
3167     or die;
3168    
3169     $map->width (50);
3170     $map->height (50);
3171     $map->alloc;
3172     $map->_load_objects ("/tmp/x.map", 1);
3173     my $t = Event::time - $t;
3174    
3175     #next unless $t < 0.0013;#d#
3176     if ($t < $min) {
3177     $min = $t;
3178     }
3179     $avg = $avg * 0.99 + $t * 0.01;
3180     }
3181     warn "XXXXXXXXXXXXXXXXXX min $min avg $avg\n";#d#
3182     exit 0;
3183     # 2007-05-22 02:33:04.569 min 0.00112509727478027 avg 0.0012259249572477
3184     };
3185    
3186 root 1.133 $RUNTIME += $TICK;
3187 root 1.35 $NEXT_TICK += $TICK;
3188    
3189 root 1.214 if ($NOW >= $NEXT_RUNTIME_WRITE) {
3190     $NEXT_RUNTIME_WRITE = $NOW + 10;
3191     Coro::async_pool {
3192     write_runtime
3193     or warn "ERROR: unable to write runtime file: $!";
3194     };
3195     }
3196    
3197 root 1.191 # my $AFTER = Event::time;
3198     # warn $AFTER - $NOW;#d#
3199 root 1.190
3200 root 1.245 if (my $sig = shift @WAIT_FOR_TICK_BEGIN) {
3201     $sig->send;
3202     }
3203     while (my $sig = shift @WAIT_FOR_TICK) {
3204     $sig->send;
3205     }
3206    
3207 root 1.265 $NOW = Event::time;
3208    
3209     # if we are delayed by four ticks or more, skip them all
3210     $NEXT_TICK = $NOW if $NOW >= $NEXT_TICK + $TICK * 4;
3211    
3212     $TICK_WATCHER->at ($NEXT_TICK);
3213     $TICK_WATCHER->start;
3214    
3215     $LOAD = ($NOW - $tick_start) / $TICK;
3216     $LOADAVG = $LOADAVG * 0.75 + $LOAD * 0.25;
3217    
3218 root 1.245 _post_tick;
3219 root 1.265
3220    
3221 root 1.35 },
3222     );
3223    
3224 root 1.206 {
3225     BDB::max_poll_time $TICK * 0.1;
3226     $BDB_POLL_WATCHER = Event->io (
3227     reentrant => 0,
3228     fd => BDB::poll_fileno,
3229     poll => 'r',
3230     prio => 0,
3231     data => WF_AUTOCANCEL,
3232     cb => \&BDB::poll_cb,
3233     );
3234     BDB::min_parallel 8;
3235    
3236     BDB::set_sync_prepare {
3237     my $status;
3238     my $current = $Coro::current;
3239     (
3240     sub {
3241     $status = $!;
3242     $current->ready; undef $current;
3243     },
3244     sub {
3245     Coro::schedule while defined $current;
3246     $! = $status;
3247     },
3248     )
3249     };
3250 root 1.77
3251 root 1.206 unless ($DB_ENV) {
3252     $DB_ENV = BDB::db_env_create;
3253    
3254     cf::sync_job {
3255 root 1.208 eval {
3256     BDB::db_env_open
3257     $DB_ENV,
3258 root 1.253 $BDBDIR,
3259 root 1.208 BDB::INIT_LOCK | BDB::INIT_LOG | BDB::INIT_MPOOL | BDB::INIT_TXN
3260     | BDB::RECOVER | BDB::REGISTER | BDB::USE_ENVIRON | BDB::CREATE,
3261     0666;
3262    
3263 root 1.253 cf::cleanup "db_env_open($BDBDIR): $!" if $!;
3264 root 1.208
3265     $DB_ENV->set_flags (BDB::AUTO_COMMIT | BDB::REGION_INIT | BDB::TXN_NOSYNC, 1);
3266     $DB_ENV->set_lk_detect;
3267     };
3268    
3269     cf::cleanup "db_env_open(db): $@" if $@;
3270 root 1.206 };
3271     }
3272     }
3273    
3274     {
3275     IO::AIO::min_parallel 8;
3276    
3277     undef $Coro::AIO::WATCHER;
3278     IO::AIO::max_poll_time $TICK * 0.1;
3279     $AIO_POLL_WATCHER = Event->io (
3280     reentrant => 0,
3281 root 1.214 data => WF_AUTOCANCEL,
3282 root 1.206 fd => IO::AIO::poll_fileno,
3283     poll => 'r',
3284     prio => 6,
3285     cb => \&IO::AIO::poll_cb,
3286     );
3287     }
3288 root 1.108
3289 root 1.262 my $_log_backtrace;
3290    
3291 root 1.260 sub _log_backtrace {
3292     my ($msg, @addr) = @_;
3293    
3294 root 1.262 $msg =~ s/\n//;
3295 root 1.260
3296 root 1.262 # limit the # of concurrent backtraces
3297     if ($_log_backtrace < 2) {
3298     ++$_log_backtrace;
3299     async {
3300     my @bt = fork_call {
3301     @addr = map { sprintf "%x", $_ } @addr;
3302     my $self = (-f "/proc/$$/exe") ? "/proc/$$/exe" : $^X;
3303     open my $fh, "exec addr2line -C -f -i -e \Q$self\E @addr 2>&1 |"
3304     or die "addr2line: $!";
3305    
3306     my @funcs;
3307     my @res = <$fh>;
3308     chomp for @res;
3309     while (@res) {
3310     my ($func, $line) = splice @res, 0, 2, ();
3311     push @funcs, "[$func] $line";
3312     }
3313 root 1.260
3314 root 1.262 @funcs
3315     };
3316 root 1.260
3317 root 1.262 LOG llevInfo, "[ABT] $msg\n";
3318     LOG llevInfo, "[ABT] $_\n" for @bt;
3319     --$_log_backtrace;
3320     };
3321     } else {
3322 root 1.260 LOG llevInfo, "[ABT] $msg\n";
3323 root 1.262 LOG llevInfo, "[ABT] [suppressed]\n";
3324     }
3325 root 1.260 }
3326    
3327 root 1.249 # load additional modules
3328     use cf::pod;
3329    
3330 root 1.125 END { cf::emergency_save }
3331    
3332 root 1.1 1
3333