flatland-presentation 0.2.22

Gfx sprite mode resolution — maps game states to sprite sheet mode ids
Documentation
//! Designer-authored player gfx presentation (`assets/gfx/player-presentation.yaml`).

use std::path::Path;

use serde::Deserialize;

use crate::SpriteModeMap;

#[derive(Debug, Clone, Default, Deserialize)]
pub struct PlayerPresentationDoc {
    #[serde(default)]
    pub player_presentation: PlayerPresentationConfig,
}

#[derive(Debug, Clone, Default, Deserialize)]
pub struct PlayerPresentationConfig {
    #[serde(default)]
    pub tile_id: Option<String>,
    /// Paperdoll skin id under `assets/paperdoll/skins/`.
    #[serde(default)]
    pub paperdoll_ref: Option<String>,
    #[serde(default)]
    pub sprite_modes: SpriteModeMap,
}

impl PlayerPresentationConfig {
    pub fn empty() -> Self {
        Self::default()
    }
}

pub fn default_player_presentation_path() -> Option<std::path::PathBuf> {
    if let Ok(p) = std::env::var("FLATLAND_PLAYER_PRESENTATION") {
        let path = std::path::PathBuf::from(p);
        if path.is_file() {
            return Some(path);
        }
    }
    if let Ok(sprites) = std::env::var("FLATLAND_SPRITES_DIR") {
        let path = std::path::PathBuf::from(sprites).join("player-presentation.yaml");
        if path.is_file() {
            return Some(path);
        }
    }
    // Installed-client sync places the file at the rev root next to manifest.yaml.
    if let Ok(home) = std::env::var("HOME") {
        let current = std::path::PathBuf::from(home)
            .join(".flatland3/assets/current/player-presentation.yaml");
        if current.is_file() {
            return Some(current);
        }
    }
    let mut dir = std::env::current_dir().ok()?;
    for _ in 0..8 {
        let candidate = dir.join("assets/gfx/player-presentation.yaml");
        if candidate.is_file() {
            return Some(candidate);
        }
        if !dir.pop() {
            break;
        }
    }
    None
}

pub fn load_player_presentation(
    path: impl AsRef<Path>,
) -> anyhow::Result<PlayerPresentationConfig> {
    let raw = std::fs::read_to_string(path.as_ref())?;
    let doc: PlayerPresentationDoc = serde_yaml::from_str(&raw)?;
    Ok(doc.player_presentation)
}

pub fn load_player_presentation_default() -> PlayerPresentationConfig {
    default_player_presentation_path()
        .and_then(|p| load_player_presentation(&p).ok())
        .unwrap_or_default()
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn loads_repo_default() {
        let path = default_player_presentation_path().expect("player-presentation.yaml");
        let cfg = load_player_presentation(&path).expect("parse");
        assert!(cfg.tile_id.is_some() || !cfg.sprite_modes.is_empty());
    }
}