--- deliantra/server/lib/cf.pm 2007/07/03 05:14:15 1.293 +++ deliantra/server/lib/cf.pm 2007/07/11 16:55:18 1.304 @@ -31,6 +31,7 @@ use IO::AIO 2.32 (); use Time::HiRes; use Compress::LZF; +use Digest::MD5 (); # configure various modules to our taste # @@ -411,6 +412,15 @@ =cut +sub _store_scalar { + open my $fh, ">", \my $buf + or die "fork_call: cannot open fh-to-buf in child : $!"; + Storable::store_fd $_[0], $fh; + close $fh; + + $buf +} + sub fork_call(&@) { my ($cb, @args) = @_; @@ -423,22 +433,31 @@ close $fh2; my $res = (Coro::Handle::unblock $fh1)->readline (undef); + warn "pst<$res>" unless $res =~ /^pst/; $res = Coro::Storable::thaw $res; waitpid $pid, 0; # should not block anymore, we expect the child to simply behave - die $$res unless "ARRAY" eq ref $res; + Carp::confess $$res unless "ARRAY" eq ref $res; return wantarray ? @$res : $res->[-1]; } else { reset_signals; local $SIG{__WARN__}; local $SIG{__DIE__}; + # just in case, this hack effectively disables event + # in the child. cleaner and slower would be canceling all watchers, + # but this works for the time being. + local $Coro::idle; + $Coro::current->prio (Coro::PRIO_MAX); + eval { close $fh1; my @res = eval { $cb->(@args) }; - syswrite $fh2, Coro::Storable::freeze +($@ ? \"$@" : \@res); + + syswrite $fh2, _store_scalar $@ ? \"$@" : \@res; + close $fh2; }; warn $@ if $@; @@ -1414,10 +1433,10 @@ s/(?<=\S)\n(?=\w)/ /g; # compress some whitespace - 1 while s/\s*\n\s*\n\s*/\n/; - - s/^\s+//; - s/\s+$//; + s/\s+\n/\n/g; # ws line-ends + s/\n\n+/\n/g; # double lines + s/^\n+//; # beginning lines + s/\n+$//; # ending lines $_ } @@ -1472,7 +1491,7 @@ my ($match, $specificity); for my $region (list) { - if ($region->match && $path =~ $region->match) { + if ($region->{match} && $path =~ $region->{match}) { ($match, $specificity) = ($region, $region->specificity) if $region->specificity > $specificity; } @@ -2359,6 +2378,10 @@ $self->enter_link; + # if exit is damned, update players death & WoR home-position + $self->contr->savebed ($slaying, $hp, $sp) + if $exit->flag (FLAG_DAMNED); + (async { $self->deactivate_recursive; # just to be sure unless (eval { @@ -2409,6 +2432,8 @@ $msg = $self->pl->expand_cfpod ($msg); + return unless @extra || length $msg; + if ($self->can_msg) { $self->send_packet ("msg " . $self->{json_coder}->encode ([$color, $type, $msg, @extra])); } else { @@ -2578,15 +2603,24 @@ The following functions and methods are available within a safe environment: - cf::object contr pay_amount pay_player map - cf::object::player player - cf::player peaceful - cf::map trigger + cf::object + contr pay_amount pay_player map x y force_find force_add + insert remove + + cf::object::player + player + + cf::player + peaceful + + cf::map + trigger =cut for ( - ["cf::object" => qw(contr pay_amount pay_player map)], + ["cf::object" => qw(contr pay_amount pay_player map force_find force_add x y + insert remove)], ["cf::object::player" => qw(player)], ["cf::player" => qw(peaceful)], ["cf::map" => qw(trigger)], @@ -2688,10 +2722,12 @@ while (my ($face, $info) = each %$faces) { my $idx = (cf::face::find $face) || cf::face::alloc $face; - cf::face::set $idx, $info->{visibility}, $info->{magicmap}; + cf::face::set_visibility $idx, $info->{visibility}; + cf::face::set_magicmap $idx, $info->{magicmap}; cf::face::set_data $idx, 0, $info->{data32}, $info->{chksum32}; cf::face::set_data $idx, 1, $info->{data64}, $info->{chksum64}; - Coro::cede; + + cf::cede_to_tick; } while (my ($face, $info) = each %$faces) { @@ -2699,11 +2735,13 @@ my $idx = cf::face::find $face or next; if (my $smooth = cf::face::find $info->{smooth}) { - cf::face::set_smooth $idx, $smooth, $info->{smoothlevel}; + cf::face::set_smooth $idx, $smooth; + cf::face::set_smoothlevel $idx, $info->{smoothlevel}; } else { warn "smooth face '$info->{smooth}' not found for face '$face'"; } - Coro::cede; + + cf::cede_to_tick; } } @@ -2712,18 +2750,46 @@ while (my ($anim, $info) = each %$anims) { cf::anim::set $anim, $info->{frames}, $info->{facings}; - Coro::cede; + cf::cede_to_tick; } cf::anim::invalidate_all; # d'oh } + { + # TODO: for gcfclient pleasure, we should give resources + # that gcfclient doesn't grok a >10000 face index. + my $res = $facedata->{resource}; + my $enc = JSON::XS->new->utf8->canonical; + + while (my ($name, $info) = each %$res) { + my $meta = $enc->encode ({ + name => $name, + type => $info->{type}, + copyright => $info->{copyright}, #TODO# + }); + my $data = pack "(w/a*)*", $meta, $info->{data}; + my $chk = Digest::MD5::md5 "$info->{chksum},$meta"; # mangle data checksum and metadata + + my $idx = (cf::face::find $name) || cf::face::alloc $name; + cf::face::set_type $idx, 1; + cf::face::set_data $idx, 0, $data, $chk; + + cf::cede_to_tick; + } + } + 1 } sub reload_regions { load_resource_file "$MAPDIR/regions" or die "unable to load regions file\n"; + + for (cf::region::list) { + $_->{match} = qr/$_->{match}/ + if exists $_->{match}; + } } sub reload_facedata {