Skip to content

Commit 3043ca6

Browse files
committed
Fix stuck at 70% generation
1 parent 44cc57c commit 3043ca6

File tree

2 files changed

+71
-9
lines changed

2 files changed

+71
-9
lines changed

src/floodfill.rs

Lines changed: 70 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -68,18 +68,30 @@ fn optimized_flood_fill_area(
6868

6969
// Pre-allocate queue with reasonable capacity to avoid reallocations
7070
let mut queue = VecDeque::with_capacity(1024);
71+
let mut iterations = 0u64;
72+
const MAX_ITERATIONS: u64 = 1_000_000; // Safety limit to prevent infinite loops
7173

7274
for z in (min_z..=max_z).step_by(step_z as usize) {
7375
for x in (min_x..=max_x).step_by(step_x as usize) {
74-
// Fast timeout check - only every few iterations
75-
if filled_area.len() % 100 == 0 {
76+
// Check timeout more frequently for small areas
77+
if iterations % 50 == 0 {
7678
if let Some(timeout) = timeout {
7779
if start_time.elapsed() > *timeout {
7880
return filled_area;
7981
}
8082
}
8183
}
8284

85+
// Safety check: prevent infinite loops
86+
iterations += 1;
87+
if iterations > MAX_ITERATIONS {
88+
eprintln!(
89+
"Warning: Flood fill exceeded max iterations ({}), aborting",
90+
MAX_ITERATIONS
91+
);
92+
return filled_area;
93+
}
94+
8395
// Skip if already visited or not inside polygon
8496
if global_visited.contains(&(x, z))
8597
|| !polygon.contains(&Point::new(x as f64, z as f64))
@@ -93,6 +105,25 @@ fn optimized_flood_fill_area(
93105
global_visited.insert((x, z));
94106

95107
while let Some((curr_x, curr_z)) = queue.pop_front() {
108+
// Additional iteration check inside inner loop
109+
iterations += 1;
110+
if iterations > MAX_ITERATIONS {
111+
eprintln!(
112+
"Warning: Flood fill exceeded max iterations ({}), aborting",
113+
MAX_ITERATIONS
114+
);
115+
return filled_area;
116+
}
117+
118+
// Timeout check in inner loop for problematic polygons
119+
if iterations % 1000 == 0 {
120+
if let Some(timeout) = timeout {
121+
if start_time.elapsed() > *timeout {
122+
return filled_area;
123+
}
124+
}
125+
}
126+
96127
// Add current point to filled area
97128
filled_area.push((curr_x, curr_z));
98129

@@ -155,19 +186,31 @@ fn original_flood_fill_area(
155186
// Pre-allocate queue and reserve space for filled_area
156187
let mut queue: VecDeque<(i32, i32)> = VecDeque::with_capacity(2048);
157188
filled_area.reserve(1000); // Reserve space to reduce reallocations
189+
let mut iterations = 0u64;
190+
const MAX_ITERATIONS: u64 = 1_000_000; // Safety limit to prevent infinite loops
158191

159192
// Scan for multiple seed points to handle U-shapes and concave polygons
160193
for z in (min_z..=max_z).step_by(step_z as usize) {
161194
for x in (min_x..=max_x).step_by(step_x as usize) {
162-
// Reduced timeout checking frequency for better performance
163-
// Use manual % check since is_multiple_of() is unstable on stable Rust
164-
#[allow(clippy::manual_is_multiple_of)]
165-
if let Some(timeout) = timeout {
166-
if &start_time.elapsed() > timeout {
167-
return filled_area;
195+
// Check timeout more frequently for problematic polygons
196+
if iterations % 50 == 0 {
197+
if let Some(timeout) = timeout {
198+
if &start_time.elapsed() > timeout {
199+
return filled_area;
200+
}
168201
}
169202
}
170203

204+
// Safety check: prevent infinite loops
205+
iterations += 1;
206+
if iterations > MAX_ITERATIONS {
207+
eprintln!(
208+
"Warning: Flood fill exceeded max iterations ({}), aborting",
209+
MAX_ITERATIONS
210+
);
211+
return filled_area;
212+
}
213+
171214
// Skip if already processed or not inside polygon
172215
if global_visited.contains(&(x, z))
173216
|| !polygon.contains(&Point::new(x as f64, z as f64))
@@ -181,6 +224,25 @@ fn original_flood_fill_area(
181224
global_visited.insert((x, z));
182225

183226
while let Some((curr_x, curr_z)) = queue.pop_front() {
227+
// Additional iteration check inside inner loop
228+
iterations += 1;
229+
if iterations > MAX_ITERATIONS {
230+
eprintln!(
231+
"Warning: Flood fill exceeded max iterations ({}), aborting",
232+
MAX_ITERATIONS
233+
);
234+
return filled_area;
235+
}
236+
237+
// Timeout check in inner loop
238+
if iterations % 1000 == 0 {
239+
if let Some(timeout) = timeout {
240+
if &start_time.elapsed() > timeout {
241+
return filled_area;
242+
}
243+
}
244+
}
245+
184246
// Only check polygon containment once per point when adding to filled_area
185247
if polygon.contains(&Point::new(curr_x as f64, curr_z as f64)) {
186248
filled_area.push((curr_x, curr_z));

src/gui.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ pub fn run_gui() {
8888
tauri::Builder::default()
8989
.plugin(
9090
LogBuilder::default()
91-
.level(LevelFilter::Trace)
91+
.level(LevelFilter::Warn)
9292
.targets([
9393
Target::new(TargetKind::LogDir {
9494
file_name: Some("arnis".into()),

0 commit comments

Comments
 (0)