alex/beta-minecraft-rust
Minecraft Beta 1.7.3 Rewrite
BRANCH main
SNAPSHOT Draw terrain GPU-driven from packed per-section buffers with GPU occlusion culling, add a render distance slider (2-128) with a quad/disk shape, cut chunk bookkeeping at high render distances, and fix a light underflow at y=0
DOWNLOAD
root crates server src dedicated properties.rs
use std::fs::File;
use std::io::{self, BufReader, BufWriter};
use std::path::PathBuf;
use java_properties::{PropertiesError, PropertiesIter, PropertiesWriter};
/// `PropertyManager`: `server.properties`, which records each default when first requested.
pub struct Properties {
path: PathBuf,
entries: Vec<(String, String)>,
}
impl Properties {
pub fn load(path: PathBuf) -> Self {
let mut properties = Self {
path,
entries: Vec::new(),
};
let loaded = match File::open(&properties.path) {
Ok(file) => PropertiesIter::new(BufReader::new(file))
.read_into(|key, value| properties.put(key, value))
.map_err(|error| {
tracing::warn!("Failed to load {}: {error}", properties.path.display());
}),
Err(error) if error.kind() == io::ErrorKind::NotFound => {
tracing::warn!("{} does not exist", properties.path.display());
Err(())
}
Err(error) => {
tracing::warn!("Failed to load {}: {error}", properties.path.display());
Err(())
}
};
if loaded.is_err() {
tracing::info!("Generating new properties file");
properties.save();
}
properties
}
fn get(&self, key: &str) -> Option<&str> {
self.entries
.iter()
.find(|(k, _)| k == key)
.map(|(_, v)| v.as_str())
}
fn put(&mut self, key: String, value: String) {
match self.entries.iter_mut().find(|(k, _)| *k == key) {
Some((_, v)) => *v = value,
None => self.entries.push((key, value)),
}
}
/// A setting the original never had, so it is not recorded.
pub fn optional_int(&self, key: &str) -> Option<i32> {
self.get(key)?.parse().ok()
}
pub fn string(&mut self, key: &str, default: &str) -> String {
if self.get(key).is_none() {
self.put(key.into(), default.into());
self.save();
}
self.get(key).unwrap_or(default).to_owned()
}
/// `Integer.parseInt`, falling back to the default.
pub fn int(&mut self, key: &str, default: i32) -> i32 {
self.string(key, &default.to_string())
.parse()
.unwrap_or_else(|_| {
self.put(key.into(), default.to_string());
default
})
}
/// `Boolean.parseBoolean`.
pub fn bool(&mut self, key: &str, default: bool) -> bool {
self.string(key, &default.to_string())
.eq_ignore_ascii_case("true")
}
pub fn set_bool(&mut self, key: &str, value: bool) {
self.put(key.into(), value.to_string());
self.save();
}
fn save(&self) {
let result = (|| -> Result<(), PropertiesError> {
let file = File::create(&self.path)?;
let mut writer = PropertiesWriter::new(BufWriter::new(file));
writer.set_comment_prefix("#")?;
writer.write_comment("Minecraft server properties")?;
writer.write_comment(
&chrono::Local::now()
.format("%a %b %d %H:%M:%S %Z %Y")
.to_string(),
)?;
for (key, value) in &self.entries {
writer.write(key, value)?;
}
writer.finish()
})();
if let Err(error) = result {
tracing::warn!("Failed to save {}: {error}", self.path.display());
}
}
}