ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/ext/map-random.ext
Revision: 1.39
Committed: Sat Mar 27 20:12:24 2010 UTC (14 years, 1 month ago) by root
Branch: MAIN
Changes since 1.38: +28 -1 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.5 cf::map->register (qr{^\?random/([0-9a-f]{32})});
6 root 1.1
7     sub init {
8     my ($self) = @_;
9    
10 root 1.5 $self->{random_id} = $1;
11    
12 root 1.14 if (0 < Coro::AIO::aio_load "$cf::RANDOMDIR/$self->{random_id}.meta", my $data) {
13 root 1.19 $self->{random} = cf::decode_json $data;
14 root 1.3 $self->{random}{custom} ||= "$self->{random}{origin_map}+$self->{random}{origin_x}+$self->{random}{origin_y}";
15 root 1.7 } else {
16     warn "unable to read meta file for $self->{random_id}\n";
17     return 0;
18 root 1.3 }
19 root 1.5
20     1
21 root 1.1 }
22    
23 root 1.6 sub thawer_merge {
24     # we have to keep some variables in memory intact
25     local $_[0]{random_id};
26     local $_[0]{random};
27    
28     $_[0]->SUPER::thawer_merge ($_[1]);
29     }
30    
31 root 1.1 sub visible_name {
32     my ($self) = @_;
33    
34 root 1.2 my $rmp = $self->{random};
35 root 1.4 "random map at $rmp->{custom}, level $rmp->{dungeon_level}"
36 root 1.1 }
37    
38     sub save_path {
39     my ($self) = @_;
40    
41 root 1.14 sprintf "%s/%s.map", $cf::RANDOMDIR, $self->{random_id}
42 root 1.1 }
43    
44     sub uniq_path {
45     undef
46     }
47    
48 root 1.8 sub load_header_orig {
49 root 1.1 my ($self) = @_;
50    
51 root 1.5 return unless $self->{random};
52    
53     $self->generate_random_map ($self->{random});
54 root 1.15 $self->activate;
55 root 1.5
56     1
57 root 1.1 }
58    
59 root 1.39 sub select_random_map {
60     my ($maps, $difficulty) = @_;
61    
62     # because I am lazy, I ignore the weighting
63    
64     my @maps = keys %$maps;
65    
66     cf::map::find "/styles/$maps[cf::rmg_rndm scalar @maps]"
67     }
68    
69 root 1.26 # called by the random map generator
70     sub find_style_;
71     sub find_style_($$) {
72     my ($path, $difficulty) = @_;
73    
74     my $map;
75    
76 root 1.39 # see if there is a metafile
77     if (0 < aio_load "$cf::MAPDIR/$path.rmg", my $meta) {
78     $meta = cf::decode_json $meta;
79    
80     # only "maps" is supported
81     if ($meta->{maps}) {
82     $map = select_random_map $meta->{maps}, $difficulty;
83     }
84     }
85    
86 root 1.26 $map = cf::map::find $path
87 root 1.27 unless aio_stat "$cf::MAPDIR/$path.map";
88 root 1.26
89     unless ($map) {
90     # search files and/or dirs
91 root 1.27 if (my ($dirs, $nondirs) = aio_scandir "$cf::MAPDIR/$path/", 1) {
92 root 1.26 my @entries = sort grep s/\.map$//, @$nondirs;
93    
94     if ($difficulty < 0) {
95     # pick a fully random map, but only a map, do not recurse
96     $map = cf::map::find "$path/$entries[cf::rmg_rndm scalar @entries]"
97     if @entries;
98     } else {
99     # pick a map with nearest difficulty value ("mapname_<difficulty>.map")
100     @entries = sort @$dirs
101     unless @entries;
102    
103     my $min_diff = 1e99;
104    
105     for my $name (@entries) {
106     if ($name =~ /_(\d+)$/) {
107     my $diff = abs $difficulty - $1 + 0.5; # prefer the more difficult version
108     ($map, $min_diff) = ($name, $diff) if $diff < $min_diff;
109     }
110     }
111    
112     unless ($map) {
113     # no map with given pattern found, choose a random map
114     $map = $entries[cf::rmg_rndm scalar @entries];
115     }
116    
117     $map = find_style_ "$path/$map", $difficulty
118     if $map;
119     }
120     }
121     }
122    
123     $map
124     }
125    
126     sub find_style($$$) {
127     my ($dir, $name, $difficulty) = @_;
128    
129     cf::cede_to_tick;
130    
131 root 1.39 my $map;
132    
133     if ($name) {
134     $map = find_style_ "$dir/$name", $difficulty;
135     } else {
136     $map = (find_style_ "$dir/default", $difficulty)
137     || (find_style_ $dir, $difficulty);
138     }
139 root 1.26
140     if ($map) {
141     $map->load;
142     $map->deactivate;
143     }
144    
145 root 1.28 #warn "return $dir,$name,$difficulty => $map\n" if $difficulty >= 0;#d#
146 root 1.26 $map
147     }
148    
149 root 1.38 cf::async_ext {
150     $Coro::current->{desc} = "random map meta file cleaner";
151     $Coro::current->nice (1);
152    
153     while () {
154     my $META_TIMEOUT = $cf::CFG{map_random_meta_timeout} || 86400 * 7;
155    
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     warn "resetting random meta data for $file";
171     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.31 xsize => (int rand 100) + 1,
189     ysize => (int rand 100) + 1,
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     my $t=EV::time;
222     $map->_save_objects ("/tmp/x", cf::IO_HEADER | cf::IO_OBJECTS | cf::IO_UNIQUES);
223     $t = EV::time-$t;
224     $m=$t if $m>$t;
225     warn $m;
226     }
227     };
228     }
229    
230 root 1.1 1
231