From 8415175e3f7a3b6d7f4fc49b34d17e75b68848ad Mon Sep 17 00:00:00 2001 From: Will Greenberg Date: Mon, 11 Nov 2024 20:38:07 -0800 Subject: [PATCH] wip --- .../{serialized_file.rs => asset_file.rs} | 206 +++--------------- rust/src/unity/mod.rs | 2 +- rust/src/unity/types/common.rs | 67 ++---- rust/src/unity/types/mod.rs | 1 + rust/src/unity/types/serialized_file.rs | 156 +++++++++++++ rust/src/unity/types/wasm.rs | 6 +- src/Common/Unity/AssetManager.ts | 53 ++--- src/Common/Unity/GameObject.ts | 18 +- 8 files changed, 237 insertions(+), 272 deletions(-) rename rust/src/unity/{serialized_file.rs => asset_file.rs} (52%) create mode 100644 rust/src/unity/types/serialized_file.rs diff --git a/rust/src/unity/serialized_file.rs b/rust/src/unity/asset_file.rs similarity index 52% rename from rust/src/unity/serialized_file.rs rename to rust/src/unity/asset_file.rs index 9377294df..536fc2f4c 100644 --- a/rust/src/unity/serialized_file.rs +++ b/rust/src/unity/asset_file.rs @@ -2,9 +2,9 @@ use deku::{bitvec::{BitSlice, BitVec}, prelude::*}; use wasm_bindgen::prelude::*; use crate::unity::types::common::{NullTerminatedAsciiString, UnityArray}; -use super::types::wasm::WasmFriendlyPPtr; - +use crate::unity::types::wasm::WasmFriendlyPPtr; use crate::unity::types::class_id::ClassID; +use crate::unity::types::serialized_file::{SerializedFileHeader, SerializedFileMetadata}; #[wasm_bindgen(js_name = "UnityAssetFile")] pub struct AssetFile { @@ -41,6 +41,7 @@ impl AssetFile { // 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, ()).unwrap(); + let header_len = data.len() - rest.len() / 8; match SerializedFileMetadata::read(rest, self.header.version) { Ok((_, metadata)) => self.metadata = Some(metadata), Err(err) => return Err(format!("failed to parse metadata: {:?}", err)), @@ -60,16 +61,20 @@ impl AssetFile { let metadata = self.get_metadata(); let mut result = Vec::new(); for obj in &metadata.objects { - let byte_start = obj.get_byte_start(); + let byte_start = self.get_data_offset() as i64 + obj.get_byte_start(); let class_id = if obj.serialized_type_index >= 0 { match metadata.type_tree.get(obj.serialized_type_index as usize) { - Some(obj_type) => obj_type.header.raw_type_id, + Some(obj_type) => { + // println!("{}: got actual type {:?}", obj.file_id, obj_type.header.raw_type_id); + obj_type.header.raw_type_id + }, None => { - println!("bogus type: index {}, len {}", obj.serialized_type_index, metadata.type_tree.len()); + println!("{}: bogus type: index {}, len {}", obj.file_id, obj.serialized_type_index, metadata.type_tree.len()); ClassID::UnknownType } } } else { + println!("{}: type defaulting to MonoBehavior", obj.file_id); ClassID::MonoBehavior }; result.push(AssetFileObject { @@ -99,167 +104,15 @@ pub struct AssetFileObject { pub class_id: ClassID, } -// Supports v21, v22, and above - -#[derive(DekuRead, Clone, Debug)] -#[deku(endian = "big")] -struct SerializedFileHeader { - pub metadata_size: i32, - pub file_size: u32, - pub version: i32, - pub data_offset: u32, - #[deku(pad_bytes_after = "3")] - pub endianness: u8, - #[deku(cond = "*version >= 22")] - pub large_files_metadata_size: Option, - #[deku(cond = "*version >= 22")] - pub large_files_file_size: Option, - #[deku(cond = "*version >= 22")] - pub large_files_data_offset: Option, - #[deku(cond = "*version >= 22")] - _unk0: Option, -} - -#[derive(DekuRead, Clone, Debug)] -#[deku(ctx = "version: i32")] -struct SerializedFileMetadata { - pub version_ascii: NullTerminatedAsciiString, - pub target_platform: u32, - pub enable_type_tree: u8, - type_tree_count: i32, - #[deku(count = "*type_tree_count", ctx = "*enable_type_tree > 0")] - pub type_tree: Vec, - object_count: i32, - #[deku(ctx = "version", count = "*object_count")] - pub objects: Vec, - - // align to the nearest 4 byte boundary - #[deku(count = "(4 - deku::byte_offset % 4) % 4")] _alignment: Vec, - - pub script_types: UnityArray, - pub externals: UnityArray, - ref_types_count: i32, - #[deku(count = "*ref_types_count", ctx = "*enable_type_tree > 0")] - pub ref_types: Vec, - pub user_information: NullTerminatedAsciiString, -} - -#[derive(DekuRead, Clone, Debug)] -#[deku(ctx = "version: i32")] -struct ObjectInfo { - pub file_id: i64, - #[deku(cond = "version <= 21")] - pub small_file_byte_start: Option, - #[deku(cond = "version >= 22")] - pub large_file_byte_start: Option, - pub byte_size: i32, - pub serialized_type_index: i32, -} - -impl ObjectInfo { - pub fn get_byte_start(&self) -> i64 { - match self.small_file_byte_start { - Some(v) => v as i64, - None => self.large_file_byte_start.unwrap(), - } - } -} - -#[derive(DekuRead, Clone, Debug)] -struct LocalSerializedObjectIdentifier { - pub local_serialized_file_index: i32, - pub local_identifier_in_file: i64, -} - -#[derive(DekuRead, Clone, Debug)] -#[deku(ctx = "has_type_tree: bool")] -struct SerializedTypeHeader { - pub raw_type_id: ClassID, - pub is_stripped_type: u8, - pub script_type_index: i16, - #[deku(cond = "*raw_type_id == ClassID::MonoBehavior")] - pub script_id: Option<[u8; 16]>, - pub old_type_hash: [u8; 16], - #[deku(cond = "has_type_tree")] - pub old_type: Option, -} - -#[derive(DekuRead, Clone, Debug)] -#[deku(ctx = "has_type_tree: bool")] -struct SerializedType { - #[deku(ctx = "has_type_tree")] - pub header: SerializedTypeHeader, - #[deku(cond = "has_type_tree", default = "0")] - type_dependencies_count: i32, - #[deku(count = "*type_dependencies_count")] - pub type_dependencies: Vec, -} - -#[derive(DekuRead, Clone, Debug)] -#[deku(ctx = "has_type_tree: bool")] -struct SerializedTypeReference { - #[deku(ctx = "has_type_tree")] - pub header: SerializedTypeHeader, - #[deku(cond = "has_type_tree", default = "0")] - type_dependencies_count: i32, - #[deku(count = "*type_dependencies_count")] - pub type_dependencies: Vec, -} - -#[derive(DekuRead, Clone, Debug)] -struct SerializedTypeReferenceDependency { - pub class_name: NullTerminatedAsciiString, - pub namespace: NullTerminatedAsciiString, - pub asm_name: NullTerminatedAsciiString, -} - -#[derive(DekuRead, Clone, Debug)] -struct OldSerializedType { - nodes_count: i32, - string_buffer_size: i32, - #[deku(count = "*nodes_count")] - nodes: Vec, - #[deku(count = "*string_buffer_size")] - string_buffer: Vec, -} - -#[derive(DekuRead, Clone, Debug)] -struct TreeTypeNode { - version: u16, - level: u8, - type_flags: u8, - type_string_offset: u32, - name_string_offset: u32, - byte_size: i32, - index: i32, - meta_flags: u32, - ref_type_hash: u64, -} - -#[derive(DekuRead, Clone, Debug)] -struct Guid { - pub data0: u32, - pub data1: u32, - pub data2: u32, - pub data3: u32, -} - -#[derive(DekuRead, Clone, Debug)] -struct FileIdentifier { - pub asset_path_ascii: NullTerminatedAsciiString, - pub guid: Guid, - pub file_type: i32, - pub path_name_ascii: NullTerminatedAsciiString, -} - #[cfg(test)] mod tests { - use std::collections::HashMap; + use std::collections::{HashMap, HashSet}; use std::path::PathBuf; use std::str::FromStr; use crate::unity::types::common::UnityVersion; use crate::unity::types::wasm::{GameObject, Mesh, MeshFilter, MeshRenderer, Transform}; + use crate::unity::types::serialized_file::ObjectInfo; use super::*; use env_logger; @@ -293,53 +146,52 @@ mod tests { let mut objects = HashMap::new(); let mut object_infos = HashMap::new(); - for obj in &metadata.objects { - object_infos.insert(obj.file_id, obj); - let obj_type = &metadata.type_tree[obj.serialized_type_index as usize]; - if !matches!(obj_type.header.raw_type_id, ClassID::GameObject) { + for obj in asset_file.get_objects() { + if !matches!(obj.class_id, ClassID::GameObject) { + object_infos.insert(obj.file_id, obj); continue; } - let byte_start = asset_file.get_data_offset() as usize + obj.get_byte_start() as usize; - let byte_size = obj.byte_size as usize; - let data = &data[byte_start..byte_start + byte_size]; + let data = &data[obj.byte_start as usize..obj.byte_start as usize + obj.byte_size]; let game_object = GameObject::create(version, data).unwrap(); objects.insert(obj.file_id, game_object); + object_infos.insert(obj.file_id, obj); } + let mut successes = HashSet::new(); for obj in objects.values() { for component_ptr in &obj.components { if component_ptr.file_index != 0 { dbg!(component_ptr); continue; } - let obj: &&ObjectInfo = object_infos.get(&component_ptr.path_id).unwrap(); - let obj_type = &metadata.type_tree[obj.serialized_type_index as usize]; - let byte_start = asset_file.get_data_offset() as usize + obj.get_byte_start() as usize; - let byte_size = obj.byte_size as usize; + let obj = object_infos.get(&component_ptr.path_id).unwrap(); + if successes.contains(&obj.file_id) { + continue; + } let bigdata = &data; - let data = &data[byte_start..byte_start + byte_size]; + let data = &data[obj.byte_start as usize..obj.byte_start as usize + obj.byte_size]; - match obj_type.header.raw_type_id { + match obj.class_id { ClassID::Transform => {Transform::create(version, data).unwrap();}, ClassID::RectTransform => {Transform::create(version, data).unwrap();}, ClassID::MeshFilter => { let filter = MeshFilter::create(version, data).unwrap(); - if filter.mesh.path_id == 0 || filter.mesh.file_index != 0 { + if filter.mesh.path_id == 0 || filter.mesh.file_index != 0 || successes.contains(&filter.mesh.path_id) { continue; } let obj = object_infos.get(&filter.mesh.path_id).unwrap(); - let byte_start = asset_file.get_data_offset() as usize + obj.get_byte_start() as usize; - let byte_size = obj.byte_size as usize; - let data = &bigdata[byte_start..byte_start + byte_size]; + let data = &bigdata[obj.byte_start as usize..obj.byte_start as usize + obj.byte_size]; println!("reading mesh {}", obj.file_id); let mut mesh = Mesh::create(version, data).unwrap(); + successes.insert(obj.file_id); mesh.submeshes.clear(); mesh.index_buffer.clear(); }, ClassID::MeshRenderer => {MeshRenderer::create(version, data).unwrap();}, - s => {}, + _ => {}, } + successes.insert(obj.file_id); } } } diff --git a/rust/src/unity/mod.rs b/rust/src/unity/mod.rs index 802530ba2..a7caeb2da 100644 --- a/rust/src/unity/mod.rs +++ b/rust/src/unity/mod.rs @@ -1,6 +1,6 @@ #![allow(dead_code)] mod version; -mod serialized_file; +mod asset_file; mod types; mod util; diff --git a/rust/src/unity/types/common.rs b/rust/src/unity/types/common.rs index 824b0d4f6..bd69d83a8 100644 --- a/rust/src/unity/types/common.rs +++ b/rust/src/unity/types/common.rs @@ -1,4 +1,5 @@ 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::*}; @@ -18,37 +19,24 @@ pub struct UnityArray { pub values: Vec, } -impl<'a, T> DekuRead<'a, UnityVersion> for UnityArray where T: DekuRead<'a, UnityVersion> { - fn read( - input: &'a deku::bitvec::BitSlice, - version: UnityVersion, - ) -> 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, version)?; - rest = new_rest; - values.push(value); - } - Ok((rest, UnityArray { - values, - })) +fn check_count(count: usize, limit: usize) -> Result<(), DekuError> { + if count > limit { + return Err(DekuError::Assertion(format!("Got unreasonably large count: {} > {}", count, limit))); } + Ok(()) } -impl<'a, T> DekuRead<'a> for UnityArray where T: DekuRead<'a> { +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: Ctx, ) -> Result<(&'a deku::bitvec::BitSlice, Self), DekuError> where Self: Sized { - let (mut rest, count) = i32::read(input, ctx)?; + let (mut rest, count) = i32::read(input, ())?; let mut values = Vec::new(); for _ in 0..count { - let (new_rest, value) = T::read(rest, ctx)?; + let (new_rest, value) = T::read(rest, ctx.clone())?; rest = new_rest; values.push(value); } @@ -70,39 +58,12 @@ pub struct Map { pub values: Vec, } -impl<'a, K, V> DekuRead<'a> for Map - where K: DekuRead<'a>, V: DekuRead<'a> -{ - fn read( - input: &'a deku::bitvec::BitSlice, - ctx: (), - ) -> Result<(&'a deku::bitvec::BitSlice, Self), DekuError> - where - Self: Sized { - let (mut rest, count) = i32::read(input, ctx)?; - let mut keys = Vec::new(); - let mut values = Vec::new(); - for _ in 0..count { - let (new_rest, key) = K::read(rest, ctx)?; - rest = new_rest; - let (new_rest, value) = V::read(rest, ctx)?; - rest = new_rest; - keys.push(key); - values.push(value); - } - Ok((rest, Map { - keys, - values, - })) - } -} - -impl<'a, K, V> DekuRead<'a, UnityVersion> for Map - where K: DekuRead<'a>, V: DekuRead<'a, UnityVersion> +impl<'a, K, V, Ctx> DekuRead<'a, Ctx> for Map + where K: DekuRead<'a, Ctx>, V: DekuRead<'a, Ctx>, Ctx: Clone { fn read( input: &'a deku::bitvec::BitSlice, - version: UnityVersion, + ctx: Ctx, ) -> Result<(&'a deku::bitvec::BitSlice, Self), DekuError> where Self: Sized { @@ -110,9 +71,9 @@ impl<'a, K, V> DekuRead<'a, UnityVersion> for Map let mut keys = Vec::new(); let mut values = Vec::new(); for _ in 0..count { - let (new_rest, key) = K::read(rest, ())?; + let (new_rest, key) = K::read(rest, ctx.clone())?; rest = new_rest; - let (new_rest, value) = V::read(rest, version)?; + let (new_rest, value) = V::read(rest, ctx.clone())?; rest = new_rest; keys.push(key); values.push(value); diff --git a/rust/src/unity/types/mod.rs b/rust/src/unity/types/mod.rs index 2acbdb633..7372a30e5 100644 --- a/rust/src/unity/types/mod.rs +++ b/rust/src/unity/types/mod.rs @@ -2,3 +2,4 @@ pub mod binary; pub mod wasm; pub mod common; pub mod class_id; +pub mod serialized_file; diff --git a/rust/src/unity/types/serialized_file.rs b/rust/src/unity/types/serialized_file.rs new file mode 100644 index 000000000..c7e968107 --- /dev/null +++ b/rust/src/unity/types/serialized_file.rs @@ -0,0 +1,156 @@ +use std::fmt::Debug; +use deku::prelude::*; + +use crate::unity::types::common::{NullTerminatedAsciiString, UnityArray}; +use crate::unity::types::class_id::ClassID; + +// Supports v21, v22, and above + +#[derive(DekuRead, Clone, Debug)] +#[deku(endian = "big")] +pub struct SerializedFileHeader { + pub metadata_size: i32, + pub file_size: u32, + pub version: i32, + pub data_offset: u32, + #[deku(pad_bytes_after = "3")] + pub endianness: u8, + #[deku(cond = "*version >= 22")] + pub large_files_metadata_size: Option, + #[deku(cond = "*version >= 22")] + pub large_files_file_size: Option, + #[deku(cond = "*version >= 22")] + pub large_files_data_offset: Option, + #[deku(cond = "*version >= 22")] + _unk0: Option, +} + +#[derive(DekuRead, Clone, Debug)] +#[deku(ctx = "version: i32")] +pub struct SerializedFileMetadata { + pub version_ascii: NullTerminatedAsciiString, + pub target_platform: u32, + pub enable_type_tree: u8, + type_tree_count: i32, + #[deku(count = "*type_tree_count", ctx = "*enable_type_tree > 0")] + pub type_tree: Vec, + #[deku(reader = r#"crate::unity::util::deku_peek(deku::rest, deku::byte_offset, "object_count")"#)] + object_count: i32, + #[deku(count = "(4 - deku::byte_offset % 4) % 4")] _alignment: Vec, + #[deku(ctx = "version", count = "*object_count")] + pub objects: Vec, + pub script_types: UnityArray, + pub externals: UnityArray, + ref_types_count: i32, + #[deku(count = "*ref_types_count", ctx = "*enable_type_tree > 0")] + pub ref_types: Vec, + pub user_information: NullTerminatedAsciiString, +} + +#[derive(DekuRead, Clone, Debug)] +#[deku(ctx = "version: i32")] +pub struct ObjectInfo { + pub file_id: i64, + #[deku(cond = "version <= 21")] + pub small_file_byte_start: Option, + #[deku(cond = "version >= 22")] + pub large_file_byte_start: Option, + pub byte_size: i32, + pub serialized_type_index: i32, +} + +impl ObjectInfo { + pub fn get_byte_start(&self) -> i64 { + match self.small_file_byte_start { + Some(v) => v as i64, + None => self.large_file_byte_start.unwrap(), + } + } +} + +#[derive(DekuRead, Clone, Debug)] +pub struct LocalSerializedObjectIdentifier { + pub local_serialized_file_index: i32, + pub local_identifier_in_file: i64, +} + +#[derive(DekuRead, Clone, Debug)] +#[deku(ctx = "has_type_tree: bool")] +pub struct SerializedTypeHeader { + pub raw_type_id: ClassID, + pub is_stripped_type: u8, + pub script_type_index: i16, + #[deku(cond = "*raw_type_id == ClassID::MonoBehavior")] + pub script_id: Option<[u8; 16]>, + pub old_type_hash: [u8; 16], + #[deku(cond = "has_type_tree")] + pub old_type: Option, +} + +#[derive(DekuRead, Clone, Debug)] +#[deku(ctx = "has_type_tree: bool")] +pub struct SerializedType { + #[deku(ctx = "has_type_tree")] + pub header: SerializedTypeHeader, + #[deku(cond = "has_type_tree", default = "0")] + type_dependencies_count: i32, + #[deku(count = "*type_dependencies_count")] + pub type_dependencies: Vec, +} + +#[derive(DekuRead, Clone, Debug)] +#[deku(ctx = "has_type_tree: bool")] +pub struct SerializedTypeReference { + #[deku(ctx = "has_type_tree")] + pub header: SerializedTypeHeader, + #[deku(cond = "has_type_tree", default = "0")] + type_dependencies_count: i32, + #[deku(count = "*type_dependencies_count")] + pub type_dependencies: Vec, +} + +#[derive(DekuRead, Clone, Debug)] +pub struct SerializedTypeReferenceDependency { + pub class_name: NullTerminatedAsciiString, + pub namespace: NullTerminatedAsciiString, + pub asm_name: NullTerminatedAsciiString, +} + +#[derive(DekuRead, Clone, Debug)] +pub struct OldSerializedType { + nodes_count: i32, + string_buffer_size: i32, + #[deku(count = "*nodes_count")] + nodes: Vec, + #[deku(count = "*string_buffer_size")] + string_buffer: Vec, +} + +#[derive(DekuRead, Clone, Debug)] +pub struct TreeTypeNode { + version: u16, + level: u8, + type_flags: u8, + type_string_offset: u32, + name_string_offset: u32, + byte_size: i32, + index: i32, + meta_flags: u32, + ref_type_hash: u64, +} + +#[derive(DekuRead, Clone, Debug)] +pub struct Guid { + pub data0: u32, + pub data1: u32, + pub data2: u32, + pub data3: u32, +} + +#[derive(DekuRead, Clone, Debug)] +pub struct FileIdentifier { + pub asset_path_ascii: NullTerminatedAsciiString, + pub guid: Guid, + pub file_type: i32, + pub path_name_ascii: NullTerminatedAsciiString, +} diff --git a/rust/src/unity/types/wasm.rs b/rust/src/unity/types/wasm.rs index 7a8fbc5b9..bf74822a2 100644 --- a/rust/src/unity/types/wasm.rs +++ b/rust/src/unity/types/wasm.rs @@ -15,7 +15,7 @@ macro_rules! define_create { let bitslice = BitSlice::from_slice(data); match binary::$t::read(&bitslice, version) { Ok((_, value)) => Ok(value.into()), - Err(err) => return Err(format!("{:?}", err)), + Err(err) => return Err(format!("Couldn't create {}: {:?}", $u, err)), } } } @@ -151,8 +151,8 @@ pub struct Mesh { #[wasm_bindgen(js_class = "UnityMesh")] impl Mesh { - pub fn set_vertex_data(&mut self, data: VertexData) { - self.vertex_data = data; + pub fn set_vertex_data(&mut self, data: Vec) { + self.vertex_data.data = data; } pub fn unpack_vertices(&self) -> Option> { diff --git a/src/Common/Unity/AssetManager.ts b/src/Common/Unity/AssetManager.ts index 4aefcc7ba..d95b8a137 100644 --- a/src/Common/Unity/AssetManager.ts +++ b/src/Common/Unity/AssetManager.ts @@ -16,20 +16,6 @@ import { GfxRenderCache } from '../../gfx/render/GfxRenderCache.js'; import { rust } from '../../rustlib.js'; import { assert, assertExists, fallbackUndefined } from '../../util.js'; -interface WasmBindgenArray { - length: number; - get(i: number): T; - free(): void; -} - -function loadWasmBindgenArray(wasmArr: WasmBindgenArray): T[] { - const jsArr: T[] = Array(wasmArr.length); - for (let i = 0; i < wasmArr.length; i++) - jsArr[i] = wasmArr.get(i); - wasmArr.free(); - return jsArr; -} - function concatBufs(a: Uint8Array, b: Uint8Array): Uint8Array { let result = new Uint8Array(a.byteLength + b.byteLength); result.set(a); @@ -228,21 +214,26 @@ export class AssetFile { if (this.waitForHeaderPromise !== null) await this.waitForHeaderPromise; - const obj = assertExists(this.unityObjectByFileID.get(pathID)); - const byteStart = this.dataOffset + obj.byte_start; - let buffer: ArrayBufferSlice; - if (this.fetcher !== null) - buffer = await this.fetcher.addRequest(byteStart.valueOf(), obj.byte_size); - else if (this.fullData !== null) - buffer = this.fullData.subarray(Number(byteStart), obj.byte_size); - else - throw "whoops"; + try { + const obj = assertExists(this.unityObjectByFileID.get(pathID)); + + let buffer: ArrayBufferSlice; + if (this.fetcher !== null) + buffer = await this.fetcher.addRequest(obj.byte_start.valueOf(), obj.byte_size); + else if (this.fullData !== null) + buffer = this.fullData.subarray(Number(obj.byte_start), obj.byte_size); + else + throw "whoops"; - const location = this.createLocation(pathID); - const classID = obj.class_id; - const data = buffer.createTypedArray(Uint8Array); - return { location, classID, assetFile: this.assetFile, data }; + const location = this.createLocation(pathID); + const classID = obj.class_id; + const data = buffer.createTypedArray(Uint8Array); + return { location, classID, assetFile: this.assetFile, data }; + } catch (e) { + debugger; + throw e; + } } public getPPtrFile(assetSystem: UnityAssetSystem, pptr: UnityPPtr): AssetFile { @@ -264,8 +255,7 @@ export class AssetFile { const streamingInfo: UnityStreamingInfo = mesh.streaming_info; if (streamingInfo.path.length !== 0) { const buf = await assetSystem.fetchStreamingInfo(streamingInfo); - const vertexData = rust.UnityVertexData.create(assetSystem.version, buf.createTypedArray(Uint8Array)); - mesh.set_vertex_data(vertexData); + mesh.set_vertex_data(buf.createTypedArray(Uint8Array)); } if (mesh.mesh_compression !== UnityMeshCompression.Off) { @@ -310,7 +300,7 @@ export class AssetFile { this.dataCache.set(pathID, v); return v; }).catch(e => { - console.error(`fufckcf to fetch ${pathID}`); + console.error(`failed to fetch ${pathID}, ${e}`); throw e; }); }); @@ -357,9 +347,8 @@ export class UnityAssetSystem { public async fetchStreamingInfo(streamingInfo: UnityStreamingInfo): Promise { assert(streamingInfo.size !== 0); - const assetFile = assertExists(this.assetFiles.get(streamingInfo.path)); return await this.fetchBytes(streamingInfo.path, { - rangeStart: assetFile.dataOffset + streamingInfo.offset, + rangeStart: streamingInfo.offset, rangeSize: streamingInfo.size, }); } diff --git a/src/Common/Unity/GameObject.ts b/src/Common/Unity/GameObject.ts index 3da6270e9..17c72e0a9 100644 --- a/src/Common/Unity/GameObject.ts +++ b/src/Common/Unity/GameObject.ts @@ -343,12 +343,18 @@ class UnityLevel { const loadGameObject = async (unityObject: UnityAssetFileObject) => { const pathID = unityObject.file_id; const objData = await assetFile.fetchObject(pathID); - const wasmGameObject = rust.UnityGameObject.create(this.runtime.version, objData.data); - const gameObject = new GameObject(objData.location, wasmGameObject); - gameObject.isActive = wasmGameObject.is_active > 0; - gameObject.layer = wasmGameObject.layer; - this.gameObjects.push(gameObject); - await gameObject.load(this); + try { + const wasmGameObject = rust.UnityGameObject.create(this.runtime.version, objData.data); + const gameObject = new GameObject(objData.location, wasmGameObject); + gameObject.isActive = wasmGameObject.is_active > 0; + gameObject.layer = wasmGameObject.layer; + this.gameObjects.push(gameObject); + await gameObject.load(this); + } catch (e) { + console.error(`failed to load gameobj: ${e}`); + console.error(unityObject); + throw e; + } }; const promises = [];