--- deliantra/server/lib/cf.pm 2007/01/21 21:28:27 1.189 +++ deliantra/server/lib/cf.pm 2007/02/05 18:29:20 1.205 @@ -10,7 +10,7 @@ use Safe; use Safe::Hole; -use Coro 3.4 (); +use Coro 3.5 (); use Coro::Event; use Coro::Timer; use Coro::Signal; @@ -50,6 +50,7 @@ our $WRITE_RUNTIME_WATCHER; our $NEXT_TICK; our $NOW; +our $USE_FSYNC = 1; # use fsync to write maps - default off our %CFG; @@ -85,6 +86,8 @@ our $EMERGENCY_POSITION; +sub cf::map::normalise; + ############################################################################# =head2 GLOBAL VARIABLES @@ -358,6 +361,7 @@ (aio_write $fh, 0, (length $value), $value, 0) <= 0 and return; + # always fsync - this file is important aio_fsync $fh and return; @@ -752,7 +756,7 @@ if (my $fh = aio_open "$filename~", O_WRONLY | O_CREAT, 0600) { chmod SAVE_MODE, $fh; aio_write $fh, 0, (length $$rdata), $$rdata, 0; - aio_fsync $fh; + aio_fsync $fh if $cf::USE_FSYNC; close $fh; if (@$objs) { @@ -760,7 +764,7 @@ chmod SAVE_MODE, $fh; my $data = Storable::nfreeze { version => 1, objs => $objs }; aio_write $fh, 0, (length $data), $data, 0; - aio_fsync $fh; + aio_fsync $fh if $cf::USE_FSYNC; close $fh; aio_rename "$filename.pst~", "$filename.pst"; } @@ -776,6 +780,12 @@ aio_unlink $filename; aio_unlink "$filename.pst"; } + + #d##TODO# nuke non .map-files if exist + if ($filename =~ s/\.map$//) { + aio_unlink $filename; + aio_unlink "$filename.pst"; + } } } @@ -792,6 +802,9 @@ my ($data, $av); + #d#TODO remove .map if file does not exist + aio_stat $filename and $filename =~ s/\.map$//; + (aio_load $filename, $data) >= 0 or return; @@ -1070,6 +1083,8 @@ sub maps($) { my ($pl) = @_; + $pl = ref $pl ? $pl->ob->name : $pl; + my $files = aio_readdir playerdir $pl or return; @@ -1080,8 +1095,7 @@ next if /\.(?:pl|pst)$/; next unless /^$PATH_SEP/o; - s/\.map$//; - push @paths, "~" . $pl->ob->name . "/" . $_; + push @paths, cf::map::normalise "~$pl/$_"; } \@paths @@ -1178,6 +1192,10 @@ sub normalise { my ($path, $base) = @_; + $path = "$path"; # make sure its a string + + $path =~ s/\.map$//; + # map plan: # # /! non-realised random map exit (special hack!) @@ -1223,7 +1241,7 @@ } } - Carp::carp "unable to resolve path '$path'."; + Carp::carp "unable to resolve path '$path' (base '$base')."; () } @@ -1248,7 +1266,7 @@ sub load_path { my ($self) = @_; - sprintf "%s/%s/%s", cf::datadir, cf::mapdir, $self->{path} + sprintf "%s/%s/%s.map", cf::datadir, cf::mapdir, $self->{path} } # the temporary/swap location @@ -1256,7 +1274,7 @@ my ($self) = @_; (my $path = $_[0]{path}) =~ s/\//$PATH_SEP/g; - sprintf "%s/%s/%s", cf::localdir, cf::tmpdir, $path + sprintf "%s/%s/%s.map", cf::localdir, cf::tmpdir, $path } # the unique path, undef == no special unique path @@ -1282,14 +1300,19 @@ utf8::encode (my $save = $self->save_path); IO::AIO::aioreq_pri 4; Coro::AIO::aio_unlink $save; IO::AIO::aioreq_pri 4; Coro::AIO::aio_unlink "$save.pst"; + + #d#TODO remove .map and also nuke + $save =~ s/\.map// or return;#d# + IO::AIO::aioreq_pri 4; Coro::AIO::aio_unlink $save;#d# + IO::AIO::aioreq_pri 4; Coro::AIO::aio_unlink "$save.pst";#d# } sub load_header_from($) { my ($self, $path) = @_; utf8::encode $path; - aio_open $path, O_RDONLY, 0 - or return; + #aio_open $path, O_RDONLY, 0 + # or return; $self->_load_header ($path) or return; @@ -1362,13 +1385,12 @@ $map->load_header or return; - if ($map->should_reset) { + if ($map->should_reset && 0) {#d#TODO# disabled, crashy (locking issue?) # doing this can freeze the server in a sync job, obviously #$cf::WAIT_FOR_TICK->wait; $map->reset; undef $guard; - $map = find $path - or return; + return find $path; } $cf::MAP{$path} = $map @@ -1381,6 +1403,8 @@ sub load { my ($self) = @_; + local $self->{deny_reset} = 1; # loading can take a long time + my $path = $self->{path}; my $guard = cf::lock_acquire "map_load:$path"; @@ -1627,8 +1651,7 @@ next if /\.pst$/; next unless /^$PATH_SEP/o; - s/\.map$//; - push @paths, $_; + push @paths, cf::map::normalise $_; } \@paths @@ -1732,7 +1755,7 @@ sub link_map { unless ($LINK_MAP) { $LINK_MAP = cf::map::find "{link}" - or do { warn "FATAL: unable to provide {link} map, exiting."; exit 1 }; + or cf::cleanup "FATAL: unable to provide {link} map, exiting."; $LINK_MAP->load; } @@ -1749,7 +1772,7 @@ $self->{_link_pos} ||= [$self->map->{path}, $self->x, $self->y] if $self->map; - $self->enter_map ($LINK_MAP || link_map, 20, 20); + $self->enter_map ($LINK_MAP || link_map, 10, 10); } sub cf::object::player::leave_link { @@ -1826,13 +1849,12 @@ $self->enter_link; (async { - my $map = cf::map::find $path; - $map = $map->customise_for ($self) if $map; - -# warn "entering ", $map->path, " at ($x, $y)\n" -# if $map; - - $map or $self->message ("The exit to '" . ($path->visible_name) . "' is closed", cf::NDI_UNIQUE | cf::NDI_RED); + my $map = eval { + my $map = cf::map::find $path; + $map = $map->customise_for ($self) if $map; + $map + } or + $self->message ("The exit to '$path' is closed", cf::NDI_UNIQUE | cf::NDI_RED); $self->leave_link ($map, $x, $y); })->prio (1); @@ -1873,7 +1895,7 @@ my $rmp = parse_random_map_params $exit->msg; if ($exit->map) { - $rmp->{region} = $exit->map->region_name; + $rmp->{region} = $exit->region->name; $rmp->{origin_map} = $exit->map->path; $rmp->{origin_x} = $exit->x; $rmp->{origin_y} = $exit->y; @@ -1900,16 +1922,21 @@ return unless $self->type == cf::PLAYER; + if ($exit->slaying eq "/!") { + #TODO: this should de-fi-ni-te-ly not be a sync-job + cf::sync_job { prepare_random_map $exit }; + } + + my $slaying = cf::map::normalise $exit->slaying, $exit->map && $exit->map->path; + my $hp = $exit->stats->hp; + my $sp = $exit->stats->sp; + $self->enter_link; (async { $self->deactivate_recursive; # just to be sure unless (eval { - prepare_random_map $exit - if $exit->slaying eq "/!"; - - my $path = new_from_path cf::map $exit->slaying, $exit->map && $exit->map->path; - $self->goto ($path, $exit->stats->hp, $exit->stats->sp); + $self->goto ($slaying, $hp, $sp); 1; }) { @@ -1980,6 +2007,7 @@ or return; # be conservative, not sure how that can happen, but we saw a crash here (shift @$queue)->[1]->($msg); + return unless $ns->valid; # temporary(?) workaround for callback destroying socket push @{ $ns->{query_queue} }, @$queue; @@ -2246,7 +2274,12 @@ } ############################################################################# -# the server's main() +# the server's init and main functions + +sub load_resources { + load_regions sprintf "%s/%s/regions", cf::datadir, cf::mapdir + or die "unable to load regions file\n";#d# +} sub cfg_load { open my $fh, "<:utf8", cf::confdir . "/config" @@ -2269,6 +2302,10 @@ } } +sub init { + load_resources; +} + sub main { # we must not ever block the main coroutine local $Coro::idle = sub { @@ -2296,6 +2333,7 @@ reentrant => 0, data => WF_AUTOCANCEL, signal => $signal, + prio => 0, cb => sub { cf::cleanup "SIG$signal"; }, @@ -2436,6 +2474,9 @@ warn "reattaching attachments to maps"; reattach $_ for values %MAP; + warn "loading reloadable resources"; + load_resources; + warn "restarting server ticker"; $TICK_WATCHER->start; @@ -2499,6 +2540,12 @@ $WAIT_FOR_TICK->broadcast; $WAIT_FOR_TICK_ONE->send if $WAIT_FOR_TICK_ONE->awaited; + Event::sweep; + Coro::cede_notself; + +# my $AFTER = Event::time; +# warn $AFTER - $NOW;#d# + # if we are delayed by four ticks or more, skip them all $NEXT_TICK = Event::time if Event::time >= $NEXT_TICK + $TICK * 4; @@ -2507,7 +2554,7 @@ }, ); -IO::AIO::max_poll_time $TICK * 0.2; +IO::AIO::max_poll_time $TICK * 0.1; undef $Coro::AIO::WATCHER; $AIO_POLL_WATCHER = Event->io (