Skip to main content

pfx_play/
settings.rs

1use std::collections::BTreeMap;
2
3use pfx_gpu::screens::DisplaySettings;
4use pfx_gpu::window::{FrameCap, FrameCaps};
5use pfx_input::BindingMap;
6use pfx_sound::{ChannelId, Mixer};
7use serde::{Deserialize, Serialize};
8
9#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
10#[serde(default)]
11pub struct Settings {
12    pub rumble: u8,
13    pub display: DisplaySettings,
14    pub pacing: Pacing,
15    pub audio: Audio,
16    #[serde(skip_serializing_if = "Option::is_none")]
17    pub binds: Option<BindingMap>,
18}
19
20impl Default for Settings {
21    fn default() -> Self {
22        Self {
23            rumble: 100,
24            display: DisplaySettings::default(),
25            pacing: Pacing::default(),
26            audio: Audio::default(),
27            binds: None,
28        }
29    }
30}
31
32#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
33pub enum Cap {
34    #[serde(rename = "30")]
35    Fps30,
36    #[serde(rename = "60")]
37    Fps60,
38    #[serde(rename = "90")]
39    Fps90,
40    #[serde(rename = "120")]
41    Fps120,
42    #[serde(rename = "uncapped")]
43    Uncapped,
44}
45
46impl Cap {
47    pub fn frame_cap(self) -> FrameCap {
48        match self {
49            Cap::Fps30 => FrameCap::Fps30,
50            Cap::Fps60 => FrameCap::Fps60,
51            Cap::Fps90 => FrameCap::Fps90,
52            Cap::Fps120 => FrameCap::Fps120,
53            Cap::Uncapped => FrameCap::Uncapped,
54        }
55    }
56}
57
58impl From<FrameCap> for Cap {
59    fn from(cap: FrameCap) -> Self {
60        match cap {
61            FrameCap::Fps30 => Cap::Fps30,
62            FrameCap::Fps60 => Cap::Fps60,
63            FrameCap::Fps90 => Cap::Fps90,
64            FrameCap::Fps120 => Cap::Fps120,
65            FrameCap::Uncapped => Cap::Uncapped,
66        }
67    }
68}
69
70#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
71#[serde(default)]
72pub struct Pacing {
73    pub focused: Cap,
74    pub background: Cap,
75    pub vrr: bool,
76    pub pause_when_minimized: bool,
77}
78
79impl Default for Pacing {
80    fn default() -> Self {
81        Self {
82            focused: Cap::Fps60,
83            background: Cap::Fps30,
84            vrr: false,
85            pause_when_minimized: true,
86        }
87    }
88}
89
90impl Pacing {
91    pub fn caps(&self) -> FrameCaps {
92        FrameCaps {
93            pause_when_minimized: self.pause_when_minimized,
94            ..FrameCaps::new(self.focused.frame_cap(), self.background.frame_cap())
95        }
96    }
97}
98
99#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
100#[serde(default)]
101pub struct Audio {
102    pub master: f32,
103    pub muted: bool,
104    pub music: f32,
105    pub effects: f32,
106    pub dialog: f32,
107    #[serde(skip_serializing_if = "BTreeMap::is_empty")]
108    pub custom: BTreeMap<u32, f32>,
109}
110
111impl Default for Audio {
112    fn default() -> Self {
113        Self {
114            master: 1.0,
115            muted: false,
116            music: 1.0,
117            effects: 1.0,
118            dialog: 1.0,
119            custom: BTreeMap::new(),
120        }
121    }
122}
123
124impl Audio {
125    pub fn channels(&self) -> Vec<(ChannelId, f32)> {
126        let mut channels = vec![
127            (ChannelId::MUSIC, self.music),
128            (ChannelId::EFFECTS, self.effects),
129            (ChannelId::DIALOG, self.dialog),
130        ];
131        channels.extend(
132            self.custom
133                .iter()
134                .map(|(index, volume)| (ChannelId::custom(*index), *volume)),
135        );
136        channels
137    }
138
139    pub fn apply(&self, mixer: &mut Mixer) {
140        mixer.set_master_volume(self.master);
141        mixer.set_master_muted(self.muted);
142        for (channel, volume) in self.channels() {
143            mixer.set_channel_volume(channel, volume);
144        }
145    }
146}