--- deliantra/server/ext/00_map_handling.ext 2006/12/30 10:16:10 1.1 +++ deliantra/server/ext/00_map_handling.ext 2006/12/31 10:28:36 1.8 @@ -132,14 +132,15 @@ 1 } -(Coro::unblock_sub { +(Coro::async { unless (write_runtime) { warn "unable to write runtime file: $!"; exit 1; } -})->(); +})->prio (Coro::PRIO_MAX); our $SCHEDULER = cf::coro { + Coro::Timer::sleep 3600;#d#TODO#for debugging only while () { Coro::Timer::sleep $SCHEDULE_INTERVAL; @@ -149,6 +150,7 @@ for my $map (values %cf::MAP) { eval { next if $map->in_memory != cf::MAP_IN_MEMORY; + next if $map->players; my $last_access = $map->last_access; # not yet, because maps might become visible to players nearby # we need a tiled meta map for this to work @@ -173,6 +175,47 @@ }; $SCHEDULER->prio (-2); +sub generate_random_map { + my ($path, $rmp) = @_; + + # mit "rum" bekleckert, nicht + cf::map::_create_random_map + $path, + $rmp->{wallstyle}, $rmp->{wall_name}, $rmp->{floorstyle}, $rmp->{monsterstyle}, + $rmp->{treasurestyle}, $rmp->{layoutstyle}, $rmp->{doorstyle}, $rmp->{decorstyle}, + $rmp->{origin_map}, $rmp->{final_map}, $rmp->{exitstyle}, $rmp->{this_map}, + $rmp->{exit_on_final_map}, + $rmp->{xsize}, $rmp->{ysize}, + $rmp->{expand2x}, $rmp->{layoutoptions1}, $rmp->{layoutoptions2}, $rmp->{layoutoptions3}, + $rmp->{symmetry}, $rmp->{difficulty}, $rmp->{difficulty_given}, $rmp->{difficulty_increase}, + $rmp->{dungeon_level}, $rmp->{dungeon_depth}, $rmp->{decoroptions}, $rmp->{orientation}, + $rmp->{origin_y}, $rmp->{origin_x}, $rmp->{random_seed}, $rmp->{total_map_hp}, + $rmp->{map_layout_style}, $rmp->{treasureoptions}, $rmp->{symmetry_used}, + $rmp->{region} +} + +sub parse_random_map_params { + my ($spec) = @_; + + my $rmp; + + for (split /\n/, $spec) { + my ($k, $v) = split /\s+/, $_, 2; + + $rmp->{lc $k} = $v if (length $k) && (length $v); + } + + $rmp +} + +sub prepare_random_map { + my ($exit) = @_; + + my $rmp = parse_random_map_params $exit->msg; + use Data::Dumper; + die Dumper $rmp; +} + sub sync_job(&) { my ($job) = @_; @@ -183,7 +226,7 @@ local $cf::FREEZE = 1; - (async { + (Coro::async { @res = eval { $job->() }; warn $@ if $@; $done = 1; @@ -194,8 +237,7 @@ Event::one_event unless Coro::nready; } - warn "job done<@res>\n";#d# - + warn "sync<@res>\n";#d# wantarray ? @res : $res[0] } @@ -224,19 +266,18 @@ $map->reset_timeout (10);#d# $map->{load_path} = $path; - warn "load header from $path\n";#d# $map } -sub cf::map::find_map_nb { +sub cf::map::find_map { my ($path, $origin) = @_; + warn "find_map<$path,$origin>\n";#d# + $path = ref $path ? $path : new cf::path $path, $origin && $origin->path; my $key = $path->as_string; - warn "find_map_nb<$path,$origin>\n";#d# - $cf::MAP{$key} || do { # do it the slow way my $map = try_load_header $path->save_path; @@ -244,11 +285,13 @@ if (!$map) { $map = try_load_header $path->load_path or return; - } - $map or return; + $map->instantiate; + + # per-player maps become, after loading, normal maps + $map->per_player (0) if $path->{user_rel}; + } - $map->instantiate; $map->path ($key); $map->{path} = $path; @@ -258,23 +301,10 @@ } } -sub cf::map::find_map { - my ($path, $origin) = @_; - - $path = new cf::path $path, $origin && $origin->path; - my $key = $path->as_string; - - warn "find_map<$path,$origin>\n";#d# - - $cf::MAP{$key} || sync_job { - cf::map::find_map_nb $path; - } -} - -sub cf::map::do_load_nb { +sub cf::map::load { my ($self) = @_; - return 0 unless $self->in_memory == cf::MAP_SWAPPED; + return if $self->in_memory != cf::MAP_SWAPPED; $self->in_memory (cf::MAP_LOADING); @@ -300,18 +330,22 @@ $self->set_darkness_map; $self->difficulty ($self->estimate_difficulty) unless $self->difficulty; + $self->activate; $self->in_memory (cf::MAP_IN_MEMORY); } -sub cf::map::do_load { - my ($self) = @_; +sub cf::map::load_map_sync { + my ($path, $origin) = @_; - warn "do_load<$self>\n";#d# + warn "load_map_sync<$path, $origin>\n";#d# sync_job { - cf::map::do_load_nb $self; - }; + my $map = cf::map::find_map $path, $origin + or return; + $map->load; + $map + } } sub cf::map::save { @@ -333,12 +367,22 @@ $self->{last_save} = $cf::RUNTIME; } +sub cf::map::swap_out { + my ($self) = @_; + + return if $self->players; + return if $self->in_memory != cf::MAP_IN_MEMORY; + + $self->save; + $self->clear; + $self->in_memory (cf::MAP_SWAPPED); +} + sub cf::map::should_reset { my ($map) = @_; # TODO: safety, remove and allow resettable per-player maps return if $map->{path}{user_rel};#d# - return if $map->per_player; return unless $map->reset_timeout; my $time = $map->fixed_resettime ? $map->reset_time : $map->last_access; @@ -350,68 +394,69 @@ my ($self) = @_; return if $self->players; + return if $self->{path}{user_rel};#d# warn "resetting map ", $self->path;#d# - return;#d# - $self->clear; - $self->in_memory (cf::MAP_SWAPPED); - $self->{load_path} = $self->{path}->load_path; - utf8::encode $self->{load_path}; -} + utf8::encode (my $save = $self->{path}->save_path); + aioreq_pri 3; IO::AIO::aio_unlink $save; + aioreq_pri 3; IO::AIO::aio_unlink "$save.pst"; -sub cf::map::swap_out { - my ($self) = @_; - - $self->save; $self->clear; $self->in_memory (cf::MAP_SWAPPED); + utf8::encode ($self->{load_path} = $self->{path}->load_path); } sub cf::object::player::enter_exit { my ($ob, $exit) = @_; - warn "enter_exit\n";#d# + return unless $ob->type == cf::PLAYER; + + my ($oldmap, $oldx, $oldy) = ($ob->map, $ob->x, $ob->y); + + #TODO: do this in the background, freeze the player if required sync_job { - warn "enter_exit<$ob,$exit>\n";#d# + my ($map, $x, $y); - if ($exit) { - my $path = new cf::path $exit->slaying, $exit->map && $exit->map->path; + if ($exit->slaying eq "/!") { + prepare_random_map $exit; + } - my $map = cf::map::find_map_nb $path->as_string; - $map = $map->customise_for ($ob) if $map; + my $path = new cf::path $exit->slaying, $exit->map && $exit->map->path; - if ($map) { - $map->do_load_nb; - $ob->enter_map ($map, $exit->stats->hp, $exit->stats->sp); - } else { - $ob->message ("The exit is closed", cf::NDI_UNIQUE | cf::NDI_RED); - } - } else { - # used on login only(?) - my $map = cf::map::find_map_nb $ob->contr->maplevel; - my ($x, $y) = ($ob->x, $ob->y); + $map = cf::map::find_map $path->as_string; + $map = $map->customise_for ($ob) if $map; + ($x, $y) = ($exit->stats->hp, $exit->stats->sp); + + unless ($map) { + $ob->message ("The exit is closed", cf::NDI_UNIQUE | cf::NDI_RED); + + # restore original map position + ($map, $x, $y) = ($oldmap, $oldx, $oldy); unless ($map) { - $map = cf::map::find_map_nb $emergency_position->[0] + $map = cf::map::find_map $emergency_position->[0] or die "FATAL: cannot load emergency map\n"; $x = $emergency_position->[1]; $y = $emergency_position->[2]; } - - $map->do_load_nb; - $ob->enter_map ($map, $x, $y); } + + # use -1, -1 as default coordinates, not 0, 0 + ($x, $y) = ($map->enter_x, $map->enter_y) + if $x <=0 && $y <= 0; + + warn "entering ", $map->path, " at ($x, $y)\n";#d# + $map->load; + $ob->enter_map ($map, $x, $y); } } sub cf::map::customise_for { my ($map, $ob) = @_; - warn "customise_for<$map,$ob>\n";#d# - if ($map->per_player) { - return cf::map::find_map_nb "~" . $ob->name . "/" . $map->{path}{path}; + return cf::map::find_map "~" . $ob->name . "/" . $map->{path}{path}; } $map @@ -420,10 +465,16 @@ sub cf::map::emergency_save { local $cf::FREEZE = 1; - warn "begin emergency map save\n"; - $_->save for values %cf::MAP; - warn "emergency map save drain\n"; + warn "enter emergency map save\n"; + my $saver = async { + warn "begin emergency map save\n"; + $_->save for values %cf::MAP; + }; + $saver->prio (Coro::PRIO_MAX); + $saver->join; + + warn "emergency map save drain\n"; Event::one_event while IO::AIO::nreqs; warn "end emergency map save\n"; }