modde-games 0.1.0

Game plugin implementations for modde
Documentation
//! MangoHud — performance overlay (FPS, CPU/GPU stats, frame timing).
//!
//! Enabled via `MANGOHUD=1` env var. Per-game config written to
//! `~/.local/share/modde/tools/{game_id}/MangoHud.conf` and pointed to
//! via `MANGOHUD_CONFIG`.

use smallvec::{SmallVec, smallvec};

use super::{
    GameTool, GeneratedConfig, ToolAvailability, ToolCategory, ToolConfig, tool_config_dir, which,
};

pub static MANGOHUD: MangoHud = MangoHud;

pub struct MangoHud;

impl GameTool for MangoHud {
    fn tool_id(&self) -> &'static str {
        "mangohud"
    }

    fn display_name(&self) -> &'static str {
        "MangoHud"
    }

    fn category(&self) -> ToolCategory {
        ToolCategory::Overlay
    }

    fn detect_available(&self) -> ToolAvailability {
        #[cfg(not(target_os = "linux"))]
        {
            return ToolAvailability::NotInstalled {
                install_hint: "MangoHud is only available on Linux".into(),
            };
        }

        #[cfg(target_os = "linux")]
        if which("mangohud").is_some() {
            ToolAvailability::Available { version: None }
        } else {
            ToolAvailability::NotInstalled {
                install_hint: "Install mangohud from your package manager".into(),
            }
        }
    }

    fn env_vars(&self, config: &ToolConfig) -> SmallVec<[(String, String); 4]> {
        let mut vars = smallvec![("MANGOHUD".into(), "1".into())];

        // Point to per-game config if we generated one
        if config.settings.as_object().map_or(false, |m| !m.is_empty()) {
            if let Some(game_id) = config.get_str("_game_id") {
                let conf_path = tool_config_dir(game_id).join("MangoHud.conf");
                vars.push(("MANGOHUD_CONFIG".into(), conf_path.to_string_lossy().into()));
            }
        }

        vars
    }

    fn generate_config(&self, config: &ToolConfig) -> Option<GeneratedConfig> {
        let game_id = config.get_str("_game_id")?;
        let settings = config.settings.as_object()?;

        let mut lines = Vec::new();
        lines.push("# Generated by modde — do not edit manually".into());

        for (key, value) in settings {
            if key.starts_with('_') {
                continue; // skip internal keys
            }
            match value {
                serde_json::Value::Bool(b) => {
                    if *b {
                        lines.push(key.clone());
                    } else {
                        lines.push(format!("{key}=0"));
                    }
                }
                serde_json::Value::Number(n) => lines.push(format!("{key}={n}")),
                serde_json::Value::String(s) => lines.push(format!("{key}={s}")),
                _ => {}
            }
        }

        let dir = tool_config_dir(game_id);
        Some(GeneratedConfig {
            path: dir.join("MangoHud.conf"),
            content: lines.join("\n") + "\n",
        })
    }

    fn default_config(&self) -> ToolConfig {
        let mut config = ToolConfig::new("mangohud");
        config.set("position", serde_json::json!("top-left"));
        config.set("fps", serde_json::json!(true));
        config.set("frametime", serde_json::json!(true));
        config.set("cpu_stats", serde_json::json!(true));
        config.set("gpu_stats", serde_json::json!(true));
        config
    }
}