Skip to content

Commit

Permalink
Merge pull request #272 from louis-e/park-relation-fix
Browse files Browse the repository at this point in the history
Park relation fix and faster saving
  • Loading branch information
louis-e authored Jan 12, 2025
2 parents c2b9f87 + f60170e commit 49a5ed8
Show file tree
Hide file tree
Showing 9 changed files with 93 additions and 88 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Pre-release Dev Build
name: [DISABLED] Pre-release Dev Build

on:
push:
Expand Down
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ itertools = "0.14.0"
log = "0.4.22"
once_cell = "1.19.0"
rand = "0.8.5"
rayon = "1.10.0"
reqwest = { version = "0.12.7", features = ["blocking", "json"] }
rfd = "0.15.1"
semver = "1.0.23"
Expand Down
33 changes: 0 additions & 33 deletions gui-src/css/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -202,39 +202,6 @@ button:hover {
width: 100%;
}

.tooltip .tooltiptext {
visibility: hidden;
width: 90%;
background-color: #808080;
color: #fff;
text-align: center;
padding: 5px 0;
border-radius: 6px;

position: absolute;
z-index: 1;
bottom: -100%;
left: 5%;
opacity: 0;
transition: opacity 0.3s;
}

.tooltip .tooltiptext::after {
content: "";
position: absolute;
top: -10px;
left: 50%;
margin-left: -5px;
border-width: 5px;
border-style: solid;
border-color: transparent transparent #808080 transparent;
}

.tooltip:hover .tooltiptext {
visibility: visible;
opacity: 1;
}

.controls-box button {
width: 100%;
}
Expand Down
3 changes: 0 additions & 3 deletions gui-src/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,6 @@ <h2 data-localize="select_world">Select World</h2>
No world selected
</span>
</button>
<span class="tooltiptext" style="font-size: 0.8em; line-height: 1.2;">
Please select a Minecraft world that can be overwritten, as the generation process will replace existing structures in the chosen world!
</span>
</div>

<div class="button-container">
Expand Down
5 changes: 3 additions & 2 deletions src/data_processing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,7 @@ pub fn generate_world(

let ground_level: i32 = args.ground_level;
let region_dir: String = format!("{}/region", args.path);
let mut editor: WorldEditor =
WorldEditor::new(&region_dir, scale_factor_x, scale_factor_z, args);
let mut editor: WorldEditor = WorldEditor::new(&region_dir, scale_factor_x, scale_factor_z);

editor.set_sign(
"↑".to_string(),
Expand Down Expand Up @@ -118,6 +117,8 @@ pub fn generate_world(
);
} else if rel.tags.contains_key("water") {
water_areas::generate_water_areas(&mut editor, rel, ground_level);
} else if rel.tags.get("leisure") == Some(&"park".to_string()) {
leisure::generate_leisure_from_relation(&mut editor, rel, ground_level, args);
}
}
}
Expand Down
36 changes: 35 additions & 1 deletion src/element_processing/leisure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::block_definitions::*;
use crate::bresenham::bresenham_line;
use crate::element_processing::tree::create_tree;
use crate::floodfill::flood_fill_area;
use crate::osm_parser::ProcessedWay;
use crate::osm_parser::{ProcessedMemberRole, ProcessedRelation, ProcessedWay};
use crate::world_editor::WorldEditor;
use rand::Rng;

Expand Down Expand Up @@ -192,3 +192,37 @@ pub fn generate_leisure(
}
}
}

pub fn generate_leisure_from_relation(
editor: &mut WorldEditor,
rel: &ProcessedRelation,
ground_level: i32,
args: &Args,
) {
if rel.tags.get("leisure") == Some(&"park".to_string()) {
// First generate individual ways with their original tags
for member in &rel.members {
if member.role == ProcessedMemberRole::Outer {
generate_leisure(editor, &member.way, ground_level, args);
}
}

// Then combine all outer ways into one
let mut combined_nodes = Vec::new();
for member in &rel.members {
if member.role == ProcessedMemberRole::Outer {
combined_nodes.extend(member.way.nodes.clone());
}
}

// Create combined way with relation tags
let combined_way = ProcessedWay {
id: rel.id,
nodes: combined_nodes,
tags: rel.tags.clone(),
};

// Generate leisure area from combined way
generate_leisure(editor, &combined_way, ground_level, args);
}
}
6 changes: 4 additions & 2 deletions src/retrieve_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -171,9 +171,11 @@ pub fn fetch_data(
// General case for when there are no elements and no specific remark
eprintln!(
"{}",
"Error! No data available in this region.".red().bold()
"Error! API returned no data. Please try again!"
.red()
.bold()
);
emit_gui_error("No data available in this region.");
emit_gui_error("API returned no data. Please try again!");
}

if debug {
Expand Down
94 changes: 48 additions & 46 deletions src/world_editor.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
use crate::args::Args;
use crate::block_definitions::*;
use crate::progress::emit_gui_progress_update;
use colored::Colorize;
use fastanvil::Region;
use fastnbt::{LongArray, Value};
use fnv::FnvHashMap;
use indicatif::{ProgressBar, ProgressStyle};
use rayon::prelude::*;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::fs::File;
use std::io::Write;
use std::sync::atomic::{AtomicU64, Ordering};

#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
Expand Down Expand Up @@ -226,23 +227,21 @@ impl WorldToModify {
}
}

pub struct WorldEditor<'a> {
pub struct WorldEditor {
region_dir: String,
world: WorldToModify,
scale_factor_x: f64,
scale_factor_z: f64,
args: &'a Args,
}

impl<'a> WorldEditor<'a> {
impl WorldEditor {
/// Initializes the WorldEditor with the region directory and template region path.
pub fn new(region_dir: &str, scale_factor_x: f64, scale_factor_z: f64, args: &'a Args) -> Self {
pub fn new(region_dir: &str, scale_factor_x: f64, scale_factor_z: f64) -> Self {
Self {
region_dir: region_dir.to_string(),
world: WorldToModify::default(),
scale_factor_x,
scale_factor_z,
args,
}
}

Expand Down Expand Up @@ -437,10 +436,8 @@ impl<'a> WorldEditor<'a> {
println!("{} Saving world...", "[5/5]".bold());
emit_gui_progress_update(90.0, "Saving world...");

let _debug: bool = self.args.debug;
let total_regions: u64 = self.world.regions.len() as u64;

let save_pb: ProgressBar = ProgressBar::new(total_regions);
let total_regions = self.world.regions.len() as u64;
let save_pb = ProgressBar::new(total_regions);
save_pb.set_style(
ProgressStyle::default_bar()
.template(
Expand All @@ -452,49 +449,54 @@ impl<'a> WorldEditor<'a> {

let total_steps: f64 = 9.0;
let progress_increment_save: f64 = total_steps / total_regions as f64;
let mut current_progress_save: f64 = 90.0;
let mut last_emitted_progress: f64 = current_progress_save;

for ((region_x, region_z), region_to_modify) in &self.world.regions {
let mut region: Region<File> = self.create_region(*region_x, *region_z);

for chunk_x in 0..32 {
for chunk_z in 0..32 {
let data: Vec<u8> = region
.read_chunk(chunk_x as usize, chunk_z as usize)
.unwrap()
.unwrap();

let mut chunk: Chunk = fastnbt::from_bytes(&data).unwrap();

if let Some(chunk_to_modify) = region_to_modify.get_chunk(chunk_x, chunk_z) {
let current_progress = AtomicU64::new(900);
let regions_processed = AtomicU64::new(0);

self.world
.regions
.par_iter()
.for_each(|((region_x, region_z), region_to_modify)| {
// Create region and handle Result properly
let mut region = self.create_region(*region_x, *region_z);

// Reusable serialization buffer
let mut ser_buffer = Vec::with_capacity(8192);

// Process modified chunks
for (&(chunk_x, chunk_z), chunk_to_modify) in &region_to_modify.chunks {
if !chunk_to_modify.sections.is_empty() || !chunk_to_modify.other.is_empty() {
let data = region
.read_chunk(chunk_x as usize, chunk_z as usize)
.unwrap()
.unwrap_or_default();

let mut chunk: Chunk = fastnbt::from_bytes(&data).unwrap();
chunk.sections = chunk_to_modify.sections().collect();
chunk.other.extend(chunk_to_modify.other.clone());
chunk.x_pos = chunk_x + region_x * 32;
chunk.z_pos = chunk_z + region_z * 32;
chunk.is_light_on = 0;

ser_buffer.clear();
fastnbt::to_writer(&mut ser_buffer, &chunk).unwrap();
region
.write_chunk(chunk_x as usize, chunk_z as usize, &ser_buffer)
.unwrap();
}
}

chunk.x_pos = chunk_x + region_x * 32;
chunk.z_pos = chunk_z + region_z * 32;
chunk.is_light_on = 0; // Force minecraft to recompute

let ser: Vec<u8> = fastnbt::to_bytes(&chunk).unwrap();
// Update progress
let regions_done = regions_processed.fetch_add(1, Ordering::SeqCst);
let new_progress = (90.0 + (regions_done as f64 * progress_increment_save)) * 10.0;
let prev_progress =
current_progress.fetch_max(new_progress as u64, Ordering::SeqCst);

// Write chunk data back to the correct location, ensuring correct chunk coordinates
let expected_chunk_location: (usize, usize) =
((chunk_x as usize) & 31, (chunk_z as usize) & 31);
region
.write_chunk(expected_chunk_location.0, expected_chunk_location.1, &ser)
.unwrap();
if new_progress as u64 - prev_progress > 1 {
emit_gui_progress_update(new_progress / 10.0, "Saving world...");
}
}

save_pb.inc(1);

current_progress_save += progress_increment_save;
if (current_progress_save - last_emitted_progress).abs() > 0.25 {
emit_gui_progress_update(current_progress_save, "Saving world...");
last_emitted_progress = current_progress_save;
}
}
save_pb.inc(1);
});

save_pb.finish();
}
Expand Down

0 comments on commit 49a5ed8

Please sign in to comment.