ck3-regions 0.0.5

Generates title-based region textures for use with the custom dynamic terrain shader system implemented in some CK3 mods.
Documentation
use std::{
    collections::HashMap,
    fs::File,
    io::prelude::*,
    path::Path
};

use lazy_static::lazy_static;

use crate::{
    config::{Config, ModeSettings},
    model::game::TitleId
};

//
// Constants
//

pub const REGION_TITLE_INDICES_KEY: &str = "region_title_indices";

const YAML_INDENT: &str = "  ";

const EXPECT_REGION_TITLE_INDICES: &str = "region title indices must be provided in title-based regions mode";

lazy_static! {
    static ref PROGRAM_NAME_AND_VERSION: String = format!("{} v{}", env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION"));
}

//
// Interface
//

pub fn write_metadata(
    metadata_yaml_path:   &Path,
    config:               &Config,
    region_title_indices: Option<&HashMap<TitleId, u32>>,
    max_region_index:     u32
) -> std::io::Result<()> {
    let mut metadata_yaml_file = File::create(metadata_yaml_path)?;

    //write_header_comment(&mut metadata_yaml_file, &config.mod_prefix)?;

    // writeln!(&mut metadata_yaml_file, "mod_prefix: {:?}", config.mod_prefix)?;

    let regions_map_relative_path = config.mod_paths.regions_map.strip_prefix(&config.mod_paths.mod_root)
         .expect("regions map path must have mod root as prefix");

    //write_regions_count_comment(&mut metadata_yaml_file, regions_map_relative_path)?;

    //writeln!(&mut metadata_yaml_file, "regions_count: {}", max_region_index + 1)?;

    match config.mode_settings {
        ModeSettings::TitleBasedRegions { region_title_tier: _ } => {
            //writeln!(&mut metadata_yaml_file, "region_title_tier: {:?}", format!("{:?}", region_title_tier).to_lowercase())?;
            //writeln!(&mut metadata_yaml_file)?;

            write_region_title_indices_comment(&mut metadata_yaml_file, regions_map_relative_path)?;

            writeln!(&mut metadata_yaml_file, "{}:", REGION_TITLE_INDICES_KEY)?;

            let mut sorted_region_title_indices: Vec<_> = region_title_indices
                .expect(EXPECT_REGION_TITLE_INDICES)
                .into_iter()
                .collect();

            assert_eq!(sorted_region_title_indices.len(), max_region_index as usize);

            sorted_region_title_indices.sort_by(|(_, idx_0), (_, idx_1)| idx_0.cmp(idx_1));
            for (title_id, region_title_index) in sorted_region_title_indices {
                writeln!(&mut metadata_yaml_file, "{}{}: {}", YAML_INDENT, title_id, region_title_index)?;
            }
        },
        ModeSettings::PredefinedRegions {..} => {},
    };

    Ok(())
}

//
// Service
//

fn _write_header_comment(yaml_file: &mut File, mod_prefix: &str) -> std::io::Result<()> {
    writeln!(
        yaml_file,
        "# This file was generated for {} using {}.\n# Please avoid making manual changes here.\n",
        mod_prefix,
        *PROGRAM_NAME_AND_VERSION,
    )
}

fn _write_regions_count_comment(yaml_file: &mut File, regions_map_relative_path: &Path) -> std::io::Result<()> {
    write!(
        yaml_file,
        r#"# Number of separately controllable dynamic terrain regions.
# Corresponds to the number of distinct 16bit pixel RG values in {},
# starting from R channel for the least significant 8 bits.
"#,
        regions_map_relative_path.display(),
    )
}

fn write_region_title_indices_comment(yaml_file: &mut File, regions_map_relative_path: &Path) -> std::io::Result<()> {
    write!(
        yaml_file,
        r#"# The following region title indices were generated along with {}
# and correspond to the 16 bits of pixel RG values in that texture file,
# starting from R channel for the least significant 8 bits.
"#,
        regions_map_relative_path.display(),
    )
}