aboutsummaryrefslogtreecommitdiff
path: root/src/classes
diff options
context:
space:
mode:
Diffstat (limited to 'src/classes')
-rw-r--r--src/classes/mod.rs2
-rw-r--r--src/classes/pptr.rs69
-rw-r--r--src/classes/renderer.rs93
3 files changed, 134 insertions, 30 deletions
diff --git a/src/classes/mod.rs b/src/classes/mod.rs
index 165d41e..bff033a 100644
--- a/src/classes/mod.rs
+++ b/src/classes/mod.rs
@@ -7,7 +7,7 @@ pub mod streaminginfo;
pub mod texture2d;
pub mod transform;
pub mod vectors;
-pub mod mesh_renderer;
+pub mod renderer;
pub mod shader;
use crate::object::{Value, parser::FromValue};
diff --git a/src/classes/pptr.rs b/src/classes/pptr.rs
index 0e66b5f..5d57c20 100644
--- a/src/classes/pptr.rs
+++ b/src/classes/pptr.rs
@@ -1,13 +1,15 @@
use crate::{
assetbundle::AssetBundle,
object::{Value, parser::FromValue},
+ serialized_file::ExternalsContext,
};
-use anyhow::{Result, anyhow, bail};
+use anyhow::{Context, Result, anyhow, bail};
use log::debug;
use serde::Serialize;
use std::{
io::{Read, Seek},
marker::PhantomData,
+ sync::Arc,
};
#[derive(Debug, Serialize)]
@@ -15,19 +17,15 @@ pub struct PPtr<T = Value> {
#[serde(skip, default)]
pub(crate) _class: PhantomData<T>,
pub class: String,
- pub source_file: usize,
+ #[serde(skip)]
+ pub ecx: Arc<ExternalsContext>,
pub file_id: i32,
pub path_id: i64,
}
impl<T> FromValue for PPtr<T> {
fn from_value(v: Value) -> Result<Self> {
- let Value::Object {
- class,
- fields,
- file,
- } = v
- else {
+ let Value::Object { class, fields, ecx } = v else {
bail!("PPtr expected but not an object")
};
let inner = class
@@ -38,7 +36,7 @@ impl<T> FromValue for PPtr<T> {
Ok(PPtr {
class: inner.to_owned(),
_class: PhantomData,
- source_file: file,
+ ecx,
file_id: fields["m_FileID"]
.as_i32()
.ok_or(anyhow!("PPtr m_FileID is not i32"))?,
@@ -54,7 +52,7 @@ impl<T: FromValue> PPtr<T> {
PPtr {
_class: PhantomData,
class: self.class,
- source_file: self.source_file,
+ ecx: self.ecx.clone(),
file_id: self.file_id,
path_id: self.path_id,
}
@@ -67,32 +65,45 @@ impl<T: FromValue> PPtr<T> {
"loading PPtr<{}> file_id={} path_id={}",
self.class, self.file_id, self.path_id
);
- let main_file = match (self.source_file, self.file_id) {
- (0, 0) => true,
- (0, 1) => false,
- (1, 0) => false,
- _ => unreachable!(),
+ let path = if self.file_id == 0 {
+ &self.ecx.name
+ } else {
+ &self.ecx.externals[self.file_id as usize - 1].path_name
};
- if main_file {
- let ob = bundle
- .main
- .objects
+ if let Some(path) = path.strip_prefix("archive:") {
+ let path = path.split_once("/").unwrap_or(("", path)).1;
+ let ni = bundle
+ .fs
+ .header
+ .nodes()
.iter()
- .find(|o| o.path_id == self.path_id)
- .ok_or(anyhow!("object with path id {} not found", self.path_id))?
- .to_owned();
- bundle.main.read_object(ob)?.parse()
- } else {
- let file = bundle.shared_assets.as_mut().ok_or(anyhow!(
- "shared assets referenced but not included in bundle"
- ))?;
+ .find(|n| n.name == path)
+ .unwrap()
+ .clone();
+ let file = bundle.get_fs_file(&ni).unwrap();
+ let mut file = file.lock().unwrap();
let ob = file
.objects
.iter()
.find(|o| o.path_id == self.path_id)
- .ok_or(anyhow!("object with path id {} not found", self.path_id))?
- .to_owned();
+ .unwrap()
+ .clone();
file.read_object(ob)?.parse()
+ } else if *path == bundle.default_resources.ecx.name {
+ let ob = bundle
+ .default_resources
+ .objects
+ .iter()
+ .find(|o| o.path_id == self.path_id)
+ .unwrap()
+ .clone();
+ bundle
+ .default_resources
+ .read_object(ob)
+ .context("reading object from default res file")?
+ .parse()
+ } else {
+ unreachable!("{path:?}")
}
}
}
diff --git a/src/classes/renderer.rs b/src/classes/renderer.rs
new file mode 100644
index 0000000..cd50524
--- /dev/null
+++ b/src/classes/renderer.rs
@@ -0,0 +1,93 @@
+use super::{
+ gameobject::GameObject, material::Material, mesh::Mesh, pptr::PPtr, transform::Transform,
+};
+use crate::object::{
+ Value,
+ parser::{Fields, FromValue},
+};
+use anyhow::{Context, Result};
+
+pub struct Renderer {
+ pub enabled: bool,
+ pub cast_shadows: u8,
+ pub game_object: PPtr<GameObject>,
+ pub materials: Vec<PPtr<Material>>,
+}
+pub struct MeshRenderer {
+ pub renderer: Renderer,
+ pub additional_vertex_streams: PPtr<Mesh>,
+}
+
+pub struct SkinnedMeshRenderer {
+ pub renderer: Renderer,
+ pub bones: Vec<PPtr<Transform>>,
+ pub mesh: PPtr<Mesh>,
+ pub root_bone: PPtr<Transform>,
+}
+
+pub struct MeshFilter {
+ pub gameobject: PPtr<GameObject>,
+ pub mesh: PPtr<Mesh>,
+}
+
+impl FromValue for Renderer {
+ fn from_value(v: Value) -> Result<Self> {
+ Self::from_fields(v.as_class("Renderer")?)
+ }
+}
+impl Renderer {
+ pub fn from_fields(mut fields: Fields) -> Result<Self> {
+ Ok(Self {
+ enabled: fields.field("m_Enabled")?,
+ cast_shadows: fields.field("m_CastShadows")?,
+ game_object: fields
+ .field("m_GameObject")
+ .context("gameobject of meshrenderer")?,
+ materials: fields
+ .remove("m_Materials")
+ .unwrap()
+ .as_vector()
+ .unwrap()
+ .into_iter()
+ .map(|e| e.parse().unwrap())
+ .collect(),
+ })
+ }
+}
+
+impl FromValue for MeshRenderer {
+ fn from_value(v: Value) -> Result<Self> {
+ let mut fields = v.as_class("MeshRenderer")?;
+ Ok(Self {
+ additional_vertex_streams: fields.field("m_AdditionalVertexStreams")?,
+ renderer: Renderer::from_fields(fields)?,
+ })
+ }
+}
+impl FromValue for SkinnedMeshRenderer {
+ fn from_value(v: Value) -> Result<Self> {
+ let mut fields = v.as_class("SkinnedMeshRenderer")?;
+ Ok(Self {
+ root_bone: fields.field("m_RootBone")?,
+ mesh: fields.field("m_Mesh")?,
+ bones: fields
+ .remove("m_Bones")
+ .unwrap()
+ .as_vector()
+ .unwrap()
+ .into_iter()
+ .map(|e| e.parse().unwrap())
+ .collect(),
+ renderer: Renderer::from_fields(fields)?,
+ })
+ }
+}
+impl FromValue for MeshFilter {
+ fn from_value(v: Value) -> Result<Self> {
+ let mut fields = v.as_class("MeshFilter")?;
+ Ok(Self {
+ mesh: fields.field("m_Mesh")?,
+ gameobject: fields.field("m_GameObject")?,
+ })
+ }
+}