redguard-preservation 0.6.2

A CLI tool to preserve Redguard files
Documentation
use crate::cli::convert::ensure_parent_dir;
use color_eyre::Result;
use log::info;
use rgpre::import::pvo;
use serde_json::json;
use std::path::Path;

pub(crate) fn handle_pvo_convert(file: &Path, output_path: &Path) -> Result<()> {
    let file_content = std::fs::read(file)?;
    let parsed = pvo::parse_pvo_file(&file_content)?;

    let nodes = parsed
        .octr_nodes
        .iter()
        .enumerate()
        .map(|(i, node)| {
            json!({
                "index": i,
                "byte_offset": node.byte_offset,
                "child_mask": format!("0x{:02X}", node.child_mask),
                "child_count": node.child_count(),
                "leaf_ref": if node.is_interior() {
                    "none".to_string()
                } else {
                    format!("0x{:08X}", node.leaf_ref)
                },
                "child_refs": node.child_refs.iter()
                    .map(|(octant, offset)| json!({
                        "octant": octant,
                        "offset": format!("0x{offset:08X}"),
                    }))
                    .collect::<Vec<_>>(),
            })
        })
        .collect::<Vec<_>>();

    let leaves = parsed
        .plst_leaves
        .iter()
        .map(|leaf| {
            json!({
                "byte_offset": leaf.byte_offset,
                "entries": leaf.entries.iter().map(|e| json!({
                    "count": e.count,
                    "mlst_start": e.mlst_start,
                })).collect::<Vec<_>>(),
            })
        })
        .collect::<Vec<_>>();

    let output = json!({
        "header": {
            "depth": parsed.header.depth,
            "total_nodes": parsed.header.total_nodes,
            "leaf_nodes": parsed.header.leaf_nodes,
            "interior_nodes": parsed.header.interior_nodes(),
            "mlst_polygon_count": parsed.header.mlst_polygon_count,
            "cell_size": parsed.header.cell_size,
            "center_x": parsed.header.center_x,
            "center_y": parsed.header.center_y,
            "center_z": parsed.header.center_z,
        },
        "octr_nodes": nodes,
        "plst_leaves": leaves,
        "mlst_indices": parsed.mlst_indices,
    });

    let json_text = serde_json::to_string_pretty(&output)
        .map_err(|e| color_eyre::eyre::eyre!("failed to serialize PVO JSON: {e}"))?;
    ensure_parent_dir(output_path)?;
    std::fs::write(output_path, json_text)?;
    info!(
        "Successfully converted PVO to JSON: {}",
        output_path.display()
    );
    Ok(())
}