Compare commits
10 commits
74940c5696
...
ce7bef559b
Author | SHA1 | Date | |
---|---|---|---|
|
ce7bef559b | ||
|
95d434841e | ||
|
f57d3491e4 | ||
|
679f97397a | ||
|
953bfa10ef | ||
|
8886be1cb9 | ||
|
36af2ae124 | ||
|
555cbb79a2 | ||
|
47dbb8e3d1 | ||
|
e74ed77703 |
36
.cargo/config.toml
Normal file
36
.cargo/config.toml
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
[build]
|
||||||
|
target = "x86_64-pc-windows-msvc"
|
||||||
|
|
||||||
|
[target.x86_64-pc-windows-msvc]
|
||||||
|
linker = "lld-link"
|
||||||
|
rustflags = [
|
||||||
|
"-C",
|
||||||
|
"link-args=/libpath:/home/user/.xwin/xwin/crt/lib/x86_64",
|
||||||
|
"-C",
|
||||||
|
"link-args=/libpath:/home/user/.xwin/xwin/sdk/lib/um/x86_64",
|
||||||
|
"-C",
|
||||||
|
"link-args=/libpath:/home/user/.xwin/xwin/sdk/lib/ucrt/x86_64"
|
||||||
|
]
|
||||||
|
|
||||||
|
[env]
|
||||||
|
CC_x86_64_pc_windows_msvc="clang-cl"
|
||||||
|
CXX_x86_64_pc_windows_msvc="clang-cl"
|
||||||
|
AR_x86_64_pc_windows_msvc="llvm-lib"
|
||||||
|
LD_x86_64_pc_windows_msvc="lld-link"
|
||||||
|
# wine can be quite spammy with log messages and they're generally uninteresting
|
||||||
|
WINEDEBUG="-all"
|
||||||
|
# Use wine to run test executables
|
||||||
|
CARGO_TARGET_X86_64_PC_WINDOWS_MSVC_RUNNER="wine"
|
||||||
|
# Note that we only disable unused-command-line-argument here since clang-cl
|
||||||
|
# doesn't implement all of the options supported by cl, but the ones it doesn't
|
||||||
|
# are _generally_ not interesting.
|
||||||
|
CL_FLAGS="-Wno-unused-command-line-argument -fuse-ld=lld-link /imsvc/home/user/.xwin/xwin/crt/include /imsvc/home/user/.xwin/xwin/sdk/include/ucrt /imsvc/home/user/.xwin/xwin/sdk/include/um /imsvc/home/user/.xwin/xwin/sdk/include/shared"
|
||||||
|
|
||||||
|
CFLAGS_x86_64_pc_windows_msvc="-Wno-unused-command-line-argument -fuse-ld=lld-link /imsvc/home/user/.xwin/xwin/crt/include /imsvc/home/user/.xwin/xwin/sdk/include/ucrt /imsvc/home/user/.xwin/xwin/sdk/include/um /imsvc/home/user/.xwin/xwin/sdk/include/shared"
|
||||||
|
CXXFLAGS_x86_64_pc_windows_msvc="-Wno-unused-command-line-argument -fuse-ld=lld-link /imsvc/home/user/.xwin/xwin/crt/include /imsvc/home/user/.xwin/xwin/sdk/include/ucrt /imsvc/home/user/.xwin/xwin/sdk/include/um /imsvc/home/user/.xwin/xwin/sdk/include/shared"
|
||||||
|
# Let cargo know what linker to invoke if you haven't already specified it
|
||||||
|
# in a .cargo/config.toml file
|
||||||
|
CARGO_TARGET_X86_64_PC_WINDOWS_MSVC_LINKER="lld-link"
|
||||||
|
CARGO_TARGET_X86_64_PC_WINDOWS_MSVC_RUSTFLAGS="-Lnative=/home/user/.xwin/xwin/crt/lib/x86_64 -Lnative=/home/user/.xwin/xwin/sdk/lib/um/x86_64 -Lnative=/home/user/.xwin/xwin/sdk/lib/ucrt/x86_64"
|
||||||
|
|
||||||
|
LDFLAGS_x86_64_pc_windows_msvc="/libpath:/home/user/.xwin/xwin/crt/lib/x86_64 libpath:/home/user/.xwin/xwin/sdk/lib/um/x86_64 /libpath:/home/user/.xwin/xwin/sdk/lib/ucrt/x86_64"
|
23
Cargo.toml
23
Cargo.toml
|
@ -1,20 +1,3 @@
|
||||||
[package]
|
[workspace]
|
||||||
name = "unreal-sdk"
|
members = ["sdk-serializer", "unreal-sdk", "sdk-generator", "pdb-helper"]
|
||||||
version = "0.1.0"
|
resolver = "2"
|
||||||
edition = "2021"
|
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
log = "0.4.0"
|
|
||||||
thiserror = "1.0.0"
|
|
||||||
itertools = "0.10.0"
|
|
||||||
rayon = "1.0.0"
|
|
||||||
bitflags = "1.0.0"
|
|
||||||
anyhow = "1.0"
|
|
||||||
widestring = "1.0"
|
|
||||||
lazy_static = "1.4.0"
|
|
||||||
once_cell = "1.17.1"
|
|
||||||
|
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
|
||||||
serde_json = "1.0"
|
|
21
pdb-helper/Cargo.toml
Normal file
21
pdb-helper/Cargo.toml
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
[package]
|
||||||
|
name = "pdb-helper"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
log = "0.4.0"
|
||||||
|
anyhow = "1.0"
|
||||||
|
once_cell = "1.17.1"
|
||||||
|
pdb = "0.8.0"
|
||||||
|
|
||||||
|
[dependencies.windows]
|
||||||
|
version = "0.44"
|
||||||
|
features = [
|
||||||
|
"Win32_Foundation",
|
||||||
|
"Win32_System_Threading",
|
||||||
|
"Win32_System_LibraryLoader",
|
||||||
|
"Win32_UI_WindowsAndMessaging",
|
||||||
|
]
|
189
pdb-helper/src/lib.rs
Normal file
189
pdb-helper/src/lib.rs
Normal file
|
@ -0,0 +1,189 @@
|
||||||
|
use std::{ptr::NonNull, sync::Mutex};
|
||||||
|
|
||||||
|
use anyhow::Context;
|
||||||
|
use once_cell::sync::OnceCell;
|
||||||
|
use pdb::{DataSymbol, FallibleIterator, ProcedureReferenceSymbol, ProcedureSymbol, SymbolData};
|
||||||
|
use windows::{core::PCWSTR, Win32::System::LibraryLoader::GetModuleHandleW};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub struct Globals {
|
||||||
|
pub names: NonNull<()>,
|
||||||
|
pub objects: NonNull<()>,
|
||||||
|
pub process_event: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
static PDB: OnceCell<Mutex<PdbCtx>> = OnceCell::new();
|
||||||
|
|
||||||
|
pub fn get_pdb() -> std::sync::MutexGuard<'static, PdbCtx> {
|
||||||
|
PDB.get_or_init(|| Mutex::new(PdbCtx::new().expect("failed to create PDB helper.")))
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct PdbCtx {
|
||||||
|
base: usize,
|
||||||
|
pdb: pdb::PDB<'static, std::fs::File>,
|
||||||
|
}
|
||||||
|
|
||||||
|
// i dont care i need this to be safe and its stored as a dyn so any Send trait is removed
|
||||||
|
unsafe impl Send for PdbCtx {}
|
||||||
|
|
||||||
|
impl PdbCtx {
|
||||||
|
pub fn new() -> anyhow::Result<Self> {
|
||||||
|
let base = unsafe {
|
||||||
|
GetModuleHandleW(PCWSTR::null())
|
||||||
|
.context("could not get process base")?
|
||||||
|
.0 as usize
|
||||||
|
};
|
||||||
|
|
||||||
|
let pdb_path = std::env::current_exe()
|
||||||
|
.context("current exe")?
|
||||||
|
.with_file_name("ShooterGame.pdb");
|
||||||
|
let pdb_file = std::fs::File::open(&pdb_path).context("pdb file open")?;
|
||||||
|
|
||||||
|
let pdb = pdb::PDB::open(pdb_file).context("parse pdb file")?;
|
||||||
|
|
||||||
|
Ok(Self { base, pdb })
|
||||||
|
}
|
||||||
|
|
||||||
|
/// returns the address of the function
|
||||||
|
pub fn find_function(&mut self, function_name: &str) -> anyhow::Result<usize> {
|
||||||
|
let globals = self.pdb.global_symbols().context("global symbols")?;
|
||||||
|
let mut iter = globals.iter();
|
||||||
|
|
||||||
|
while let Some(symbol) = iter.next()? {
|
||||||
|
match symbol.parse() {
|
||||||
|
Ok(pdb::SymbolData::ProcedureReference(data))
|
||||||
|
if data.name.map(|name| name.to_string() == function_name) == Some(true) =>
|
||||||
|
{
|
||||||
|
log::trace!("{data:?}");
|
||||||
|
let dbg_info = self.pdb.debug_information()?;
|
||||||
|
let mods = dbg_info
|
||||||
|
.modules()?
|
||||||
|
.nth(data.module.context("module idx none")?)
|
||||||
|
.context("module not found")?
|
||||||
|
.context("module found but none")?;
|
||||||
|
let a = self
|
||||||
|
.pdb
|
||||||
|
.module_info(&mods)
|
||||||
|
.context("module info not found")?
|
||||||
|
.context("module info found but none")?;
|
||||||
|
let sym = a
|
||||||
|
.symbols_at(data.symbol_index)
|
||||||
|
.context("symbol not found")?
|
||||||
|
.next()
|
||||||
|
.context("symbol failed to read")?
|
||||||
|
.context("symbol read but none")?
|
||||||
|
.parse()
|
||||||
|
.context("symbol failed to parse")?;
|
||||||
|
|
||||||
|
log::debug!("actual symbol: {sym:?}");
|
||||||
|
|
||||||
|
if let SymbolData::Procedure(ProcedureSymbol { offset, .. }) = sym {
|
||||||
|
// asdf
|
||||||
|
let get_names = offset
|
||||||
|
.to_rva(&self.pdb.address_map()?)
|
||||||
|
.context("rva none")?;
|
||||||
|
return Ok(self.base + get_names.0 as usize);
|
||||||
|
} else {
|
||||||
|
return Err(anyhow::anyhow!("no proceduresymbol found"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Err(anyhow::anyhow!("no procedureref found"));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse_names(&mut self, data: ProcedureReferenceSymbol) -> anyhow::Result<usize> {
|
||||||
|
log::trace!("{data:?}");
|
||||||
|
let dbg_info = self.pdb.debug_information()?;
|
||||||
|
let mods = dbg_info
|
||||||
|
.modules()?
|
||||||
|
.nth(data.module.context("module idx none")?)
|
||||||
|
.context("module not found")?
|
||||||
|
.context("module found but none")?;
|
||||||
|
let a = self
|
||||||
|
.pdb
|
||||||
|
.module_info(&mods)
|
||||||
|
.context("module info not found")?
|
||||||
|
.context("module info found but none")?;
|
||||||
|
let sym = a
|
||||||
|
.symbols_at(data.symbol_index)
|
||||||
|
.context("symbol not found")?
|
||||||
|
.next()
|
||||||
|
.context("symbol failed to read")?
|
||||||
|
.context("symbol read but none")?
|
||||||
|
.parse()
|
||||||
|
.context("symbol failed to parse")?;
|
||||||
|
|
||||||
|
log::debug!("actual symbol: {sym:?}");
|
||||||
|
|
||||||
|
if let SymbolData::Procedure(ProcedureSymbol { offset, .. }) = sym {
|
||||||
|
// asdf
|
||||||
|
let get_names = offset
|
||||||
|
.to_rva(&self.pdb.address_map()?)
|
||||||
|
.context("rva none")?;
|
||||||
|
let get_names = unsafe {
|
||||||
|
core::mem::transmute::<_, unsafe extern "win64" fn() -> *mut ()>(
|
||||||
|
self.base + get_names.0 as usize,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
let names = unsafe { get_names() };
|
||||||
|
|
||||||
|
log::debug!("names: {:?}", names);
|
||||||
|
|
||||||
|
Ok(names as usize)
|
||||||
|
} else {
|
||||||
|
Err(anyhow::anyhow!("no proceduresymbol found"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse_objects(&mut self, data: DataSymbol) -> anyhow::Result<usize> {
|
||||||
|
let get_names = data
|
||||||
|
.offset
|
||||||
|
.to_rva(&self.pdb.address_map()?)
|
||||||
|
.context("rva none")?;
|
||||||
|
let objects = self.base + get_names.0 as usize;
|
||||||
|
|
||||||
|
Ok(objects)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn find_ue_globals(&mut self) -> anyhow::Result<Globals> {
|
||||||
|
let globals = self.pdb.global_symbols().context("global symbols")?;
|
||||||
|
let mut iter = globals.iter();
|
||||||
|
|
||||||
|
let mut names = None;
|
||||||
|
let mut objects = None;
|
||||||
|
|
||||||
|
while let Some(symbol) = iter.next()? {
|
||||||
|
match symbol.parse() {
|
||||||
|
Ok(pdb::SymbolData::Data(data)) if data.name.to_string() == "GUObjectArray" => {
|
||||||
|
objects = Some(self.parse_objects(data)?);
|
||||||
|
}
|
||||||
|
Ok(pdb::SymbolData::ProcedureReference(data))
|
||||||
|
if data.name.map(|name| name.to_string() == "FName::GetNames")
|
||||||
|
== Some(true) =>
|
||||||
|
{
|
||||||
|
names = Some(self.parse_names(data)?);
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let process_event = self
|
||||||
|
.find_function("UObject::ProcessEvent")
|
||||||
|
.context("could not find UObject::ProcessEvent!")?;
|
||||||
|
|
||||||
|
let names = names.context("could not find names!")?;
|
||||||
|
let objects = objects.context("could not find objects!")?;
|
||||||
|
|
||||||
|
Ok(Globals {
|
||||||
|
names: NonNull::new(names as _).context("GNames was null!")?,
|
||||||
|
objects: NonNull::new(objects as _).context("GObjects was null!")?,
|
||||||
|
process_event,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
2
sdk-generator/.gitignore
vendored
Normal file
2
sdk-generator/.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
/target
|
||||||
|
/Cargo.lock
|
28
sdk-generator/Cargo.toml
Normal file
28
sdk-generator/Cargo.toml
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
[package]
|
||||||
|
name = "sdk-generator"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
name = "sdk_generator_version"
|
||||||
|
path = "src/lib.rs"
|
||||||
|
crate-type = ["cdylib"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
log = "0.4.0"
|
||||||
|
anyhow = "1.0"
|
||||||
|
pdb-helper = {path = "../pdb-helper"}
|
||||||
|
|
||||||
|
simple_logger = "*"
|
||||||
|
|
||||||
|
unreal-sdk = {path = "../unreal-sdk"}
|
||||||
|
|
||||||
|
[dependencies.windows]
|
||||||
|
version = "0.44"
|
||||||
|
features = [
|
||||||
|
"Win32_Foundation",
|
||||||
|
"Win32_System_Threading",
|
||||||
|
]
|
11
sdk-generator/build.rs
Normal file
11
sdk-generator/build.rs
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
println!("cargo:rerun-if-changed=build.rs");
|
||||||
|
|
||||||
|
let root = PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap());
|
||||||
|
|
||||||
|
let def = root.join("proxy.def");
|
||||||
|
println!("cargo:rustc-link-lib=dylib=d3d11");
|
||||||
|
println!("cargo:rustc-link-arg=/def:{}", def.display());
|
||||||
|
}
|
20
sdk-generator/proxy.def
Normal file
20
sdk-generator/proxy.def
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
LIBRARY VERSION.dll
|
||||||
|
EXPORTS
|
||||||
|
GetFileVersionInfoA=c:\windows\system32\version.dll.GetFileVersionInfoA
|
||||||
|
GetFileVersionInfoByHandle=c:\windows\system32\version.dll.GetFileVersionInfoByHandle
|
||||||
|
GetFileVersionInfoExA=c:\windows\system32\version.dll.GetFileVersionInfoExA
|
||||||
|
GetFileVersionInfoExW=c:\windows\system32\version.dll.GetFileVersionInfoExW
|
||||||
|
GetFileVersionInfoSizeA=c:\windows\system32\version.dll.GetFileVersionInfoSizeA
|
||||||
|
GetFileVersionInfoSizeExA=c:\windows\system32\version.dll.GetFileVersionInfoSizeExA
|
||||||
|
GetFileVersionInfoSizeExW=c:\windows\system32\version.dll.GetFileVersionInfoSizeExW
|
||||||
|
GetFileVersionInfoSizeW=c:\windows\system32\version.dll.GetFileVersionInfoSizeW
|
||||||
|
GetFileVersionInfoW=c:\windows\system32\version.dll.GetFileVersionInfoW
|
||||||
|
VerFindFileA=c:\windows\system32\version.dll.VerFindFileA
|
||||||
|
VerFindFileW=c:\windows\system32\version.dll.VerFindFileW
|
||||||
|
VerInstallFileA=c:\windows\system32\version.dll.VerInstallFileA
|
||||||
|
VerInstallFileW=c:\windows\system32\version.dll.VerInstallFileW
|
||||||
|
VerLanguageNameA=c:\windows\system32\version.dll.VerLanguageNameA
|
||||||
|
VerLanguageNameW=c:\windows\system32\version.dll.VerLanguageNameW
|
||||||
|
VerQueryValueA=c:\windows\system32\version.dll.VerQueryValueA
|
||||||
|
VerQueryValueW=c:\windows\system32\version.dll.VerQueryValueW
|
||||||
|
|
88
sdk-generator/src/lib.rs
Normal file
88
sdk-generator/src/lib.rs
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
use std::{collections::HashSet, time::Duration};
|
||||||
|
|
||||||
|
use pdb_helper as pdb;
|
||||||
|
use simple_logger::SimpleLogger;
|
||||||
|
use unreal_sdk::sdk::output::rust::generate_partial_sdk_to_tmp;
|
||||||
|
use windows::s;
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "win64" fn DllMain(_module: usize, reason: u32, _: usize) -> bool {
|
||||||
|
match reason {
|
||||||
|
1 => {
|
||||||
|
if std::env::current_exe()
|
||||||
|
.expect("current exe")
|
||||||
|
.file_name()
|
||||||
|
.expect("file name")
|
||||||
|
.to_string_lossy()
|
||||||
|
== "ShooterGame.exe"
|
||||||
|
{
|
||||||
|
SimpleLogger::new().init().unwrap();
|
||||||
|
log::info!("hello");
|
||||||
|
std::thread::spawn(move || {
|
||||||
|
let _wnd = loop {
|
||||||
|
let window = unsafe {
|
||||||
|
windows::Win32::UI::WindowsAndMessaging::FindWindowA(
|
||||||
|
None,
|
||||||
|
s!("ARK: Survival Evolved"),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
if window.0 != 0 {
|
||||||
|
log::debug!("found window: {window:?}");
|
||||||
|
break window;
|
||||||
|
}
|
||||||
|
|
||||||
|
log::trace!("window was 0");
|
||||||
|
std::thread::sleep(std::time::Duration::from_millis(150));
|
||||||
|
};
|
||||||
|
|
||||||
|
let globals = pdb::get_pdb().find_ue_globals().expect("globals");
|
||||||
|
unreal_sdk::global_tables::names::GNAMES
|
||||||
|
.write()
|
||||||
|
.unwrap()
|
||||||
|
.set_names(globals.names.cast());
|
||||||
|
unreal_sdk::global_tables::objects::GOBJECTS
|
||||||
|
.write()
|
||||||
|
.unwrap()
|
||||||
|
.set_objects(globals.objects.cast());
|
||||||
|
|
||||||
|
std::thread::sleep(Duration::from_secs(30));
|
||||||
|
let sdk = unreal_sdk::sdk::Sdk::new().patch();
|
||||||
|
_ = generate_partial_sdk_to_tmp(
|
||||||
|
&sdk,
|
||||||
|
HashSet::from_iter([
|
||||||
|
"Package_ShooterGame",
|
||||||
|
"Package_DeathItemCache",
|
||||||
|
"Package_WeapC4",
|
||||||
|
"Package_ExplorerChest_Base",
|
||||||
|
"Package_PointOfInterestBP_MissionStart",
|
||||||
|
"Package_BP_DedicatedStorage",
|
||||||
|
"Package_ElectricGenerator",
|
||||||
|
"Package_ExplorerChest_Base",
|
||||||
|
"Package_FeedingTroughBaseBP",
|
||||||
|
"Package_MilkGlider_Character_BP",
|
||||||
|
"Package_PointOfInterestBP_MissionStart",
|
||||||
|
"Package_SleepingBag",
|
||||||
|
"Package_StorageBox_Huge",
|
||||||
|
"Package_StorageBox_TekGenerator",
|
||||||
|
"Package_StructureAmmoContainer",
|
||||||
|
"Package_StructureTurretBaseBP_Heavy",
|
||||||
|
"Package_StructureTurretBaseBP",
|
||||||
|
"Package_StructureTurretTek",
|
||||||
|
"Package_Structure_DinoLeash",
|
||||||
|
"Package_Structure_TekAlarm",
|
||||||
|
"Package_BP_DedicatedStorage",
|
||||||
|
"Package_Buff_Companion_HLNA",
|
||||||
|
"Package_Buff_TekArmor_Pants",
|
||||||
|
"Package_Buff_TekArmor_Gloves",
|
||||||
|
"Package_Buff_TekArmor_Sword",
|
||||||
|
"Package_Buff_TekArmor_Shirt_Rework",
|
||||||
|
]),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
2
sdk-serializer/.gitignore
vendored
Normal file
2
sdk-serializer/.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
/target
|
||||||
|
/Cargo.lock
|
26
sdk-serializer/Cargo.toml
Normal file
26
sdk-serializer/Cargo.toml
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
[package]
|
||||||
|
name = "sdk-serializer"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
name = "sdk_serializer_version"
|
||||||
|
path = "src/lib.rs"
|
||||||
|
crate-type = ["cdylib"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
log = "0.4.0"
|
||||||
|
anyhow = "1.0"
|
||||||
|
pdb-helper = {path = "../pdb-helper"}
|
||||||
|
simple_logger = "*"
|
||||||
|
|
||||||
|
unreal-sdk = {path = "../unreal-sdk"}
|
||||||
|
|
||||||
|
[dependencies.windows]
|
||||||
|
version = "0.44"
|
||||||
|
features = [
|
||||||
|
"Win32_Foundation",
|
||||||
|
"Win32_System_Threading",
|
||||||
|
]
|
11
sdk-serializer/build.rs
Normal file
11
sdk-serializer/build.rs
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
println!("cargo:rerun-if-changed=build.rs");
|
||||||
|
|
||||||
|
let root = PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap());
|
||||||
|
|
||||||
|
let def = root.join("proxy.def");
|
||||||
|
println!("cargo:rustc-link-lib=dylib=d3d11");
|
||||||
|
println!("cargo:rustc-link-arg=/def:{}", def.display());
|
||||||
|
}
|
20
sdk-serializer/proxy.def
Normal file
20
sdk-serializer/proxy.def
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
LIBRARY VERSION.dll
|
||||||
|
EXPORTS
|
||||||
|
GetFileVersionInfoA=c:\windows\system32\version.dll.GetFileVersionInfoA
|
||||||
|
GetFileVersionInfoByHandle=c:\windows\system32\version.dll.GetFileVersionInfoByHandle
|
||||||
|
GetFileVersionInfoExA=c:\windows\system32\version.dll.GetFileVersionInfoExA
|
||||||
|
GetFileVersionInfoExW=c:\windows\system32\version.dll.GetFileVersionInfoExW
|
||||||
|
GetFileVersionInfoSizeA=c:\windows\system32\version.dll.GetFileVersionInfoSizeA
|
||||||
|
GetFileVersionInfoSizeExA=c:\windows\system32\version.dll.GetFileVersionInfoSizeExA
|
||||||
|
GetFileVersionInfoSizeExW=c:\windows\system32\version.dll.GetFileVersionInfoSizeExW
|
||||||
|
GetFileVersionInfoSizeW=c:\windows\system32\version.dll.GetFileVersionInfoSizeW
|
||||||
|
GetFileVersionInfoW=c:\windows\system32\version.dll.GetFileVersionInfoW
|
||||||
|
VerFindFileA=c:\windows\system32\version.dll.VerFindFileA
|
||||||
|
VerFindFileW=c:\windows\system32\version.dll.VerFindFileW
|
||||||
|
VerInstallFileA=c:\windows\system32\version.dll.VerInstallFileA
|
||||||
|
VerInstallFileW=c:\windows\system32\version.dll.VerInstallFileW
|
||||||
|
VerLanguageNameA=c:\windows\system32\version.dll.VerLanguageNameA
|
||||||
|
VerLanguageNameW=c:\windows\system32\version.dll.VerLanguageNameW
|
||||||
|
VerQueryValueA=c:\windows\system32\version.dll.VerQueryValueA
|
||||||
|
VerQueryValueW=c:\windows\system32\version.dll.VerQueryValueW
|
||||||
|
|
59
sdk-serializer/src/lib.rs
Normal file
59
sdk-serializer/src/lib.rs
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
use pdb_helper as pdb;
|
||||||
|
use simple_logger::SimpleLogger;
|
||||||
|
use std::time::Duration;
|
||||||
|
use windows::s;
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "win64" fn DllMain(_module: usize, reason: u32, _: usize) -> bool {
|
||||||
|
match reason {
|
||||||
|
1 => {
|
||||||
|
if std::env::current_exe()
|
||||||
|
.expect("current exe")
|
||||||
|
.file_name()
|
||||||
|
.expect("file name")
|
||||||
|
.to_string_lossy()
|
||||||
|
== "ShooterGame.exe"
|
||||||
|
{
|
||||||
|
SimpleLogger::new().init().unwrap();
|
||||||
|
log::info!("hello");
|
||||||
|
std::thread::spawn(move || {
|
||||||
|
let _wnd = loop {
|
||||||
|
let window = unsafe {
|
||||||
|
windows::Win32::UI::WindowsAndMessaging::FindWindowA(
|
||||||
|
None,
|
||||||
|
s!("ARK: Survival Evolved"),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
if window.0 != 0 {
|
||||||
|
log::debug!("found window: {window:?}");
|
||||||
|
break window;
|
||||||
|
}
|
||||||
|
|
||||||
|
log::trace!("window was 0");
|
||||||
|
std::thread::sleep(std::time::Duration::from_millis(150));
|
||||||
|
};
|
||||||
|
|
||||||
|
let globals = pdb::get_pdb().find_ue_globals().expect("globals");
|
||||||
|
unreal_sdk::global_tables::names::GNAMES
|
||||||
|
.write()
|
||||||
|
.unwrap()
|
||||||
|
.set_names(globals.names.cast());
|
||||||
|
unreal_sdk::global_tables::objects::GOBJECTS
|
||||||
|
.write()
|
||||||
|
.unwrap()
|
||||||
|
.set_objects(globals.objects.cast());
|
||||||
|
|
||||||
|
std::thread::sleep(Duration::from_secs(30));
|
||||||
|
|
||||||
|
let sdk = unreal_sdk::sdk::repr::Sdk::build().expect("sdk");
|
||||||
|
|
||||||
|
sdk.save_to_path("z:/tmp/sdk.ron").expect("writing sdk");
|
||||||
|
log::info!("done.");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
2
unreal-sdk/.gitignore
vendored
Normal file
2
unreal-sdk/.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
/target
|
||||||
|
/Cargo.lock
|
24
unreal-sdk/Cargo.toml
Normal file
24
unreal-sdk/Cargo.toml
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
[package]
|
||||||
|
name = "unreal-sdk"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
log = "0.4.0"
|
||||||
|
thiserror = "1.0.0"
|
||||||
|
itertools = "0.10.0"
|
||||||
|
rayon = "1.0.0"
|
||||||
|
bitflags = "1.0.0"
|
||||||
|
anyhow = "1.0"
|
||||||
|
widestring = "1.0"
|
||||||
|
lazy_static = "1.4.0"
|
||||||
|
once_cell = "1.17.1"
|
||||||
|
|
||||||
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
|
|
||||||
|
serde_json = "1.0"
|
||||||
|
serde_json_any_key = "2.0.0"
|
||||||
|
|
||||||
|
ron = "0.8.0"
|
1
unreal-sdk/rust-toolchain
Normal file
1
unreal-sdk/rust-toolchain
Normal file
|
@ -0,0 +1 @@
|
||||||
|
nightly
|
|
@ -1,9 +1,12 @@
|
||||||
use std::collections::{btree_map::Entry, BTreeMap};
|
use std::collections::{btree_map::Entry, BTreeMap};
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use rayon::prelude::{IntoParallelRefIterator, ParallelIterator};
|
use rayon::prelude::{IntoParallelIterator, IntoParallelRefIterator, ParallelIterator};
|
||||||
|
use ron::ser::PrettyConfig;
|
||||||
|
|
||||||
|
use crate::global_tables::objects::GOBJECTS;
|
||||||
use crate::sdk::repr::*;
|
use crate::sdk::repr::*;
|
||||||
use crate::v2_types::{
|
use crate::v2_types::{
|
||||||
any_type::{self, AnyField, AnyObject, AnyProperty, AnyStruct},
|
any_type::{self, AnyField, AnyObject, AnyProperty, AnyStruct},
|
||||||
|
@ -11,12 +14,79 @@ use crate::v2_types::{
|
||||||
AsUObject, UArrayPropertyTrait, UBoolPropertyTrait, UEnumPropertyTrait, UEnumTrait,
|
AsUObject, UArrayPropertyTrait, UBoolPropertyTrait, UEnumPropertyTrait, UEnumTrait,
|
||||||
UObjectNonConst, UObjectTrait, UPropertyTrait, UStructPropertyTrait, *,
|
UObjectNonConst, UObjectTrait, UPropertyTrait, UStructPropertyTrait, *,
|
||||||
},
|
},
|
||||||
UClass, UEnum, UFunction, UProperty, UScriptStruct,
|
UClass, UEnum, UFunction, UProperty,
|
||||||
};
|
};
|
||||||
|
use crate::v2_types::{UScriptStruct, UStruct};
|
||||||
|
|
||||||
use super::repr::{
|
use super::repr::{
|
||||||
Class, ClassField, ClassMethod, Enum, Package, ProcessedPackage, Type, UnrealType,
|
Class, ClassField, ClassMethod, Enum, Package, ProcessedPackage, Type, UnrealType,
|
||||||
};
|
};
|
||||||
|
use super::FoldIntoPackages;
|
||||||
|
|
||||||
|
impl Sdk {
|
||||||
|
pub fn build() -> anyhow::Result<Self> {
|
||||||
|
let packages = Self::get_packages()?;
|
||||||
|
|
||||||
|
let packages = packages
|
||||||
|
.into_par_iter()
|
||||||
|
.map(|pkg| {
|
||||||
|
let package_ref = pkg
|
||||||
|
.package_object
|
||||||
|
.as_package_ref()
|
||||||
|
.context("object was not a package object.");
|
||||||
|
|
||||||
|
let output =
|
||||||
|
package_ref.and_then(|package_ref| pkg.process().map(|pkg| (package_ref, pkg)));
|
||||||
|
|
||||||
|
output
|
||||||
|
})
|
||||||
|
// remove empty packages
|
||||||
|
.filter(|pkg| {
|
||||||
|
pkg.as_ref()
|
||||||
|
.map(|(_, pkg)| !pkg.types.is_empty())
|
||||||
|
.unwrap_or(true)
|
||||||
|
})
|
||||||
|
.collect::<anyhow::Result<BTreeMap<_, _>>>()?;
|
||||||
|
|
||||||
|
Ok(Self { packages })
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_json(&self) -> Result<String, serde_json::Error> {
|
||||||
|
serde_json::to_string(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_ron(&self) -> Result<String, ron::Error> {
|
||||||
|
ron::ser::to_string_pretty(self, PrettyConfig::new().compact_arrays(true))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn save_to_path<P: AsRef<Path>>(&self, path: P) -> Result<(), anyhow::Error> {
|
||||||
|
self.to_ron()
|
||||||
|
.context("failed to serialize")
|
||||||
|
.and_then(|text| std::fs::write(path, text).context("failed to write to file."))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_packages() -> anyhow::Result<Vec<Package>> {
|
||||||
|
let objects = GOBJECTS
|
||||||
|
.read()
|
||||||
|
.map_err(|_| anyhow::anyhow!("couldn't read gobject table"))?;
|
||||||
|
let objects = objects.as_objects().context("no object array")?;
|
||||||
|
|
||||||
|
let sorted_objects = objects
|
||||||
|
.iter()
|
||||||
|
.filter_map(|item| item.object())
|
||||||
|
.fold_into_packages();
|
||||||
|
|
||||||
|
let packages = sorted_objects
|
||||||
|
.into_iter()
|
||||||
|
.map(|(package_object, children)| Package {
|
||||||
|
package_object,
|
||||||
|
children,
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
Ok(packages)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn default_or_anon(name: &str) -> bool {
|
fn default_or_anon(name: &str) -> bool {
|
||||||
name.contains("Default__")
|
name.contains("Default__")
|
||||||
|
@ -61,6 +131,7 @@ impl Enum {
|
||||||
});
|
});
|
||||||
|
|
||||||
Ok(UnrealType::Enum(Enum {
|
Ok(UnrealType::Enum(Enum {
|
||||||
|
obj_ref: value.as_uobject().object_ref(),
|
||||||
name: value.get_name().context("could not get name")?,
|
name: value.get_name().context("could not get name")?,
|
||||||
full_name: value.get_full_name().context("could not get full name")?,
|
full_name: value.get_full_name().context("could not get full name")?,
|
||||||
values,
|
values,
|
||||||
|
@ -69,11 +140,112 @@ impl Enum {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Class {
|
impl Class {
|
||||||
pub fn from_uclass(value: UClass) -> anyhow::Result<UnrealType> {
|
pub fn from_uclass(class: UClass) -> anyhow::Result<UnrealType> {
|
||||||
todo!()
|
Ok(UnrealType::Class(Self {
|
||||||
|
kind: StructKind::Object,
|
||||||
|
..Self::from_struct_inner(unsafe { class.cast() })?
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
pub fn from_uscriptstruct(value: UScriptStruct) -> anyhow::Result<UnrealType> {
|
|
||||||
todo!()
|
pub fn from_actor(class: UClass) -> anyhow::Result<UnrealType> {
|
||||||
|
Ok(UnrealType::Actor(Self {
|
||||||
|
kind: StructKind::Actor,
|
||||||
|
..Self::from_struct_inner(unsafe { class.cast() })?
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_struct(strct: UScriptStruct) -> anyhow::Result<UnrealType> {
|
||||||
|
Ok(UnrealType::Struct(Self {
|
||||||
|
kind: StructKind::Struct,
|
||||||
|
..Self::from_struct_inner(unsafe { strct.cast() })?
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_struct_inner(strct: UStruct) -> anyhow::Result<Self> {
|
||||||
|
let name = strct.get_name().context("could not get function name")?;
|
||||||
|
let full_name = strct
|
||||||
|
.get_full_name()
|
||||||
|
.context("could not get full function name")?;
|
||||||
|
|
||||||
|
let super_class = strct.super_field().and_then(|supr| {
|
||||||
|
if supr != strct {
|
||||||
|
Some(supr.as_uobject().object_ref())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let (fields, methods) = Self::process_children(&strct);
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
obj_ref: strct.as_uobject().object_ref(),
|
||||||
|
kind: StructKind::Struct,
|
||||||
|
size: *strct.property_size() as u32,
|
||||||
|
name,
|
||||||
|
full_name,
|
||||||
|
super_class,
|
||||||
|
properties_size: *strct.property_size() as u32,
|
||||||
|
min_alignment: *strct.min_alignment() as u32,
|
||||||
|
fields,
|
||||||
|
methods,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// returns tuple of (fields, methods)
|
||||||
|
fn process_children(strct: &UStruct) -> (Vec<ClassField>, Vec<ClassMethod>) {
|
||||||
|
enum ClassChild {
|
||||||
|
Field(ClassField),
|
||||||
|
Method(ClassMethod),
|
||||||
|
}
|
||||||
|
|
||||||
|
let (fields, methods) = strct
|
||||||
|
.iter_children()
|
||||||
|
.map(|field| -> anyhow::Result<Option<ClassChild>> {
|
||||||
|
let child = match any_type::AnyField::from_field(field) {
|
||||||
|
AnyField::Property(prop) => Some(ClassChild::Field(ClassField::from_uprop(prop)?)),
|
||||||
|
AnyField::Struct(strct)
|
||||||
|
if let AnyStruct::Function(func) = AnyStruct::from_struct(strct) => {
|
||||||
|
{
|
||||||
|
Some(ClassChild::Method(ClassMethod::from_ufunction(func)?))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(child)
|
||||||
|
})
|
||||||
|
.filter_map(|prop| match prop {
|
||||||
|
Ok(field) => field,
|
||||||
|
Err(err) => {
|
||||||
|
log::warn!("skipping field because: {err}");
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.fold(
|
||||||
|
(Vec::new(), Vec::new()),
|
||||||
|
|(mut fields, mut methods), child| {
|
||||||
|
match child {
|
||||||
|
ClassChild::Field(field) => fields.push(field),
|
||||||
|
ClassChild::Method(method) => methods.push(method),
|
||||||
|
}
|
||||||
|
(fields, methods)
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
(fields, methods)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_dependent_types(&self) -> Vec<ObjectRef> {
|
||||||
|
self.fields
|
||||||
|
.iter()
|
||||||
|
.filter_map(|field| field.ty.dependent_type())
|
||||||
|
.chain(
|
||||||
|
self.methods
|
||||||
|
.iter()
|
||||||
|
.flat_map(|method| method.get_dependent_types()),
|
||||||
|
)
|
||||||
|
.chain(self.super_class)
|
||||||
|
.collect::<Vec<_>>()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,6 +262,10 @@ impl ClassField {
|
||||||
ty: resolve_type(prop).context("failed to get field type")?,
|
ty: resolve_type(prop).context("failed to get field type")?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_dependent_types(&self) -> Vec<ObjectRef> {
|
||||||
|
self.ty.dependent_type().into_iter().collect()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ClassMethod {
|
impl ClassMethod {
|
||||||
|
@ -115,29 +291,69 @@ impl ClassMethod {
|
||||||
parameters: params,
|
parameters: params,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_dependent_types(&self) -> Vec<ObjectRef> {
|
||||||
|
self.parameters
|
||||||
|
.iter()
|
||||||
|
.filter_map(|field| field.ty.dependent_type())
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Package {
|
impl Package {
|
||||||
pub fn process(self) -> anyhow::Result<ProcessedPackage> {
|
pub fn process(self) -> anyhow::Result<ProcessedPackage> {
|
||||||
self.children
|
let types = self
|
||||||
|
.children
|
||||||
.par_iter()
|
.par_iter()
|
||||||
.filter_map(|&object| -> Option<UnrealType> {
|
.filter_map(|&object| -> Option<UnrealType> {
|
||||||
match AnyObject::from_object(object) {
|
let ty = match AnyObject::from_object(object) {
|
||||||
AnyObject::Field(field) => match AnyField::from_field(field) {
|
AnyObject::Field(field) => match AnyField::from_field(field) {
|
||||||
AnyField::Enum(my_enum) => {}
|
AnyField::Enum(my_enum) => Enum::from_uenum(my_enum),
|
||||||
AnyField::Struct(my_struct) => match AnyStruct::from_struct(my_struct) {
|
AnyField::Struct(my_struct) => match AnyStruct::from_struct(my_struct) {
|
||||||
my_struct @ AnyStruct::Class(_)
|
AnyStruct::Class(class) => Class::from_uclass(class),
|
||||||
| my_struct @ AnyStruct::ScriptStruct(_) => {}
|
AnyStruct::ScriptStruct(strct) => Class::from_struct(strct),
|
||||||
_ => {}
|
AnyStruct::Actor(actor) => Class::from_actor(actor),
|
||||||
},
|
_ => {
|
||||||
_ => {}
|
return None;
|
||||||
},
|
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
todo!()
|
match ty {
|
||||||
});
|
Ok(ty) => {
|
||||||
todo!()
|
return Some(ty);
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
log::error!("failed to serialize object {object:?}: {err}");
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.map(|ty| (ty.obj_ref(), ty))
|
||||||
|
.collect::<BTreeMap<_, _>>();
|
||||||
|
|
||||||
|
let dependencies = types
|
||||||
|
.iter()
|
||||||
|
.flat_map(|(_, ty)| ty.get_dependent_types().into_iter().map(|obj| obj.package))
|
||||||
|
.sorted()
|
||||||
|
.dedup()
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
Ok(ProcessedPackage {
|
||||||
|
package_object: self
|
||||||
|
.package_object
|
||||||
|
.as_package_ref()
|
||||||
|
.context("not actually a package object")?,
|
||||||
|
types,
|
||||||
|
dependencies,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,7 @@ pub struct ObjectRef {
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
pub struct Sdk {
|
pub struct Sdk {
|
||||||
packages: BTreeMap<PackageRef, ProcessedPackage>,
|
pub packages: BTreeMap<PackageRef, ProcessedPackage>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A package represents some group of packages that are related to another,
|
/// A package represents some group of packages that are related to another,
|
||||||
|
@ -58,7 +58,7 @@ pub struct ProcessedPackage {
|
||||||
/// all types extracted from this package referenced by their `ObjectRef`.
|
/// all types extracted from this package referenced by their `ObjectRef`.
|
||||||
pub types: BTreeMap<ObjectRef, UnrealType>,
|
pub types: BTreeMap<ObjectRef, UnrealType>,
|
||||||
/// All other packages that types in this package depend on directly.
|
/// All other packages that types in this package depend on directly.
|
||||||
pub dependencies: Vec<ObjectRef>,
|
pub dependencies: Vec<PackageRef>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
@ -69,6 +69,26 @@ pub enum UnrealType {
|
||||||
Enum(Enum),
|
Enum(Enum),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl UnrealType {
|
||||||
|
pub fn obj_ref(&self) -> ObjectRef {
|
||||||
|
match self {
|
||||||
|
UnrealType::Class(obj) => obj.obj_ref,
|
||||||
|
UnrealType::Struct(obj) => obj.obj_ref,
|
||||||
|
UnrealType::Actor(obj) => obj.obj_ref,
|
||||||
|
UnrealType::Enum(obj) => obj.obj_ref,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_dependent_types(&self) -> Vec<ObjectRef> {
|
||||||
|
match self {
|
||||||
|
UnrealType::Class(obj) | UnrealType::Struct(obj) | UnrealType::Actor(obj) => {
|
||||||
|
obj.get_dependent_types()
|
||||||
|
}
|
||||||
|
UnrealType::Enum(_) => vec![],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
pub enum StructKind {
|
pub enum StructKind {
|
||||||
Object,
|
Object,
|
||||||
|
@ -78,6 +98,7 @@ pub enum StructKind {
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
pub struct Enum {
|
pub struct Enum {
|
||||||
|
pub obj_ref: ObjectRef,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub full_name: String,
|
pub full_name: String,
|
||||||
pub values: BTreeMap<u32, String>,
|
pub values: BTreeMap<u32, String>,
|
||||||
|
@ -85,6 +106,7 @@ pub struct Enum {
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
pub struct Class {
|
pub struct Class {
|
||||||
|
pub obj_ref: ObjectRef,
|
||||||
pub kind: StructKind,
|
pub kind: StructKind,
|
||||||
pub size: u32,
|
pub size: u32,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
|
@ -94,9 +116,6 @@ pub struct Class {
|
||||||
pub min_alignment: u32,
|
pub min_alignment: u32,
|
||||||
pub fields: Vec<ClassField>,
|
pub fields: Vec<ClassField>,
|
||||||
pub methods: Vec<ClassMethod>,
|
pub methods: Vec<ClassMethod>,
|
||||||
/// types this class depends on; includes super types, types of fields and
|
|
||||||
/// types of function parameters.
|
|
||||||
pub dependencies: Vec<ObjectRef>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
@ -209,3 +228,19 @@ pub enum Type {
|
||||||
Class(ObjectRef),
|
Class(ObjectRef),
|
||||||
Struct(ObjectRef),
|
Struct(ObjectRef),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Type {
|
||||||
|
pub fn dependent_type(&self) -> Option<ObjectRef> {
|
||||||
|
match self {
|
||||||
|
Type::Ptr(ty) | Type::Ref(ty) | Type::Array(ty) | Type::RawArray { ty, .. } => {
|
||||||
|
ty.dependent_type()
|
||||||
|
}
|
||||||
|
Type::WeakPtr(ty) | Type::SoftPtr(ty) | Type::LazyPtr(ty) | Type::AssetPtr(ty) => {
|
||||||
|
Some(*ty)
|
||||||
|
}
|
||||||
|
Type::Enum { underlying, .. } => underlying.dependent_type(),
|
||||||
|
Type::Class(ty) | Type::Struct(ty) => Some(*ty),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue