--- deliantra/server/lib/cf.pm 2007/01/08 23:36:16 1.153 +++ deliantra/server/lib/cf.pm 2007/01/09 15:36:19 1.154 @@ -17,6 +17,7 @@ use Coro::Semaphore; use Coro::AIO; +use Data::Dumper; use Digest::MD5; use Fcntl; use IO::AIO 2.32 (); @@ -156,8 +157,29 @@ =over 4 +=item dumpval $ref + =cut +sub dumpval { + eval { + local $SIG{__DIE__}; + my $d; + if (1) { + $d = new Data::Dumper([$_[0]], ["*var"]); + $d->Terse(1); + $d->Indent(2); + $d->Quotekeys(0); + $d->Useqq(1); + #$d->Bless(...); + $d->Seen($_[1]) if @_ > 1; + $d = $d->Dump(); + } + $d =~ s/([\x00-\x07\x09\x0b\x0c\x0e-\x1f])/sprintf "\\x%02x", ord($1)/ge; + $d + } || "[unable to dump $_[0]: '$@']"; +} + use JSON::Syck (); # TODO# replace by JSON::PC once working =item $ref = cf::from_json $json @@ -337,6 +359,9 @@ package cf::path; +# used to convert map paths into valid unix filenames by repalcing / by ∕ +our $PATH_SEP = "∕"; # U+2215, chosen purely for visual reasons + sub new { my ($class, $path, $base) = @_; @@ -409,8 +434,7 @@ # escape the /'s in the path sub _escaped_path { - # ∕ is U+2215 - (my $path = $_[0]{path}) =~ s/\//∕/g; + (my $path = $_[0]{path}) =~ s/\//$PATH_SEP/g; $path } @@ -1078,6 +1102,8 @@ package cf::player; +use Coro::AIO; + =head3 cf::player =over 4 @@ -1139,7 +1165,7 @@ return if $pl->{deny_save}; - Coro::AIO::aio_mkdir playerdir $pl, 0770; + aio_mkdir playerdir $pl, 0770; $pl->{last_save} = $cf::RUNTIME; $pl->save_pl ($path); @@ -1159,6 +1185,13 @@ $self } +=item $pl->quit_character + +Nukes the player without looking back. If logged in, the connection will +be destroyed. May block for a long time. + +=cut + sub quit_character { my ($pl) = @_; @@ -1172,12 +1205,64 @@ my $path = playerdir $pl; my $temp = "$path~$cf::RUNTIME~deleting~"; - Coro::AIO::aio_rename $path, $temp; + aio_rename $path, $temp; delete $cf::PLAYER{$pl->ob->name}; $pl->destroy; IO::AIO::aio_rmtree $temp; } +=item cf::player::list_logins + +Returns am arrayref of all valid playernames in the system, can take a +while and may block, so not sync_job-capable, ever. + +=cut + +sub list_logins { + my $dirs = aio_readdir cf::localdir . "/" . cf::playerdir + or return []; + + my @logins; + + for my $login (@$dirs) { + my $fh = aio_open path $login, Fcntl::O_RDONLY, 0 or next; + aio_read $fh, 0, 512, my $buf, 0 or next; + $buf !~ /^password -------------$/ or next; # official not-valid tag + + utf8::decode $login; + push @logins, $login; + } + + \@logins +} + +=item $player->maps + +Returns an arrayref of cf::path's of all maps that are private for this +player. May block. + +=cut + +sub maps($) { + my ($pl) = @_; + + my $files = aio_readdir playerdir $pl + or return; + + my @paths; + + for (@$files) { + utf8::decode $_; + next if /\.(?:pl|pst)$/; + next unless /^$PATH_SEP/; + + s/$PATH_SEP/\//g; + push @paths, new cf::path "~" . $pl->ob->name . "/" . $_; + } + + \@paths +} + =item $player->ext_reply ($msgid, $msgtype, %msg) Sends an ext reply to the player.