ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/ext/map-random.ext
Revision: 1.47
Committed: Fri Feb 3 03:01:45 2012 UTC (12 years, 3 months ago) by root
Branch: MAIN
CVS Tags: rel-3_1, HEAD
Changes since 1.46: +2 -2 lines
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 root 1.17 #! perl # mandatory
2 root 1.1
3 root 1.26 use Coro::AIO;
4    
5 root 1.47 CONF META_TIMEOUT : map_random_meta_timeout = 86400 * 7;
6    
7 root 1.5 cf::map->register (qr{^\?random/([0-9a-f]{32})});
8 root 1.1
9     sub init {
10     my ($self) = @_;
11    
12 root 1.5 $self->{random_id} = $1;
13    
14 root 1.14 if (0 < Coro::AIO::aio_load "$cf::RANDOMDIR/$self->{random_id}.meta", my $data) {
15 root 1.19 $self->{random} = cf::decode_json $data;
16 root 1.3 $self->{random}{custom} ||= "$self->{random}{origin_map}+$self->{random}{origin_x}+$self->{random}{origin_y}";
17 root 1.7 } else {
18 root 1.45 cf::info "unable to read meta file for $self->{random_id}\n";
19 root 1.7 return 0;
20 root 1.3 }
21 root 1.5
22     1
23 root 1.1 }
24    
25 root 1.6 sub thawer_merge {
26     # we have to keep some variables in memory intact
27     local $_[0]{random_id};
28     local $_[0]{random};
29    
30     $_[0]->SUPER::thawer_merge ($_[1]);
31     }
32    
33 root 1.1 sub visible_name {
34     my ($self) = @_;
35    
36 root 1.2 my $rmp = $self->{random};
37 root 1.4 "random map at $rmp->{custom}, level $rmp->{dungeon_level}"
38 root 1.1 }
39    
40     sub save_path {
41     my ($self) = @_;
42    
43 root 1.14 sprintf "%s/%s.map", $cf::RANDOMDIR, $self->{random_id}
44 root 1.1 }
45    
46     sub uniq_path {
47     undef
48     }
49    
50 root 1.8 sub load_header_orig {
51 root 1.1 my ($self) = @_;
52    
53 root 1.5 return unless $self->{random};
54    
55     $self->generate_random_map ($self->{random});
56 root 1.15 $self->activate;
57 root 1.5
58     1
59 root 1.1 }
60    
61 root 1.39 sub select_random_map {
62     my ($maps, $difficulty) = @_;
63    
64     # because I am lazy, I ignore the weighting
65    
66     my @maps = keys %$maps;
67    
68     cf::map::find "/styles/$maps[cf::rmg_rndm scalar @maps]"
69     }
70    
71 root 1.26 # called by the random map generator
72     sub find_style_;
73 root 1.41 sub find_style_($$$) {
74     my ($path, $difficulty, $recurse) = @_;
75 root 1.26
76     my $map;
77    
78 root 1.39 # see if there is a metafile
79     if (0 < aio_load "$cf::MAPDIR/$path.rmg", my $meta) {
80     $meta = cf::decode_json $meta;
81    
82     # only "maps" is supported
83     if ($meta->{maps}) {
84     $map = select_random_map $meta->{maps}, $difficulty;
85     }
86     }
87    
88 root 1.26 $map = cf::map::find $path
89 root 1.27 unless aio_stat "$cf::MAPDIR/$path.map";
90 root 1.26
91     unless ($map) {
92     # search files and/or dirs
93 root 1.27 if (my ($dirs, $nondirs) = aio_scandir "$cf::MAPDIR/$path/", 1) {
94 root 1.41 my @entries = sort grep s/\.(?:map|rmg)$//, @$nondirs;
95 root 1.26
96     if ($difficulty < 0) {
97     # pick a fully random map, but only a map, do not recurse
98     $map = cf::map::find "$path/$entries[cf::rmg_rndm scalar @entries]"
99     if @entries;
100     } else {
101     # pick a map with nearest difficulty value ("mapname_<difficulty>.map")
102     @entries = sort @$dirs
103 root 1.41 unless @entries || !$recurse;
104 root 1.26
105     my $min_diff = 1e99;
106    
107     for my $name (@entries) {
108     if ($name =~ /_(\d+)$/) {
109 root 1.41 my $diff = abs $difficulty - $1 + 0.25 + 0.25 * cf::rmg_rndm; # prefer the more difficult version
110 root 1.26 ($map, $min_diff) = ($name, $diff) if $diff < $min_diff;
111     }
112     }
113    
114     unless ($map) {
115     # no map with given pattern found, choose a random map
116     $map = $entries[cf::rmg_rndm scalar @entries];
117     }
118    
119     $map = find_style_ "$path/$map", $difficulty
120     if $map;
121     }
122     }
123     }
124    
125     $map
126     }
127    
128 root 1.41 sub find_style($$$$) {
129     my ($dir, $name, $difficulty, $recurse) = @_;
130 root 1.42
131 root 1.26 cf::cede_to_tick;
132    
133 root 1.39 my $map;
134    
135     if ($name) {
136 root 1.41 $map = find_style_ "$dir/$name", $difficulty, $recurse;
137 root 1.39 } else {
138 root 1.41 $map = (find_style_ "$dir/default", $difficulty, $recurse)
139     || (find_style_ $dir, $difficulty, $recurse);
140 root 1.39 }
141 root 1.26
142     if ($map) {
143     $map->load;
144     $map->deactivate;
145     }
146    
147 root 1.28 #warn "return $dir,$name,$difficulty => $map\n" if $difficulty >= 0;#d#
148 root 1.26 $map
149     }
150    
151 root 1.38 cf::async_ext {
152 root 1.43 local $Coro::current->{desc} = "random map meta file cleaner";
153 root 1.38 $Coro::current->nice (1);
154    
155     while () {
156     Coro::AnyEvent::idle_upto $META_TIMEOUT / 10 * 2;
157    
158     my ($files) = Coro::AIO::aio_readdirx $cf::RANDOMDIR, IO::AIO::READDIR_STAT_ORDER
159     or return;
160    
161     for my $file (@$files) {
162     next unless $file =~ /\.meta$/;
163    
164     Coro::AIO::aio_stat "$cf::RANDOMDIR/$file"
165     and next;
166    
167     my $age = $cf::NOW - (stat _)[8];
168    
169     if ($age > $META_TIMEOUT) {
170 root 1.45 cf::trace "resetting random meta data for $file";
171 root 1.38 IO::AIO::aio_unlink "$cf::RANDOMDIR/$file";
172     }
173     }
174    
175     Coro::AnyEvent::sleep $META_TIMEOUT / 10;
176     }
177 root 1.18 };
178 root 1.3
179 root 1.20 # map generator stresstest, NEVER enable under normal circumstances
180 root 1.29 if ($ENV{STRESSTEST}) {
181 root 1.11 cf::async {
182     my $seed = 0;
183     while () {
184     my $map = cf::map::new;
185     $map->generate_random_map ({
186     region => "scorn",
187     random_seed => $seed++,
188 root 1.44 xsize => (cf::rndm 1, 100),
189     ysize => (cf::rndm 1, 100),
190 root 1.11 });
191 root 1.29 warn sprintf "%d: %dx%d o# %d\n", $seed, $map->width, $map->height, &cf::object::objects_size;#d#
192 root 1.11 $map->destroy;
193     }
194     };
195     }
196    
197 root 1.25 # prefetch test, load some ocean-maps
198     if (0) {
199     cf::async {
200     # 0.58
201     Coro::Timer::sleep 2;
202     for my $x (200..219) {
203     for my $y (200..219) {
204     (cf::map::find "/world/world_$x\_$y")->load;
205     }
206     }
207     };
208     }
209    
210 root 1.35 # save test
211 root 1.37 if (0) {
212 root 1.35 cf::async {
213 root 1.37 # 0.080
214 root 1.35 Coro::Timer::sleep 2;
215     my $map = cf::map::find "/mlab/citydeclouds2";
216     $map->load_header;
217     $map->load;
218     $map->post_load_original;
219     my $m=100;
220     for (1..50) {
221 root 1.40 my $t=AE::time;
222 root 1.35 $map->_save_objects ("/tmp/x", cf::IO_HEADER | cf::IO_OBJECTS | cf::IO_UNIQUES);
223 root 1.40 $t = AE::time-$t;
224 root 1.35 $m=$t if $m>$t;
225     warn $m;
226     }
227     };
228     }
229