diff --git a/format.txt b/format.txt index 1d714eb..3b24240 100644 --- a/format.txt +++ b/format.txt @@ -106,7 +106,6 @@ Attribute - ESH int derived[26] int skills[18] bool skill_tags[18] - bool opt_traits[27] - bool type[11] + bool opt_traits[38] int perks[111] int addictions[10] \ No newline at end of file diff --git a/src/fot.rs b/src/fot.rs index e5829f2..36cfddb 100644 --- a/src/fot.rs +++ b/src/fot.rs @@ -1,3 +1,4 @@ +mod attributes; mod decoder; mod entity; mod entitylist; diff --git a/src/fot/attributes.rs b/src/fot/attributes.rs new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/fot/attributes.rs @@ -0,0 +1 @@ + diff --git a/src/fot/decoder.rs b/src/fot/decoder.rs index e21be3d..8ed4058 100644 --- a/src/fot/decoder.rs +++ b/src/fot/decoder.rs @@ -19,7 +19,7 @@ impl Decoder for String { let bytes = rd.as_byte_arr(); let pos = match bytes.iter().position(|&c| c == 0) { Some(pos) => pos, - None => return Err(anyhow!("No zero-terminator found")) + None => return Err(anyhow!("No zero-terminator found")), }; let str = str::from_utf8(rd.as_bytes(pos)?)?; rd.skip(1); diff --git a/src/fot/entitylist.rs b/src/fot/entitylist.rs index dff9525..3da4c22 100644 --- a/src/fot/entitylist.rs +++ b/src/fot/entitylist.rs @@ -1,11 +1,11 @@ -use super::decoder::{DecoderCtx, Decoder}; +use super::decoder::{Decoder, DecoderCtx}; use super::entity::Entity; use super::fstring::{FString, FStringEncoding}; use super::stream::{ReadStream, WriteStream}; -use super::tag::{Tag, CTag}; -use std::path::Path; -use anyhow::Result; +use super::tag::{CTag, Tag}; use anyhow::anyhow; +use anyhow::Result; +use std::path::Path; #[derive(Clone, Copy, PartialEq)] pub enum EntityEncoding { @@ -59,13 +59,13 @@ impl EntityList { } pub fn get_entity(&self, id: usize) -> &Entity { - &self.ents[id-1] + &self.ents[id - 1] } pub fn dump_to_entfile(&self, ent: &Entity, path: &Path) -> Result<()> { let esh = match &ent.esh { Some(esh) => esh, - None => return Err(anyhow!("entity has no esh")) + None => return Err(anyhow!("entity has no esh")), }; let tag = DEFAULT_ENTITY_TAG.to_tag(); @@ -174,4 +174,4 @@ impl<'a> IntoIterator for &'a EntityList { fn into_iter(self) -> Self::IntoIter { (1..).zip(&self.ents) } -} \ No newline at end of file +} diff --git a/src/fot/esh.rs b/src/fot/esh.rs index 1290a09..b1d62b6 100644 --- a/src/fot/esh.rs +++ b/src/fot/esh.rs @@ -93,14 +93,14 @@ impl Decoder for ESHValue { let entity_id = rd.read_u16()?; let flags = rd.read_u16()?; ESHValue::EntityFlags(ESHEntityFlags { entity_id, flags }) - }, + } Self::TYPE_FRAME => { let unk1 = rd.read_bytes(0x24)?; let c = rd.read_f32()? * 4.; let b = rd.read_f32()? * 4.; let a = rd.read_f32()? * 4.; ESHValue::Frame(ESHFrame { unk1, a, b, c }) - }, + } Self::TYPE_RECT => { let top = rd.read_i32()?; let left = rd.read_i32()?; @@ -112,7 +112,7 @@ impl Decoder for ESHValue { right, bottom, }) - }, + } _ => { let data = rd.read_bytes(data_size as usize)?; ESHValue::Unknown(ESHUnknown { data_type, data }) @@ -127,56 +127,56 @@ impl Decoder for ESHValue { wd.write_u32(unk.data.len() as u32)?; wd.write_bytes(&unk.data); - }, + } ESHValue::Bool(val) => { wd.write_u32(Self::TYPE_BOOL)?; wd.write_u32(1)?; wd.write_u8(*val as u8)?; - }, + } ESHValue::Float(val) => { wd.write_u32(Self::TYPE_FLOAT)?; wd.write_u32(4)?; wd.write_f32(*val)?; - }, + } ESHValue::Int(val) => { wd.write_u32(Self::TYPE_INT)?; wd.write_u32(4)?; wd.write_i32(*val)?; - }, + } ESHValue::String(str) => { wd.write_u32(Self::TYPE_STRING)?; wd.write_u32(str.get_enc_size() as u32)?; wd.write(str)?; - }, + } ESHValue::Sprite(spr) => { wd.write_u32(Self::TYPE_SPRITE)?; wd.write_u32(spr.get_enc_size() as u32)?; wd.write(spr)?; - }, + } ESHValue::Enum(spr) => { wd.write_u32(Self::TYPE_ENUM)?; wd.write_u32(spr.get_enc_size() as u32)?; wd.write(spr)?; - }, + } ESHValue::Binary(bin) => { wd.write_u32(Self::TYPE_ESBIN)?; wd.write_u32(bin.len() as u32)?; wd.write_bytes(bin); - }, + } ESHValue::EntityFlags(eflags) => { wd.write_u32(Self::TYPE_ENTTITYFLAGS)?; wd.write_u32(ESHEntityFlags::SIZE as u32)?; wd.write_u16(eflags.entity_id)?; wd.write_u16(eflags.flags)?; - }, + } ESHValue::Frame(frame) => { wd.write_u32(Self::TYPE_FRAME)?; wd.write_u32(ESHFrame::SIZE as u32)?; @@ -185,7 +185,7 @@ impl Decoder for ESHValue { wd.write_f32(frame.c / 4.)?; wd.write_f32(frame.b / 4.)?; wd.write_f32(frame.a / 4.)?; - }, + } ESHValue::Rect(rect) => { wd.write_u32(Self::TYPE_RECT)?; wd.write_u32(ESHRect::SIZE as u32)?; diff --git a/src/fot/fstring.rs b/src/fot/fstring.rs index b687563..415b7b4 100644 --- a/src/fot/fstring.rs +++ b/src/fot/fstring.rs @@ -38,11 +38,7 @@ impl Decoder for FString { } else { // WCS2 let bytes = rd.as_bytes(len * 2)?; - let chars: Vec = bytes - .iter() - .step_by(2) - .copied() - .collect(); + let chars: Vec = bytes.iter().step_by(2).copied().collect(); let (str, _, _) = WINDOWS_1251.decode(&chars); Ok(FString { encoding: FStringEncoding::WCS2, diff --git a/src/fot/save.rs b/src/fot/save.rs index ba28224..8e81db3 100644 --- a/src/fot/save.rs +++ b/src/fot/save.rs @@ -46,7 +46,7 @@ impl Save { return Err(anyhow!("Unable to determine world block size")); } - let mut rd = ReadStream::new(&raw, world_offset); + let mut rd = ReadStream::new(&raw.mem, world_offset); let world = World::decode(&mut rd, (world_offset, world_size))?; Ok(Save { raw, world }) } diff --git a/src/fot/stream.rs b/src/fot/stream.rs index 77081a8..a69594f 100644 --- a/src/fot/stream.rs +++ b/src/fot/stream.rs @@ -6,15 +6,15 @@ use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; use std::io::Cursor; pub struct ReadStream<'a> { - raw: &'a Raw, + mem: &'a [u8], rdr: Cursor<&'a [u8]>, } impl<'a> ReadStream<'a> { - pub fn new(raw: &'a Raw, offset: usize) -> ReadStream<'a> { - let mut rdr = Cursor::new(&raw.mem[..]); + pub fn new(mem: &'a [u8], offset: usize) -> ReadStream<'a> { + let mut rdr = Cursor::new(mem); rdr.set_position(offset as u64); - ReadStream { raw: raw, rdr: rdr } + ReadStream { mem, rdr } } pub fn offset(&self) -> usize { @@ -26,7 +26,7 @@ impl<'a> ReadStream<'a> { } pub fn size(&self) -> usize { - self.raw.mem.len() + self.mem.len() } pub fn is_end(&self) -> bool { @@ -34,15 +34,15 @@ impl<'a> ReadStream<'a> { } pub fn as_byte_arr(&self) -> &[u8] { - &self.raw.mem[self.offset()..] + &self.mem[self.offset()..] } pub fn as_bytes(&mut self, size: usize) -> Result<&'a [u8]> { - if self.offset() + size > self.raw.mem.len() { - dbg!(self.offset(), size, self.raw.mem.len()); + if self.offset() + size > self.mem.len() { + dbg!(self.offset(), size, self.mem.len()); Err(anyhow!("as_bytes/read_bytes size is bigger than buffer")) } else { - let buf = &self.raw.mem[self.offset()..self.offset() + size]; + let buf = &self.mem[self.offset()..self.offset() + size]; self.skip(size); Ok(buf) } diff --git a/src/fot/world.rs b/src/fot/world.rs index 7c8d338..a220e3a 100644 --- a/src/fot/world.rs +++ b/src/fot/world.rs @@ -11,8 +11,8 @@ use anyhow::Result; use deflate::deflate_bytes_zlib; use inflate::inflate_bytes_zlib; +use super::esh::{ESHValue, ESH}; use std::path::Path; -use super::esh::{ESH, ESHValue}; pub struct World { pub offset: usize, @@ -21,14 +21,13 @@ pub struct World { pub tag: Tag, pub uncompressed_size: u32, //pub data: Raw, - pub mission: FString, pub sgd: SGD, pub ssg: SSG, pub entlist: EntityList, - pub unparsed: Vec + pub unparsed: Vec, } impl World { @@ -45,8 +44,18 @@ impl World { println!(""); if let ESHValue::Binary(attributes) = &esh.props["Attributes"] { - let raw = Raw { offset: 0, size: attributes.len(), mem: attributes.to_vec() }; - let mut rd = ReadStream::new(&raw, 0); + let mut rd = ReadStream::new(&attributes, 0); + + let size = rd.read_u32()?; + let attrs_esh: ESH = rd.read()?; + for (name, value) in &attrs_esh.props { + println!("{} {}", name, value); + } + } + + println!(""); + if let ESHValue::Binary(attributes) = &esh.props["Modifiers"] { + let mut rd = ReadStream::new(&attributes, 0); let size = rd.read_u32()?; let attrs_esh: ESH = rd.read()?; @@ -59,8 +68,8 @@ impl World { } } -pub type WorldOffsetSize = (usize,usize); -impl DecoderCtx for World { +pub type WorldOffsetSize = (usize, usize); +impl DecoderCtx for World { fn decode<'a>(enc: &mut ReadStream<'a>, ctx: WorldOffsetSize) -> Result { let offset = ctx.0; let size = ctx.1; @@ -69,14 +78,7 @@ impl DecoderCtx for World { let uncompressed_size = enc.read_u32()?; enc.skip(4); - let data = { - let inflated = inflate_bytes_zlib(enc.as_bytes(size)?).map_err(|e| anyhow!(e))?; - Raw { - offset, - size, - mem: inflated, - } - }; + let data = inflate_bytes_zlib(enc.as_bytes(size)?).map_err(|e| anyhow!(e))?; let mut rd = ReadStream::new(&data, 0); let mission: FString = rd.read()?; @@ -85,7 +87,7 @@ impl DecoderCtx for World { let entlist: EntityList = rd.read_ctx(0, EntityEncoding::World)?; - let unparsed = rd.read_bytes(data.mem.len() - rd.offset())?; + let unparsed = rd.read_bytes(data.len() - rd.offset())?; Ok(World { offset, @@ -104,7 +106,7 @@ impl DecoderCtx for World { fn encode(&self, wd: &mut WriteStream, _: ()) -> Result<()> { let data = { let mut wd = WriteStream::new(self.uncompressed_size as usize); - + wd.write(&self.mission)?; wd.write(&self.sgd)?; wd.write(&self.ssg)?;