flatland_client_lib/
settings.rs1use std::path::PathBuf;
4
5use serde::{Deserialize, Serialize};
6
7#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
8pub struct ClientSettings {
9 #[serde(default = "default_version")]
10 pub version: String,
11 #[serde(default)]
12 pub keys: ClientKeyBindings,
13}
14
15fn default_version() -> String {
16 "1".into()
17}
18
19impl Default for ClientSettings {
20 fn default() -> Self {
21 Self {
22 version: default_version(),
23 keys: ClientKeyBindings::default(),
24 }
25 }
26}
27
28#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
29pub struct ClientKeyBindings {
30 #[serde(default = "default_target_t1")]
31 pub target_t1: String,
32 #[serde(default = "default_target_t2")]
33 pub target_t2: String,
34 #[serde(default = "default_auto_t1")]
35 pub auto_t1: String,
36 #[serde(default = "default_auto_t2")]
37 pub auto_t2: String,
38 #[serde(default = "default_loadout")]
39 pub loadout_menu: String,
40 #[serde(default = "default_rotation_editor")]
41 pub rotation_editor: String,
42 #[serde(default = "default_dodge")]
43 pub dodge: String,
44 #[serde(default = "default_lunge")]
45 pub lunge: String,
46 #[serde(default = "default_block")]
47 pub block: String,
48 #[serde(default = "default_clear_t1")]
49 pub clear_target_t1: String,
50 #[serde(default = "default_clear_t2")]
51 pub clear_target_t2: String,
52 #[serde(default = "default_hotbar")]
54 pub hotbar: Vec<Option<String>>,
55}
56
57fn default_target_t1() -> String {
58 "Tab".into()
59}
60fn default_target_t2() -> String {
61 "Shift+Tab".into()
62}
63fn default_auto_t1() -> String {
64 "r".into()
65}
66fn default_auto_t2() -> String {
67 "Shift+r".into()
68}
69fn default_loadout() -> String {
70 "l".into()
71}
72fn default_rotation_editor() -> String {
73 "o".into()
74}
75fn default_dodge() -> String {
76 "c".into()
77}
78fn default_lunge() -> String {
79 "Shift+Space".into()
80}
81fn default_block() -> String {
82 "q".into()
83}
84fn default_clear_t1() -> String {
85 "0".into()
86}
87fn default_clear_t2() -> String {
88 "Shift+0".into()
89}
90fn default_hotbar() -> Vec<Option<String>> {
91 Vec::new()
92}
93
94impl Default for ClientKeyBindings {
95 fn default() -> Self {
96 Self {
97 target_t1: default_target_t1(),
98 target_t2: default_target_t2(),
99 auto_t1: default_auto_t1(),
100 auto_t2: default_auto_t2(),
101 loadout_menu: default_loadout(),
102 rotation_editor: default_rotation_editor(),
103 dodge: default_dodge(),
104 lunge: default_lunge(),
105 block: default_block(),
106 clear_target_t1: default_clear_t1(),
107 clear_target_t2: default_clear_t2(),
108 hotbar: default_hotbar(),
109 }
110 }
111}
112
113impl ClientKeyBindings {
114 pub fn hotbar_ability(&self, slot_1_to_9: u8) -> Option<&str> {
116 if !(1..=9).contains(&slot_1_to_9) {
117 return None;
118 }
119 self.hotbar
120 .get((slot_1_to_9 - 1) as usize)
121 .and_then(|a| a.as_deref())
122 .filter(|id| !id.is_empty())
123 }
124}
125
126fn find_settings_path() -> PathBuf {
127 if let Ok(p) = std::env::var("FLATLAND_CLIENT_SETTINGS") {
128 let path = PathBuf::from(p);
129 if path.is_file() {
130 return path;
131 }
132 }
133 if let Some(rev) = crate::assets::synced_rev_dir() {
134 let path = rev.join("config/client-settings.yaml");
135 if path.is_file() {
136 return path;
137 }
138 }
139 if let Ok(home) = std::env::var("HOME") {
140 let path = PathBuf::from(home).join(".flatland3/assets/current/config/client-settings.yaml");
141 if path.is_file() {
142 return path;
143 }
144 }
145 let mut dir = std::env::current_dir().unwrap_or_else(|_| PathBuf::from("."));
146 for _ in 0..8 {
147 let candidate = dir.join("assets/config/client-settings.yaml");
148 if candidate.is_file() {
149 return candidate;
150 }
151 if !dir.pop() {
152 break;
153 }
154 }
155 let manifest = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
156 for ancestor in manifest.ancestors() {
157 let candidate = ancestor.join("assets/config/client-settings.yaml");
158 if candidate.is_file() {
159 return candidate;
160 }
161 }
162 PathBuf::from("assets/config/client-settings.yaml")
163}
164
165pub fn load_client_settings() -> ClientSettings {
166 let path = find_settings_path();
167 let Ok(raw) = std::fs::read_to_string(&path) else {
168 return ClientSettings::default();
169 };
170 serde_yaml::from_str(&raw).unwrap_or_default()
171}