Skip to content

Commit

Permalink
Bugfixes and documentation improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
TCA166 committed Apr 30, 2024
1 parent f9736af commit fd3d94a
Show file tree
Hide file tree
Showing 7 changed files with 138 additions and 49 deletions.
6 changes: 5 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,12 @@ check: src/*.rs src/structures/*.rs

doc: src/*.rs src/structures/*.rs
@echo "Building documentation..."
cargo doc --no-deps --document-private-items
cargo doc --no-deps --document-private-items --bin ck3_history_extractor

dependencies:
@echo "Installing dependencies..."
sudo dnf install rust cargo rustup rust-src

clean:
@echo "Cleaning up..."
cargo clean
61 changes: 42 additions & 19 deletions src/game_object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@ use std::{cell::Ref, collections::{hash_map, HashMap}, slice};

use crate::structures::Shared;

/// A value that can be stored in a SaveFile and is held by a GameObject
///
/// This is a wrapper around a String or a GameObject
/// A value that can be stored in a SaveFile and is held by a GameObject.
/// This is a wrapper around a String or a GameObject.
#[derive(Debug)]
pub enum SaveFileValue{
String(Shared<String>),
Expand All @@ -13,9 +12,14 @@ pub enum SaveFileValue{

impl SaveFileValue {

/// Get the value as a string reference
/// Get the value as a string reference.
/// Mainly used for convenience.
///
/// ## Returns
/// # Panics
///
/// If the value is not a string
///
/// # Returns
///
/// A reference to the string
pub fn as_string_ref(&self) -> Option<Ref<'_, String>>{
Expand All @@ -27,11 +31,11 @@ impl SaveFileValue {

/// Get the value as a string
///
/// ## Panics
/// # Panics
///
/// Panics if the value is not a string
///
/// ## Returns
/// # Returns
///
/// A reference to the string
pub fn as_string(&self) -> Shared<String>{
Expand All @@ -43,7 +47,11 @@ impl SaveFileValue {

/// Get the value as a GameObject reference
///
/// ## Returns
/// # Panics
///
/// Panics if the value is not a GameObject
///
/// # Returns
///
/// A reference to the GameObject
pub fn as_object_ref(&self) -> Option<Ref<'_, GameObject>>{
Expand All @@ -55,9 +63,12 @@ impl SaveFileValue {

}

/// Representation of a save file object
///
/// Acts like a named dictionary and array, may be either or both
/// Representation of a save file object.
/// These are the main data structure used to store game data.
/// Each belongs to a section, but that is not stored here.
/// Acts like a named dictionary and array, may be either or both or neither.
/// Each has a name, which isn't unique.
/// Holds [SaveFileValue]s, which are either strings or other GameObjects.
#[derive(Debug)]
pub struct GameObject{
inner: HashMap<String, SaveFileValue>,
Expand All @@ -76,7 +87,7 @@ impl GameObject{
}
}

/// Create a new GameObject
/// Create a new empty GameObject
pub fn new() -> GameObject{
GameObject{
inner: HashMap::new(),
Expand All @@ -90,7 +101,7 @@ impl GameObject{
self.name = name;
}

/// Insert a new key value pair into the GameObject
/// Insert a new key value pair into the GameObject dictionary
pub fn insert(&mut self, key: String, value: SaveFileValue){
self.inner.insert(key, value);
}
Expand All @@ -100,12 +111,24 @@ impl GameObject{
self.inner.get(key)
}

/// Get the value of a key as a string
/// Get the value of a key as a string.
/// Mainly used for convenience.
///
/// # Panics
///
/// If the key is missing or the value is not a string
///
pub fn get_string_ref(&self, key: &str) -> Ref<'_, String>{
self.inner.get(key).unwrap().as_string_ref().unwrap()
}

/// Get the value of a key as a GameObject
/// Get the value of a key as a GameObject.
/// Mainly used for convenience.
///
/// # Panics
///
/// If the key is missing or the value is not a GameObject
///
pub fn get_object_ref(&self, key: &str) -> Ref<'_, GameObject>{
self.inner.get(key).unwrap().as_object_ref().unwrap()
}
Expand All @@ -126,22 +149,22 @@ impl GameObject{
self.array.push(value);
}

/// Get the length of the GameObject array
/// Checks if the dictionary and array are empty
pub fn is_empty(&self) -> bool{
self.inner.is_empty() && self.array.is_empty()
}

/// Get the length of the GameObject array
/// Gets the iterator for the underlying array
pub fn get_array_iter(&self) -> slice::Iter<SaveFileValue>{
self.array.iter()
}

/// Get the length of the GameObject array
/// Gets the iterator for the underlying dictionary
pub fn get_obj_iter(&self) -> hash_map::Iter<String, SaveFileValue>{
self.inner.iter()
}

/// Get the keys of the GameObject
/// Get the keys of the GameObject dictionary
pub fn get_keys(&self) -> Vec<String>{
self.inner.keys().map(|x| x.clone()).collect()
}
Expand Down
3 changes: 2 additions & 1 deletion src/game_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ use crate::structures::{Character, Culture, Dynasty, Faith, GameObjectDerived, M
use crate::game_object::GameObject;

/// A struct representing all known game objects
///
/// It is guaranteed to always return a reference to the same object for the same key.
/// Naturally the value of that reference may change as values are added to the game state.
pub struct GameState{
Expand Down Expand Up @@ -35,10 +34,12 @@ impl GameState{
}
}

/// Add a lookup table for traits
pub fn add_lookup(&mut self, array:Vec<Shared<String>>){
self.traits_lookup = array;
}

/// Get a trait by id
pub fn get_trait(&self, id:u32) -> Shared<String>{
self.traits_lookup[id as usize].clone()
}
Expand Down
6 changes: 5 additions & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,11 @@ fn main() {
let o = i.to_object().unwrap();
let database = o.get_object_ref("database");
for d in database.get_obj_iter(){
game_state.add_memory(d.1.as_object_ref().unwrap());
let mem = d.1.as_object_ref();
if mem.is_none() {
continue;
}
game_state.add_memory(mem.unwrap());
}
}
"played_character" => {
Expand Down
53 changes: 48 additions & 5 deletions src/save_file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use crate::game_object::{GameObject, SaveFileValue};

/// A function that reads a single character from a file
///
/// ## Returns
/// # Returns
///
/// The character read or None if the end of the file is reached
fn fgetc(file: &mut File) -> Option<char>{ // Shoutout to my C literate homies out there
Expand All @@ -18,12 +18,30 @@ fn fgetc(file: &mut File) -> Option<char>{ // Shoutout to my C literate homies o
return Some(buffer[0] as char);
}


/// A struct that represents a section in a ck3 save file
/// Each section has a name, and holds a file handle to the section
///
/// # Validity
///
/// The section is guaranteed to be valid when you get it.
/// However once you call [Section::to_object] or [Section::skip] the section becomes invalid.
/// Trying to do anything with an invalid section will panic.
///
/// # Example
///
/// ```
/// let save = SaveFile::new("save.ck3");
/// let section = save.next();
/// let object = section.to_object().unwrap();
/// ```
pub struct Section{
name: String,
file:Option<File>
}

impl Section{
/// Create a new section
fn new(name: &str, file: File) -> Section{
Section{
name: name.to_string(),
Expand All @@ -36,11 +54,19 @@ impl Section{
&self.name
}

/// Invalidate the section
fn invalidate(&mut self){
self.file = None;
}

/// Convert the section to a GameObject and invalidate it
/// Convert the section to a GameObject and invalidate it.
/// This is a rather costly process as it has to read the entire section contents and parse them.
/// You can then make a choice if you want to parse the object or [Section::skip] it.
/// The section must be valid.
///
/// # Panics
///
/// If the section is invalid
pub fn to_object(&mut self) -> Option<GameObject>{
if self.file.is_none(){
panic!("Invalid section");
Expand Down Expand Up @@ -150,7 +176,13 @@ impl Section{
return Some(object);
}

/// Skip the current section and invalidate it
/// Skip the current section and invalidate it.
/// This is a rather cheap operation as it only reads the file until the end of the section.
/// The section must be valid.
///
/// # Panics
///
/// If the section is invalid
pub fn skip(&mut self){
if self.file.is_none(){
panic!("Invalid section");
Expand Down Expand Up @@ -180,14 +212,24 @@ impl Section{
}
}

/// A struct that represents a ck3 save file
/// A struct that represents a ck3 save file.
/// This struct is an iterator that returns sections from the save file.
///
/// # Example
///
/// ```
/// let save = SaveFile::new("save.ck3");
/// for section in save{
/// println!("Section: {}", section.get_name());
/// }
pub struct SaveFile{
file: File
}

impl SaveFile{

/// Create a new SaveFile instance
/// Create a new SaveFile instance.
/// The filename must be valid of course.
pub fn new(filename: &str) -> SaveFile{
SaveFile{
file: File::open(filename).unwrap(),
Expand All @@ -201,6 +243,7 @@ impl Iterator for SaveFile{
type Item = Section;

/// Get the next object in the save file
/// If the file pointer has reached the end of the file then it will return None.
fn next(&mut self) -> Option<Section>{
let mut key = String::new();
let file = &mut self.file;
Expand Down
32 changes: 15 additions & 17 deletions src/structures/memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,28 @@ use serde::Serialize;
use serde::ser::SerializeStruct;
use super::{Character, GameObjectDerived, Shared};
use crate::game_object::GameObject;
use crate::game_state::GameState;

pub struct Memory {
pub id: u32,
pub date: Shared<String>,
pub r#type: Shared<String>,
pub participants: Vec<(Shared<String>, Shared<Character>)>,
pub participants: Vec<(String, Shared<Character>)>,
}

fn get_participants(participants:&mut Vec<(String, Shared<Character>)>, base:&Ref<'_, GameObject>, game_state:&mut GameState){
let participants_node = base.get("participants");
if participants_node.is_some(){
for part in participants_node.unwrap().as_object_ref().unwrap().get_obj_iter(){
participants.push((part.0.clone(), game_state.get_character(part.1.as_string().borrow().as_str()).clone()));
}
}
}

impl GameObjectDerived for Memory {
fn from_game_object(base: Ref<'_, GameObject>, game_state: &mut crate::game_state::GameState) -> Self {
let part = base.get("participants").unwrap().as_object_ref().unwrap(); //FIXME sometimes missing?
fn from_game_object(base: Ref<'_, GameObject>, game_state: &mut GameState) -> Self {
let mut participants = Vec::new();
for k in part.get_keys(){
let v = part.get(&k).unwrap();
participants.push((Rc::from(RefCell::from(k)), game_state.get_character(v.as_string_ref().unwrap().as_str()).clone()));
}
println!("Memory: {:?}", base);
get_participants(&mut participants, &base, game_state);
Memory{
date: base.get("creation_date").unwrap().as_string(),
r#type: base.get("type").unwrap().as_string(),
Expand All @@ -38,17 +43,10 @@ impl GameObjectDerived for Memory {
}
}

fn init(&mut self, base: Ref<'_, GameObject>, game_state: &mut crate::game_state::GameState) {
let part = base.get("participants").unwrap().as_object_ref().unwrap();
let mut participants = Vec::new();
for k in part.get_keys(){
let v = part.get(&k).unwrap();
participants.push((Rc::from(RefCell::from(k)), game_state.get_character(v.as_string_ref().unwrap().as_str()).clone()));
}
fn init(&mut self, base: Ref<'_, GameObject>, game_state: &mut GameState) {
self.date = base.get("date").unwrap().as_string();
self.r#type = base.get("type").unwrap().as_string();
self.participants = participants;
self.id = base.get_name().parse::<u32>().unwrap();
get_participants(&mut self.participants, &base, game_state);
}

fn get_id(&self) -> u32 {
Expand Down
Loading

0 comments on commit fd3d94a

Please sign in to comment.