Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,5 @@ dirs = "^6"
thiserror = "^2"
charming = { version = "0.6.0", features = ["ssr"] }
rand = "0.9.1"
base64 = "0.22.1"
flate2 = "1.0"
1 change: 1 addition & 0 deletions blueprints/vanilla_mall.txt

Large diffs are not rendered by default.

114 changes: 114 additions & 0 deletions src/blueprint/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
use std::path::PathBuf;

use crate::{core::{BenchmarkError, Result}, util::blueprint_string::{parse_blueprint, save_blueprint_json, BlueprintString}};


#[derive(Debug, Clone)]
pub struct BlueprintConfig {
pub string: Option<String>,
pub file: PathBuf,
pub output: PathBuf,
pub recursive: bool,
}

pub async fn run(
config: &BlueprintConfig
) -> Result<()> {
tracing::debug!("Running blueprint generation");

if config.string.is_some() {
process_string(config)?;
}
let recursive = config.recursive;
// Get the path provided by the blueprint config
// and process that path.
if config.file.is_file() {
return process_file(&config, &config.file);

Check failure on line 26 in src/blueprint/mod.rs

View workflow job for this annotation

GitHub Actions / Lint, Format & Test Rust

this expression creates a reference which is immediately dereferenced by the compiler

Check failure on line 26 in src/blueprint/mod.rs

View workflow job for this annotation

GitHub Actions / Lint, Format & Test Rust

unneeded `return` statement
} else if config.file.is_dir() {
return process_directory(&config.file, &config, recursive);

Check failure on line 28 in src/blueprint/mod.rs

View workflow job for this annotation

GitHub Actions / Lint, Format & Test Rust

this expression creates a reference which is immediately dereferenced by the compiler
} else {
tracing::error!("Provided path is neither a file nor a directory: {:?}", config.file);
return Err(BenchmarkError::InvalidBlueprintPath { path: config.file.clone(), reason: "Provided path is neither a file nor a directory".into() });
}
}

fn process_string(config: &BlueprintConfig) -> Result<()> {
tracing::debug!("Using blueprint string: {:?}", config.string);

let temp_file = config.file.with_file_name(".temp.txt");
std::fs::write(&temp_file, config.string.as_ref().unwrap())?;
tracing::debug!("Temporary blueprint file created at: {:?}", temp_file);

let result = process_file(&config, &temp_file);

Check failure on line 42 in src/blueprint/mod.rs

View workflow job for this annotation

GitHub Actions / Lint, Format & Test Rust

this expression creates a reference which is immediately dereferenced by the compiler

std::fs::remove_file(&temp_file)?;
tracing::debug!("Temporary blueprint file removed: {:?}", temp_file);
return result;

Check failure on line 46 in src/blueprint/mod.rs

View workflow job for this annotation

GitHub Actions / Lint, Format & Test Rust

unneeded `return` statement
}

fn create_save_file(
blueprint: &BlueprintString,
config: &BlueprintConfig,
) -> Result<()> {
let output_path = &config.output;
tracing::debug!("Creating save file at: {:?}", output_path);

// Ensure the output directory exists
if let Some(parent) = output_path.parent() {
std::fs::create_dir_all(parent)?;
}

save_blueprint_json(blueprint, output_path)
.map_err(|e| BenchmarkError::BlueprintEncode { reason: e.to_string() })?;

tracing::debug!("Save file created successfully at: {:?}", output_path);
Ok(())
}


fn process_file(
config: &BlueprintConfig,
file_path: &PathBuf,
) -> Result<()> {
tracing::debug!("Processing file: {:?}", file_path);

if !file_path.exists() {
tracing::error!("File does not exist: {:?}", file_path);
return Err(BenchmarkError::InvalidBlueprintPath { path: file_path.clone(), reason: "File does not exist".into() });
}

let file_content = std::fs::read_to_string(file_path)
.map_err(|e| BenchmarkError::InvalidBlueprintString { path: file_path.clone(), reason: e.to_string() })?;

// crate::util::blueprint_string::from_str(&file_content)
let blueprint = parse_blueprint(&file_content)
.map_err(|e| BenchmarkError::BlueprintDecode { path: file_path.clone(), reason: e.to_string() })?;

// Depending on Blueprint this might be huge
tracing::debug!("Decoded file content: {:?}", blueprint);

// We got the blueprint, as a json string.
// From here we should type/parse it to a blueprint structure, then create a save file.
create_save_file(&blueprint, &config)?;

Check failure on line 92 in src/blueprint/mod.rs

View workflow job for this annotation

GitHub Actions / Lint, Format & Test Rust

this expression creates a reference which is immediately dereferenced by the compiler

Ok(())
}

fn process_directory(
path: &PathBuf,
config: &BlueprintConfig,
recursive: bool,
) -> Result<()> {
tracing::debug!("Processing directory: {:?}", path);
for entry in std::fs::read_dir(path)? {
let entry = entry?;
let path = entry.path();
if path.is_dir() && recursive {
tracing::debug!("Recursively processing directory: {:?}", path);
process_directory(&path, &config, recursive)?;

Check failure on line 108 in src/blueprint/mod.rs

View workflow job for this annotation

GitHub Actions / Lint, Format & Test Rust

this expression creates a reference which is immediately dereferenced by the compiler
} else if path.is_file() {
process_file(&config, &path)?;

Check failure on line 110 in src/blueprint/mod.rs

View workflow job for this annotation

GitHub Actions / Lint, Format & Test Rust

this expression creates a reference which is immediately dereferenced by the compiler
}
}
Ok(())
}
12 changes: 12 additions & 0 deletions src/core/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,18 @@ pub enum BenchmarkError {

#[error("Invalid run order: {input}. Valid options: sequential, random, grouped")]
InvalidRunOrder { input: String },

#[error("Invalid blueprint path: {path} - {reason}")]
InvalidBlueprintPath { path: PathBuf, reason: String },

#[error("Invalid blueprint string: {path} - {reason}")]
InvalidBlueprintString { path: PathBuf, reason: String },

#[error("Blueprint decoding error: {path} - {reason}")]
BlueprintDecode { path: PathBuf, reason: String },

#[error("Blueprint encoding error: {reason}")]
BlueprintEncode { reason: String },
}

/// Get a hint for the FactorioProcessFailed error, if it exists
Expand Down
25 changes: 25 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
//! Parses CLI arguments, sets up logging, and dispatches to subcommands.

mod benchmark;
mod blueprint;
mod core;
mod util;

use crate::core::Result;
use clap::{Parser, Subcommand};
Expand Down Expand Up @@ -52,6 +54,19 @@ enum Commands {
)]
run_order: benchmark::RunOrder,
},
Blueprint {
#[arg(long, group = "blueprint_source")]
string: Option<String>,

#[arg(long, group = "blueprint_source", default_value = "blueprints")]
file: PathBuf,

#[arg(long, default_value = "generated_saves/")]
output: PathBuf,

#[arg(long, default_value = "false")]
recursive: bool,
},
}

#[tokio::main]
Expand Down Expand Up @@ -102,6 +117,16 @@ async fn main() -> Result<()> {

benchmark::run(global_config, benchmark_config).await
}
// Run the blueprint generation with a newly created blueprint config
Commands::Blueprint { string, file, output, recursive } => {
let blueprint_config = blueprint::BlueprintConfig {
string,
file,
output,
recursive,
};
blueprint::run(&blueprint_config).await
}
};

// If benchmark::run results in an error, print and exit
Expand Down
Loading
Loading