1use smallvec::{SmallVec, smallvec};
8
9use super::{
10 GameTool, GeneratedConfig, ToolAvailability, ToolCategory, ToolConfig, tool_config_dir, which,
11};
12
13pub static MANGOHUD: MangoHud = MangoHud;
14
15pub struct MangoHud;
16
17impl GameTool for MangoHud {
18 fn tool_id(&self) -> &'static str {
19 "mangohud"
20 }
21
22 fn display_name(&self) -> &'static str {
23 "MangoHud"
24 }
25
26 fn category(&self) -> ToolCategory {
27 ToolCategory::Overlay
28 }
29
30 fn description(&self) -> &'static str {
31 "Performance HUD overlay for FPS, frame timing, CPU, and GPU telemetry."
32 }
33
34 fn settings_schema(&self) -> Vec<super::ToolSettingSpec> {
35 let mut specs = vec![
36 super::ToolSettingSpec::select(
37 "position",
38 "Position",
39 "Screen corner used for the MangoHud overlay.",
40 &[
41 "top-left",
42 "top-center",
43 "top-right",
44 "middle-left",
45 "middle-right",
46 "bottom-left",
47 "bottom-center",
48 "bottom-right",
49 ],
50 ),
51 super::ToolSettingSpec::bool("horizontal", "Horizontal", "Use horizontal HUD layout."),
52 super::ToolSettingSpec::bool(
53 "hud_compact",
54 "Compact HUD",
55 "Use MangoHud compact HUD layout.",
56 ),
57 super::ToolSettingSpec::bool(
58 "no_display",
59 "No display",
60 "Collect/log without showing the overlay.",
61 ),
62 super::ToolSettingSpec::text(
63 "custom_text_center",
64 "Center text",
65 "Custom text shown in the HUD center column.",
66 ),
67 super::ToolSettingSpec::number(
68 "background_alpha",
69 "Background alpha",
70 "HUD background opacity.",
71 0.0,
72 1.0,
73 0.05,
74 ),
75 super::ToolSettingSpec::number(
76 "round_corners",
77 "Round corners",
78 "HUD background corner radius.",
79 0.0,
80 32.0,
81 1.0,
82 ),
83 super::ToolSettingSpec::text(
84 "background_color",
85 "Background color",
86 "HUD background color, such as 020202.",
87 ),
88 super::ToolSettingSpec::number(
89 "font_size",
90 "Font size",
91 "HUD font size.",
92 6.0,
93 48.0,
94 1.0,
95 ),
96 super::ToolSettingSpec::text("text_color", "Text color", "Default HUD text color."),
97 super::ToolSettingSpec::path("font_file", "Font file", "Optional font file path."),
98 super::ToolSettingSpec::number(
99 "offset_x",
100 "Offset X",
101 "Horizontal overlay offset.",
102 -400.0,
103 400.0,
104 1.0,
105 ),
106 super::ToolSettingSpec::number(
107 "offset_y",
108 "Offset Y",
109 "Vertical overlay offset.",
110 -400.0,
111 400.0,
112 1.0,
113 ),
114 super::ToolSettingSpec::text("toggle_hud", "Toggle HUD", "Key used to toggle the HUD."),
115 super::ToolSettingSpec::number(
116 "table_columns",
117 "Table columns",
118 "MangoHud table column count.",
119 1.0,
120 8.0,
121 1.0,
122 ),
123 super::ToolSettingSpec::bool("fps", "FPS", "Show the current frame rate."),
124 super::ToolSettingSpec::bool("frame_timing", "Frame timing", "Show frame timing data."),
125 super::ToolSettingSpec::bool(
126 "frametime",
127 "Frame time graph",
128 "Show frame-time graph data.",
129 ),
130 super::ToolSettingSpec::bool(
131 "show_fps_limit",
132 "Show FPS limit",
133 "Show active FPS limit.",
134 ),
135 super::ToolSettingSpec::bool(
136 "frame_count",
137 "Frame count",
138 "Show rendered frame count.",
139 ),
140 super::ToolSettingSpec::bool("histogram", "Histogram", "Show frame-time histogram."),
141 super::ToolSettingSpec::text("fps_limit", "FPS limit", "FPS limit list or value."),
142 super::ToolSettingSpec::select(
143 "fps_limit_method",
144 "FPS limit method",
145 "MangoHud FPS limiter mode.",
146 &["late", "early"],
147 ),
148 super::ToolSettingSpec::text(
149 "toggle_fps_limit",
150 "Toggle FPS limit",
151 "Key used to toggle FPS limiting.",
152 ),
153 super::ToolSettingSpec::select(
154 "gl_vsync",
155 "OpenGL VSync",
156 "OpenGL VSync setting.",
157 &["-1", "0", "1", "n"],
158 ),
159 super::ToolSettingSpec::text("vsync", "VSync", "VSync setting."),
160 super::ToolSettingSpec::text(
161 "fps_metrics",
162 "FPS metrics",
163 "Low-percentile FPS metrics, such as 0.01 or 0.001.",
164 ),
165 super::ToolSettingSpec::text("fps_color", "FPS color", "FPS text color."),
166 super::ToolSettingSpec::bool(
167 "fps_color_change",
168 "FPS color change",
169 "Change FPS color by threshold.",
170 ),
171 super::ToolSettingSpec::bool("cpu_stats", "CPU stats", "Show CPU load and clocks."),
172 super::ToolSettingSpec::bool(
173 "cpu_load_change",
174 "CPU load change",
175 "Show CPU load changes.",
176 ),
177 super::ToolSettingSpec::bool("core_load", "Core load", "Show per-core load."),
178 super::ToolSettingSpec::bool("core_bars", "Core bars", "Show per-core bars."),
179 super::ToolSettingSpec::bool("cpu_mhz", "CPU MHz", "Show CPU clock speed."),
180 super::ToolSettingSpec::bool("cpu_temp", "CPU temperature", "Show CPU temperature."),
181 super::ToolSettingSpec::bool("cpu_power", "CPU power", "Show CPU power."),
182 super::ToolSettingSpec::bool(
183 "cpu_efficiency",
184 "CPU efficiency",
185 "Show CPU efficiency.",
186 ),
187 super::ToolSettingSpec::bool("core_type", "Core type", "Show CPU core types."),
188 super::ToolSettingSpec::text("cpu_text", "CPU label", "Custom CPU label."),
189 super::ToolSettingSpec::text("cpu_color", "CPU color", "CPU text color."),
190 super::ToolSettingSpec::bool("gpu_stats", "GPU stats", "Show GPU load and clocks."),
191 super::ToolSettingSpec::bool(
192 "gpu_load_change",
193 "GPU load change",
194 "Show GPU load changes.",
195 ),
196 super::ToolSettingSpec::bool("vram", "VRAM", "Show VRAM usage."),
197 super::ToolSettingSpec::bool(
198 "gpu_core_clock",
199 "GPU core clock",
200 "Show GPU core clock.",
201 ),
202 super::ToolSettingSpec::bool(
203 "gpu_mem_clock",
204 "GPU memory clock",
205 "Show GPU memory clock.",
206 ),
207 super::ToolSettingSpec::bool("gpu_temp", "GPU temperature", "Show GPU temperature."),
208 super::ToolSettingSpec::bool(
209 "gpu_mem_temp",
210 "GPU memory temperature",
211 "Show GPU memory temperature.",
212 ),
213 super::ToolSettingSpec::bool(
214 "gpu_junction_temp",
215 "GPU junction temperature",
216 "Show GPU junction temperature.",
217 ),
218 super::ToolSettingSpec::bool("gpu_fan", "GPU fan", "Show GPU fan speed."),
219 super::ToolSettingSpec::bool("gpu_power", "GPU power", "Show GPU power."),
220 super::ToolSettingSpec::bool(
221 "gpu_power_limit",
222 "GPU power limit",
223 "Show GPU power limit.",
224 ),
225 super::ToolSettingSpec::bool(
226 "gpu_efficiency",
227 "GPU efficiency",
228 "Show GPU efficiency.",
229 ),
230 super::ToolSettingSpec::bool(
231 "flip_efficiency",
232 "Flip efficiency",
233 "Show flip efficiency.",
234 ),
235 super::ToolSettingSpec::bool("gpu_voltage", "GPU voltage", "Show GPU voltage."),
236 super::ToolSettingSpec::bool(
237 "throttling_status",
238 "Throttling status",
239 "Show throttling status.",
240 ),
241 super::ToolSettingSpec::bool(
242 "throttling_status_graph",
243 "Throttling graph",
244 "Show throttling graph.",
245 ),
246 super::ToolSettingSpec::bool("gpu_name", "GPU name", "Show GPU name."),
247 super::ToolSettingSpec::bool("vulkan_driver", "Vulkan driver", "Show Vulkan driver."),
248 super::ToolSettingSpec::text("gpu_text", "GPU label", "Custom GPU label."),
249 super::ToolSettingSpec::text("gpu_color", "GPU color", "GPU text color."),
250 super::ToolSettingSpec::text("gpu_list", "GPU list", "GPU list selector."),
251 super::ToolSettingSpec::text("pci_dev", "PCI device", "PCI device selector."),
252 ];
253 specs.extend([
254 super::ToolSettingSpec::bool("ram", "RAM", "Show RAM usage."),
255 super::ToolSettingSpec::bool("io_read", "IO read", "Show disk read throughput."),
256 super::ToolSettingSpec::bool("io_write", "IO write", "Show disk write throughput."),
257 super::ToolSettingSpec::bool("procmem", "Process memory", "Show process memory."),
258 super::ToolSettingSpec::bool("proc_vram", "Process VRAM", "Show process VRAM."),
259 super::ToolSettingSpec::bool("swap", "Swap", "Show swap usage."),
260 super::ToolSettingSpec::bool("ram_temp", "RAM temperature", "Show RAM temperature."),
261 super::ToolSettingSpec::text("vram_color", "VRAM color", "VRAM text color."),
262 super::ToolSettingSpec::text("ram_color", "RAM color", "RAM text color."),
263 super::ToolSettingSpec::text("io_color", "IO color", "IO text color."),
264 super::ToolSettingSpec::text(
265 "frametime_color",
266 "Frame-time color",
267 "Frame-time text color.",
268 ),
269 super::ToolSettingSpec::bool("wine", "Wine", "Show Wine/Proton version."),
270 super::ToolSettingSpec::bool("winesync", "Wine sync", "Show Wine sync method."),
271 super::ToolSettingSpec::bool(
272 "engine_version",
273 "Engine version",
274 "Show game engine version.",
275 ),
276 super::ToolSettingSpec::bool(
277 "engine_short_names",
278 "Engine short names",
279 "Shorten engine names.",
280 ),
281 super::ToolSettingSpec::bool("gamemode", "GameMode status", "Show GameMode status."),
282 super::ToolSettingSpec::bool("vkbasalt", "vkBasalt status", "Show vkBasalt status."),
283 super::ToolSettingSpec::bool("fcat", "FCAT", "Show FCAT overlay."),
284 super::ToolSettingSpec::bool("fex_stats", "FEX stats", "Show FEX stats."),
285 super::ToolSettingSpec::bool("fsr", "FSR", "Show FSR state."),
286 super::ToolSettingSpec::bool("hdr", "HDR", "Show HDR state."),
287 super::ToolSettingSpec::bool("present_mode", "Present mode", "Show present mode."),
288 super::ToolSettingSpec::bool(
289 "display_server",
290 "Display server",
291 "Show display server.",
292 ),
293 super::ToolSettingSpec::bool("arch", "Architecture", "Show process architecture."),
294 super::ToolSettingSpec::bool("resolution", "Resolution", "Show resolution."),
295 super::ToolSettingSpec::bool("refresh_rate", "Refresh rate", "Show refresh rate."),
296 super::ToolSettingSpec::bool("time", "Time", "Show clock."),
297 super::ToolSettingSpec::bool("version", "MangoHud version", "Show MangoHud version."),
298 super::ToolSettingSpec::bool("battery", "Battery", "Show battery state."),
299 super::ToolSettingSpec::bool(
300 "battery_watt",
301 "Battery watts",
302 "Show battery power draw.",
303 ),
304 super::ToolSettingSpec::bool(
305 "battery_time",
306 "Battery time",
307 "Show battery time remaining.",
308 ),
309 super::ToolSettingSpec::bool(
310 "device_battery",
311 "Device battery",
312 "Show controller/device battery.",
313 ),
314 super::ToolSettingSpec::bool(
315 "media_player",
316 "Media player",
317 "Show media player information.",
318 ),
319 super::ToolSettingSpec::bool("network", "Network", "Show network throughput."),
320 super::ToolSettingSpec::text("wine_color", "Wine color", "Wine text color."),
321 super::ToolSettingSpec::text("engine_color", "Engine color", "Engine text color."),
322 super::ToolSettingSpec::text("battery_color", "Battery color", "Battery text color."),
323 super::ToolSettingSpec::text(
324 "media_player_color",
325 "Media color",
326 "Media player text color.",
327 ),
328 super::ToolSettingSpec::path(
329 "output_folder",
330 "Output folder",
331 "MangoHud log output folder.",
332 ),
333 super::ToolSettingSpec::number(
334 "log_duration",
335 "Log duration",
336 "Log duration in seconds.",
337 0.0,
338 86400.0,
339 1.0,
340 ),
341 super::ToolSettingSpec::bool(
342 "autostart_log",
343 "Autostart logging",
344 "Start logging automatically.",
345 ),
346 super::ToolSettingSpec::number(
347 "log_interval",
348 "Log interval",
349 "Logging interval.",
350 0.0,
351 10000.0,
352 1.0,
353 ),
354 super::ToolSettingSpec::text(
355 "toggle_logging",
356 "Toggle logging",
357 "Key used to toggle logging.",
358 ),
359 super::ToolSettingSpec::bool(
360 "log_versioning",
361 "Log versioning",
362 "Version MangoHud log files.",
363 ),
364 super::ToolSettingSpec::bool(
365 "upload_logs",
366 "Upload logs",
367 "Enable MangoHud log upload integration.",
368 ),
369 super::ToolSettingSpec::text("exec", "Exec", "Command executed by MangoHud."),
370 super::ToolSettingSpec::bool(
371 "temp_fahrenheit",
372 "Fahrenheit",
373 "Show temperatures in Fahrenheit.",
374 ),
375 super::ToolSettingSpec::number(
376 "af",
377 "Anisotropic filtering",
378 "Anisotropic filtering override.",
379 0.0,
380 16.0,
381 1.0,
382 ),
383 super::ToolSettingSpec::number(
384 "picmip",
385 "Picmip",
386 "Texture picmip override.",
387 -10.0,
388 10.0,
389 1.0,
390 ),
391 super::ToolSettingSpec::bool("bicubic", "Bicubic", "Enable bicubic scaling flag."),
392 super::ToolSettingSpec::bool(
393 "trilinear",
394 "Trilinear",
395 "Enable trilinear filtering flag.",
396 ),
397 super::ToolSettingSpec::bool("retro", "Retro", "Enable retro scaling flag."),
398 ]);
399 for spec in &mut specs {
400 spec.section = mangohud_setting_section(spec.key);
401 }
402 specs
403 }
404
405 fn detect_available(&self) -> ToolAvailability {
406 #[cfg(not(target_os = "linux"))]
407 {
408 return ToolAvailability::NotInstalled {
409 install_hint: "MangoHud is only available on Linux".into(),
410 };
411 }
412
413 #[cfg(target_os = "linux")]
414 if which("mangohud").is_some() {
415 ToolAvailability::Available { version: None }
416 } else {
417 ToolAvailability::NotInstalled {
418 install_hint: "Install mangohud from your package manager".into(),
419 }
420 }
421 }
422
423 fn env_vars(&self, config: &ToolConfig) -> SmallVec<[(String, String); 4]> {
424 let mut vars = smallvec![("MANGOHUD".into(), "1".into())];
425
426 if config.settings.as_object().is_some_and(|m| !m.is_empty())
428 && let Some(game_id) = config.get_str("_game_id")
429 {
430 let conf_path = tool_config_dir(game_id).join("MangoHud.conf");
431 vars.push(("MANGOHUD_CONFIG".into(), conf_path.to_string_lossy().into()));
432 }
433
434 vars
435 }
436
437 fn generate_config(&self, config: &ToolConfig) -> Option<GeneratedConfig> {
438 let game_id = config.get_str("_game_id")?;
439 let settings = config.settings.as_object()?;
440
441 let mut lines = Vec::new();
442 lines.push("# Generated by modde — do not edit manually".into());
443
444 for (key, value) in settings {
445 if key.starts_with('_') {
446 continue; }
448 match value {
449 serde_json::Value::Bool(b) => {
450 if *b {
451 lines.push(key.clone());
452 } else {
453 lines.push(format!("{key}=0"));
454 }
455 }
456 serde_json::Value::Number(n) => lines.push(format!("{key}={n}")),
457 serde_json::Value::String(s) => lines.push(format!("{key}={s}")),
458 _ => {}
459 }
460 }
461
462 let dir = tool_config_dir(game_id);
463 Some(GeneratedConfig {
464 path: dir.join("MangoHud.conf"),
465 content: lines.join("\n") + "\n",
466 })
467 }
468
469 fn default_config(&self) -> ToolConfig {
470 let mut config = ToolConfig::new("mangohud");
471 config.set("position", serde_json::json!("top-left"));
472 config.set("fps", serde_json::json!(true));
473 config.set("frametime", serde_json::json!(true));
474 config.set("cpu_stats", serde_json::json!(true));
475 config.set("gpu_stats", serde_json::json!(true));
476 config
477 }
478}
479
480fn mangohud_setting_section(key: &str) -> &'static str {
481 match key {
482 "position" | "horizontal" | "hud_compact" | "no_display" | "custom_text_center"
483 | "background_alpha" | "round_corners" | "background_color" | "font_size"
484 | "text_color" | "font_file" | "offset_x" | "offset_y" | "toggle_hud" | "table_columns" => {
485 "Layout"
486 }
487 "fps" | "frame_timing" | "frametime" | "show_fps_limit" | "frame_count" | "histogram"
488 | "fps_limit" | "fps_limit_method" | "toggle_fps_limit" | "gl_vsync" | "vsync"
489 | "fps_metrics" | "fps_color" | "fps_color_change" => "FPS and Frame Timing",
490 "cpu_stats" | "cpu_load_change" | "core_load" | "core_bars" | "cpu_mhz" | "cpu_temp"
491 | "cpu_power" | "cpu_efficiency" | "core_type" | "cpu_text" | "cpu_color" => "CPU",
492 "gpu_stats"
493 | "gpu_load_change"
494 | "gpu_core_clock"
495 | "gpu_mem_clock"
496 | "gpu_temp"
497 | "gpu_mem_temp"
498 | "gpu_junction_temp"
499 | "gpu_fan"
500 | "gpu_power"
501 | "gpu_power_limit"
502 | "gpu_efficiency"
503 | "flip_efficiency"
504 | "gpu_voltage"
505 | "throttling_status"
506 | "throttling_status_graph"
507 | "gpu_name"
508 | "vulkan_driver"
509 | "gpu_text"
510 | "gpu_color"
511 | "gpu_list"
512 | "pci_dev" => "GPU",
513 "vram" | "ram" | "io_read" | "io_write" | "procmem" | "proc_vram" | "swap" | "ram_temp"
514 | "vram_color" | "ram_color" | "io_color" | "frametime_color" => "Memory and IO",
515 "wine" | "winesync" | "engine_version" | "engine_short_names" | "gamemode" | "vkbasalt"
516 | "fcat" | "fex_stats" | "fsr" | "hdr" | "present_mode" | "display_server" | "arch"
517 | "resolution" | "refresh_rate" | "time" | "version" | "battery" | "battery_watt"
518 | "battery_time" | "device_battery" | "media_player" | "network" | "wine_color"
519 | "engine_color" | "battery_color" | "media_player_color" => "Compatibility",
520 "output_folder" | "log_duration" | "autostart_log" | "log_interval" | "toggle_logging"
521 | "log_versioning" | "upload_logs" | "exec" => "Logging",
522 "temp_fahrenheit" | "af" | "picmip" | "bicubic" | "trilinear" | "retro" => "Filtering",
523 _ => "General",
524 }
525}