1use core::fmt;
3use read_properties::Properties;
7use std::fs::File;
8use std::io::BufReader;
9use std::io::{Error, ErrorKind};
10use std::net::Ipv4Addr;
11use std::path::Path;
12use std::str::FromStr;
13pub mod read_properties;
14#[derive(Debug)]
33pub enum Difficulty {
34 Easy,
35 Normal,
36 Hard,
37}
38
39#[derive(Debug)]
40pub enum Gamemode {
41 Adventure,
42 Survival,
43 Creative,
44 Spectator,
45}
46
47#[derive(Debug)]
48pub enum WorldPreset {
49 Normal,
50 Flat,
51 LargeBiomes,
52 Amplified,
53 SingleBiomeSurface,
54}
55
56#[derive(Debug)]
59pub struct Settings {
60 pub enable_jmx_monitoring: bool,
61 pub rcon_port: u16,
62 pub level_seed: Option<i64>,
63 pub gamemode: Gamemode,
64 pub enable_command_block: bool,
65 pub enable_query: bool,
66 pub enforce_secure_profile: bool,
67 pub level_name: Option<String>,
68 pub motd: Option<String>,
69 pub query_port: u16,
70 pub pvp: bool,
71 pub generate_structures: bool,
72 pub max_chained_neighbor_updates: Option<i32>,
73 pub difficulty: Difficulty,
74 pub network_compression_threshold: i32,
75 pub max_tick_time: i64,
76 pub require_resource_pack: bool,
77 pub use_native_transport: bool,
78 pub max_players: u32,
79 pub online_mode: bool,
80 pub enable_status: bool,
81 pub allow_flight: bool,
82 pub initial_disabled_packs: Option<String>,
83 pub broadcast_rcon_to_ops: bool,
84 pub view_distance: u8,
85 pub server_ip: Option<Ipv4Addr>,
86 pub resource_pack_prompt: Option<String>,
87 pub allow_nether: bool,
88 pub server_port: u16,
89 pub enable_rcon: bool,
90 pub sync_chunk_writes: bool,
91 pub op_permission_level: u8,
92 pub prevent_proxy_connections: bool,
93 pub hide_online_players: bool,
94 pub resource_pack: Option<String>,
95 pub entity_broadcast_range_percentage: u8,
96 pub simulation_distance: u8,
97 pub rcon_password: Option<String>,
98 pub player_idle_timeout: i32,
99 pub force_gamemode: bool,
100 pub rate_limit: u32,
101 pub hardcore: bool,
102 pub white_list: bool,
103 pub broadcast_console_to_ops: bool,
104 pub spawn_npcs: bool,
105 pub spawn_animals: bool,
106 pub log_ips: bool,
107 pub function_permission_level: u8,
108 pub initial_enabled_packs: String,
109 pub level_type: WorldPreset,
110 pub spawn_monsters: bool,
111 pub enforce_whitelist: bool,
112 pub spawn_protection: u16,
113 pub resource_pack_sha1: Option<String>,
114 pub max_world_size: u32,
115 }
118
119fn read(filepath: &Path) -> std::io::Result<Properties> {
120 let file = File::open(filepath)?;
121 let mut reader = BufReader::new(file);
122 read_properties::read_properties(&mut reader)
123 .map_err(|e| Error::new(ErrorKind::Other, e.to_string()))
124}
125impl FromStr for Gamemode {
126 type Err = ();
127
128 fn from_str(input: &str) -> Result<Gamemode, Self::Err> {
129 match input.to_lowercase().as_str() {
130 "creative" => Ok(Gamemode::Creative),
131 "survival" => Ok(Gamemode::Survival),
132 "spectator" => Ok(Gamemode::Spectator),
133 "adventure" => Ok(Gamemode::Adventure),
134 _ => Err(()),
135 }
136 }
137}
138impl FromStr for WorldPreset {
139 type Err = ();
140
141 fn from_str(input: &str) -> Result<Self, Self::Err> {
142 match input.to_lowercase().as_str() {
143 "normal" => Ok(WorldPreset::Normal),
144 "flat" => Ok(WorldPreset::Flat),
145 "largebiomes" => Ok(WorldPreset::LargeBiomes),
146 "amplified" => Ok(WorldPreset::Amplified),
147 "singlebiomesurface" => Ok(WorldPreset::SingleBiomeSurface),
148 _ => Err(()),
149 }
150 }
151}
152impl FromStr for Difficulty {
153 type Err = ();
154
155 fn from_str(input: &str) -> Result<Difficulty, Self::Err> {
156 match input.to_lowercase().as_str() {
157 "easy" => Ok(Difficulty::Easy),
158 "normal" => Ok(Difficulty::Normal),
159 "hard" => Ok(Difficulty::Hard),
160 _ => Err(()), }
162 }
163}
164impl fmt::Display for Difficulty {
165 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
166 let difficulty = match self {
167 Difficulty::Easy => "easy",
168 Difficulty::Normal => "normal",
169 Difficulty::Hard => "hard",
170 };
171 write!(f, "{}", difficulty)
172 }
173}
174
175impl Settings {
176 pub fn new() -> Self {
177 let config_file = read(Path::new(crate::consts::file_paths::PROPERTIES))
178 .expect("Error reading {server.properties} file");
179 Self {
180 enable_jmx_monitoring: Self::get_bool(&config_file, "enable-jmx-monitoring", false),
181 rcon_port: Self::get_u16(&config_file, "rcon.port", 25575),
182 level_seed: Self::get_optional_i64(&config_file, "level-seed"),
183 gamemode: Self::get_enum::<Gamemode>(&config_file, "gamemode", Gamemode::Survival),
184 enable_command_block: Self::get_bool(&config_file, "enable-command-block", false),
185 max_players: Self::get_u32(&config_file, "max-players", 20),
186 server_ip: Self::get_optional_ip(&config_file, "server-ip"),
187 server_port: Self::get_u16(&config_file, "server-port", 25565),
188 allow_flight: Self::get_bool(&config_file, "allow-flight", false),
189 allow_nether: Self::get_bool(&config_file, "allow-nether", true),
190 broadcast_console_to_ops: Self::get_bool(
191 &config_file,
192 "broadcast-console-to-ops",
193 true,
194 ),
195 difficulty: config_file
196 .get_property("difficulty")
197 .unwrap_or("easy")
198 .parse::<Difficulty>()
199 .unwrap_or(Difficulty::Easy),
200 broadcast_rcon_to_ops: Self::get_bool(&config_file, "broadcast-rcon-to-ops", true),
201 enable_query: Self::get_bool(&config_file, "enable-query", true),
202 enable_rcon: Self::get_bool(&config_file, "enable-rcon", false),
203 enable_status: Self::get_bool(&config_file, "enable-status", true),
204 enforce_secure_profile: Self::get_bool(&config_file, "enforce-secure-profil", true),
205 enforce_whitelist: Self::get_bool(&config_file, "enforce-whitelist", false),
206 entity_broadcast_range_percentage: Self::get_u8(
207 &config_file,
208 "entity-broadcast-range-percentage",
209 100,
210 ),
211 force_gamemode: Self::get_bool(&config_file, "force-gamemode", false),
212 function_permission_level: Self::get_u8(&config_file, "function-permission-level", 2),
213 generate_structures: Self::get_bool(&config_file, "generate-strucutre", true),
214 hardcore: Self::get_bool(&config_file, "hardcore", false),
215 hide_online_players: Self::get_bool(&config_file, "hide-online-players", false),
216 initial_disabled_packs: Self::get_optional_string(
217 &config_file,
218 "initial-disabled-packs",
219 ),
220 initial_enabled_packs: Self::get_optional_string(&config_file, "initial-enabled-packs")
221 .unwrap_or_else(|| "vanilla".to_string()),
222 level_name: Self::get_optional_string(&config_file, "level-name"),
223 level_type: config_file
224 .get_property("level-type")
225 .unwrap_or("normal")
226 .parse::<WorldPreset>()
227 .unwrap_or(WorldPreset::Normal),
228 log_ips: Self::get_bool(&config_file, "log-ips", true), max_chained_neighbor_updates: Self::get_optional_i32(
230 &config_file,
231 "max-chained-neighbor-updates",
232 ),
233 max_tick_time: Self::get_i64(&config_file, "max-tick-time", 60000),
234 max_world_size: Self::get_u32(&config_file, "max-world-size", 29999984),
235 motd: Self::get_optional_string(&config_file, "motd"),
236 network_compression_threshold: Self::get_i32(
237 &config_file,
238 "network-compression-threshold",
239 256,
240 ),
241 online_mode: Self::get_bool(&config_file, "online-mode", true),
242 op_permission_level: Self::get_u8(&config_file, "op-permission-level", 4),
243 player_idle_timeout: Self::get_i32(&config_file, "player-idle-timeout", 0),
244 prevent_proxy_connections: Self::get_bool(
245 &config_file,
246 "prevent-proxy-connections",
247 false,
248 ),
249 pvp: Self::get_bool(&config_file, "pvp", true),
250 query_port: Self::get_u16(&config_file, "query-port", 25565),
251 rate_limit: Self::get_u32(&config_file, "rate-limit", 0),
252 rcon_password: Self::get_optional_string(&config_file, "rcon.password"),
253 require_resource_pack: Self::get_bool(&config_file, "require-ressource-pack", false),
254 resource_pack: Self::get_optional_string(&config_file, "resource-pack"),
255 resource_pack_prompt: Self::get_optional_string(&config_file, "resource-pack-prompt"),
256 resource_pack_sha1: Self::get_optional_string(&config_file, "ressource-pack-sha1"),
257 simulation_distance: Self::get_u8(&config_file, "simulation-distance", 10),
258 spawn_animals: Self::get_bool(&config_file, "spawn-animals", true),
259 spawn_monsters: Self::get_bool(&config_file, "spawn-monster", true),
260 spawn_npcs: Self::get_bool(&config_file, "spawn-npcs", true),
261 spawn_protection: Self::get_u16(&config_file, "spawn-protection", 16),
262 sync_chunk_writes: Self::get_bool(&config_file, "sync-chunk-writes", false),
263 use_native_transport: Self::get_bool(&config_file, "use-native-transport", true),
264 view_distance: Self::get_u8(&config_file, "view-distance", 10),
265 white_list: Self::get_bool(&config_file, "white-list", false),
266 }
267 }
268 fn get_bool(config: &Properties, key: &str, default: bool) -> bool {
269 config
270 .get_property(key)
271 .unwrap_or(default.to_string().as_str())
272 .parse()
273 .unwrap_or(default)
274 }
275 fn get_u16(config: &Properties, key: &str, default: u16) -> u16 {
276 config
277 .get_property(key)
278 .unwrap_or(default.to_string().as_str())
279 .parse()
280 .unwrap_or(default)
281 }
282 fn get_u32(config: &Properties, key: &str, default: u32) -> u32 {
283 config
284 .get_property(key)
285 .unwrap_or(default.to_string().as_str())
286 .parse()
287 .unwrap_or(default)
288 }
289 fn get_u8(config: &Properties, key: &str, default: u8) -> u8 {
290 config
291 .get_property(key)
292 .unwrap_or(default.to_string().as_str())
293 .parse()
294 .unwrap_or(default)
295 }
296 fn get_i32(config: &Properties, key: &str, default: i32) -> i32 {
297 config
298 .get_property(key)
299 .unwrap_or(default.to_string().as_str())
300 .parse()
301 .unwrap_or(default)
302 }
303 fn get_i64(config: &Properties, key: &str, default: i64) -> i64 {
304 config
305 .get_property(key)
306 .unwrap_or(default.to_string().as_str())
307 .parse()
308 .unwrap_or(default)
309 }
310 fn get_enum<T: std::str::FromStr>(config: &Properties, key: &str, default: T) -> T {
311 config
312 .get_property(key)
313 .unwrap_or("")
314 .parse()
315 .unwrap_or(default)
316 }
317 fn get_optional_string(config: &Properties, key: &str) -> Option<String> {
318 config
319 .get_property(key)
320 .ok()
321 .filter(|s| !s.is_empty())
322 .map(String::from)
323 }
324
325 fn get_optional_i64(config: &Properties, key: &str) -> Option<i64> {
326 config.get_property(key).ok().and_then(|s| s.parse().ok())
327 }
328 fn get_optional_i32(config: &Properties, key: &str) -> Option<i32> {
329 config.get_property(key).ok().and_then(|s| s.parse().ok())
330 }
331
332 fn get_optional_ip(config: &Properties, key: &str) -> Option<Ipv4Addr> {
333 config.get_property(key).ok().and_then(|s| s.parse().ok())
334 }
335}