From d1c0520316a7b340d2e09c07cbce07a16d66b175 Mon Sep 17 00:00:00 2001 From: Janis Date: Thu, 20 Apr 2023 23:43:56 +0200 Subject: [PATCH] calculating dependencies --- src/lib.rs | 195 +++++++++++++++++++++++++++++--------------- src/v2_types/mod.rs | 4 + 2 files changed, 134 insertions(+), 65 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 9eb2010..684c581 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -22,20 +22,19 @@ pub mod sdk { }; use anyhow::Context; - use rayon::prelude::{IntoParallelRefIterator, ParallelIterator}; + use rayon::prelude::{IntoParallelIterator, IntoParallelRefIterator, ParallelIterator}; use crate::{ global_tables::objects::{FindClass, GOBJECTS}, v2_types::{ - any_type::{self, AnyProperty}, + any_type::{self, AnyField, AnyObject, AnyProperty, AnyStruct}, traits::{ AsUObject, StaticClass, UArrayPropertyTrait, UBytePropertyTrait, UEnumPropertyTrait, UEnumTrait, UFunctionTrait, UObjectNonConst, UObjectPropertyBaseTrait, UObjectTrait, UPropertyTrait, UStructNonConst, UStructPropertyTrait, UStructTrait, }, - EFunctionFlags, EPropertyFlags, UAnyType, UClass, UEnum, UFunction, UObject, - UScriptStruct, UStruct, + EFunctionFlags, EPropertyFlags, UAnyType, UClass, UEnum, UFunction, UObject, UStruct, }, }; @@ -86,23 +85,18 @@ pub mod sdk { pub struct Package { package: UObject, objects: Vec, - dependencies: Vec, } #[derive(Debug)] pub struct ProcessedPackage { pub package: UObject, pub types: HashMap, - pub package_dependencies: Vec, + pub package_dependencies: HashMap>, } impl Package { pub fn new(package: UObject, objects: Vec) -> Self { - Self { - package, - objects, - dependencies: Vec::new(), - } + Self { package, objects } } pub fn process(self) -> ProcessedPackage { @@ -110,35 +104,47 @@ pub mod sdk { .objects .par_iter() .filter_map(|&object| { - let ty = UAnyType::from_uobject(object.as_uobject()); - log::trace!("ty: {ty:?}"); - - match ty { - UAnyType::UClass(class) => { - if let Ok(class) = self.process_struct(unsafe { class.cast() }) { - return Some((object, Types::Class(class))); + match AnyObject::from_object(object) { + AnyObject::Field(field) => match AnyField::from_field(field) { + AnyField::Enum(enm) => { + if let Ok(enm) = Self::process_enum(enm) { + return Some((object, Types::Enum(enm))); + } } - } - UAnyType::UScriptStruct(class) => { - if let Ok(class) = self.process_struct(unsafe { class.cast() }) { - return Some((object, Types::Class(class))); - } - } - UAnyType::UEnum(obj) => { - if let Ok(enm) = Self::process_enum(obj) { - return Some((object, Types::Enum(enm))); - } - } + AnyField::Struct(strt) => match AnyStruct::from_struct(strt) { + strt @ AnyStruct::ScriptStruct(_) | strt @ AnyStruct::Class(_) => { + if let Ok(class) = self.process_struct(unsafe { strt.cast() }) { + return Some((object, Types::Class(class))); + } + } + _ => {} + }, + _ => {} + }, _ => {} } + None }) .collect::>(); + let mut dependencies = types + .iter() + .filter_map(|(_, ty)| match ty { + Types::Class(class) => Some(class.referenced_types()), + _ => None, + }) + .map(|refs| refs.into_iter()) + .flatten() + .fold_into_packages(); + + // remove any objects in Self + dependencies.remove(&self.package); + ProcessedPackage { package: self.package, types, - package_dependencies: self.dependencies, + package_dependencies: dependencies, } } @@ -146,25 +152,20 @@ pub mod sdk { let name = strct .get_name() .context("failed to get struct or class name")?; - let is_struct = strct.is_a(&UScriptStruct::static_class().unwrap()); + let full_name = strct + .get_full_name() + .context("failed to get struct or class full name")?; let is_class = strct.is_a(&UClass::static_class().unwrap()); - // process outers for classes - if !is_struct { - if let Some(outer) = strct.outer() { - if outer.is_a(&UStruct::static_class().unwrap()) { - // depend on this - } - } - } - - let super_struct = if let Some(spr) = *strct.super_field() && spr != strct { - if spr.package_object() != self.package { - log::warn!("encountered external dependency"); - // TODO: return dependency on strct.package_object() - } + let super_struct = if let Some(spr) = *strct.super_field() { + if spr != strct { Some(spr) - } else {None}; + } else { + None + } + } else { + None + }; let (fields, methods) = self.process_children(strct)?; @@ -175,6 +176,7 @@ pub mod sdk { super_class: super_struct, fields, methods, + full_name, }) } @@ -466,14 +468,46 @@ pub mod sdk { } } - pub struct Sdk {} + trait FoldIntoPackages: Iterator + Sized { + fn fold_into_packages(self) -> HashMap> { + self.map(|obj| (obj.package_object(), obj)).fold( + HashMap::>::new(), + |mut acc, (pkg, obj)| { + match acc.entry(pkg) { + Entry::Occupied(mut entry) => { + entry.get_mut().push(obj); + } + Entry::Vacant(entry) => { + entry.insert(vec![obj]); + } + } + + acc + }, + ) + } + } + + impl FoldIntoPackages for T where T: Iterator {} + + pub struct Sdk { + pub packages: HashMap, + } impl Sdk { pub fn new() -> Self { - Self {} + let packages = Self::package_objects(); + + let packages = packages + .into_par_iter() + .map(|pkg| pkg.process()) + .map(|pkg| (pkg.package, pkg)) + .collect(); + + Self { packages } } - pub fn package_objects(&self) -> Vec { + pub fn package_objects() -> Vec { let gobjects = GOBJECTS.read().unwrap(); let objects = gobjects.as_objects().unwrap(); @@ -482,22 +516,7 @@ pub mod sdk { // ensure item contains object .filter_map(|item| item.object()) // get package object - .map(|obj| (obj.package_object(), obj)) - .fold( - HashMap::>::new(), - |mut acc, (pkg, obj)| { - match acc.entry(pkg) { - Entry::Occupied(mut entry) => { - entry.get_mut().push(obj); - } - Entry::Vacant(entry) => { - entry.insert(vec![obj]); - } - } - - acc - }, - ); + .fold_into_packages(); sorted_objects .into_iter() @@ -654,6 +673,22 @@ pub mod sdk { Class(UStruct), } + impl Type { + pub fn referenced_type(&self) -> Option { + match self { + Type::Ptr(t) | Type::Ref(t) | Type::Array(t) | Type::RawArray { ty: t, .. } => { + t.referenced_type() + } + Type::WeakPtr(o) | Type::SoftPtr(o) | Type::LazyPtr(o) | Type::AssetPtr(o) => { + Some(o.as_uobject()) + } + Type::Class(o) => Some(o.as_uobject()), + Type::Primitive(_) | Type::Name | Type::String | Type::Text => None, + Type::Enum { enum_type, .. } => Some(enum_type.as_uobject()), + } + } + } + #[derive(Debug)] pub struct ClassField { pub offset: u32, @@ -683,11 +718,41 @@ pub mod sdk { pub is_class: bool, pub size: u32, pub name: String, + pub full_name: String, pub super_class: Option, pub fields: Vec, pub methods: Vec, } + impl Class { + pub fn referenced_types(&self) -> Vec { + let mut types = Vec::new(); + self.super_class.map(|obj| types.push(obj.as_uobject())); + + for field in &self.fields { + types.extend(field.ty.referenced_type()); + } + + for method in &self.methods { + types.extend( + method + .return_type + .as_ref() + .and_then(|ty| ty.referenced_type()), + ); + types.extend( + method + .parameters + .iter() + .map(|param| ¶m.ty) + .filter_map(|ty| ty.referenced_type()), + ); + } + + types + } + } + #[derive(Debug)] pub enum Types { Class(Class), diff --git a/src/v2_types/mod.rs b/src/v2_types/mod.rs index a8d889e..bd2b1c1 100644 --- a/src/v2_types/mod.rs +++ b/src/v2_types/mod.rs @@ -804,6 +804,10 @@ pub mod traits { .unwrap_or(self.as_uobject()) } + fn is_in_package(&self, package: super::UObject) -> bool { + self.package_object() == package + } + fn is_a(&self, other: &super::UClass) -> bool { self.class() .map(|class| class.iter_super_classes().contains(other))