From fb82e26b4ad6e643f17a8b219a261b6bf66bc09a Mon Sep 17 00:00:00 2001 From: "Jasper St. Pierre" Date: Tue, 21 Jan 2025 23:50:01 -0800 Subject: [PATCH] new deku --- rust/Cargo.lock | 134 ++++++++++++-- rust/Cargo.toml | 2 +- rust/src/unity/asset_file.rs | 15 +- rust/src/unity/types/binary.rs | 36 ++-- rust/src/unity/types/class_id.rs | 2 +- rust/src/unity/types/common.rs | 157 +++++++--------- rust/src/unity/types/wasm.rs | 12 +- rust/src/unity/util.rs | 14 +- rust/src/wow/animation.rs | 6 +- rust/src/wow/blp.rs | 4 +- rust/src/wow/common.rs | 36 ++-- rust/src/wow/db.rs | 301 ++++++++++++++----------------- rust/src/wow/m2.rs | 2 +- 13 files changed, 395 insertions(+), 326 deletions(-) diff --git a/rust/Cargo.lock b/rust/Cargo.lock index 62cdfc5ef..13d30c34f 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -198,8 +198,18 @@ version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850" dependencies = [ - "darling_core", - "darling_macro", + "darling_core 0.14.4", + "darling_macro 0.14.4", +] + +[[package]] +name = "darling" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" +dependencies = [ + "darling_core 0.20.10", + "darling_macro 0.20.10", ] [[package]] @@ -212,21 +222,46 @@ dependencies = [ "ident_case", "proc-macro2", "quote", - "strsim", + "strsim 0.10.0", "syn 1.0.109", ] +[[package]] +name = "darling_core" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim 0.11.1", + "syn 2.0.96", +] + [[package]] name = "darling_macro" version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e" dependencies = [ - "darling_core", + "darling_core 0.14.4", "quote", "syn 1.0.109", ] +[[package]] +name = "darling_macro" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" +dependencies = [ + "darling_core 0.20.10", + "quote", + "syn 2.0.96", +] + [[package]] name = "deku" version = "0.16.0" @@ -234,8 +269,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "819b87cc7a05b3abe3fc38e59b3980a5fd3162f25a247116441a9171d3e84481" dependencies = [ "bitvec", - "deku_derive", + "deku_derive 0.16.0", +] + +[[package]] +name = "deku" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9711031e209dc1306d66985363b4397d4c7b911597580340b93c9729b55f6eb" +dependencies = [ + "bitvec", + "deku_derive 0.18.1", "log", + "no_std_io2", + "rustversion", ] [[package]] @@ -244,13 +291,26 @@ version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4e2ca12572239215a352a74ad7c776d7e8a914f8a23511c6cbedddd887e5009e" dependencies = [ - "darling", - "proc-macro-crate", + "darling 0.14.4", + "proc-macro-crate 1.3.1", "proc-macro2", "quote", "syn 1.0.109", ] +[[package]] +name = "deku_derive" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58cb0719583cbe4e81fb40434ace2f0d22ccc3e39a74bb3796c22b451b4f139d" +dependencies = [ + "darling 0.20.10", + "proc-macro-crate 3.2.0", + "proc-macro2", + "quote", + "syn 2.0.96", +] + [[package]] name = "env_filter" version = "0.1.3" @@ -494,6 +554,15 @@ dependencies = [ "simba", ] +[[package]] +name = "no_std_io2" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a3564ce7035b1e4778d8cb6cacebb5d766b5e8fe5a75b9e441e33fb61a872c6" +dependencies = [ + "memchr", +] + [[package]] name = "noclip-macros" version = "0.1.0" @@ -509,7 +578,7 @@ version = "0.0.0" dependencies = [ "byteorder", "console_error_panic_hook", - "deku", + "deku 0.18.1", "env_logger 0.10.2", "getrandom", "inflate", @@ -591,7 +660,7 @@ version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dcbff9bc912032c62bf65ef1d5aea88983b420f4f839db1e9b0c281a25c9c799" dependencies = [ - "proc-macro-crate", + "proc-macro-crate 1.3.1", "proc-macro2", "quote", "syn 1.0.109", @@ -614,7 +683,7 @@ name = "polymorph" version = "0.1.0" source = "git+https://github.com/wgreenberg/polymorph#2379ecce20537cb1b4524800a9c59a81c52eb53d" dependencies = [ - "deku", + "deku 0.16.0", "env_logger 0.11.6", "hashers", "log", @@ -646,7 +715,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" dependencies = [ "once_cell", - "toml_edit", + "toml_edit 0.19.15", +] + +[[package]] +name = "proc-macro-crate" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" +dependencies = [ + "toml_edit 0.22.22", ] [[package]] @@ -744,6 +822,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +[[package]] +name = "rustversion" +version = "1.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4" + [[package]] name = "safe_arch" version = "0.7.4" @@ -772,6 +856,12 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + [[package]] name = "syn" version = "1.0.109" @@ -851,7 +941,18 @@ checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ "indexmap", "toml_datetime", - "winnow", + "winnow 0.5.40", +] + +[[package]] +name = "toml_edit" +version = "0.22.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" +dependencies = [ + "indexmap", + "toml_datetime", + "winnow 0.6.24", ] [[package]] @@ -1065,6 +1166,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "winnow" +version = "0.6.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8d71a593cc5c42ad7876e2c1fda56f314f3754c084128833e64f1345ff8a03a" +dependencies = [ + "memchr", +] + [[package]] name = "wyz" version = "0.5.1" diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 49fbd8da0..93d6ccab7 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -25,7 +25,7 @@ opt-level = "s" [dependencies] byteorder = "1.4.3" console_error_panic_hook = "0.1.7" -deku = { version = "0.16.0", features = ["logging"] } +deku = { version = "0.18.0", features = ["logging"] } env_logger = "0.10.1" inflate = "0.4.5" js-sys = "0.3.60" diff --git a/rust/src/unity/asset_file.rs b/rust/src/unity/asset_file.rs index 400ea859d..c1a4206e7 100644 --- a/rust/src/unity/asset_file.rs +++ b/rust/src/unity/asset_file.rs @@ -1,5 +1,7 @@ -use deku::bitvec::BitSlice; -use deku::{DekuContainerRead, DekuRead}; +use std::io::Cursor; + +use deku::reader::Reader; +use deku::{DekuContainerRead, DekuReader}; use wasm_bindgen::prelude::*; use crate::unity::types::wasm::WasmFriendlyPPtr; @@ -39,11 +41,12 @@ impl AssetFile { pub fn append_metadata_chunk(&mut self, data: &[u8]) -> Result<(), String> { // data will be the file from bytes 0..data_offset, so skip to where the metadata starts - let bitslice = BitSlice::from_slice(data); - let (rest, _) = SerializedFileHeader::read(&bitslice, ()) + let mut cursor = Cursor::new(data); + let mut reader = Reader::new(&mut cursor); + let _header = SerializedFileHeader::from_reader_with_ctx(&mut reader, ()) .map_err(|err| format!("failed to parse metadata file header: {:?}", err))?; - match SerializedFileMetadata::read(rest, self.header.version) { - Ok((_, metadata)) => self.metadata = Some(metadata), + match SerializedFileMetadata::from_reader_with_ctx(&mut reader, self.header.version) { + Ok(metadata) => self.metadata = Some(metadata), Err(err) => return Err(format!("failed to parse metadata: {:?}", err)), } Ok(()) diff --git a/rust/src/unity/types/binary.rs b/rust/src/unity/types/binary.rs index 096c0db9b..046bca39b 100644 --- a/rust/src/unity/types/binary.rs +++ b/rust/src/unity/types/binary.rs @@ -1,3 +1,4 @@ + use deku::prelude::*; // https://github.com/AssetRipper/TypeTreeDumps/blob/main/StructsDump/release/2019.4.39f1.dump @@ -153,14 +154,14 @@ pub struct Mesh { } #[derive(DekuRead, Clone, Copy, Debug)] -#[deku(type = "i32")] +#[deku(id_type = "i32")] pub enum IndexFormat { UInt16 = 0, UInt32 = 1, } #[derive(DekuRead, Clone, Copy, Debug)] -#[deku(type = "u8")] +#[deku(id_type = "u8")] pub enum MeshCompression { Off = 0, Low = 1, @@ -220,21 +221,12 @@ pub struct ByteArray { pub data: Vec, } -impl<'a> DekuRead<'a> for ByteArray { - fn read( - input: &'a deku::bitvec::BitSlice, - ctx: (), - ) -> Result<(&'a deku::bitvec::BitSlice, Self), DekuError> - where Self: Sized { - let (rest, count) = i32::read(input, ctx)?; - let (data_bits, rest) = rest.split_at(count as usize * 8); - let bytes = data_bits.domain().region().unwrap().1; - Ok(( - rest, - Self { - data: bytes.to_vec(), - }, - )) +impl<'a, Ctx> DekuReader<'a, Ctx> for ByteArray where Ctx: Copy { + fn from_reader_with_ctx(reader: &mut Reader, _ctx: Ctx) -> Result { + let count = i32::from_reader_with_ctx(reader, ())? as usize; + let mut buf = vec![0x00; count]; + reader.read_bytes(count, &mut buf)?; + Ok(ByteArray{ data: buf }) } } @@ -271,7 +263,7 @@ pub struct ChannelInfo { } #[derive(DekuRead, Clone, Debug)] -#[deku(type = "u8")] +#[deku(id_type = "u8")] pub enum VertexFormat { #[deku(id = "0")] Float, #[deku(id = "1")] Float16, @@ -390,7 +382,7 @@ pub struct GLTextureSettings { } #[derive(DekuRead, Clone, Debug)] -#[deku(type = "i32")] +#[deku(id_type = "i32")] pub enum TextureFilterMode { Nearest = 0, Bilinear = 1, @@ -398,7 +390,7 @@ pub enum TextureFilterMode { } #[derive(DekuRead, Clone, Debug)] -#[deku(type = "i32")] +#[deku(id_type = "i32")] pub enum TextureWrapMode { Repeat = 0, Clamp = 1, @@ -408,7 +400,7 @@ pub enum TextureWrapMode { // copied from https://github.com/Unity-Technologies/UnityCsReference/blob/129a67089d125df5b95b659d3535deaf9968e86c/Editor/Mono/AssetPipeline/TextureImporterEnums.cs#L37 #[derive(DekuRead, Clone, Debug)] -#[deku(type = "i32")] +#[deku(id_type = "i32")] pub enum TextureFormat { // Alpha 8 bit texture format. Alpha8 = 1, @@ -523,7 +515,7 @@ pub enum TextureFormat { } #[derive(DekuRead, Clone, Debug)] -#[deku(type = "i32")] +#[deku(id_type = "i32")] pub enum ColorSpace { Linear = 0x00, SRGB = 0x01, diff --git a/rust/src/unity/types/class_id.rs b/rust/src/unity/types/class_id.rs index 391d4b1c8..441cea177 100644 --- a/rust/src/unity/types/class_id.rs +++ b/rust/src/unity/types/class_id.rs @@ -3,7 +3,7 @@ use deku::prelude::*; #[wasm_bindgen(js_name = "UnityClassID")] #[derive(DekuRead, Debug, Copy, Clone, PartialEq)] -#[deku(type = "i32")] +#[deku(id_type = "i32")] #[repr(i32)] pub enum ClassID { #[deku(id = "-1")] UnknownType, diff --git a/rust/src/unity/types/common.rs b/rust/src/unity/types/common.rs index 266b3e284..1db830d1e 100644 --- a/rust/src/unity/types/common.rs +++ b/rust/src/unity/types/common.rs @@ -1,8 +1,10 @@ +use std::borrow::Cow; +use std::io::Cursor; use std::{collections::HashMap, fmt::Debug, hash::Hash, marker::PhantomData}; use std::clone::Clone; use wasm_bindgen::prelude::*; -use deku::{bitvec::{BitSlice, Msb0}, ctx::BitSize, prelude::*}; +use deku::{ctx::BitSize, prelude::*}; // Important: these must be ordered by chronological release date, so // PartialOrd can correctly compare them. @@ -21,28 +23,22 @@ pub struct UnityArray { fn check_count(count: usize, limit: usize) -> Result<(), DekuError> { if count > limit { - return Err(DekuError::Assertion(format!("Got unreasonably large count: {} > {}", count, limit))); + return Err(DekuError::Assertion(Cow::from(format!("Got unreasonably large count: {} > {}", count, limit)))); } Ok(()) } -impl<'a, T, Ctx> DekuRead<'a, Ctx> for UnityArray where T: DekuRead<'a, Ctx>, Ctx: Clone { - fn read( - input: &'a deku::bitvec::BitSlice, - ctx: Ctx, - ) -> Result<(&'a deku::bitvec::BitSlice, Self), DekuError> - where - Self: Sized { - let (mut rest, count) = i32::read(input, ())?; - let mut values = Vec::new(); - for _ in 0..count { - let (new_rest, value) = T::read(rest, ctx.clone())?; - rest = new_rest; - values.push(value); - } - Ok((rest, UnityArray { - values, - })) +impl<'a, T, Ctx> DekuReader<'a, Ctx> for UnityArray where T: DekuReader<'a, Ctx>, Ctx: Clone { + fn from_reader_with_ctx(reader: &mut Reader, ctx: Ctx) -> Result { + let count = i32::from_reader_with_ctx(reader, ())? as usize; + let mut values = Vec::new(); + for _ in 0..count { + let value = T::from_reader_with_ctx(reader, ctx.clone())?; + values.push(value); + } + Ok(UnityArray { + values, + }) } } @@ -58,30 +54,23 @@ pub struct Map { pub values: Vec, } -impl<'a, K, V, Ctx> DekuRead<'a, Ctx> for Map - where K: DekuRead<'a, Ctx>, V: DekuRead<'a, Ctx>, Ctx: Clone +impl<'a, K, V, Ctx> DekuReader<'a, Ctx> for Map + where K: DekuReader<'a, Ctx>, V: DekuReader<'a, Ctx>, Ctx: Clone { - fn read( - input: &'a deku::bitvec::BitSlice, - ctx: Ctx, - ) -> Result<(&'a deku::bitvec::BitSlice, Self), DekuError> - where - Self: Sized { - let (mut rest, count) = i32::read(input, ())?; - let mut keys = Vec::new(); - let mut values = Vec::new(); - for _ in 0..count { - let (new_rest, key) = K::read(rest, ctx.clone())?; - rest = new_rest; - let (new_rest, value) = V::read(rest, ctx.clone())?; - rest = new_rest; - keys.push(key); - values.push(value); - } - Ok((rest, Map { - keys, - values, - })) + fn from_reader_with_ctx(reader: &mut Reader, ctx: Ctx) -> Result { + let count = i32::from_reader_with_ctx(reader, ())?; + let mut keys = Vec::new(); + let mut values = Vec::new(); + for _ in 0..count { + let key = K::from_reader_with_ctx(reader, ctx.clone())?; + let value = V::from_reader_with_ctx(reader, ctx.clone())?; + keys.push(key); + values.push(value); + } + Ok(Map { + keys, + values, + }) } } @@ -213,15 +202,15 @@ pub struct Matrix4x4 { pub e3: Vec4, } -fn unpack_i32s(input: &BitSlice, num_items: usize, bit_size: usize) -> Result<(&BitSlice, Vec), DekuError> { +fn unpack_i32s(buf: &mut [u8], num_items: usize, bit_size: usize) -> Result, DekuError> { let mut result = Vec::new(); - let mut rest = input; + let mut cursor = Cursor::new(buf); + let mut reader = Reader::new(&mut cursor); for _ in 0..num_items { - let (new_rest, value) = i32::read(rest, BitSize(bit_size))?; - rest = new_rest; + let value = i32::from_reader_with_ctx(&mut reader, BitSize(bit_size))?; result.push(value); } - Ok((rest, result)) + Ok(result) } #[derive(Clone, Debug)] @@ -235,21 +224,19 @@ impl From for Vec { } } -impl<'a> DekuRead<'a> for Packedi32Vec { - fn read(input: &'a BitSlice, ctx: ()) -> Result<(&'a BitSlice, Self), DekuError> - where - Self: Sized { - let (mut rest, num_items) = u32::read(input, ctx)?; - let (new_rest, byte_array_count) = u32::read(rest, ctx)?; - rest = new_rest; - let (new_rest, bit_size) = u8::read(&rest[8 * byte_array_count as usize..], ctx)?; - // align - let last_rest = &new_rest[3*8..]; - let (_, data) = unpack_i32s(rest, num_items as usize, bit_size as usize)?; - - Ok((last_rest, Packedi32Vec { - data, - })) +impl<'a, Ctx> DekuReader<'a, Ctx> for Packedi32Vec where Ctx: Clone { + fn from_reader_with_ctx(reader: &mut Reader, _ctx: Ctx) -> Result { + let num_items = u32::from_reader_with_ctx(reader, ())? as usize; + let byte_array_count = u32::from_reader_with_ctx(reader, ())? as usize; + let mut buf = vec![0x00; byte_array_count]; + reader.read_bytes(byte_array_count, &mut buf)?; + let bit_size = u8::from_reader_with_ctx(reader, ())?; + reader.skip_bits(3*8)?; // align + let data = unpack_i32s(&mut buf, num_items as usize, bit_size as usize)?; + + Ok(Packedi32Vec { + data, + }) } } @@ -264,30 +251,26 @@ impl From for Vec { } } -impl<'a> DekuRead<'a> for Packedf32Vec { - fn read(input: &'a BitSlice, ctx: ()) -> Result<(&'a BitSlice, Self), DekuError> - where - Self: Sized { - let (mut rest, num_items) = u32::read(input, ctx)?; - let (new_rest, scale) = f32::read(rest, ctx)?; - rest = new_rest; - let (new_rest, start) = f32::read(rest, ctx)?; - rest = new_rest; - let (new_rest, byte_array_count) = u32::read(rest, ctx)?; - rest = new_rest; - let (new_rest, bit_size) = u8::read(&rest[8 * byte_array_count as usize..], ctx)?; - // align - let last_rest = &new_rest[3*8..]; - - let max = ((1 << bit_size) as f32) - 1.0; - let (_, ints) = unpack_i32s(rest, num_items as usize, bit_size as usize)?; - let mut result = Vec::new(); - for v in ints { - result.push(start + (v as f32) * scale / max); - } - - Ok((last_rest, Packedf32Vec { - data: result, - })) +impl<'a, Ctx> DekuReader<'a, Ctx> for Packedf32Vec where Ctx: Clone { + fn from_reader_with_ctx(reader: &mut Reader, _ctx: Ctx) -> Result { + let num_items = u32::from_reader_with_ctx(reader, ())?; + let scale = f32::from_reader_with_ctx(reader, ())?; + let start = f32::from_reader_with_ctx(reader, ())?; + let byte_array_count = u32::from_reader_with_ctx(reader, ())? as usize; + let mut buf = vec![0x00; byte_array_count]; + reader.read_bytes(byte_array_count, &mut buf)?; + let bit_size = u8::from_reader_with_ctx(reader, ())?; + reader.skip_bits(3*8)?; // align + + let max = ((1 << bit_size) as f32) - 1.0; + let ints = unpack_i32s(&mut buf, num_items as usize, bit_size as usize)?; + let mut result = Vec::new(); + for v in ints { + result.push(start + (v as f32) * scale / max); + } + + Ok(Packedf32Vec { + data: result, + }) } } diff --git a/rust/src/unity/types/wasm.rs b/rust/src/unity/types/wasm.rs index 45c1487b3..7cff46550 100644 --- a/rust/src/unity/types/wasm.rs +++ b/rust/src/unity/types/wasm.rs @@ -1,9 +1,11 @@ use std::collections::HashMap; +use std::io::Cursor; +use deku::reader::Reader; use deku::DekuContainerRead; use noclip_macros::{FromStructPerField, FromEnumPerVariant, from}; use wasm_bindgen::prelude::*; -use deku::{DekuRead, bitvec::BitSlice}; +use deku::DekuReader; use crate::unity::types::common::CharArray; use super::common::{ColorRGBA, Matrix4x4, PPtr, Quaternion, Vec2, Vec3, Vec4, AABB, UnityVersion}; @@ -14,9 +16,11 @@ macro_rules! define_create { #[wasm_bindgen(js_class = $u)] impl $t { pub fn create(version: UnityVersion, data: &[u8]) -> Result<$t, String> { - let bitslice = BitSlice::from_slice(data); - match binary::$t::read(&bitslice, version) { - Ok((_, value)) => Ok(value.into()), + let mut data2 = data; + let mut cursor = Cursor::new(&mut data2); + let mut reader = Reader::new(&mut cursor); + match binary::$t::from_reader_with_ctx(&mut reader, version) { + Ok(value) => Ok(value.into()), Err(err) => return Err(format!("Couldn't create {}: {:?}", $u, err)), } } diff --git a/rust/src/unity/util.rs b/rust/src/unity/util.rs index bd137d3ef..9564dab98 100644 --- a/rust/src/unity/util.rs +++ b/rust/src/unity/util.rs @@ -1,15 +1,15 @@ -use deku::{bitvec::{BitSlice, Msb0}, prelude::*}; +use deku::prelude::*; use std::fmt::Debug; -pub fn deku_peek<'a, T>(input: &'a BitSlice, byte_offset: usize, msg: &str) -> Result<(&'a BitSlice, T), DekuError> - where for<'b> T: DekuRead<'b, ()> + Debug +pub fn deku_peek<'a, T, R: deku::no_std_io::Read + deku::no_std_io::Seek>(reader: &mut Reader, msg: &str) -> Result + where for<'b> T: DekuReader<'b, ()> + Debug { println!("deku_peek - {}", msg); - println!(" offset: {}", byte_offset); - match T::read(input, ()) { - Ok((rest, value)) => { + println!(" offset: {}", reader.bits_read); + match T::from_reader_with_ctx(reader, ()) { + Ok(value) => { println!(" value: {:?}", value); - Ok((rest, value)) + Ok(value) } Err(err) => { println!(" ERROR: {:?}", err); diff --git a/rust/src/wow/animation.rs b/rust/src/wow/animation.rs index c7b1d1c95..11ca02b02 100644 --- a/rust/src/wow/animation.rs +++ b/rust/src/wow/animation.rs @@ -74,8 +74,7 @@ pub struct M2TrackPartial { } impl M2TrackPartial { - pub fn allocate(&mut self, data: &[u8]) -> Result<(), String> - where for<'a> T: DekuRead<'a> { + pub fn allocate(&mut self, data: &[u8]) -> Result<(), String> where for<'a> T: DekuReader<'a> { self.timestamps = Some(self.timestamps_unallocated.to_vec(data)?); self.values = Some(self.values_unallocated.to_vec(data)?); @@ -102,8 +101,7 @@ pub struct M2Track { } impl M2Track { - pub fn allocate(&mut self, data: &[u8]) -> Result<(), String> - where for<'a> T: DekuRead<'a> { + pub fn allocate(&mut self, data: &[u8]) -> Result<(), String> where for<'a> T: DekuReader<'a> { let mut timestamps = Vec::new(); for arr in self.timestamps_unallocated.to_vec(data)? { timestamps.push(arr.to_vec(data)?); diff --git a/rust/src/wow/blp.rs b/rust/src/wow/blp.rs index 0cb6abfd1..7c47e2caa 100644 --- a/rust/src/wow/blp.rs +++ b/rust/src/wow/blp.rs @@ -3,7 +3,7 @@ use wasm_bindgen::prelude::*; #[wasm_bindgen(js_name = "WowColorEncoding")] #[derive(Debug, DekuRead, Copy, Clone)] -#[deku(type = "u8")] +#[deku(id_type = "u8")] pub enum ColorEncoding { #[deku(id = "1")] Uncompressed, @@ -15,7 +15,7 @@ pub enum ColorEncoding { #[wasm_bindgen(js_name = "WowPixelFormat")] #[derive(Debug, DekuRead, Copy, Clone)] -#[deku(type = "u8")] +#[deku(id_type = "u8")] pub enum PixelFormat { #[deku(id = "0")] Dxt1, diff --git a/rust/src/wow/common.rs b/rust/src/wow/common.rs index 265cf9e2c..bd78284f7 100644 --- a/rust/src/wow/common.rs +++ b/rust/src/wow/common.rs @@ -1,6 +1,6 @@ -use deku::{bitvec::{BitSlice, BitVec}, ctx::ByteSize, prelude::*}; +use deku::{ctx::ByteSize, prelude::*}; use wasm_bindgen::prelude::*; -use std::ops::{Mul, AddAssign}; +use std::{io::Cursor, ops::{AddAssign, Mul}}; use crate::geometry::AABB; @@ -28,19 +28,19 @@ pub struct Chunk { } pub fn parse_with_byte_size(data: &[u8]) -> Result - where for<'a> T: DekuRead<'a, ByteSize> + where for<'a> T: DekuReader<'a, ByteSize> { parse_inner(data, ByteSize(data.len())) } pub fn parse(data: &[u8]) -> Result - where for<'a> T: DekuRead<'a, ()> + where for<'a> T: DekuReader<'a, ()> { parse_inner(data, ()) } pub fn parse_array(data: &[u8], size_per_data: usize) -> Result, String> - where for<'a> T: DekuRead<'a, ()> + where for<'a> T: DekuReader<'a, ()> { if data.len() % size_per_data != 0 { return Err(format!( @@ -50,24 +50,25 @@ pub fn parse_array(data: &[u8], size_per_data: usize) -> Result, Strin )); } let num_elements = data.len() / size_per_data; - let bitvec = BitVec::from_slice(data); + let mut data2 = data; + let mut cursor = Cursor::new(&mut data2); + let mut reader = Reader::new(&mut cursor); let mut result = Vec::with_capacity(num_elements); - let mut rest = bitvec.as_bitslice(); for _ in 0..num_elements { - let (new_rest, element) = T::read(rest, ()) + let element = T::from_reader_with_ctx(&mut reader, ()) .map_err(|e| format!("{:?}", e))?; result.push(element); - rest = new_rest; } Ok(result) } fn parse_inner(data: &[u8], ctx: V) -> Result - where for<'a> T: DekuRead<'a, V> + where for<'a> T: DekuReader<'a, V> { - let bitvec = BitVec::from_slice(data); - let (_, element) = T::read(bitvec.as_bitslice(), ctx) - .map_err(|e| format!("{:?}", e))?; + let mut data2 = data; + let mut cursor = Cursor::new(&mut data2); + let mut reader = Reader::new(&mut cursor); + let element = T::from_reader_with_ctx(&mut reader, ctx).map_err(|e| format!("{:?}", e))?; Ok(element) } @@ -300,14 +301,15 @@ pub struct WowArray { pub element_type: std::marker::PhantomData, } -impl WowArray where for<'a> T: DekuRead<'a> { +impl WowArray where for<'a> T: DekuReader<'a> { pub fn to_vec(&self, data: &[u8]) -> Result, String> { let mut result = Vec::with_capacity(self.count as usize); - let mut bitslice = BitSlice::from_slice(&data[self.offset as usize..]); + let mut data2 = &data[self.offset as usize..]; + let mut cursor = Cursor::new(&mut data2); + let mut reader = Reader::new(&mut cursor); for _ in 0..self.count { - let (new_bitslice, element) = T::read(bitslice, ()) + let element = T::from_reader_with_ctx(&mut reader, ()) .map_err(|e| format!("{:?}", e))?; - bitslice = new_bitslice; result.push(element); } Ok(result) diff --git a/rust/src/wow/db.rs b/rust/src/wow/db.rs index cf636aa55..9ff3333d5 100644 --- a/rust/src/wow/db.rs +++ b/rust/src/wow/db.rs @@ -1,8 +1,7 @@ -use std::collections::{HashMap, HashSet}; +use std::{collections::{HashMap, HashSet}, io::{Cursor, Seek}}; use deku::prelude::*; use super::common::*; -use deku::bitvec::{BitVec, BitSlice, Msb0}; use wasm_bindgen::prelude::*; #[derive(DekuRead, Debug, Clone)] @@ -42,7 +41,7 @@ pub struct Wdc4Db2SectionHeader { } #[derive(DekuRead, Debug, Clone)] -#[deku(type = "u32")] +#[deku(id_type = "u32")] pub enum StorageType { #[deku(id = "0")] None { @@ -128,23 +127,34 @@ impl Wdc4Db2File { } } -fn bitslice_to_u32(bits: &BitSlice, bit_offset: usize, num_bits: usize) -> u32 { - let mut result: u32 = 0; - for bit_num in bit_offset..bit_offset + num_bits { - let byte_index = bit_num >> 3; - let bit_index = 7 - (bit_num % 8); - if bits[byte_index * 8 + bit_index] { - result |= 1 << (bit_num - bit_offset); +fn from_u32(v: u32) -> Result + where for<'a> T: DekuReader<'a, ()> +{ + let mut v_bytes = v.to_le_bytes(); + let mut cursor = Cursor::new(&mut v_bytes); + let mut reader = Reader::new(&mut cursor); + T::from_reader_with_ctx(&mut reader, ()) +} + +fn read_field_to_u32(reader: &mut Reader, field_offset_bits: usize, field_size_bits: usize) -> Result { + // Assumes the reader points to the start of the record + let old = reader.seek(std::io::SeekFrom::Current(0i64)).unwrap(); + reader.skip_bits(field_offset_bits)?; + assert!(field_size_bits <= 32); + let num_bits_to_read = (field_size_bits + 7) & !7; + + let mut result = 0; + if let Some(bits) = reader.read_bits(num_bits_to_read)? { + for bit_num in 0..field_size_bits { + let byte_index = bit_num >> 3; + let bit_index = 7 - (bit_num % 8); + if bits[byte_index * 8 + bit_index] { + result |= 1 << bit_num; + } } } - result -} -fn from_u32(v: u32) -> Result - where for<'a> T: DekuRead<'a, ()> -{ - let v_bytes = v.to_le_bytes(); - let (_, result) = T::read(BitSlice::from_slice(&v_bytes), ())?; + reader.seek(std::io::SeekFrom::Start(old)).unwrap(); Ok(result) } @@ -155,20 +165,19 @@ impl Wdc4Db2File { println!("{:?}", info); for palette_index in 0..info.additional_data_size / 4 { let palette_u32 = self.get_palette_data(field_index, palette_index as usize); - println!(" {}: {} {}", palette_index, palette_u32, from_u32::(palette_u32).unwrap()); + println!(" {}: {} {}", palette_index, palette_u32, f32::from_bits(palette_u32)); } } } - pub fn read_vec<'a, T>(&self, input: &'a BitSlice, _bit_offset: usize, field_number: usize) -> Result<(&'a BitSlice, Vec), DekuError> - where for<'b> T: DekuRead<'b, ()> + pub fn read_vec<'a, T, R: deku::no_std_io::Read + deku::no_std_io::Seek>(&self, reader: &mut Reader, field_number: usize) -> Result, DekuError> + where for<'b> T: DekuReader<'b, ()> { let field_offset = self.field_storage_info[field_number].field_offset_bits as usize; let field_size = self.field_storage_info[field_number].field_size_bits as usize; - let _field_bits = &input[field_offset..field_offset + field_size]; let result = match &self.field_storage_info[field_number].storage_type { StorageType::BitpackedIndexedArray { offset_bits: _, size_bits: _, array_count } => { - let index = bitslice_to_u32(input, field_offset, field_size); + let index = read_field_to_u32(reader, field_offset, field_size)?; let mut result: Vec = Vec::with_capacity(*array_count as usize); for _ in 0..*array_count as usize { let palette_element = self.get_palette_data(field_number, index as usize); @@ -178,79 +187,77 @@ impl Wdc4Db2File { }, _ => panic!("called read_vec() on field {}, which is a non-BitpackedIndexedArray type. call read_field instead", field_number), }; - Ok((&input[field_offset + field_size..], result)) + Ok(result) } - pub fn read_string_helper<'a>(&self, input: &'a BitSlice, string_data: &'a BitSlice) -> Result<(&'a BitSlice, String), DekuError> - { + pub fn read_string_helper<'a, R: deku::no_std_io::Read + deku::no_std_io::Seek>(&self, reader: &mut Reader, string_offset: u32) -> Result { let mut string = String::new(); - let mut rest = string_data; + let old = reader.seek(std::io::SeekFrom::Current(0)).unwrap(); + reader.seek(std::io::SeekFrom::Current(string_offset as i64)).unwrap(); + loop { - let (new_rest, byte) = u8::read(rest, ())?; - rest = new_rest; + let byte = u8::from_reader_with_ctx(reader, ())?; if byte == 0 { - return Ok((input, string)); + break; } string.push(byte as char); if string.len() > 100 { panic!("bad string data: {}", string); } } + + reader.seek(std::io::SeekFrom::Start(old)).unwrap(); + Ok(string) } - pub fn read_string_direct<'a>(&self, input: &'a BitSlice) -> Result<(&'a BitSlice, String), DekuError> - { - let (field_rest, string_offset) = u32::read(input, ())?; - let string_rest = &input[string_offset as usize * 8..]; - self.read_string_helper(field_rest, string_rest) + pub fn read_string_direct<'a, R: deku::no_std_io::Read + deku::no_std_io::Seek>(&self, reader: &mut Reader) -> Result { + let string_offset = u32::from_reader_with_ctx(reader, ())?; + self.read_string_helper(reader, string_offset) } - pub fn read_string<'a>(&self, input: &'a BitSlice, bit_offset: usize, field_number: usize) -> Result<(&'a BitSlice, String), DekuError> - { - let (field_rest, string_offset) = self.read_field::(input, bit_offset, field_number)?; - let string_rest = &input[string_offset as usize * 8..]; - self.read_string_helper(field_rest, string_rest) + pub fn read_string<'a, R: deku::no_std_io::Read + deku::no_std_io::Seek>(&self, reader: &mut Reader, field_number: usize) -> Result { + let string_offset = self.read_field::(reader, field_number)?; + self.read_string_helper(reader, string_offset) } - pub fn read_field<'a, T>(&self, input: &'a BitSlice, _bit_offset: usize, field_number: usize) -> Result<(&'a BitSlice, T), DekuError> - where for<'b> T: DekuRead<'b, ()> + pub fn read_field<'a, T, R: deku::no_std_io::Read + deku::no_std_io::Seek>(&self, reader: &mut Reader, field_number: usize) -> Result + where for<'b> T: DekuReader<'b, ()> { let field_offset = self.field_storage_info[field_number].field_offset_bits as usize; let field_size = self.field_storage_info[field_number].field_size_bits as usize; - let field_bits = &input[field_offset..field_offset + field_size]; let result = match &self.field_storage_info[field_number].storage_type { StorageType::None { .. } => { - let (_, result) = T::read(field_bits, ())?; - result + let old = reader.seek(std::io::SeekFrom::Current(0i64)).unwrap(); + reader.skip_bits(field_offset)?; + let v = T::from_reader_with_ctx(reader, ())?; + reader.seek(std::io::SeekFrom::Start(old)).unwrap(); + v }, - StorageType::Bitpacked { offset_bits: _, size_bits, flags: _ } => { + StorageType::Bitpacked { offset_bits: _, size_bits, flags: _ } | StorageType::BitpackedSigned { offset_bits: _, size_bits, flags: _ } => { let size_bits = *size_bits as usize; - from_u32(bitslice_to_u32(input, field_offset, size_bits))? + let v = read_field_to_u32(reader, field_offset, size_bits)?; + from_u32(v)? }, StorageType::CommonData { default_value, .. } => { let default = from_u32(*default_value)?; - let index = bitslice_to_u32(input, field_offset, field_size); + let index = read_field_to_u32(reader, field_offset, field_size)?; let common_element = self.get_common_data(field_number, index).unwrap_or(default); from_u32(common_element)? }, - StorageType::BitpackedIndexed { .. } => { - let index = bitslice_to_u32(input, field_offset, field_size); + StorageType::BitpackedIndexed { .. } => { + let index = read_field_to_u32(reader, field_offset, field_size)?; let palette_element = self.get_palette_data(field_number, index as usize); from_u32(palette_element)? }, StorageType::BitpackedIndexedArray { offset_bits: _, size_bits: _, array_count: _ } => { panic!("read_value() called on field {}, which is a BitpackedIndexedArray type. use read_vec() instead", field_number) }, - StorageType::BitpackedSigned { offset_bits: _, size_bits, flags: _ } => { - let size_bits = *size_bits as usize; - from_u32(bitslice_to_u32(input, field_offset, size_bits))? - }, }; - Ok((&input[field_offset + field_size..], result)) + Ok(result) } fn get_common_data(&self, field_number: usize, needle: u32) -> Option { - let mut offset = 0; + let mut offset: usize = 0; for field_number_i in 0..field_number { match &self.field_storage_info[field_number_i].storage_type { StorageType::CommonData {..} => { @@ -307,38 +314,40 @@ pub struct DatabaseTable { impl DatabaseTable { pub fn new(data: &[u8]) -> Result, String> - where for<'a> T: DekuRead<'a, Wdc4Db2File> + where for<'a> T: DekuReader<'a, Wdc4Db2File> { let (_, db2) = Wdc4Db2File::from_bytes((&data, 0)) .map_err(|e| format!("{:?}", e))?; let mut records: Vec = Vec::with_capacity(db2.header.record_count as usize); let mut ids: Vec = Vec::with_capacity(db2.header.record_count as usize); let records_start = db2.section_headers[0].file_offset as usize; - let bitvec = BitVec::from_slice(&data[records_start..]); - let mut rest = bitvec.as_bitslice(); + let mut data2 = data; + let mut cursor = Cursor::new(&mut data2); + let mut reader = Reader::new(&mut cursor); + + reader.seek(std::io::SeekFrom::Start(records_start as u64)).unwrap(); let mut id = db2.header.min_id; - for _ in 0..db2.header.record_count { - let (new_rest, value) = T::read(rest, db2.clone()) + for i in 0..db2.header.record_count { + let value = T::from_reader_with_ctx(&mut reader, db2.clone()) .map_err(|e| format!("{:?}", e))?; + // our abuse of Deku in the database system always puts the cursor back where it started, so advance to the next record manually + let new_pos = reader.seek(std::io::SeekFrom::Current(0)).unwrap(); + dbg!(records_start, new_pos, i, db2.header.record_size); records.push(value); ids.push(id); id += 1; - let bits_read = rest.len() - new_rest.len(); - assert_eq!(db2.header.record_size as usize * 8, bits_read); - rest = new_rest; } let strings_start = records_start + (db2.header.record_count * db2.header.record_size) as usize; // if a list of IDs is provided, correct our auto-generated IDs - let id_list_start = strings_start + db2.header.string_table_size as usize; - let id_list_size = db2.section_headers[0].id_list_size as usize; + let id_list_start: usize = strings_start + db2.header.string_table_size as usize; + let id_list_size: usize = db2.section_headers[0].id_list_size as usize; if id_list_size > 0 { - let mut bitslice = BitSlice::from_slice(&data[id_list_start..]); + reader.seek(std::io::SeekFrom::Start(id_list_start as u64)).unwrap(); assert_eq!(id_list_size, records.len() * 4); for i in 0..records.len() { - (rest, id) = u32::read(bitslice, ()) + id = u32::from_reader_with_ctx(&mut reader, ()) .map_err(|e| format!("{:?}", e))?; - bitslice = rest; ids[i] = id; } } @@ -358,74 +367,74 @@ impl DatabaseTable { #[wasm_bindgen(js_name = "WowLightParamsRecord")] #[deku(ctx = "db2: Wdc4Db2File")] pub struct LightParamsRecord { - #[deku(reader = "db2.read_field(deku::input_bits, deku::bit_offset, 0)")] + #[deku(reader = "db2.read_field(deku::reader, 0)")] _celestial_overrides: Vec3, - #[deku(reader = "db2.read_field(deku::input_bits, deku::bit_offset, 1)")] + #[deku(reader = "db2.read_field(deku::reader, 1)")] pub light_data_id: u32, - #[deku(reader = "db2.read_field(deku::input_bits, deku::bit_offset, 2)")] + #[deku(reader = "db2.read_field(deku::reader, 2)")] pub highlight_sky: bool, - #[deku(reader = "db2.read_field(deku::input_bits, deku::bit_offset, 3)")] + #[deku(reader = "db2.read_field(deku::reader, 3)")] pub skybox_id: u32, - #[deku(reader = "db2.read_field(deku::input_bits, deku::bit_offset, 5)")] + #[deku(reader = "db2.read_field(deku::reader, 5)")] pub glow: f32, - #[deku(reader = "db2.read_field(deku::input_bits, deku::bit_offset, 6)")] + #[deku(reader = "db2.read_field(deku::reader, 6)")] pub water_shallow_alpha: f32, - #[deku(reader = "db2.read_field(deku::input_bits, deku::bit_offset, 7)")] + #[deku(reader = "db2.read_field(deku::reader, 7)")] pub water_deep_alpha: f32, - #[deku(reader = "db2.read_field(deku::input_bits, deku::bit_offset, 8)")] + #[deku(reader = "db2.read_field(deku::reader, 8)")] pub ocean_shallow_alpha: f32, - #[deku(reader = "db2.read_field(deku::input_bits, deku::bit_offset, 9)")] + #[deku(reader = "db2.read_field(deku::reader, 9)")] pub ocean_deep_alpha: f32, - #[deku(reader = "db2.read_field(deku::input_bits, deku::bit_offset, 10)", pad_bits_after = "1")] + #[deku(reader = "db2.read_field(deku::reader, 10)")] pub flags: f32, } #[derive(DekuRead, Debug, Clone)] #[deku(ctx = "db2: Wdc4Db2File")] struct LightDataRecord { - #[deku(reader = "db2.read_field(deku::input_bits, deku::bit_offset, 0)")] + #[deku(reader = "db2.read_field(deku::reader, 0)")] pub light_param_id: u32, - #[deku(reader = "db2.read_field(deku::input_bits, deku::bit_offset, 1)")] + #[deku(reader = "db2.read_field(deku::reader, 1)")] pub time: u32, - #[deku(reader = "db2.read_field(deku::input_bits, deku::bit_offset, 2)")] + #[deku(reader = "db2.read_field(deku::reader, 2)")] pub direct_color: u32, - #[deku(reader = "db2.read_field(deku::input_bits, deku::bit_offset, 3)")] + #[deku(reader = "db2.read_field(deku::reader, 3)")] pub ambient_color: u32, - #[deku(reader = "db2.read_field(deku::input_bits, deku::bit_offset, 4)")] + #[deku(reader = "db2.read_field(deku::reader, 4)")] pub sky_top_color: u32, - #[deku(reader = "db2.read_field(deku::input_bits, deku::bit_offset, 5)")] + #[deku(reader = "db2.read_field(deku::reader, 5)")] pub sky_middle_color: u32, - #[deku(reader = "db2.read_field(deku::input_bits, deku::bit_offset, 6)")] + #[deku(reader = "db2.read_field(deku::reader, 6)")] pub sky_band1_color: u32, - #[deku(reader = "db2.read_field(deku::input_bits, deku::bit_offset, 7)")] + #[deku(reader = "db2.read_field(deku::reader, 7)")] pub sky_band2_color: u32, - #[deku(reader = "db2.read_field(deku::input_bits, deku::bit_offset, 8)")] + #[deku(reader = "db2.read_field(deku::reader, 8)")] pub sky_smog_color: u32, - #[deku(reader = "db2.read_field(deku::input_bits, deku::bit_offset, 9)")] + #[deku(reader = "db2.read_field(deku::reader, 9)")] pub sky_fog_color: u32, - #[deku(reader = "db2.read_field(deku::input_bits, deku::bit_offset, 10)")] + #[deku(reader = "db2.read_field(deku::reader, 10)")] pub sun_color: u32, - #[deku(reader = "db2.read_field(deku::input_bits, deku::bit_offset, 11)")] + #[deku(reader = "db2.read_field(deku::reader, 11)")] pub cloud_sun_color: u32, - #[deku(reader = "db2.read_field(deku::input_bits, deku::bit_offset, 12)")] + #[deku(reader = "db2.read_field(deku::reader, 12)")] pub cloud_emissive_color: u32, - #[deku(reader = "db2.read_field(deku::input_bits, deku::bit_offset, 13)")] + #[deku(reader = "db2.read_field(deku::reader, 13)")] pub cloud_layer1_ambient_color: u32, - #[deku(reader = "db2.read_field(deku::input_bits, deku::bit_offset, 14)")] + #[deku(reader = "db2.read_field(deku::reader, 14)")] pub cloud_layer2_ambient_color: u32, - #[deku(reader = "db2.read_field(deku::input_bits, deku::bit_offset, 15)")] + #[deku(reader = "db2.read_field(deku::reader, 15)")] pub ocean_close_color: u32, - #[deku(reader = "db2.read_field(deku::input_bits, deku::bit_offset, 16)")] + #[deku(reader = "db2.read_field(deku::reader, 16)")] pub ocean_far_color: u32, - #[deku(reader = "db2.read_field(deku::input_bits, deku::bit_offset, 17)")] + #[deku(reader = "db2.read_field(deku::reader, 17)")] pub river_close_color: u32, - #[deku(reader = "db2.read_field(deku::input_bits, deku::bit_offset, 18)")] + #[deku(reader = "db2.read_field(deku::reader, 18)")] pub river_far_color: u32, - #[deku(reader = "db2.read_field(deku::input_bits, deku::bit_offset, 19)")] + #[deku(reader = "db2.read_field(deku::reader, 19)")] pub shadow_opacity: u32, - #[deku(reader = "db2.read_field(deku::input_bits, deku::bit_offset, 20)")] + #[deku(reader = "db2.read_field(deku::reader, 20)")] pub fog_end: f32, - #[deku(reader = "db2.read_field(deku::input_bits, deku::bit_offset, 21)", pad_bits_after = "40")] + #[deku(reader = "db2.read_field(deku::reader, 21)")] pub fog_scaler: f32, } @@ -641,70 +650,70 @@ impl Lerp for LightResult { #[derive(DekuRead, Clone, Debug)] #[deku(ctx = "db2: Wdc4Db2File")] pub struct LiquidType { - #[deku(reader = "db2.read_string(deku::input_bits, deku::bit_offset, 0)")] + #[deku(reader = "db2.read_string(deku::reader, 0)")] pub name: String, - #[deku(reader = "db2.read_string_direct(deku::rest)")] + #[deku(reader = "db2.read_string_direct(deku::reader)")] pub tex0: String, - #[deku(reader = "db2.read_string_direct(deku::rest)")] + #[deku(reader = "db2.read_string_direct(deku::reader)")] pub tex1: String, - #[deku(reader = "db2.read_string_direct(deku::rest)")] + #[deku(reader = "db2.read_string_direct(deku::reader)")] pub tex2: String, - #[deku(reader = "db2.read_string_direct(deku::rest)")] + #[deku(reader = "db2.read_string_direct(deku::reader)")] pub tex3: String, - #[deku(reader = "db2.read_string_direct(deku::rest)")] + #[deku(reader = "db2.read_string_direct(deku::reader)")] pub tex4: String, - #[deku(reader = "db2.read_string_direct(deku::rest)")] + #[deku(reader = "db2.read_string_direct(deku::reader)")] pub tex5: String, - #[deku(reader = "db2.read_field(deku::input_bits, deku::bit_offset, 2)")] + #[deku(reader = "db2.read_field(deku::reader, 2)")] pub flags: u16, - #[deku(reader = "db2.read_field(deku::input_bits, deku::bit_offset, 3)")] + #[deku(reader = "db2.read_field(deku::reader, 3)")] pub _sound_bank: u8, - #[deku(reader = "db2.read_field(deku::input_bits, deku::bit_offset, 4)")] + #[deku(reader = "db2.read_field(deku::reader, 4)")] pub _sound_id: u32, - #[deku(reader = "db2.read_field(deku::input_bits, deku::bit_offset, 5)")] + #[deku(reader = "db2.read_field(deku::reader, 5)")] pub _f6: u32, - #[deku(reader = "db2.read_field(deku::input_bits, deku::bit_offset, 6)")] + #[deku(reader = "db2.read_field(deku::reader, 6)")] pub _max_darken_depth: f32, - #[deku(reader = "db2.read_field(deku::input_bits, deku::bit_offset, 7)")] + #[deku(reader = "db2.read_field(deku::reader, 7)")] pub _fog_darken_intensity: f32, - #[deku(reader = "db2.read_field(deku::input_bits, deku::bit_offset, 8)")] + #[deku(reader = "db2.read_field(deku::reader, 8)")] pub _ambient_darken_intensity: f32, - #[deku(reader = "db2.read_field(deku::input_bits, deku::bit_offset, 9)")] + #[deku(reader = "db2.read_field(deku::reader, 9)")] pub _dir_darken_intensity: f32, - #[deku(reader = "db2.read_field(deku::input_bits, deku::bit_offset, 10)")] + #[deku(reader = "db2.read_field(deku::reader, 10)")] pub _light_id: u32, - #[deku(reader = "db2.read_field(deku::input_bits, deku::bit_offset, 11)")] + #[deku(reader = "db2.read_field(deku::reader, 11)")] pub _particle_scale: f32, - #[deku(reader = "db2.read_field(deku::input_bits, deku::bit_offset, 12)")] + #[deku(reader = "db2.read_field(deku::reader, 12)")] pub _particle_movement: u32, - #[deku(reader = "db2.read_field(deku::input_bits, deku::bit_offset, 13)")] + #[deku(reader = "db2.read_field(deku::reader, 13)")] pub _particle_tex_slots: u32, - #[deku(reader = "db2.read_field(deku::input_bits, deku::bit_offset, 14)")] + #[deku(reader = "db2.read_field(deku::reader, 14)")] pub _particle_material_id: u32, - #[deku(reader = "db2.read_field(deku::input_bits, deku::bit_offset, 15)")] + #[deku(reader = "db2.read_field(deku::reader, 15)")] pub _minimap_colors: u32, - #[deku(reader = "db2.read_vec(deku::input_bits, deku::bit_offset, 16)")] + #[deku(reader = "db2.read_vec(deku::reader, 16)")] pub _unknown_colors: Vec, - #[deku(reader = "db2.read_vec(deku::input_bits, deku::bit_offset, 17)")] + #[deku(reader = "db2.read_vec(deku::reader, 17)")] pub _shader_color: Vec, - #[deku(reader = "db2.read_vec(deku::input_bits, deku::bit_offset, 18)")] + #[deku(reader = "db2.read_vec(deku::reader, 18)")] pub _shader_f32_params: Vec, - #[deku(reader = "db2.read_vec(deku::input_bits, deku::bit_offset, 19)")] + #[deku(reader = "db2.read_vec(deku::reader, 19)")] pub _shader_int_params: Vec, - #[deku(reader = "db2.read_vec(deku::input_bits, deku::bit_offset, 20)", pad_bits_after = "5")] + #[deku(reader = "db2.read_vec(deku::reader, 20)")] pub _coeffecients: Vec, } #[derive(DekuRead, Clone, Debug)] #[deku(ctx = "db2: Wdc4Db2File")] pub struct LightSkyboxRecord { - #[deku(reader = "db2.read_string(deku::input_bits, deku::bit_offset, 0)")] + #[deku(reader = "db2.read_string(deku::reader, 0)")] pub name: String, - #[deku(reader = "db2.read_field(deku::input_bits, deku::bit_offset, 1)")] + #[deku(reader = "db2.read_field(deku::reader, 1)")] pub flags: u16, - #[deku(reader = "db2.read_field(deku::input_bits, deku::bit_offset, 2)")] + #[deku(reader = "db2.read_field(deku::reader, 2)")] pub _skybox_file_data_id: u32, - #[deku(reader = "db2.read_field(deku::input_bits, deku::bit_offset, 3)", pad_bits_after = "26")] + #[deku(reader = "db2.read_field(deku::reader, 3)")] pub _celestial_skybox_file_data_id: u32, } @@ -922,38 +931,6 @@ mod test { use super::*; use crate::wow::sheep::SheepfileManager; - #[test] - fn test_bitslicing() { - let slice = BitSlice::from_slice(&[ - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0x01, 0x18, 0x00, 0x00, - ]); - assert_eq!(bitslice_to_u32(slice, 96, 10), 1); - assert_eq!(bitslice_to_u32(slice, 106, 1), 0); - assert_eq!(bitslice_to_u32(slice, 107, 2), 3); - assert_eq!(bitslice_to_u32(slice, 109, 4), 0); - assert_eq!(bitslice_to_u32(slice, 113, 3), 0); - assert_eq!(bitslice_to_u32(slice, 116, 2), 0); - assert_eq!(bitslice_to_u32(slice, 118, 3), 0); - assert_eq!(bitslice_to_u32(slice, 121, 2), 0); - let slice = BitSlice::from_slice(&[ - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0x02, 0x38, 0x0, 0x0, - ]); - assert_eq!(bitslice_to_u32(slice, 96, 10), 2); - assert_eq!(bitslice_to_u32(slice, 106, 1), 0); - assert_eq!(bitslice_to_u32(slice, 107, 2), 3); - assert_eq!(bitslice_to_u32(slice, 109, 4), 1); - assert_eq!(bitslice_to_u32(slice, 113, 3), 0); - assert_eq!(bitslice_to_u32(slice, 116, 2), 0); - assert_eq!(bitslice_to_u32(slice, 118, 3), 0); - assert_eq!(bitslice_to_u32(slice, 121, 2), 0); - } - #[test] fn test() { let sheep_path = "../data/WorldOfWarcraft/sheep0"; diff --git a/rust/src/wow/m2.rs b/rust/src/wow/m2.rs index 1ca5a23d7..cd70c57d3 100644 --- a/rust/src/wow/m2.rs +++ b/rust/src/wow/m2.rs @@ -376,7 +376,7 @@ pub struct M2Material { #[wasm_bindgen(js_name = "WowM2BlendingMode")] #[derive(DekuRead, Debug, Copy, Clone)] -#[deku(type = "u16")] +#[deku(id_type = "u16")] pub enum M2BlendingMode { Opaque = 0, AlphaKey = 1,