diff --git a/rust-toolchain b/rust-toolchain new file mode 100644 index 0000000..07ade69 --- /dev/null +++ b/rust-toolchain @@ -0,0 +1 @@ +nightly \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index ae1c35c..d939dd8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,9 @@ +#![feature(const_trait_impl, const_ptr_as_ref, const_nonnull_new)] + mod core_types; pub mod global_tables; pub mod types; +pub mod v2_types; pub mod sdk { use std::{ diff --git a/src/v2_types/mod.rs b/src/v2_types/mod.rs new file mode 100644 index 0000000..971388b --- /dev/null +++ b/src/v2_types/mod.rs @@ -0,0 +1,434 @@ +//! This module is an attempt to define Unreal Types using just a pointer +//! because I thought that was proabably a lot safer and ergonomic than having a +//! bunch of nesting structures, and having to worry a lot more about aliasing +//! references. every type is also stored in an UnsafeCell which, if I +//! understand UnsafeCell and unsafe Rust correctly, should tell the compiler +//! that the contents might very well change under its feet (which they might). +#![allow(non_upper_case_globals)] +use bitflags::bitflags; +use std::{cell::UnsafeCell, ptr::NonNull}; + +#[derive(Debug)] +#[repr(transparent)] +pub struct VTbl(NonNull<()>); + +impl VTbl {} + +bitflags! { + #[repr(C)] + pub struct EObjectFlags: u32 { + const RF_NoFlags = 0x00000000; + const RF_Public = 0x00000001; + const RF_Standalone = 0x00000002; + const RF_MarkAsNative = 0x00000004; + const RF_Transactional = 0x00000008; + const RF_ClassDefaultObject = 0x00000010; + const RF_ArchetypeObject = 0x00000020; + const RF_Transient = 0x00000040; + const RF_MarkAsRootSet = 0x00000080; + const RF_TagGarbageTemp = 0x00000100; + const RF_NeedInitialization = 0x00000200; + const RF_NeedLoad = 0x00000400; + const RF_KeepForCooker = 0x00000800; + const RF_NeedPostLoad = 0x00001000; + const RF_NeedPostLoadSubobjects = 0x00002000; + const RF_NewerVersionExists = 0x00004000; + const RF_BeginDestroyed = 0x00008000; + const RF_FinishDestroyed = 0x00010000; + const RF_BeingRegenerated = 0x00020000; + const RF_DefaultSubObject = 0x00040000; + const RF_WasLoaded = 0x00080000; + const RF_TextExportTransient = 0x00100000; + const RF_LoadCompleted = 0x00200000; + const RF_InheritableComponentTemplate = 0x00400000; + const RF_DuplicateTransient = 0x00800000; + const RF_StrongRefOnFrame = 0x01000000; + const RF_NonPIEDuplicateTransient = 0x02000000; + const RF_Dynamic = 0x04000000; + const RF_WillBeLoaded = 0x08000000; + const RF_HasExternalPackage = 0x10000000; + } +} + +macro_rules! define_utypes { + ($($ty:ident),+) => { + $( + #[repr(transparent)] + #[derive(Debug, Clone, Copy)] + pub struct $ty(NonNull>); + + impl_asuobject!($ty); + + impl const traits::UObject for $ty {} + )+ + }; + ($($ty:ident => $name:literal),+) => { + $( + #[repr(transparent)] + #[derive(Debug, Clone, Copy)] + pub struct $ty(NonNull>); + + impl $ty { + pub const fn static_class_name() -> &'static str { + concat!("Class CoreUObject.", $name) + } + } + + impl_asuobject!($ty); + + impl const traits::UObjectTrait for $ty {} + )+ + }; +} + +macro_rules! impl_const_trait_for { + + ($trt:ty: $($ty:ty),+) => { + $( + impl const $trt for $ty {} + )+ + }; +} + +macro_rules! impl_asuobject { + ($($ty:ty),+) => { + $( + impl $ty { + pub const fn from_raw(raw: *mut ()) -> Option { + match NonNull::new(raw) { + Some(ptr) => Some(Self(ptr.cast())), + None => None, + } + } + + pub const fn from_nonnull(raw: NonNull>) -> Self { + Self(raw) + } + } + + impl const traits::AsUObject for $ty { + fn as_uobject(&self) -> self::UObject { + self::UObject(self.0) + } + } + )+ + }; +} + +define_utypes!( + UObject => "Object", + UField => "Field", + UEnum => "Enum", + UStruct => "Struct", + UScriptStruct => "ScriptStruct", + UClass => "Class", + UProperty => "Property", + UFunction => "Function", + UNumericProperty => "NumericProperty", + UByteProperty => "ByteProperty", + UUInt16Property => "UInt16Property", + UUInt32Property => "UInt32Property", + UUInt64Property => "UInt64Property", + UInt8Property => "Int8Property", + UInt16Property => "Int16Property", + UIntProperty => "IntProperty", // i32 + UInt64Property => "Int64Property", + UFloatProperty => "FloatProperty", + UDoubleProperty => "DoubleProperty", + UBoolProperty => "BoolProperty", + UObjectPropertyBase => "ObjectPropertyBase", + UObjectProperty => "ObjectProperty", + UClassProperty => "ClassProperty", + UInterfaceProperty => "InterfaceProperty", + UWeakObjectProperty => "WeakObjectProperty", + ULazyObjectProperty => "LazyObjectProperty", + UAssetObjectProperty => "AssetObjectProperty", + UAssetClassProperty => "AssetClassProperty", + USoftObjectProperty => "SoftObjectProperty", + UNameProperty => "NameProperty", + UStructProperty => "StructProperty", + UStrProperty => "StrProperty", + UTextProperty => "TextProperty", + UArrayProperty => "ArrayProperty", + UMapProperty => "MapProperty", + UDelegateProperty => "DelegateProperty", + UMulticastDelegateProperty => "MulticastDelegateProperty", + UEnumProperty => "EnumProperty" +); +// impl_const_trait_for!( +// traits::UFieldTrait: UField, +// UEnum, +// UStruct, +// UClass, +// UProperty +// ); + +// impl_const_trait_for!(traits::UStructTrait: UStruct, UClass); +// impl_const_trait_for!(traits::UEnumTrait: UEnum); +// impl_const_trait_for!(traits::UPropertyTrait: UProperty); + +impl UObject { + #![allow(dead_code)] + + const fn raw_ptr(&self) -> *const () { + unsafe { self.0.as_ref().get() as _ } + } + + const fn raw_mut(&self) -> *mut () { + unsafe { self.0.as_ref().get() as _ } + } +} + +#[derive(PartialEq, Eq, PartialOrd, Ord, Debug)] +pub enum ECppForm { + Regular, + Namespaced, + EnumClass, +} + +impl UEnum { + pub fn cpp_form(&self) -> Option { + match *traits::UEnumTrait::cpp_form_raw(self) { + 0 => Some(ECppForm::Regular), + 1 => Some(ECppForm::Namespaced), + 2 => Some(ECppForm::EnumClass), + _ => None, + } + } +} + +mod traits { + use std::ptr::NonNull; + + use crate::core_types::{FName, FString, TArray}; + + use super::{EObjectFlags, VTbl}; + + #[const_trait] + pub trait AsUObject { + fn as_uobject(&self) -> super::UObject; + } + + #[const_trait] + pub trait UObjectTrait: ~const AsUObject { + fn vtbl(&self) -> &VTbl { + unsafe { &*self.as_uobject().raw_ptr().offset(0).cast() } + } + fn object_flags(&self) -> &EObjectFlags { + unsafe { &*self.as_uobject().raw_ptr().offset(8).cast() } + } + fn internal_index(&self) -> &u32 { + unsafe { &*self.as_uobject().raw_ptr().offset(12).cast() } + } + fn class(&self) -> &Option { + unsafe { &*self.as_uobject().raw_ptr().offset(16).cast() } + } + fn name(&self) -> &FName { + unsafe { &*self.as_uobject().raw_ptr().offset(24).cast() } + } + fn outer(&self) -> &Option { + unsafe { &*self.as_uobject().raw_ptr().offset(32).cast() } + } + } + + #[const_trait] + pub trait UFieldTrait: ~const AsUObject { + fn next(&self) -> &Option { + unsafe { &*self.as_uobject().raw_ptr().offset(40).cast() } + } + } + + #[const_trait] + pub trait UEnumTrait: ~const AsUObject { + fn cpp_type(&self) -> &FString { + unsafe { &*self.as_uobject().raw_ptr().offset(48).cast() } + } + fn names(&self) -> &TArray { + unsafe { &*self.as_uobject().raw_ptr().offset(64).cast() } + } + fn cpp_form_raw(&self) -> &u32 { + unsafe { &*self.as_uobject().raw_ptr().offset(80).cast() } + } + } + + impl const UFieldTrait for T where T: ~const UEnumTrait {} + + #[const_trait] + pub trait UStructTrait: ~const UFieldTrait { + fn super_field(&self) -> &Option { + unsafe { &*self.as_uobject().raw_ptr().offset(48).cast() } + } + fn children(&self) -> &Option { + unsafe { &*self.as_uobject().raw_ptr().offset(56).cast() } + } + fn property_size(&self) -> &u32 { + unsafe { &*self.as_uobject().raw_ptr().offset(64).cast() } + } + fn min_alignment(&self) -> &u32 { + unsafe { &*self.as_uobject().raw_ptr().offset(68).cast() } + } + } + + #[const_trait] + pub trait UScriptStructTrait: ~const UStructTrait {} + + #[const_trait] + pub trait UClassTrait: ~const UStructTrait {} + + #[const_trait] + pub trait UFunctionTrait: ~const UStructTrait { + fn function_flags(&self) -> &u32 { + unsafe { &*self.as_uobject().raw_ptr().offset(144).cast() } + } + fn rep_offset(&self) -> &u16 { + unsafe { &*self.as_uobject().raw_ptr().offset(148).cast() } + } + fn num_params(&self) -> &u8 { + unsafe { &*self.as_uobject().raw_ptr().offset(150).cast() } + } + fn params_size(&self) -> &u16 { + unsafe { &*self.as_uobject().raw_ptr().offset(152).cast() } + } + fn return_value_offset(&self) -> &u16 { + unsafe { &*self.as_uobject().raw_ptr().offset(154).cast() } + } + fn rpc_id(&self) -> &u16 { + unsafe { &*self.as_uobject().raw_ptr().offset(156).cast() } + } + fn rpc_response_id(&self) -> &u16 { + unsafe { &*self.as_uobject().raw_ptr().offset(158).cast() } + } + fn first_property_to_init(&self) -> &Option { + unsafe { &*self.as_uobject().raw_ptr().offset(160).cast() } + } + fn func(&self) -> &Option> { + unsafe { &*self.as_uobject().raw_ptr().offset(168).cast() } + } + } + + #[const_trait] + pub trait UPropertyTrait: ~const UFieldTrait { + fn array_dim(&self) -> &i32 { + unsafe { &*self.as_uobject().raw_ptr().offset(48).cast() } + } + fn element_size(&self) -> &i32 { + unsafe { &*self.as_uobject().raw_ptr().offset(52).cast() } + } + fn property_flags(&self) -> &u64 { + unsafe { &*self.as_uobject().raw_ptr().offset(56).cast() } + } + fn rep_index(&self) -> &i16 { + unsafe { &*self.as_uobject().raw_ptr().offset(64).cast() } + } + fn rep_notify_function(&self) -> &FName { + unsafe { &*self.as_uobject().raw_ptr().offset(68).cast() } + } + fn offset(&self) -> &i32 { + unsafe { &*self.as_uobject().raw_ptr().offset(76).cast() } + } + fn property_link_next(&self) -> &Option { + unsafe { &*self.as_uobject().raw_ptr().offset(80).cast() } + } + fn next_ref(&self) -> &Option { + unsafe { &*self.as_uobject().raw_ptr().offset(88).cast() } + } + fn destructor_link_next(&self) -> &Option { + unsafe { &*self.as_uobject().raw_ptr().offset(96).cast() } + } + fn post_construct_link_next(&self) -> &Option { + unsafe { &*self.as_uobject().raw_ptr().offset(104).cast() } + } + } + + #[const_trait] + pub trait UBytePropertyTrait: ~const UPropertyTrait { + fn uenum(&self) -> &Option { + unsafe { &*self.as_uobject().raw_ptr().offset(112).cast() } + } + } + + #[const_trait] + pub trait UBoolPropertyTrait: ~const UPropertyTrait { + fn field_size(&self) -> &u8 { + unsafe { &*self.as_uobject().raw_ptr().offset(112).cast() } + } + fn byte_offset(&self) -> &u8 { + unsafe { &*self.as_uobject().raw_ptr().offset(113).cast() } + } + fn byte_mask(&self) -> &u8 { + unsafe { &*self.as_uobject().raw_ptr().offset(114).cast() } + } + fn field_mask(&self) -> &u8 { + unsafe { &*self.as_uobject().raw_ptr().offset(115).cast() } + } + } + + #[const_trait] + pub trait UObjectPropertyBaseTrait: ~const UPropertyTrait { + fn property_class(&self) -> &Option { + unsafe { &*self.as_uobject().raw_ptr().offset(112).cast() } + } + } + + #[const_trait] + pub trait UInterfacePropertyTrait: ~const UPropertyTrait { + fn interface_class(&self) -> &Option { + unsafe { &*self.as_uobject().raw_ptr().offset(112).cast() } + } + } + + #[const_trait] + pub trait UStructPropertyTrait: ~const UPropertyTrait { + fn ustruct(&self) -> &Option { + unsafe { &*self.as_uobject().raw_ptr().offset(112).cast() } + } + } + + #[const_trait] + pub trait UArrayPropertyTrait: ~const UPropertyTrait { + fn inner(&self) -> &Option { + unsafe { &*self.as_uobject().raw_ptr().offset(112).cast() } + } + } + + #[const_trait] + pub trait UMapPropertyTrait: ~const UPropertyTrait { + fn key_prop(&self) -> &Option { + unsafe { &*self.as_uobject().raw_ptr().offset(112).cast() } + } + fn value_prop(&self) -> &Option { + unsafe { &*self.as_uobject().raw_ptr().offset(120).cast() } + } + } + + #[const_trait] + pub trait UClassPropertyTrait: ~const UObjectPropertyBaseTrait { + fn meta_class(&self) -> &Option { + unsafe { &*self.as_uobject().raw_ptr().offset(120).cast() } + } + } + + #[const_trait] + pub trait UAssetClassPropertyTrait: ~const UObjectPropertyBaseTrait { + fn meta_class(&self) -> &Option { + unsafe { &*self.as_uobject().raw_ptr().offset(120).cast() } + } + } + + #[const_trait] + pub trait UDelegatePropertyTrait: ~const UPropertyTrait { + fn signature_function(&self) -> &Option { + unsafe { &*self.as_uobject().raw_ptr().offset(112).cast() } + } + } + + #[const_trait] + pub trait UEnumPropertyTrait: ~const UPropertyTrait { + fn underlying_type(&self) -> &Option { + unsafe { &*self.as_uobject().raw_ptr().offset(112).cast() } + } + fn uenum(&self) -> &Option { + unsafe { &*self.as_uobject().raw_ptr().offset(120).cast() } + } + } +}