From 4a3fc19713117938d321a3ff680b6b72f7b8cb3e Mon Sep 17 00:00:00 2001 From: Thinkofdeath Date: Tue, 29 Sep 2015 23:24:58 +0100 Subject: [PATCH] Add basic cvar saving and loading --- src/console/mod.rs | 62 +++++++++++++++++++++++++++++++++++++++++++--- src/main.rs | 10 ++++++-- 2 files changed, 67 insertions(+), 5 deletions(-) diff --git a/src/console/mod.rs b/src/console/mod.rs index 6c7c9d7..baeb435 100644 --- a/src/console/mod.rs +++ b/src/console/mod.rs @@ -16,6 +16,8 @@ use std::marker::PhantomData; use std::collections::HashMap; use std::any::Any; use std::sync::{Arc, Mutex}; +use std::fs; +use std::io::{BufWriter, Write, BufRead, BufReader}; use log; use ui; @@ -31,13 +33,28 @@ pub struct CVar { pub default: &'static Fn() -> T, } -impl Var for CVar {} +impl Var for CVar { + fn serialize(&self, val: &Box) -> String { + format!("\"{}\"", val.downcast_ref::().unwrap()) + } + + fn deserialize(&self, input: &String) -> Box { + Box::new((&input[1..input.len() - 1]).to_owned()) + } + + fn description(&self) -> &'static str { self.description } + fn can_serialize(&self) -> bool { self.serializable } +} pub trait Var { - + fn serialize(&self, val: &Box) -> String; + fn deserialize(&self, input: &String) -> Box; + fn description(&self) -> &'static str; + fn can_serialize(&self) -> bool; } pub struct Console { + names: HashMap, vars: HashMap<&'static str, Box>, var_values: HashMap<&'static str, Box>, @@ -51,6 +68,7 @@ pub struct Console { impl Console { pub fn new() -> Console { let mut con = Console { + names: HashMap::new(), vars: HashMap::new(), var_values: HashMap::new(), @@ -72,6 +90,7 @@ impl Console { if self.vars.contains_key(var.name) { panic!("Key registered twice {}", var.name); } + self.names.insert(var.name.to_owned(), var.name); self.var_values.insert(var.name, Box::new((var.default)())); self.vars.insert(var.name, Box::new(var)); } @@ -83,6 +102,7 @@ impl Console { pub fn set(&mut self, var: CVar, val: T) where CVar : Var { self.var_values.insert(var.name, Box::new(val)); + self.save_config(); } pub fn is_active(&self) -> bool { @@ -145,6 +165,42 @@ impl Console { } } + pub fn load_config(&mut self) { + if let Ok(file) = fs::File::open("conf.cfg") { + let reader = BufReader::new(file); + for line in reader.lines() { + let line = line.unwrap(); + if line.starts_with("#") || line.is_empty() { + continue; + } + let parts = line.splitn(2, ' ').map(|v| v.to_owned()).collect::>(); + let (name, arg) = (&parts[0], &parts[1]); + if let Some(var_name) = self.names.get(name) { + let var = self.vars.get(var_name).unwrap(); + let val = var.deserialize(&arg); + if var.can_serialize() { + self.var_values.insert(var_name, val); + } + } else { + println!("Missing prop"); + } + } + } + } + + pub fn save_config(&self) { + let mut file = BufWriter::new(fs::File::create("conf.cfg").unwrap()); + for (name, var) in &self.vars { + if !var.can_serialize() { + continue; + } + for line in var.description().lines() { + write!(file, "# {}\n", line).unwrap(); + } + write!(file, "{} {}\n\n", name, var.serialize(self.var_values.get(name).unwrap())).unwrap(); + } + } + fn log(&mut self, record: &log::LogRecord) { let mut file = record.location().file(); if let Some(pos) = file.rfind("src/") { @@ -213,4 +269,4 @@ impl log::Log for ConsoleProxy { } unsafe impl Send for ConsoleProxy {} -unsafe impl Sync for ConsoleProxy {} \ No newline at end of file +unsafe impl Sync for ConsoleProxy {} diff --git a/src/main.rs b/src/main.rs index 5c691cc..7fd0251 100644 --- a/src/main.rs +++ b/src/main.rs @@ -45,7 +45,8 @@ use glfw::{Action, Context, Key}; const CL_BRAND: console::CVar = console::CVar { ty: PhantomData, name: "cl_brand", - description: "cl_brand has the value of the clients current 'brand'. e.g. \"Steven\" or \"Vanilla\"", + description: "cl_brand has the value of the clients current 'brand'. \ + e.g. \"Steven\" or \"Vanilla\"", mutable: false, serializable: false, default: &|| "steven".to_owned(), @@ -60,7 +61,12 @@ pub struct Game { fn main() { let con = Arc::new(Mutex::new(console::Console::new())); - con.lock().unwrap().register(CL_BRAND); + { + let mut con = con.lock().unwrap(); + con.register(CL_BRAND); + con.load_config(); + con.save_config(); + } let proxy = console::ConsoleProxy::new(con.clone()); log::set_logger(|max_log_level| { max_log_level.set(log::LogLevelFilter::Trace);