mirror of
https://github.com/louis-e/arnis.git
synced 2025-12-23 22:37:56 -05:00
Preserver block properties in bedrock
This commit is contained in:
@@ -531,6 +531,200 @@ pub fn to_bedrock_block(block: Block) -> BedrockBlock {
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts an internal Block with optional Java properties to a BedrockBlock.
|
||||
///
|
||||
/// This function extends `to_bedrock_block` by also handling block-specific properties
|
||||
/// like stair facing/shape, slab type, etc. Java property names and values are converted
|
||||
/// to their Bedrock equivalents.
|
||||
pub fn to_bedrock_block_with_properties(
|
||||
block: Block,
|
||||
java_properties: Option<&fastnbt::Value>,
|
||||
) -> BedrockBlock {
|
||||
let java_name = block.name();
|
||||
|
||||
// Extract Java properties as a map if present
|
||||
let props_map = java_properties.and_then(|v| {
|
||||
if let fastnbt::Value::Compound(map) = v {
|
||||
Some(map)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
|
||||
// Handle stairs with facing/shape properties
|
||||
if java_name.ends_with("_stairs") {
|
||||
return convert_stairs(java_name, props_map);
|
||||
}
|
||||
|
||||
// Handle slabs with type property (top/bottom/double)
|
||||
if java_name.ends_with("_slab") {
|
||||
return convert_slab(java_name, props_map);
|
||||
}
|
||||
|
||||
// Handle logs with axis property
|
||||
if java_name.ends_with("_log") || java_name.ends_with("_wood") {
|
||||
return convert_log(java_name, props_map);
|
||||
}
|
||||
|
||||
// Fall back to basic conversion without properties
|
||||
to_bedrock_block(block)
|
||||
}
|
||||
|
||||
/// Convert Java stair block to Bedrock format with proper orientation.
|
||||
fn convert_stairs(
|
||||
java_name: &str,
|
||||
props: Option<&std::collections::HashMap<String, fastnbt::Value>>,
|
||||
) -> BedrockBlock {
|
||||
// Get the base stair name for Bedrock
|
||||
let bedrock_name = java_name; // Most stairs have the same name
|
||||
|
||||
let mut states = HashMap::new();
|
||||
|
||||
// Convert facing: Java uses "north/south/east/west", Bedrock uses "weirdo_direction" (0-3)
|
||||
// Bedrock: 0=east, 1=west, 2=south, 3=north
|
||||
if let Some(props) = props {
|
||||
if let Some(fastnbt::Value::String(facing)) = props.get("facing") {
|
||||
let direction = match facing.as_str() {
|
||||
"east" => 0,
|
||||
"west" => 1,
|
||||
"south" => 2,
|
||||
"north" => 3,
|
||||
_ => 0,
|
||||
};
|
||||
states.insert(
|
||||
"weirdo_direction".to_string(),
|
||||
BedrockBlockStateValue::Int(direction),
|
||||
);
|
||||
}
|
||||
|
||||
// Convert half: Java uses "top/bottom", Bedrock uses "upside_down_bit"
|
||||
if let Some(fastnbt::Value::String(half)) = props.get("half") {
|
||||
let upside_down = half == "top";
|
||||
states.insert(
|
||||
"upside_down_bit".to_string(),
|
||||
BedrockBlockStateValue::Bool(upside_down),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// If no properties were set, use defaults
|
||||
if states.is_empty() {
|
||||
states.insert(
|
||||
"weirdo_direction".to_string(),
|
||||
BedrockBlockStateValue::Int(0),
|
||||
);
|
||||
states.insert(
|
||||
"upside_down_bit".to_string(),
|
||||
BedrockBlockStateValue::Bool(false),
|
||||
);
|
||||
}
|
||||
|
||||
BedrockBlock {
|
||||
name: format!("minecraft:{bedrock_name}"),
|
||||
states,
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert Java slab block to Bedrock format with proper type.
|
||||
fn convert_slab(
|
||||
java_name: &str,
|
||||
props: Option<&std::collections::HashMap<String, fastnbt::Value>>,
|
||||
) -> BedrockBlock {
|
||||
let mut states = HashMap::new();
|
||||
|
||||
// Convert type: Java uses "top/bottom/double", Bedrock uses "top_slot_bit"
|
||||
if let Some(props) = props {
|
||||
if let Some(fastnbt::Value::String(slab_type)) = props.get("type") {
|
||||
let top_slot = slab_type == "top";
|
||||
states.insert(
|
||||
"top_slot_bit".to_string(),
|
||||
BedrockBlockStateValue::Bool(top_slot),
|
||||
);
|
||||
// Note: "double" slabs in Java become full blocks in Bedrock (different block ID)
|
||||
}
|
||||
}
|
||||
|
||||
// Default to bottom if not specified
|
||||
if !states.contains_key("top_slot_bit") {
|
||||
states.insert(
|
||||
"top_slot_bit".to_string(),
|
||||
BedrockBlockStateValue::Bool(false),
|
||||
);
|
||||
}
|
||||
|
||||
// Handle special slab name mappings (same as in to_bedrock_block)
|
||||
let bedrock_name = match java_name {
|
||||
"stone_slab" => "stone_block_slab",
|
||||
"stone_brick_slab" => "stone_block_slab",
|
||||
"oak_slab" => "wooden_slab",
|
||||
"spruce_slab" => "wooden_slab",
|
||||
"birch_slab" => "wooden_slab",
|
||||
"jungle_slab" => "wooden_slab",
|
||||
"acacia_slab" => "wooden_slab",
|
||||
"dark_oak_slab" => "wooden_slab",
|
||||
_ => java_name,
|
||||
};
|
||||
|
||||
// Add wood_type for wooden slabs
|
||||
if bedrock_name == "wooden_slab" {
|
||||
let wood_type = java_name.trim_end_matches("_slab");
|
||||
states.insert(
|
||||
"wood_type".to_string(),
|
||||
BedrockBlockStateValue::String(wood_type.to_string()),
|
||||
);
|
||||
}
|
||||
|
||||
// Add stone_slab_type for stone slabs
|
||||
if bedrock_name == "stone_block_slab" {
|
||||
let slab_type = if java_name == "stone_brick_slab" {
|
||||
"stone_brick"
|
||||
} else {
|
||||
"stone"
|
||||
};
|
||||
states.insert(
|
||||
"stone_slab_type".to_string(),
|
||||
BedrockBlockStateValue::String(slab_type.to_string()),
|
||||
);
|
||||
}
|
||||
|
||||
BedrockBlock {
|
||||
name: format!("minecraft:{bedrock_name}"),
|
||||
states,
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert Java log/wood block to Bedrock format with proper axis.
|
||||
fn convert_log(
|
||||
java_name: &str,
|
||||
props: Option<&std::collections::HashMap<String, fastnbt::Value>>,
|
||||
) -> BedrockBlock {
|
||||
let bedrock_name = java_name;
|
||||
let mut states = HashMap::new();
|
||||
|
||||
// Convert axis: Java uses "x/y/z", Bedrock uses "pillar_axis"
|
||||
if let Some(props) = props {
|
||||
if let Some(fastnbt::Value::String(axis)) = props.get("axis") {
|
||||
states.insert(
|
||||
"pillar_axis".to_string(),
|
||||
BedrockBlockStateValue::String(axis.clone()),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Default to y-axis if not specified
|
||||
if states.is_empty() {
|
||||
states.insert(
|
||||
"pillar_axis".to_string(),
|
||||
BedrockBlockStateValue::String("y".to_string()),
|
||||
);
|
||||
}
|
||||
|
||||
BedrockBlock {
|
||||
name: format!("minecraft:{bedrock_name}"),
|
||||
states,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
@@ -562,4 +756,69 @@ mod tests {
|
||||
Some(BedrockBlockStateValue::String(s)) if s == "white"
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_stairs_with_properties() {
|
||||
use crate::block_definitions::OAK_STAIRS;
|
||||
use std::collections::HashMap as StdHashMap;
|
||||
|
||||
// Create Java properties for a south-facing stair
|
||||
let mut props = StdHashMap::new();
|
||||
props.insert(
|
||||
"facing".to_string(),
|
||||
fastnbt::Value::String("south".to_string()),
|
||||
);
|
||||
props.insert(
|
||||
"half".to_string(),
|
||||
fastnbt::Value::String("bottom".to_string()),
|
||||
);
|
||||
let java_props = fastnbt::Value::Compound(props);
|
||||
|
||||
let bedrock = to_bedrock_block_with_properties(OAK_STAIRS, Some(&java_props));
|
||||
assert_eq!(bedrock.name, "minecraft:oak_stairs");
|
||||
|
||||
// Check weirdo_direction is set correctly (south = 2)
|
||||
assert!(matches!(
|
||||
bedrock.states.get("weirdo_direction"),
|
||||
Some(BedrockBlockStateValue::Int(2))
|
||||
));
|
||||
|
||||
// Check upside_down_bit is false for bottom half
|
||||
assert!(matches!(
|
||||
bedrock.states.get("upside_down_bit"),
|
||||
Some(BedrockBlockStateValue::Bool(false))
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_stairs_upside_down() {
|
||||
use crate::block_definitions::STONE_BRICK_STAIRS;
|
||||
use std::collections::HashMap as StdHashMap;
|
||||
|
||||
// Create Java properties for an upside-down north-facing stair
|
||||
let mut props = StdHashMap::new();
|
||||
props.insert(
|
||||
"facing".to_string(),
|
||||
fastnbt::Value::String("north".to_string()),
|
||||
);
|
||||
props.insert(
|
||||
"half".to_string(),
|
||||
fastnbt::Value::String("top".to_string()),
|
||||
);
|
||||
let java_props = fastnbt::Value::Compound(props);
|
||||
|
||||
let bedrock = to_bedrock_block_with_properties(STONE_BRICK_STAIRS, Some(&java_props));
|
||||
|
||||
// Check weirdo_direction is set correctly (north = 3)
|
||||
assert!(matches!(
|
||||
bedrock.states.get("weirdo_direction"),
|
||||
Some(BedrockBlockStateValue::Int(3))
|
||||
));
|
||||
|
||||
// Check upside_down_bit is true for top half
|
||||
assert!(matches!(
|
||||
bedrock.states.get("upside_down_bit"),
|
||||
Some(BedrockBlockStateValue::Bool(true))
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,9 @@
|
||||
|
||||
use super::common::{ChunkToModify, SectionToModify, WorldToModify};
|
||||
use super::WorldMetadata;
|
||||
use crate::bedrock_block_map::{to_bedrock_block, BedrockBlock, BedrockBlockStateValue};
|
||||
use crate::bedrock_block_map::{
|
||||
to_bedrock_block_with_properties, BedrockBlock, BedrockBlockStateValue,
|
||||
};
|
||||
use crate::coordinate_system::cartesian::XZBBox;
|
||||
use crate::coordinate_system::geographic::LLBBox;
|
||||
|
||||
@@ -520,6 +522,9 @@ impl BedrockWriter {
|
||||
/// Converts from internal YZX ordering to Bedrock's XZY ordering:
|
||||
/// - Internal: index = y*256 + z*16 + x
|
||||
/// - Bedrock: index = x*256 + z*16 + y
|
||||
///
|
||||
/// Also propagates stored block properties (e.g., stair facing/shape) to the
|
||||
/// Bedrock palette, ensuring blocks with non-default states are serialized correctly.
|
||||
fn build_palette_and_indices(
|
||||
&self,
|
||||
section: &SectionToModify,
|
||||
@@ -541,7 +546,11 @@ impl BedrockWriter {
|
||||
let internal_idx = y * 256 + z * 16 + x;
|
||||
let block = section.blocks[internal_idx];
|
||||
|
||||
let bedrock_block = to_bedrock_block(block);
|
||||
// Get stored properties for this block position (if any)
|
||||
let properties = section.properties.get(&internal_idx);
|
||||
|
||||
// Convert to Bedrock format, preserving properties
|
||||
let bedrock_block = to_bedrock_block_with_properties(block, properties);
|
||||
let key = format!("{:?}", (&bedrock_block.name, &bedrock_block.states));
|
||||
|
||||
let palette_index = if let Some(&idx) = palette_map.get(&key) {
|
||||
|
||||
Reference in New Issue
Block a user