Skip to content

Commit

Permalink
Write startup settings
Browse files Browse the repository at this point in the history
  • Loading branch information
raiguard committed Mar 2, 2022
1 parent 603683c commit 9282114
Show file tree
Hide file tree
Showing 5 changed files with 145 additions and 24 deletions.
22 changes: 13 additions & 9 deletions src/directory.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use anyhow::Result;
use anyhow::{anyhow, Result};
use console::style;
use std::collections::HashMap;
use std::ffi::OsString;
Expand Down Expand Up @@ -248,21 +248,25 @@ impl Directory {
}
}

// TODO: Use Result
pub fn sync_settings(&mut self, save_settings: &PropertyTree) -> Option<()> {
pub fn sync_settings(&mut self, save_settings: &PropertyTree) -> Result<()> {
let startup_settings = self
.mod_settings
.settings
.get_mut("settings-startup")?
.as_dictionary_mut()?;

for (setting_name, setting_value) in save_settings.as_dictionary()? {
.get_mut("startup")
.ok_or_else(|| anyhow!("No startup settings in mod-settings.dat"))?
.as_dictionary_mut()
.ok_or_else(|| anyhow!("Could not read PropertyTree dictionary."))?;

for (setting_name, setting_value) in save_settings
.as_dictionary()
.ok_or_else(|| anyhow!("Could not read PropertyTree dictionary"))?
{
startup_settings.insert(setting_name.clone(), setting_value.clone());
}

self.mod_settings.write().ok()?;
self.mod_settings.write()?;

Some(())
Ok(())
}
}

Expand Down
4 changes: 3 additions & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,9 @@ fn main() -> Result<()> {

combined_enable.append(&mut mods);

directory.sync_settings(&save_file.startup_settings);
directory.sync_settings(&save_file.startup_settings)?;

println!("Synced startup settings");
}
// Manually enable
combined_enable.append(&mut app.enable.to_vec());
Expand Down
30 changes: 18 additions & 12 deletions src/mod_settings.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
use anyhow::Result;
use byteorder::{LittleEndian, ReadBytesExt};
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use std::fs;
use std::io::{Cursor, Seek, SeekFrom};
use std::path::PathBuf;

use crate::read::PropertyTree;

#[derive(Debug)]
pub struct ModSettings {
pub settings: PropertyTree,

Expand Down Expand Up @@ -42,16 +43,21 @@ impl ModSettings {
}

pub fn write(&self) -> Result<()> {
let contents = vec![
self.version_major,
self.version_minor,
self.version_patch,
self.version_build,
0,
];
// contents.append(self.settings.write());
// let mut file = fs::write(self.path, &contents);

unimplemented!()
let mut output = vec![];

// Factorio version number
output.write_u16::<LittleEndian>(self.version_major)?;
output.write_u16::<LittleEndian>(self.version_minor)?;
output.write_u16::<LittleEndian>(self.version_patch)?;
output.write_u16::<LittleEndian>(self.version_build)?;
// Internal flag - always false
output.push(false as u8);

// Settings PropertyTree
self.settings.write(&mut output)?;

fs::write(&self.path, output)?;

Ok(())
}
}
111 changes: 111 additions & 0 deletions src/read.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use anyhow::anyhow;
use anyhow::Result;
use byteorder::WriteBytesExt;
use byteorder::{LittleEndian, ReadBytesExt};
use semver::Version;
use semver::VersionReq;
Expand Down Expand Up @@ -61,21 +62,25 @@ impl PropertyTree {
}

/// Index into a PropertyTree list or dictionary.
#[allow(unused)]
pub fn get<T: PropertyTreeKey>(&self, key: T) -> Option<&Self> {
key.index_into(self)
}

/// Mutably index into a PropertyTree list or dictionary.
#[allow(unused)]
pub fn get_mut<T: PropertyTreeKey>(&mut self, key: T) -> Option<&mut Self> {
key.index_into_mut(self)
}

/// Returns `true` if the `PropertyTree` is a list.
#[allow(unused)]
pub fn is_list(&self) -> bool {
matches!(self, Self::List(_))
}

/// If the `PropertyTree` is a list, returns the associated vector. Otherwise returns `None`.
#[allow(unused)]
pub fn as_list(&self) -> Option<&Vec<PropertyTree>> {
match self {
Self::List(list) => Some(list),
Expand All @@ -84,6 +89,7 @@ impl PropertyTree {
}

/// If the `PropertyTree` is a list, returns the associated mutable vector. Otherwise returns `None`.
#[allow(unused)]
pub fn as_list_mut(&mut self) -> Option<&mut Vec<PropertyTree>> {
match self {
Self::List(list) => Some(list),
Expand All @@ -92,6 +98,7 @@ impl PropertyTree {
}

/// Returns `true` if the `PropertyTree` is a list.
#[allow(unused)]
pub fn is_dictionary(&self) -> bool {
matches!(self, Self::Dictionary(_))
}
Expand All @@ -111,6 +118,77 @@ impl PropertyTree {
_ => None,
}
}

/// Serializes the `PropertyTree` into the given bytestream.
pub fn write(&self, output: &mut Vec<u8>) -> Result<()> {
// Each PropertyTree type has a flag as the second byte that doesn't matter, so we just ignore it
match self {
PropertyTree::None => {
// PropertyTree type
output.write_u8(0)?;
// Internal flag
output.write_u8(0)?;
}
PropertyTree::Boolean(bool) => {
// PropertyTree type
output.write_u8(1)?;
// Internal flag
output.write_u8(0)?;
// Data
output.write_u8(if *bool { 1 } else { 0 })?;
}
PropertyTree::Number(num) => {
// PropertyTree type
output.write_u8(2)?;
// Internal flag
output.write_u8(0)?;
// Data
output.write_f64::<LittleEndian>(*num)?;
}
PropertyTree::String(str) => {
// PropertyTree type
output.write_u8(3)?;
// Internal flag
output.write_u8(0)?;
// Data
output.write_pt_string(str)?;
}
PropertyTree::List(list) => {
// PropertyTree type
output.write_u8(4)?;
// Internal flag
output.write_u8(0)?;

// Length of the list
output.write_u32::<LittleEndian>(list.len() as u32)?;

// List contents
for item in list {
// List keys are empty strings
output.write_pt_string(&None)?;
item.write(output)?;
}
}
PropertyTree::Dictionary(dict) => {
// PropertyTree type
output.write_u8(5)?;
// Internal flag
output.write_u8(0)?;

// Length of the list
output.write_u32::<LittleEndian>(dict.len() as u32)?;

// Dictionary contents
for (key, value) in dict {
// Dictionary keys always exist
output.write_pt_string(&Some(key.to_string()))?;
value.write(output)?;
}
}
};

Ok(())
}
}

pub trait PropertyTreeKey {
Expand Down Expand Up @@ -216,3 +294,36 @@ pub trait ReadFactorioDat: io::Read {

/// All types that implement `Read` get methods defined in `ReadFactorioDat` for free.
impl<R: io::Read + ?Sized> ReadFactorioDat for R {}

pub trait WriteFactorioDat: io::Write {
fn write_u32_optimized(&mut self, num: u32) -> io::Result<()> {
if num < 255 {
self.write_u8(num as u8)?;
} else {
// Represented as the first byte being 255
self.write_u8(255)?;
self.write_u32::<LittleEndian>(num)?;
}

Ok(())
}

fn write_pt_string(&mut self, str: &Option<String>) -> io::Result<()> {
if let Some(str) = str {
// Not-empty flag
self.write_u8(0)?;
// String length
self.write_u32_optimized(str.len() as u32)?;
// String contents
self.write_all(str.as_bytes())?;
} else {
// Empty flag
self.write_u8(1)?;
}

Ok(())
}
}

/// All types that implement `Write` get methods defined in `WriteFactorioDat` for free.
impl<R: io::Write + ?Sized> WriteFactorioDat for R {}
2 changes: 0 additions & 2 deletions src/sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,6 @@ impl SaveFile {

let startup_settings = PropertyTree::load(&mut cursor)?;

println!("FILE SETTINGS: {:#?}", startup_settings);

Ok(Self {
mods,
map_version: Version::new(
Expand Down

0 comments on commit 9282114

Please sign in to comment.