diff options
-rw-r--r-- | src/classes.rs | 101 | ||||
-rw-r--r-- | src/classes/assetinfo.rs | 23 | ||||
-rw-r--r-- | src/classes/gameobject.rs | 40 | ||||
-rw-r--r-- | src/classes/mod.rs | 109 | ||||
-rw-r--r-- | src/classes/pptr.rs | 39 | ||||
-rw-r--r-- | src/classes/transform.rs | 26 | ||||
-rw-r--r-- | src/object.rs | 35 |
7 files changed, 272 insertions, 101 deletions
diff --git a/src/classes.rs b/src/classes.rs deleted file mode 100644 index 87bce8c..0000000 --- a/src/classes.rs +++ /dev/null @@ -1,101 +0,0 @@ -use crate::object::Value; -use anyhow::Result; -use serde::Serialize; -use std::collections::BTreeMap; - -#[derive(Serialize)] -pub enum HValue { - PPtr(PPtr), - Pair(Box<HValue>, Box<HValue>), - Value([Value; 1]), - Map(BTreeMap<String, HValue>), - AssetInfo(AssetInfo), - - Array(Vec<HValue>), - Object { - class: String, - fields: BTreeMap<String, HValue>, - }, -} - -impl HValue { - pub fn from_value(v: Value) -> Result<HValue> { - Ok(match v { - Value::Array(a) => Self::Array( - a.into_iter() - .map(|e| HValue::from_value(e)) - .collect::<Result<Vec<_>>>()?, - ), - Value::Object { class, fields } => { - let mut fields = fields - .into_iter() - .map(|(k, v)| Ok((k, HValue::from_value(v)?))) - .collect::<Result<BTreeMap<_, _>>>()?; - - match class.as_str() { - x if x.starts_with("PPtr<") => { - let inner = x.strip_prefix("PPtr<").unwrap().strip_suffix(">").unwrap(); - Self::PPtr(PPtr { - class: inner.to_owned(), - file_id: fields["m_FileID"].as_value().unwrap().as_i32().unwrap(), - path_id: fields["m_PathID"].as_value().unwrap().as_i64().unwrap(), - }) - } - "AssetInfo" => Self::AssetInfo(AssetInfo { - preload_index: fields["preloadIndex"].as_value().unwrap().as_i32().unwrap(), - preload_size: fields["preloadSize"].as_value().unwrap().as_i32().unwrap(), - asset: fields.remove("asset").unwrap().as_pptr().unwrap(), - }), - "map" => { - let Self::Array(a) = fields.remove("Array").unwrap() else { - unreachable!() - }; - Self::Map( - a.into_iter() - .map(|e| { - let Self::Pair(k, v) = e else { unreachable!() }; - (k.as_value().unwrap().clone().as_string().unwrap(), *v) - }) - .collect(), - ) - } - "pair" => Self::Pair( - Box::new(fields.remove("first").unwrap()), - Box::new(fields.remove("second").unwrap()), - ), - "vector" => fields.remove("Array").unwrap(), - _ => Self::Object { class, fields }, - } - } - x => Self::Value([x]), - }) - } - pub fn as_value(&self) -> Option<&Value> { - if let HValue::Value(v) = self { - Some(&v[0]) - } else { - None - } - } - pub fn as_pptr(self) -> Option<PPtr> { - if let HValue::PPtr(v) = self { - Some(v) - } else { - None - } - } -} - -#[derive(Debug, Serialize)] -pub struct PPtr { - class: String, - file_id: i32, - path_id: i64, -} - -#[derive(Debug, Serialize)] -pub struct AssetInfo { - preload_index: i32, - preload_size: i32, - asset: PPtr, -} diff --git a/src/classes/assetinfo.rs b/src/classes/assetinfo.rs new file mode 100644 index 0000000..dadcea3 --- /dev/null +++ b/src/classes/assetinfo.rs @@ -0,0 +1,23 @@ +use super::{gameobject::GameObject, pptr::PPtr}; +use crate::object::Value; +use anyhow::Result; +use serde::Serialize; + +#[derive(Debug, Serialize)] +pub struct AssetInfo { + pub preload_index: i32, + pub preload_size: i32, + pub asset: PPtr<GameObject>, +} +impl AssetInfo { + pub fn from_value(v: Value) -> Result<Self> { + let mut fields = v.as_class("AssetInfo").unwrap(); + Ok(AssetInfo { + preload_index: fields["preloadIndex"].as_i32().unwrap(), + preload_size: fields["preloadSize"].as_i32().unwrap(), + asset: PPtr::from_value(fields.remove("asset").unwrap()) + .unwrap() + .cast(), + }) + } +} diff --git a/src/classes/gameobject.rs b/src/classes/gameobject.rs new file mode 100644 index 0000000..fde042d --- /dev/null +++ b/src/classes/gameobject.rs @@ -0,0 +1,40 @@ +use anyhow::Result; +use serde::Serialize; +use crate::object::Value; +use super::pptr::PPtr; + +#[derive(Debug, Serialize)] +pub struct GameObject { + pub components: Vec<PPtr>, + pub layer: u32, + pub tag: u16, + pub name: String, + pub is_active: bool, +} +impl GameObject { + pub fn from_value(v: Value) -> Result<Self> { + let mut fields = v.as_class("GameObject").unwrap(); + Ok(GameObject { + components: fields + .remove("m_Component") + .unwrap() + .as_array() + .unwrap() + .into_iter() + .map(|e| { + PPtr::from_value( + e.as_class("ComponentPair") + .unwrap() + .remove("component") + .unwrap(), + ) + .unwrap() + }) + .collect(), + layer: fields["m_Layer"].as_u32().unwrap(), + tag: fields["m_Tag"].as_u16().unwrap(), + name: fields["m_Name"].clone().as_string().unwrap(), + is_active: fields["m_IsActive"].as_bool().unwrap(), + }) + } +} diff --git a/src/classes/mod.rs b/src/classes/mod.rs new file mode 100644 index 0000000..bfde8ad --- /dev/null +++ b/src/classes/mod.rs @@ -0,0 +1,109 @@ +pub mod assetinfo; +pub mod gameobject; +pub mod pptr; +pub mod transform; + +use crate::object::Value; +use anyhow::Result; +use assetinfo::AssetInfo; +use gameobject::GameObject; +use pptr::PPtr; +use serde::Serialize; +use std::collections::BTreeMap; +use transform::Transform; + +#[derive(Debug, Serialize)] +pub enum HValue { + AssetInfo(AssetInfo), + GameObject(GameObject), + Transform(Transform), + PPtr(PPtr), + + Pair(Box<HValue>, Box<HValue>), + Value([Value; 1]), + Map(BTreeMap<String, HValue>), + Array(Vec<HValue>), + Object { + class: String, + fields: BTreeMap<String, HValue>, + }, +} + +impl HValue { + pub fn from_value(v: Value) -> Result<HValue> { + Ok(match v { + value @ Value::Object { .. } => { + let class = value.class_name().unwrap(); + match class.as_str() { + x if x.starts_with("PPtr<") => Self::PPtr(PPtr::from_value(value)?), + "AssetInfo" => Self::AssetInfo(AssetInfo::from_value(value)?), + "GameObject" => Self::GameObject(GameObject::from_value(value)?), + _ => { + let Value::Object { class, fields } = value else { + unreachable!() + }; + let mut fields = fields + .into_iter() + .map(|(k, v)| Ok((k, HValue::from_value(v)?))) + .collect::<Result<BTreeMap<_, _>>>()?; + match class.as_str() { + "map" => { + let Self::Array(a) = fields.remove("Array").unwrap() else { + unreachable!() + }; + Self::Map( + a.into_iter() + .map(|e| { + let Self::Pair(k, v) = e else { unreachable!() }; + (k.as_value().unwrap().clone().as_string().unwrap(), *v) + }) + .collect(), + ) + } + "pair" => Self::Pair( + Box::new(fields.remove("first").unwrap()), + Box::new(fields.remove("second").unwrap()), + ), + "vector" => fields.remove("Array").unwrap(), + _ => Self::Object { class, fields }, + } + } + } + } + Value::Array(a) => Self::Array( + a.into_iter() + .map(|e| HValue::from_value(e)) + .collect::<Result<Vec<_>>>()?, + ), + x => Self::Value([x]), + }) + } + pub fn as_value(&self) -> Option<&Value> { + if let HValue::Value(v) = self { + Some(&v[0]) + } else { + None + } + } + pub fn as_pptr(self) -> Option<PPtr> { + if let HValue::PPtr(v) = self { + Some(v) + } else { + None + } + } + pub fn as_array(self) -> Option<Vec<HValue>> { + if let HValue::Array(v) = self { + Some(v) + } else { + None + } + } + pub fn as_class(self, name: &str) -> Option<BTreeMap<String, HValue>> { + if let HValue::Object { class, fields } = self { + if class == name { Some(fields) } else { None } + } else { + None + } + } +} diff --git a/src/classes/pptr.rs b/src/classes/pptr.rs new file mode 100644 index 0000000..1f615ab --- /dev/null +++ b/src/classes/pptr.rs @@ -0,0 +1,39 @@ +use super::HValue; +use crate::object::Value; +use anyhow::Result; +use serde::Serialize; +use std::marker::PhantomData; + +#[derive(Debug, Serialize)] +pub struct PPtr<T = HValue> { + _class: PhantomData<T>, + pub class: String, + pub file_id: i32, + pub path_id: i64, +} +impl PPtr { + pub fn from_value(v: Value) -> Result<Self> { + let Value::Object { class, fields } = v else { + unreachable!() + }; + let inner = class + .strip_prefix("PPtr<") + .unwrap() + .strip_suffix(">") + .unwrap(); + Ok(PPtr { + class: inner.to_owned(), + _class: PhantomData, + file_id: fields["m_FileID"].as_i32().unwrap(), + path_id: fields["m_PathID"].as_i64().unwrap(), + }) + } + pub fn cast<T>(self) -> PPtr<T> { + PPtr { + _class: PhantomData, + class: self.class, + file_id: self.file_id, + path_id: self.path_id, + } + } +} diff --git a/src/classes/transform.rs b/src/classes/transform.rs new file mode 100644 index 0000000..518e248 --- /dev/null +++ b/src/classes/transform.rs @@ -0,0 +1,26 @@ +use super::pptr::PPtr; +use crate::object::Value; +use anyhow::Result; +use serde::Serialize; + +#[derive(Debug, Serialize)] +pub struct Transform { + pub father: PPtr<Transform>, + pub children: Vec<PPtr<Transform>>, +} +impl Transform { + pub fn from_value(v: Value) -> Result<Self> { + let mut fields = v.as_class("Transform").unwrap(); + Ok(Self { + children: fields + .remove("m_Children") + .unwrap() + .as_array() + .unwrap() + .into_iter() + .map(|e| PPtr::from_value(e).unwrap().cast()) + .collect(), + father: PPtr::from_value(fields.remove("m_Father").unwrap())?.cast(), + }) + } +} diff --git a/src/object.rs b/src/object.rs index 061f58e..0068fc2 100644 --- a/src/object.rs +++ b/src/object.rs @@ -122,6 +122,13 @@ pub fn read_value( } impl Value { + pub fn class_name(&self) -> Option<&String> { + if let Value::Object { class, .. } = self { + Some(class) + } else { + None + } + } pub fn as_class(self, name: &str) -> Option<BTreeMap<String, Value>> { if let Value::Object { class, fields } = self { if class == name { Some(fields) } else { None } @@ -150,6 +157,34 @@ impl Value { None } } + pub fn as_u32(&self) -> Option<u32> { + if let Value::U32(s) = self { + Some(*s) + } else { + None + } + } + pub fn as_u16(&self) -> Option<u16> { + if let Value::U16(s) = self { + Some(*s) + } else { + None + } + } + pub fn as_bool(&self) -> Option<bool> { + if let Value::Bool(s) = self { + Some(*s) + } else { + None + } + } + pub fn as_array(self) -> Option<Vec<Value>> { + if let Value::Array(s) = self { + Some(s) + } else { + None + } + } pub fn to_json(self) -> serde_json::Value { match self { Value::Bool(x) => serde_json::Value::Bool(x), |