--- deliantra/server/lib/cf.pm 2007/07/03 05:14:15 1.293 +++ deliantra/server/lib/cf.pm 2007/07/14 14:33:30 1.306 @@ -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; } @@ -2239,19 +2258,20 @@ $self->enter_map ($map, $x, $y); } -=item $player_object->goto ($path, $x, $y[, $check->($map)]) +=item $player_object->goto ($path, $x, $y[, $check->($map)[, $done->()]]) Moves the player to the given map-path and coordinates by first freezing her, loading and preparing them map, calling the provided $check callback that has to return the map if sucecssful, and then unfreezes the player on -the new (success) or old (failed) map position. +the new (success) or old (failed) map position. In either case, $done will +be called at the end of this process. =cut our $GOTOGEN; sub cf::object::player::goto { - my ($self, $path, $x, $y, $check) = @_; + my ($self, $path, $x, $y, $check, $done) = @_; # do generation counting so two concurrent goto's will be executed in-order my $gen = $self->{_goto_generation} = ++$GOTOGEN; @@ -2281,6 +2301,8 @@ delete $self->{_goto_generation}; $self->leave_link ($map, $x, $y); } + + $done->() if $done; })->prio (1); } @@ -2359,6 +2381,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 +2435,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 { @@ -2442,6 +2470,8 @@ sub cf::client::ext_event($$%) { my ($self, $type, %msg) = @_; + return unless $self->extcmd; + $msg{msgtype} = "event_$type"; $self->send_packet ("ext " . $self->{json_coder}->encode (\%msg)); } @@ -2578,15 +2608,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 +2727,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 +2740,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 +2755,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 {