calculating dependencies

This commit is contained in:
Janis 2023-04-20 23:43:56 +02:00
parent 211605c20c
commit d1c0520316
2 changed files with 134 additions and 65 deletions

View file

@ -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<UObject>,
dependencies: Vec<UObject>,
}
#[derive(Debug)]
pub struct ProcessedPackage {
pub package: UObject,
pub types: HashMap<UObject, Types>,
pub package_dependencies: Vec<UObject>,
pub package_dependencies: HashMap<UObject, Vec<UObject>>,
}
impl Package {
pub fn new(package: UObject, objects: Vec<UObject>) -> 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)));
}
}
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) {
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)));
}
}
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::<HashMap<_, _>>();
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,24 +468,9 @@ pub mod sdk {
}
}
pub struct Sdk {}
impl Sdk {
pub fn new() -> Self {
Self {}
}
pub fn package_objects(&self) -> Vec<Package> {
let gobjects = GOBJECTS.read().unwrap();
let objects = gobjects.as_objects().unwrap();
let sorted_objects = objects
.iter()
// ensure item contains object
.filter_map(|item| item.object())
// get package object
.map(|obj| (obj.package_object(), obj))
.fold(
trait FoldIntoPackages: Iterator<Item = UObject> + Sized {
fn fold_into_packages(self) -> HashMap<UObject, Vec<UObject>> {
self.map(|obj| (obj.package_object(), obj)).fold(
HashMap::<UObject, Vec<UObject>>::new(),
|mut acc, (pkg, obj)| {
match acc.entry(pkg) {
@ -497,7 +484,39 @@ pub mod sdk {
acc
},
);
)
}
}
impl<T> FoldIntoPackages for T where T: Iterator<Item = UObject> {}
pub struct Sdk {
pub packages: HashMap<UObject, ProcessedPackage>,
}
impl Sdk {
pub fn new() -> 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() -> Vec<Package> {
let gobjects = GOBJECTS.read().unwrap();
let objects = gobjects.as_objects().unwrap();
let sorted_objects = objects
.iter()
// ensure item contains object
.filter_map(|item| item.object())
// get package object
.fold_into_packages();
sorted_objects
.into_iter()
@ -654,6 +673,22 @@ pub mod sdk {
Class(UStruct),
}
impl Type {
pub fn referenced_type(&self) -> Option<UObject> {
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<UStruct>,
pub fields: Vec<ClassField>,
pub methods: Vec<ClassMethod>,
}
impl Class {
pub fn referenced_types(&self) -> Vec<UObject> {
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| &param.ty)
.filter_map(|ty| ty.referenced_type()),
);
}
types
}
}
#[derive(Debug)]
pub enum Types {
Class(Class),

View file

@ -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))