implement basic CLI with clap, list-entities and find-entities

This commit is contained in:
mykola2312 2023-09-09 21:41:42 +03:00
parent 7c2fbba153
commit 6030fc29ce
7 changed files with 341 additions and 52 deletions

214
Cargo.lock generated
View file

@ -8,6 +8,54 @@ version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234"
[[package]]
name = "anstream"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1f58811cfac344940f1a400b6e6231ce35171f614f26439e80f8c1465c5cc0c"
dependencies = [
"anstyle",
"anstyle-parse",
"anstyle-query",
"anstyle-wincon",
"colorchoice",
"utf8parse",
]
[[package]]
name = "anstyle"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "15c4c2c83f81532e5845a733998b6971faca23490340a418e9b72a3ec9de12ea"
[[package]]
name = "anstyle-parse"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "938874ff5980b03a87c5524b3ae5b59cf99b1d6bc836848df7bc5ada9643c333"
dependencies = [
"utf8parse",
]
[[package]]
name = "anstyle-query"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b"
dependencies = [
"windows-sys",
]
[[package]]
name = "anstyle-wincon"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "58f54d10c6dfa51283a066ceab3ec1ab78d13fae00aa49243a45e4571fb79dfd"
dependencies = [
"anstyle",
"windows-sys",
]
[[package]]
name = "byteorder"
version = "1.4.3"
@ -20,6 +68,52 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "clap"
version = "4.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a13b88d2c62ff462f88e4a121f17a82c1af05693a2f192b5c38d14de73c19f6"
dependencies = [
"clap_builder",
"clap_derive",
]
[[package]]
name = "clap_builder"
version = "4.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2bb9faaa7c2ef94b2743a21f5a29e6f0010dff4caa69ac8e9d6cf8b6fa74da08"
dependencies = [
"anstream",
"anstyle",
"clap_lex",
"strsim",
]
[[package]]
name = "clap_derive"
version = "4.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0862016ff20d69b84ef8247369fabf5c008a7417002411897d40ee1f4532b873"
dependencies = [
"heck",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "clap_lex"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd7cc57abe963c6d3b9d8be5b06ba7c8957a930305ca90304f24ef040aa6f961"
[[package]]
name = "colorchoice"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
[[package]]
name = "deflate"
version = "1.0.0"
@ -49,6 +143,7 @@ name = "fot-save-edit"
version = "0.1.0"
dependencies = [
"byteorder",
"clap",
"deflate",
"encoding_rs",
"indexmap",
@ -62,6 +157,12 @@ version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a"
[[package]]
name = "heck"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
[[package]]
name = "indexmap"
version = "2.0.0"
@ -86,3 +187,116 @@ name = "memmem"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a64a92489e2744ce060c349162be1c5f33c6969234104dbd99ddb5feb08b8c15"
[[package]]
name = "proc-macro2"
version = "1.0.66"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
dependencies = [
"proc-macro2",
]
[[package]]
name = "strsim"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]]
name = "syn"
version = "2.0.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c324c494eba9d92503e6f1ef2e6df781e78f6a7705a0202d9801b198807d518a"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "unicode-ident"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c"
[[package]]
name = "utf8parse"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
[[package]]
name = "windows-sys"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
[[package]]
name = "windows_aarch64_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
[[package]]
name = "windows_i686_gnu"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
[[package]]
name = "windows_i686_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
[[package]]
name = "windows_x86_64_gnu"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
[[package]]
name = "windows_x86_64_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"

View file

@ -2,11 +2,14 @@
name = "fot-save-edit"
version = "0.1.0"
edition = "2021"
auhtors = ["mykola2312", "puuuuh"]
repository = "https://github.com/mykola2312/fot-save-edit/"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
byteorder = "1.4.3"
clap = { version = "4.4.2", features = ["derive"] }
deflate = "1.0.0"
encoding_rs = "0.8.33"
indexmap = "2.0.0"

View file

@ -1,14 +1,14 @@
mod attributes;
mod decoder;
mod entity;
mod entitylist;
mod esh;
mod ferror;
mod fstring;
mod raw;
pub mod attributes;
pub mod decoder;
pub mod entity;
pub mod entitylist;
pub mod esh;
pub mod ferror;
pub mod fstring;
pub mod raw;
pub mod save;
mod sgd;
mod ssg;
mod stream;
mod tag;
mod world;
pub mod sgd;
pub mod ssg;
pub mod stream;
pub mod tag;
pub mod world;

View file

@ -267,12 +267,12 @@ impl ESH {
pub fn get_nested(&self, name: &str) -> Result<ESH, FE> {
let value = match self.get(name) {
Some(value) => value,
None => return Err(FE::NoESHValue)
None => return Err(FE::NoESHValue),
};
if let ESHValue::Binary(bin) = value {
let mut rd = ReadStream::new(bin, 0);
let _ = rd.read_u32()?;
rd.read::<ESH>()
} else {

View file

@ -12,7 +12,7 @@ pub enum FError {
NoESHValue,
ESHValueNonBinary,
AttributesNonBinary,
ValueNoESBIN
ValueNoESBIN,
}
impl std::fmt::Display for FError {
@ -35,7 +35,7 @@ impl std::fmt::Display for FError {
FE::NoESHValue => write!(f, "Entity has no specific ESH value"),
FE::ESHValueNonBinary => write!(f, "ESH value is not binary"),
FE::AttributesNonBinary => write!(f, "Attributes Binary != true"),
FE::ValueNoESBIN => write!(f, "Value has no esbin")
FE::ValueNoESBIN => write!(f, "Value has no esbin"),
}
}
}

View file

@ -1,6 +1,5 @@
use super::decoder::DecoderCtx;
use super::entitylist::{EntityEncoding, EntityList};
use super::esh::ESHValue;
use super::ferror::FError as FE;
use super::fstring::FString;
use super::sgd::SGD;
@ -28,30 +27,6 @@ pub struct World {
impl World {
const WORLD_HDR_LEN: usize = 0x13;
pub fn test(&mut self) -> Result<(), FE> {
//let actor_type = self.entlist.get_type_idx("Actor").unwrap();
//let ent = self.entlist.get_entity_mut(2122);
let ent = self.entlist.get_entity_mut(2122);
let esh = ent.get_esh_mut()?;
for (name, value) in &esh.props {
println!("{} {}", name, value);
}
//self.entlist.dump_to_entfile(ent, Path::new("D:\\actor.ent"))?;
println!("");
let mut attribs = esh.get_nested("Current Attributes")?;
for (name, value) in &attribs.props {
println!("{} {}", name, value);
}
attribs.set("hitPoints", ESHValue::Int(999));
attribs.set("poisonPoints", ESHValue::Int(0));
esh.set_nested("Current Attributes", attribs)?;
Ok(())
}
}
pub type WorldOffsetSize = (usize, usize);

View file

@ -1,19 +1,116 @@
#![deny(rust_2018_idioms)]
use std::env;
use clap::{Parser, Subcommand, ValueEnum};
use std::collections::HashMap;
use std::io::{stdout, BufWriter, Write};
use std::path::Path;
mod fot;
use fot::attributes::*;
use fot::entitylist::EntityList;
use fot::save::Save;
fn main() {
let args: Vec<_> = env::args().collect();
let save_path = args.get(1).unwrap();
let out_path = match args.get(2) {
Some(path) => path,
None => "out.sav"
#[derive(Parser)]
#[command(author, version, about, long_about = None)]
struct Cli {
/// Input file path (.sav or .ent)
#[arg(short, long)]
input: String,
// Specify save file or ent file type
#[arg(value_enum)]
kind: Kind,
/// Output file path
#[arg(short, long)]
output: String,
#[command(subcommand)]
command: Commands,
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum)]
enum Kind {
Save,
Ent,
}
#[derive(Subcommand, Debug)]
enum Commands {
ListEntities,
/// Find entities, kv = key1=value,key2=value2
FindEntities {
kv: String,
},
}
fn list_entities(entlist: &EntityList) {
let mut bf = BufWriter::new(stdout().lock());
for (id, ent) in entlist {
let type_name = if ent.type_idx != 0xFFFF {
entlist.get_type_name(ent.type_idx).str.as_str()
} else {
"<no type>"
};
write!(bf, "{}\t{}\n", id, type_name).expect("failed to write stdout");
}
}
fn find_entities(entlist: &EntityList, line: String) {
let kv = line
.split(",")
.map(|kv| kv.split_once("="))
.collect::<Option<HashMap<&str, &str>>>()
.unwrap();
let mut bf = BufWriter::new(stdout().lock());
for (id, ent) in entlist {
let type_name = if ent.type_idx != 0xFFFF {
entlist.get_type_name(ent.type_idx).str.as_str()
} else {
"<no type>"
};
let esh = match &ent.esh {
Some(esh) => esh,
None => continue,
};
for (name, value) in &esh.props {
let key = name.str.as_str();
if kv.contains_key(key) {
let svalue = value.to_string();
if svalue == kv[key] {
write!(bf, "{}\t{}\n", id, type_name).expect("failed to write stdout");
}
}
}
}
}
fn do_save(cli: Cli) {
let mut save = match Save::load(Path::new(cli.input.as_str())) {
Ok(save) => save,
Err(fe) => panic!("{}", fe),
};
let mut save = Save::load(Path::new(save_path)).expect("load save");
save.world.test().expect("test");
save.save(Path::new(out_path)).expect("failed to save");
match cli.command {
Commands::ListEntities => {
list_entities(&save.world.entlist);
},
Commands::FindEntities { kv } => {
find_entities(&save.world.entlist, kv);
}
}
}
fn main() {
let cli = Cli::parse();
match cli.kind {
Kind::Save => do_save(cli),
Kind::Ent => todo!(),
}
//let mut save = Save::load(Path::new(save_path)).expect("load save");
//save.save(Path::new(out_path)).expect("failed to save");
}