--- deliantra/server/lib/cf.pm 2007/04/05 13:44:31 1.234 +++ deliantra/server/lib/cf.pm 2007/04/16 10:14:25 1.240 @@ -18,6 +18,7 @@ use Coro::Signal; use Coro::Semaphore; use Coro::AIO; +use Coro::Storable; use BDB (); use Data::Dumper; @@ -30,6 +31,7 @@ # configure various modules to our taste # +$Storable::canonical = 1; # reduce rsync transfers Coro::State::cctx_stacksize 256000; # 1-2MB stack, for deep recursions in maze generator Compress::LZF::sfreeze_cr { }; # prime Compress::LZF so it does not use require later @@ -76,9 +78,6 @@ our $RANDOM_MAPS = cf::localdir . "/random"; our $BDB_ENV_DIR = cf::localdir . "/db"; -our $WAIT_FOR_TICK; $WAIT_FOR_TICK ||= new Coro::Signal; -our $WAIT_FOR_TICK_ONE; $WAIT_FOR_TICK_ONE ||= new Coro::Signal; - # used to convert map paths into valid unix filenames by replacing / by ∕ our $PATH_SEP = "∕"; # U+2215, chosen purely for visual reasons @@ -136,12 +135,11 @@ Configuration for the server, loaded from C, or from wherever your confdir points to. -=item $cf::WAIT_FOR_TICK, $cf::WAIT_FOR_TICK_ONE +=item cf::wait_for_tick, cf::wait_for_tick_begin -These are Coro::Signal objects that are C<< ->broadcast >> (WAIT_FOR_TICK) -or C<< ->send >> (WAIT_FOR_TICK_ONE) on after normal server tick -processing has been done. Call C<< ->wait >> on them to maximise the -window of cpu time available, or simply to synchronise to the server tick. +These are functions that inhibit the current coroutine one tick. cf::wait_for_tick_begin only +returns directly I the tick processing (and consequently, can only wake one process +per tick), while cf::wait_for_tick wakes up all waiters after tick processing. =back @@ -1159,10 +1157,36 @@ $self->ns->ext_event ($type, %msg); } -package cf; +=head3 cf::region -=back +=over 4 + +=cut + +package cf::region; + +=item cf::region::find_by_path $path + +Tries to decuce the probable region for a map knowing only its path. + +=cut + +sub find_by_path($) { + my ($path) = @_; + my ($match, $specificity); + + for my $region (list) { + if ($region->match && $path =~ $region->match) { + ($match, $specificity) = ($region, $region->specificity) + if $region->specificity > $specificity; + } + } + + $match +} + +=back =head3 cf::map @@ -1403,6 +1427,9 @@ $self->prepare_orig; } + $self->default_region (cf::region::find_by_path $self->{path}) + unless $self->default_region; + 1 } @@ -1454,6 +1481,7 @@ $self->alloc; $self->pre_load; + Coro::cede; $self->_load_objects ($self->{load_path}, 1) or return; @@ -1470,9 +1498,9 @@ } Coro::cede; - # now do the right thing for maps $self->link_multipart_objects; + Coro::cede; unless ($self->{deny_activate}) { $self->decay_objects; @@ -1484,9 +1512,11 @@ unless $self->difficulty; Coro::cede; $self->activate; + Coro::cede; } $self->post_load; + Coro::cede; $self->in_memory (cf::MAP_IN_MEMORY); } @@ -2309,36 +2339,48 @@ warn "loading facedata from $path\n"; - my $faces; - 0 < aio_load $path, $faces + my $facedata; + 0 < aio_load $path, $facedata or die "$path: $!"; - Coro::cede; - $faces = Storable::thaw $faces; - Coro::cede; + $facedata = Coro::Storable::thaw $facedata; - my $meta = delete $faces->{""}; - $meta->{version} == 1 + $facedata->{version} == 2 or cf::cleanup "$path: version mismatch, cannot proceed."; - 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_data $idx, 0, $info->{data32}, $info->{chksum32}; - cf::face::set_data $idx, 1, $info->{data64}, $info->{chksum64}; - Coro::cede; + { + my $faces = $facedata->{faceinfo}; + + 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_data $idx, 0, $info->{data32}, $info->{chksum32}; + cf::face::set_data $idx, 1, $info->{data64}, $info->{chksum64}; + Coro::cede; + } + + while (my ($face, $info) = each %$faces) { + next unless $info->{smooth}; + my $idx = cf::face::find $face + or next; + if (my $smooth = cf::face::find $info->{smooth}) { + cf::face::set_smooth $idx, $smooth, $info->{smoothlevel}; + } else { + warn "smooth face '$info->{smooth}' not found for face '$face'"; + } + Coro::cede; + } } - while (my ($face, $info) = each %$faces) { - next unless $info->{smooth}; - my $idx = cf::face::find $face - or next; - if (my $smooth = cf::face::find $info->{smooth}) { - cf::face::set_smooth $idx, $smooth; - } else { - warn "smooth face '$info->{smooth}' not found for face '$face'"; + { + my $anims = $facedata->{animinfo}; + + while (my ($anim, $info) = each %$anims) { + cf::anim::set $anim, $info->{frames}, $info->{facings}; + Coro::cede; } - Coro::cede; + + cf::anim::invalidate_all; # d'oh } 1 @@ -2602,6 +2644,23 @@ my $bug_warning = 0; +our @WAIT_FOR_TICK; +our @WAIT_FOR_TICK_BEGIN; + +sub wait_for_tick { + return unless $TICK_WATCHER->is_active; + my $signal = new Coro::Signal; + push @WAIT_FOR_TICK, $signal; + $signal->wait; +} + +sub wait_for_tick_begin { + return unless $TICK_WATCHER->is_active; + my $signal = new Coro::Signal; + push @WAIT_FOR_TICK_BEGIN, $signal; + $signal->wait; +} + $TICK_WATCHER = Event->timer ( reentrant => 0, parked => 1, @@ -2629,8 +2688,12 @@ }; } - $WAIT_FOR_TICK->broadcast; - $WAIT_FOR_TICK_ONE->send if $WAIT_FOR_TICK_ONE->awaited; + if (my $sig = shift @WAIT_FOR_TICK_BEGIN) { + $sig->send; + } + while (my $sig = shift @WAIT_FOR_TICK) { + $sig->send; + } # my $AFTER = Event::time; # warn $AFTER - $NOW;#d#