Add basic cvar saving and loading

This commit is contained in:
Thinkofdeath 2015-09-29 23:24:58 +01:00
parent 12a88b07b9
commit 4a3fc19713
2 changed files with 67 additions and 5 deletions

View File

@ -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<T: Sized + Any + 'static> {
pub default: &'static Fn() -> T,
}
impl Var for CVar<String> {}
impl Var for CVar<String> {
fn serialize(&self, val: &Box<Any>) -> String {
format!("\"{}\"", val.downcast_ref::<String>().unwrap())
}
fn deserialize(&self, input: &String) -> Box<Any> {
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<Any>) -> String;
fn deserialize(&self, input: &String) -> Box<Any>;
fn description(&self) -> &'static str;
fn can_serialize(&self) -> bool;
}
pub struct Console {
names: HashMap<String, &'static str>,
vars: HashMap<&'static str, Box<Var>>,
var_values: HashMap<&'static str, Box<Any>>,
@ -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<T: Sized + Any>(&mut self, var: CVar<T>, val: T) where CVar<T> : 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::<Vec<String>>();
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 {}
unsafe impl Sync for ConsoleProxy {}

View File

@ -45,7 +45,8 @@ use glfw::{Action, Context, Key};
const CL_BRAND: console::CVar<String> = 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);