Compare commits

...

6 Commits
v2.4.0 ... main

Author SHA1 Message Date
Louis Erbkamm
5d97391820 Merge pull request #664 from louis-e/single-bbox 2025-12-07 20:32:41 +01:00
louis-e
bef3cfb090 Allow only one bbox selection at a time 2025-12-07 19:37:49 +01:00
Louis Erbkamm
5a898944f7 Merge pull request #663 from louis-e/fix-world-lock-during-map-preview
Fix world lock held during map preview generation
2025-12-07 19:24:40 +01:00
louis-e
9fdd960009 Fix world lock held during map preview generation 2025-12-07 18:18:12 +01:00
Louis Erbkamm
58e4a337d9 Merge pull request #661 from louis-e/disable-transparent
Disable transparent flag
2025-12-07 15:06:33 +01:00
louis-e
236a7e5af9 Disable transparent flag 2025-12-07 15:04:02 +01:00
4 changed files with 102 additions and 42 deletions

View File

@@ -275,6 +275,8 @@ pub fn generate_world_with_options(
// Save world
editor.save();
emit_gui_progress_update(99.0, "Finalizing world...");
// Update player spawn Y coordinate based on terrain height after generation
#[cfg(feature = "gui")]
if world_format == WorldFormat::JavaAnvil {
@@ -303,8 +305,6 @@ pub fn generate_world_with_options(
}
}
emit_gui_progress_update(99.0, "Finalizing world...");
// For Bedrock format, emit event to open the mcworld file
if world_format == WorldFormat::BedrockMcWorld {
if let Some(path_str) = output_path.to_str() {
@@ -312,41 +312,72 @@ pub fn generate_world_with_options(
}
}
// Generate top-down map preview silently in background after completion (Java only)
// Skip map preview for very large areas to avoid memory issues
const MAX_MAP_PREVIEW_AREA: i64 = 6400 * 6900;
let world_width = (xzbbox.max_x() - xzbbox.min_x()) as i64;
let world_height = (xzbbox.max_z() - xzbbox.min_z()) as i64;
let world_area = world_width * world_height;
if world_format == WorldFormat::JavaAnvil && world_area <= MAX_MAP_PREVIEW_AREA {
let world_path = args.path.clone();
let bounds = (
xzbbox.min_x(),
xzbbox.max_x(),
xzbbox.min_z(),
xzbbox.max_z(),
);
std::thread::spawn(move || {
// Use catch_unwind to prevent any panic from affecting the application
let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
map_renderer::render_world_map(&world_path, bounds.0, bounds.1, bounds.2, bounds.3)
}));
match result {
Ok(Ok(_path)) => {
// Notify the GUI that the map preview is ready
emit_map_preview_ready();
}
Ok(Err(e)) => {
eprintln!("Warning: Failed to generate map preview: {}", e);
}
Err(_) => {
eprintln!("Warning: Map preview generation panicked unexpectedly");
}
}
});
}
Ok(output_path)
}
/// Information needed to generate a map preview after world generation is complete
#[derive(Clone)]
pub struct MapPreviewInfo {
pub world_path: PathBuf,
pub min_x: i32,
pub max_x: i32,
pub min_z: i32,
pub max_z: i32,
pub world_area: i64,
}
impl MapPreviewInfo {
/// Create MapPreviewInfo from world bounds
pub fn new(world_path: PathBuf, xzbbox: &XZBBox) -> Self {
let world_width = (xzbbox.max_x() - xzbbox.min_x()) as i64;
let world_height = (xzbbox.max_z() - xzbbox.min_z()) as i64;
Self {
world_path,
min_x: xzbbox.min_x(),
max_x: xzbbox.max_x(),
min_z: xzbbox.min_z(),
max_z: xzbbox.max_z(),
world_area: world_width * world_height,
}
}
}
/// Maximum area for which map preview generation is allowed (to avoid memory issues)
pub const MAX_MAP_PREVIEW_AREA: i64 = 6400 * 6900;
/// Start map preview generation in a background thread.
/// This should be called AFTER the world generation is complete, the session lock is released,
/// and the GUI has been notified of 100% completion.
///
/// For Java worlds only, and only if the world area is within limits.
pub fn start_map_preview_generation(info: MapPreviewInfo) {
if info.world_area > MAX_MAP_PREVIEW_AREA {
return;
}
std::thread::spawn(move || {
// Use catch_unwind to prevent any panic from affecting the application
let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
map_renderer::render_world_map(
&info.world_path,
info.min_x,
info.max_x,
info.min_z,
info.max_z,
)
}));
match result {
Ok(Ok(_path)) => {
// Notify the GUI that the map preview is ready
emit_map_preview_ready();
}
Ok(Err(e)) => {
eprintln!("Warning: Failed to generate map preview: {}", e);
}
Err(_) => {
eprintln!("Warning: Map preview generation panicked unexpectedly");
}
}
});
}

View File

@@ -963,17 +963,27 @@ fn gui_start_generation(
let _ = data_processing::generate_world_with_options(
parsed_elements,
xzbbox,
xzbbox.clone(),
args.bbox,
ground,
&args,
generation_options,
generation_options.clone(),
);
// Explicitly release session lock before showing Done message
// so Minecraft can open the world immediately
drop(_session_lock);
emit_gui_progress_update(100.0, "Done! World generation completed.");
println!("{}", "Done! World generation completed.".green().bold());
// Start map preview generation silently in background (Java only)
if world_format == WorldFormat::JavaAnvil {
let preview_info = data_processing::MapPreviewInfo::new(
generation_options.path.clone(),
&xzbbox,
);
data_processing::start_map_preview_generation(preview_info);
}
return Ok(());
}
@@ -1006,7 +1016,7 @@ fn gui_start_generation(
let _ = data_processing::generate_world_with_options(
parsed_elements,
xzbbox,
xzbbox.clone(),
args.bbox,
ground,
&args,
@@ -1017,6 +1027,16 @@ fn gui_start_generation(
drop(_session_lock);
emit_gui_progress_update(100.0, "Done! World generation completed.");
println!("{}", "Done! World generation completed.".green().bold());
// Start map preview generation silently in background (Java only)
if world_format == WorldFormat::JavaAnvil {
let preview_info = data_processing::MapPreviewInfo::new(
generation_options.path.clone(),
&xzbbox,
);
data_processing::start_map_preview_generation(preview_info);
}
Ok(())
}
Err(e) => {

9
src/gui/js/bbox.js vendored
View File

@@ -899,6 +899,15 @@ $(document).ready(function () {
});
}
// If it's a rectangle, remove any existing rectangles first
if (e.layerType === 'rectangle') {
drawnItems.eachLayer(function(layer) {
if (layer instanceof L.Rectangle) {
drawnItems.removeLayer(layer);
}
});
}
// Check if it's a rectangle and set proper styles before adding it to the layer
if (e.layerType === 'rectangle') {
e.layer.setStyle({

View File

@@ -16,7 +16,7 @@
"minWidth": 1000,
"minHeight": 650,
"resizable": true,
"transparent": true,
"transparent": false,
"center": true,
"theme": "Dark",
"additionalBrowserArgs": "--disable-features=VizDisplayCompositor"