Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prepare release #315

Merged
merged 2 commits into from
Jan 21, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.lock

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

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "arnis"
version = "2.1.3"
version = "2.2.0"
edition = "2021"
description = "Arnis - Generate real life cities in Minecraft"
homepage = "https://github.com/louis-e/arnis"
Expand Down
4 changes: 2 additions & 2 deletions src/data_processing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ pub fn generate_world(
}

// Set sign for player orientation
editor.set_sign(
/*editor.set_sign(
"↑".to_string(),
"Generated World".to_string(),
"This direction".to_string(),
Expand All @@ -221,7 +221,7 @@ pub fn generate_world(
-61,
9,
6,
);
);*/

ground_pb.inc(block_counter % batch_size);
ground_pb.finish();
Expand Down
187 changes: 105 additions & 82 deletions src/world_editor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,7 @@ impl WorldEditor {
self.world.get_block(x, y, z).is_some()
}

#[allow(clippy::too_many_arguments)]
#[allow(clippy::too_many_arguments, dead_code)]
pub fn set_sign(
&mut self,
line1: String,
Expand Down Expand Up @@ -537,100 +537,84 @@ impl WorldEditor {
.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)
// Read existing chunk data if it exists
let existing_data = region.read_chunk(chunk_x as usize, chunk_z as usize)
.unwrap()
.unwrap_or_default();

// Parse existing chunk or create new one
let mut chunk: Chunk = if !existing_data.is_empty() {
fastnbt::from_bytes(&existing_data).unwrap()
} else {
Chunk {
sections: Vec::new(),
x_pos: chunk_x + (region_x * 32),
z_pos: chunk_z + (region_z * 32),
is_light_on: 0,
other: FnvHashMap::default(),
}
};

// Update sections while preserving existing data
let new_sections: Vec<Section> = chunk_to_modify.sections().collect();
for new_section in new_sections {
if let Some(existing_section) = chunk.sections.iter_mut()
.find(|s| s.y == new_section.y)
{
// Merge block states
existing_section.block_states.palette = new_section.block_states.palette;
existing_section.block_states.data = new_section.block_states.data;
} else {
// Add new section if it doesn't exist
chunk.sections.push(new_section);
}
}

// Preserve existing block entities and merge with new ones
if let Some(existing_entities) = chunk.other.get_mut("block_entities") {
if let Some(new_entities) = chunk_to_modify.other.get("block_entities") {
if let (Value::List(existing), Value::List(new)) = (existing_entities, new_entities) {
// Remove old entities that are replaced by new ones
existing.retain(|e| {
if let Value::Compound(map) = e {
let (x, y, z) = get_entity_coords(map);
!new.iter().any(|new_e| {
if let Value::Compound(new_map) = new_e {
let (nx, ny, nz) = get_entity_coords(new_map);
x == nx && y == ny && z == nz
} else {
false
}
})
} else {
true
}
});
// Add new entities
existing.extend(new.clone());
}
}
} else {
// If no existing entities, just add the new ones
if let Some(new_entities) = chunk_to_modify.other.get("block_entities") {
chunk.other.insert("block_entities".to_string(), new_entities.clone());
}
}

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

// Create Level wrapper for modified chunks too
let level_data = HashMap::from([(
"Level".to_string(),
Value::Compound(HashMap::from([
("xPos".to_string(), Value::Int(chunk.x_pos)),
("zPos".to_string(), Value::Int(chunk.z_pos)),
(
"isLightOn".to_string(),
Value::Byte(i8::try_from(chunk.is_light_on).unwrap()),
),
(
"sections".to_string(),
Value::List(
chunk
.sections
.iter()
.map(|section| {
Value::Compound(HashMap::from([
("Y".to_string(), Value::Byte(section.y)),
(
"block_states".to_string(),
Value::Compound(HashMap::from([
(
"palette".to_string(),
Value::List(
section
.block_states
.palette
.iter()
.map(|item| {
Value::Compound(
HashMap::from([(
"Name"
.to_string(
),
Value::String(
item.name
.clone(
),
),
)]),
)
})
.collect(),
),
),
(
"data".to_string(),
Value::LongArray(
section
.block_states
.data
.clone()
.unwrap_or_else(|| {
LongArray::new(vec![])
}),
),
),
])),
),
]))
})
.collect(),
),
),
])),
)]);

// Create Level wrapper and save
let level_data = create_level_wrapper(&chunk);
ser_buffer.clear();
fastnbt::to_writer(&mut ser_buffer, &level_data).unwrap();
region
.write_chunk(chunk_x as usize, chunk_z as usize, &ser_buffer)
.unwrap();
region.write_chunk(chunk_x as usize, chunk_z as usize, &ser_buffer).unwrap();
}
}

Expand Down Expand Up @@ -670,3 +654,42 @@ impl WorldEditor {
save_pb.finish();
}
}

// Helper function to get entity coordinates
fn get_entity_coords(entity: &HashMap<String, Value>) -> (i32, i32, i32) {
let x = if let Value::Int(x) = entity.get("x").unwrap_or(&Value::Int(0)) { *x } else { 0 };
let y = if let Value::Int(y) = entity.get("y").unwrap_or(&Value::Int(0)) { *y } else { 0 };
let z = if let Value::Int(z) = entity.get("z").unwrap_or(&Value::Int(0)) { *z } else { 0 };
(x, y, z)
}

fn create_level_wrapper(chunk: &Chunk) -> HashMap<String, Value> {
HashMap::from([
("Level".to_string(), Value::Compound(HashMap::from([
("xPos".to_string(), Value::Int(chunk.x_pos)),
("zPos".to_string(), Value::Int(chunk.z_pos)),
("isLightOn".to_string(), Value::Byte(i8::try_from(chunk.is_light_on).unwrap())),
("sections".to_string(), Value::List(chunk.sections.iter().map(|section| {
Value::Compound(HashMap::from([
("Y".to_string(), Value::Byte(section.y)),
("block_states".to_string(), Value::Compound(HashMap::from([
("palette".to_string(), Value::List(
section.block_states.palette.iter().map(|item| {
let mut palette_item = HashMap::from([
("Name".to_string(), Value::String(item.name.clone())),
]);
if let Some(props) = &item.properties {
palette_item.insert("Properties".to_string(), props.clone());
}
Value::Compound(palette_item)
}).collect()
)),
("data".to_string(), Value::LongArray(
section.block_states.data.clone().unwrap_or_else(|| LongArray::new(vec![]))
)),
]))),
]))
}).collect())),
])))
])
}
2 changes: 1 addition & 1 deletion tauri.conf.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"$schema": "https://schema.tauri.app/config/2",
"productName": "Arnis",
"version": "2.1.3",
"version": "2.2.0",
"identifier": "com.louisdev.arnis",
"build": {
"frontendDist": "gui-src"
Expand Down
Loading