diff --git a/README.md b/README.md index f8c7412..e40484c 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ | Object Logging |✅|✅|✅|✅|✅|✅|✅|✅|✅ | Object Editing |✅|❔|❔|✅|❔|✅|❔|❔|❔ | `FMemory` Functions |✅|✅|✅|✅|✅|✅|✅|✅|✅ -| Dumper |✅|✅|✅|✅|️️️️️️✅|✅|✅|✅️|️️️️✅️ +| Dumper |✅|✅|✅|✅|✅|✅|✅|✅|️️️️️️✅ | Property Editing (Object XML) |✅|❔|❔|✅|❔|✅|❔|❔|❔ | Add List Entry (Object XML) |✅|❔|❔|❔|❔|❔|❔|❔|❔ | Add Map Entry (Object XML) |✅|❔|❔|❔|❔|❔|❔|❔|❔ @@ -33,6 +33,7 @@ | Custom Constructor |✅|✅|✅|✅|✅|✅|✅|✅|✅ | Add Properties |✅|✅|✅|✅|✅|✅|✅|✅|✅ | Register Struct |✅|✅|✅|✅|✅|✅|✅|✅|✅ +| Call Blueprint Methods |✅|✅|✅|✅|✅|✅|✅|✅|✅ Features marked with ❔ are currently untested. @@ -167,10 +168,10 @@ First, we add an `Item` element with an `id` attribute. The ID is which item in Inside the `Item` element, we're back to what's already been covered. In this example, items have an `EquipID` property and we're setting the `EquipID` of the __2nd__ item to `100`. #### Editing Items in a DataTable -Finally, _DataTables_! There's only two notable differences: the `row-struct` attribute and `id`s are now row names. This example is from _Clair Obscur_'s `DT_jRPG_CharacterDefinitions.uasset`. +Finally, _DataTables_! There's only one notable difference: the `id`s are now row names. This example is from _Clair Obscur_'s `DT_jRPG_CharacterDefinitions.uasset`. ```xml - + @@ -185,10 +186,10 @@ Finally, _DataTables_! There's only two notable differences: the `row-struct` a A DataTable's __Class__ is... `DataTable`! Who could've guessed? As such, the __Root Element__ in our XML has to be `DataTable`. -But, we also need to specify the __Class (Struct)__ for the __Items (Rows)__ in the DataTable so we can edit them. You do that by adding a `row-struct` attribute with the DataTable's __RowStruct__ name, `S_jRPG_CharacterDefinition` in this example. - For our `Item` element's ID, instead of a number we use the __Row's name__ that we want to edit. Inside the `Item` element, it's no different than lists from earlier. +You can optionally override the data type for a DataTable by specifying a struct name for the `row-struct` attribute on the root element. This used to be required in previous versions of UE Toolkit, but the data type is automatically retrived now. + That covers everything, congrats on finishing this 🎉🎉🎉! #### Misc. Stuff (Enums, Type Hints) @@ -205,6 +206,8 @@ Some Unreal types may not be generated and need to be supplied. `UE.Toolkit.Core that were missing in my testing. Add it to your project using **NuGet** and add `UE.Toolkit.Core.Types.Unreal;` in the `File Usings` config before dumping. +The dumper supports two different schemas: a `Structs Only` schema that only generates the types as unmanaged structs and `Structs and Classes`, which generates C# classes for types that inherit from UObject. Classes will also generate methods that are exposed to blueprints. + ## Code Only Features ### Using Unreal's Memory Allocator `FMemory` diff --git a/UE.Toolkit.Core/Types/Interfaces/IFunctionParam.cs b/UE.Toolkit.Core/Types/Interfaces/IFunctionParam.cs new file mode 100644 index 0000000..11c96c4 --- /dev/null +++ b/UE.Toolkit.Core/Types/Interfaces/IFunctionParam.cs @@ -0,0 +1,126 @@ +using UE.Toolkit.Core.Types.Unreal.Common.FunctionParam; +using UE.Toolkit.Core.Types.Unreal.Factories; +using UE.Toolkit.Core.Types.Unreal.Factories.Interfaces; +using UE.Toolkit.Core.Types.Unreal.UE5_4_4; +using UE.Toolkit.Core.Types.Unreal.UE5_6_1; + +namespace UE.Toolkit.Core.Types.Interfaces; + +public interface IFunctionParam +{ + string PropertyType { get; } + void Write(nint Destination); + void Read(nint Destination); +} + +public abstract class FunctionParamCopyable(Ptr rvalue, string propertyType, IUnrealMemoryInternal? memory = null) + : IFunctionParam, IDisposable where T : unmanaged +{ + public unsafe T Value => *RValue.Value; + + protected Ptr RValue => rvalue; + + protected IUnrealMemoryInternal? Memory => memory; + + public string PropertyType => propertyType; + + private static unsafe void Copy(T* source, T* destination) => *destination = *source; + + public unsafe void Write(nint Destination) => Copy(RValue.Value, (T*)Destination); + + public unsafe void Read(nint Destination) => Copy((T*)Destination, RValue.Value); + + protected bool IsDisposed; + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (!IsDisposed) + { + if (disposing) { } + unsafe { Memory?.Free((nint)RValue.Value); } + IsDisposed = true; + } + } + + ~FunctionParamCopyable() => Dispose(false); +} + +public enum ProcessEventResult +{ + Success, + CouldNotFindFunction, + ParameterTypeMismatch, +} + +public static class FunctionParamFactory +{ + + private static Dictionary PropertyNameToParamName = []; + + private static IFunctionParam CreateStructParam(IFStructProperty property, IUnrealMemoryInternal? Memory) + => new StructParam(Memory?.Malloc(property.ElementSize) ?? nint.Zero, property.ElementSize, Memory); + + private static unsafe IFunctionParam CreateBoolParam(IFBoolProperty property, IUnrealMemoryInternal? Memory) + => new BoolParam(new((bool*)(Memory?.Malloc(sizeof(bool)) ?? nint.Zero)), property.FieldMask, Memory); + + public static unsafe IFunctionParam CreateParam(IFProperty property, IUnrealFactory factory, + ITypeReflectionInternal reflection, IUnrealMemoryInternal? Memory) + { + return property.ClassPrivate.Name switch + { + "BoolProperty" => CreateBoolParam(factory.CreateFBoolProperty(property.Ptr), Memory), + "Int8Property" => new Int8Param(new((byte*)(Memory?.Malloc(sizeof(byte)) ?? nint.Zero)), Memory), + "ByteProperty" => new ByteParam(new((byte*)(Memory?.Malloc(sizeof(byte)) ?? nint.Zero)), Memory), + "Int16Property" => new Int16Param(new((short*)(Memory?.Malloc(sizeof(short)) ?? nint.Zero)), Memory), + "Int32Property" => new Int32Param(new((int*)(Memory?.Malloc(sizeof(int)) ?? nint.Zero)), Memory), + "IntProperty" => new IntParam(new((int*)(Memory?.Malloc(sizeof(int)) ?? nint.Zero)), Memory), + "Int64Property" => new Int64Param(new((long*)(Memory?.Malloc(sizeof(long)) ?? nint.Zero)), Memory), + "UInt16Property" => new UInt16Param(new((ushort*)(Memory?.Malloc(sizeof(ushort)) ?? nint.Zero)), Memory), + "UInt32Property" => new UInt32Param(new((uint*)(Memory?.Malloc(sizeof(uint)) ?? nint.Zero)), Memory), + "UInt64Property" => new UInt64Param(new((ulong*)(Memory?.Malloc(sizeof(ulong)) ?? nint.Zero)), Memory), + "FloatProperty" => new FloatParam(new((float*)(Memory?.Malloc(sizeof(float)) ?? nint.Zero)), Memory), + "DoubleProperty" => new DoubleParam(new((double*)(Memory?.Malloc(sizeof(double)) ?? nint.Zero)), Memory), + "NameProperty" => new NameParam(new((FName*)(Memory?.Malloc(sizeof(FName)) ?? nint.Zero)), Memory), + "StrProperty" => new StringParam(new((FString*)(Memory?.Malloc(sizeof(FString)) ?? nint.Zero)), Memory), + "StructProperty" => CreateStructParam(factory.CreateFStructProperty(property.Ptr), Memory), + "TextProperty" => new TextParam(Memory?.Malloc(reflection.GetFTextSize()) ?? nint.Zero, reflection.GetFTextSize(), Memory), + "ObjectProperty" or "ClassProperty" or "ClassPtrProperty" + => new ObjectParam(new((nint*)(Memory?.Malloc(sizeof(nint)) ?? nint.Zero)), Memory), + "ArrayProperty" => new ArrayParam(new((TArray*)(Memory?.Malloc(sizeof(TArray)) ?? nint.Zero)), Memory), + "EnumProperty" => new EnumParam(new(Memory?.Malloc(property.ElementSize) ?? nint.Zero), property.ElementSize, Memory), + "MapProperty" => new MapParam(new((TMap*)(Memory?.Malloc(sizeof(TMap)) ?? nint.Zero)), Memory), + "SetProperty" => new SetParam(new((TSet*)(Memory?.Malloc(sizeof(TSet)) ?? nint.Zero)), Memory), + "InterfaceProperty" => new InterfaceParam(new((TScriptInterface*)(Memory?.Malloc(sizeof(TScriptInterface)) ?? nint.Zero)), Memory), + "SoftClassProperty" => new SoftClassParam(new((TSoftClassPtr*)(Memory?.Malloc(sizeof(TSoftClassPtr)) ?? nint.Zero)), Memory), + "SoftObjectProperty" => new SoftObjectParam(new((TSoftObjectPtr*)(Memory?.Malloc(sizeof(TSoftObjectPtr)) ?? nint.Zero)), Memory), + "Utf8StrProperty" => new Utf8StringParam(new((FUtf8String*)(Memory?.Malloc(sizeof(FUtf8String)) ?? nint.Zero)), Memory), + "AnsiStrProperty" => new AnsiStringParam(new((FAnsiString*)(Memory?.Malloc(sizeof(FAnsiString)) ?? nint.Zero)), Memory), + "DelegateProperty" => new DelegateParam(new((FScriptDelegate*)(Memory?.Malloc(sizeof(FScriptDelegate)) ?? nint.Zero)), Memory), + "MulticastInlineDelegateProperty" => new MulticastInlineDelegateParam(new((FMulticastScriptDelegate*)(Memory?.Malloc(sizeof(FMulticastScriptDelegate)) ?? nint.Zero)), Memory), + "MulticastSparseDelegateProperty" => new MulticastSparseDelegateParam(new((FMulticastSparseDelegateProperty*)(Memory?.Malloc(sizeof(FMulticastSparseDelegateProperty)) ?? nint.Zero)), Memory), + _ => throw new NotSupportedException($"CreateParam with property {property.ClassPrivate.Name}") + }; + } + + public static string? GetParamNameFromProperty(IFProperty property, IUnrealFactory factory, ITypeReflectionInternal reflection) + { + try + { + var PropertyName = property.ClassPrivate.Name; + if (PropertyNameToParamName.TryGetValue(PropertyName, out var ParamName)) return ParamName; + var BlankParam = CreateParam(property, factory, reflection, null); + PropertyNameToParamName[PropertyName] = BlankParam.GetType().Name; + return PropertyNameToParamName[PropertyName]; + } + catch (NotSupportedException ex) + { + return null; + } + } +} \ No newline at end of file diff --git a/UE.Toolkit.Core/Types/Interfaces/ITypeReflectionInternal.cs b/UE.Toolkit.Core/Types/Interfaces/ITypeReflectionInternal.cs new file mode 100644 index 0000000..3dc4a13 --- /dev/null +++ b/UE.Toolkit.Core/Types/Interfaces/ITypeReflectionInternal.cs @@ -0,0 +1,21 @@ +namespace UE.Toolkit.Core.Types.Interfaces; + +public interface ITypeReflectionInternal +{ + #region FText + + /// + /// Get the FText type used by the currently running version of the engine. + /// UE 5.4 and later have a significantly different FText implement compared to earlier versions. + /// + /// Type information for the FText. + Type GetFText(); + /// + /// Get the size of the FText type used by the currently running version of the engine. + /// UE 5.4 and later have a significantly different FText implement compared to earlier versions. + /// + /// Size of FText. + int GetFTextSize(); + + #endregion +} \ No newline at end of file diff --git a/UE.Toolkit.Core/Types/Unreal/Common/FunctionParam/AnsiStringParam.cs b/UE.Toolkit.Core/Types/Unreal/Common/FunctionParam/AnsiStringParam.cs new file mode 100644 index 0000000..901f425 --- /dev/null +++ b/UE.Toolkit.Core/Types/Unreal/Common/FunctionParam/AnsiStringParam.cs @@ -0,0 +1,7 @@ +using UE.Toolkit.Core.Types.Interfaces; +using UE.Toolkit.Core.Types.Unreal.UE5_6_1; + +namespace UE.Toolkit.Core.Types.Unreal.Common.FunctionParam; + +public class AnsiStringParam(Ptr rvalue, IUnrealMemoryInternal? memory = null) + : FunctionParamCopyable(rvalue, "AnsiStrProperty", memory); \ No newline at end of file diff --git a/UE.Toolkit.Core/Types/Unreal/Common/FunctionParam/ArrayParam.cs b/UE.Toolkit.Core/Types/Unreal/Common/FunctionParam/ArrayParam.cs new file mode 100644 index 0000000..02bee07 --- /dev/null +++ b/UE.Toolkit.Core/Types/Unreal/Common/FunctionParam/ArrayParam.cs @@ -0,0 +1,7 @@ +using UE.Toolkit.Core.Types.Interfaces; +using UE.Toolkit.Core.Types.Unreal.UE5_4_4; + +namespace UE.Toolkit.Core.Types.Unreal.Common.FunctionParam; + +public class ArrayParam(Ptr> rvalue, IUnrealMemoryInternal? memory = null) + : FunctionParamCopyable>(rvalue, "ArrayProperty", memory); \ No newline at end of file diff --git a/UE.Toolkit.Core/Types/Unreal/Common/FunctionParam/BoolParam.cs b/UE.Toolkit.Core/Types/Unreal/Common/FunctionParam/BoolParam.cs new file mode 100644 index 0000000..30ce7cb --- /dev/null +++ b/UE.Toolkit.Core/Types/Unreal/Common/FunctionParam/BoolParam.cs @@ -0,0 +1,56 @@ +using UE.Toolkit.Core.Types.Interfaces; + +namespace UE.Toolkit.Core.Types.Unreal.Common.FunctionParam; + +public class BoolParam(Ptr rvalue, int fieldMask, IUnrealMemoryInternal? memory = null) : IFunctionParam, IDisposable +{ + public unsafe bool Value => *RValue.Value; + + protected Ptr RValue => rvalue; + + protected IUnrealMemoryInternal? Memory => memory; + + public string PropertyType => "BoolProperty"; + + public int FieldMask => fieldMask; + + private static unsafe void CopyByte(byte* source, byte* destination) => *destination = *source; + + private unsafe bool IsStateDifferent(nint Destination) + { + var isDestTrue = (*(byte*)Destination & Convert.ToByte(FieldMask)) != 0; + return isDestTrue != Value; + } + + public unsafe void Write(nint Destination) + { + if (FieldMask == byte.MaxValue) CopyByte((byte*)RValue.Value, (byte*)Destination); + else *(byte*)Destination ^= (byte)(Convert.ToByte(IsStateDifferent(Destination)) * FieldMask); + } + + public unsafe void Read(nint Destination) + { + if (FieldMask == byte.MaxValue) CopyByte((byte*)Destination, (byte*)RValue.Value); + else *RValue.Value = IsStateDifferent(Destination); + } + + protected bool IsDisposed; + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (!IsDisposed) + { + if (disposing) { } + unsafe { Memory?.Free((nint)RValue.Value); } + IsDisposed = true; + } + } + + ~BoolParam() => Dispose(false); +} \ No newline at end of file diff --git a/UE.Toolkit.Core/Types/Unreal/Common/FunctionParam/ByteParam.cs b/UE.Toolkit.Core/Types/Unreal/Common/FunctionParam/ByteParam.cs new file mode 100644 index 0000000..23c2e6f --- /dev/null +++ b/UE.Toolkit.Core/Types/Unreal/Common/FunctionParam/ByteParam.cs @@ -0,0 +1,6 @@ +using UE.Toolkit.Core.Types.Interfaces; + +namespace UE.Toolkit.Core.Types.Unreal.Common.FunctionParam; + +public class ByteParam(Ptr rvalue, IUnrealMemoryInternal? memory = null) + : FunctionParamCopyable(rvalue, "ByteProperty", memory); \ No newline at end of file diff --git a/UE.Toolkit.Core/Types/Unreal/Common/FunctionParam/DelegateParam.cs b/UE.Toolkit.Core/Types/Unreal/Common/FunctionParam/DelegateParam.cs new file mode 100644 index 0000000..be1bb2a --- /dev/null +++ b/UE.Toolkit.Core/Types/Unreal/Common/FunctionParam/DelegateParam.cs @@ -0,0 +1,7 @@ +using UE.Toolkit.Core.Types.Interfaces; +using UE.Toolkit.Core.Types.Unreal.UE5_4_4; + +namespace UE.Toolkit.Core.Types.Unreal.Common.FunctionParam; + +public class DelegateParam(Ptr rvalue, IUnrealMemoryInternal? memory = null) + : FunctionParamCopyable(rvalue, "DelegateProperty", memory); \ No newline at end of file diff --git a/UE.Toolkit.Core/Types/Unreal/Common/FunctionParam/DoubleParam.cs b/UE.Toolkit.Core/Types/Unreal/Common/FunctionParam/DoubleParam.cs new file mode 100644 index 0000000..985cc54 --- /dev/null +++ b/UE.Toolkit.Core/Types/Unreal/Common/FunctionParam/DoubleParam.cs @@ -0,0 +1,6 @@ +using UE.Toolkit.Core.Types.Interfaces; + +namespace UE.Toolkit.Core.Types.Unreal.Common.FunctionParam; + +public class DoubleParam(Ptr rvalue, IUnrealMemoryInternal? memory = null) + : FunctionParamCopyable(rvalue, "DoubleProperty", memory); \ No newline at end of file diff --git a/UE.Toolkit.Core/Types/Unreal/Common/FunctionParam/EnumParam.cs b/UE.Toolkit.Core/Types/Unreal/Common/FunctionParam/EnumParam.cs new file mode 100644 index 0000000..d59aa13 --- /dev/null +++ b/UE.Toolkit.Core/Types/Unreal/Common/FunctionParam/EnumParam.cs @@ -0,0 +1,41 @@ +using System.Runtime.InteropServices; +using UE.Toolkit.Core.Types.Interfaces; + +namespace UE.Toolkit.Core.Types.Unreal.Common.FunctionParam; + +public class EnumParam(nint ptr, int size, IUnrealMemoryInternal? memory = null) : IFunctionParam, IDisposable +{ + public string PropertyType => "EnumProperty"; + + private int Size => size; + + private nint Ptr => ptr; + + private IUnrealMemoryInternal? Memory => memory; + + private unsafe void Copy(nint source, nint destination) + => NativeMemory.Copy((void*)source, (void*)destination, (nuint)Size); + + public void Write(nint Destination) => Copy(Ptr, Destination); + public void Read(nint Destination) => Copy(Destination, Ptr); + + private bool IsDisposed; + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (!IsDisposed) + { + if (disposing) { } + Memory?.Free(Ptr); + IsDisposed = true; + } + } + + ~EnumParam() => Dispose(false); +} \ No newline at end of file diff --git a/UE.Toolkit.Core/Types/Unreal/Common/FunctionParam/FloatParam.cs b/UE.Toolkit.Core/Types/Unreal/Common/FunctionParam/FloatParam.cs new file mode 100644 index 0000000..618457b --- /dev/null +++ b/UE.Toolkit.Core/Types/Unreal/Common/FunctionParam/FloatParam.cs @@ -0,0 +1,6 @@ +using UE.Toolkit.Core.Types.Interfaces; + +namespace UE.Toolkit.Core.Types.Unreal.Common.FunctionParam; + +public class FloatParam(Ptr rvalue, IUnrealMemoryInternal? memory = null) + : FunctionParamCopyable(rvalue, "FloatProperty", memory); \ No newline at end of file diff --git a/UE.Toolkit.Core/Types/Unreal/Common/FunctionParam/Int16Param.cs b/UE.Toolkit.Core/Types/Unreal/Common/FunctionParam/Int16Param.cs new file mode 100644 index 0000000..b308535 --- /dev/null +++ b/UE.Toolkit.Core/Types/Unreal/Common/FunctionParam/Int16Param.cs @@ -0,0 +1,6 @@ +using UE.Toolkit.Core.Types.Interfaces; + +namespace UE.Toolkit.Core.Types.Unreal.Common.FunctionParam; + +public class Int16Param(Ptr rvalue, IUnrealMemoryInternal? memory = null) + : FunctionParamCopyable(rvalue, "Int16Property", memory); \ No newline at end of file diff --git a/UE.Toolkit.Core/Types/Unreal/Common/FunctionParam/Int32Param.cs b/UE.Toolkit.Core/Types/Unreal/Common/FunctionParam/Int32Param.cs new file mode 100644 index 0000000..7709b13 --- /dev/null +++ b/UE.Toolkit.Core/Types/Unreal/Common/FunctionParam/Int32Param.cs @@ -0,0 +1,6 @@ +using UE.Toolkit.Core.Types.Interfaces; + +namespace UE.Toolkit.Core.Types.Unreal.Common.FunctionParam; + +public class Int32Param(Ptr rvalue, IUnrealMemoryInternal? memory = null) + : FunctionParamCopyable(rvalue, "Int32Property", memory); \ No newline at end of file diff --git a/UE.Toolkit.Core/Types/Unreal/Common/FunctionParam/Int64Param.cs b/UE.Toolkit.Core/Types/Unreal/Common/FunctionParam/Int64Param.cs new file mode 100644 index 0000000..421e8f2 --- /dev/null +++ b/UE.Toolkit.Core/Types/Unreal/Common/FunctionParam/Int64Param.cs @@ -0,0 +1,6 @@ +using UE.Toolkit.Core.Types.Interfaces; + +namespace UE.Toolkit.Core.Types.Unreal.Common.FunctionParam; + +public class Int64Param(Ptr rvalue, IUnrealMemoryInternal? memory = null) + : FunctionParamCopyable(rvalue, "Int64Property", memory); \ No newline at end of file diff --git a/UE.Toolkit.Core/Types/Unreal/Common/FunctionParam/Int8Param.cs b/UE.Toolkit.Core/Types/Unreal/Common/FunctionParam/Int8Param.cs new file mode 100644 index 0000000..4713fb9 --- /dev/null +++ b/UE.Toolkit.Core/Types/Unreal/Common/FunctionParam/Int8Param.cs @@ -0,0 +1,6 @@ +using UE.Toolkit.Core.Types.Interfaces; + +namespace UE.Toolkit.Core.Types.Unreal.Common.FunctionParam; + +public class Int8Param(Ptr rvalue, IUnrealMemoryInternal? memory = null) + : FunctionParamCopyable(rvalue, "Int8Property", memory); \ No newline at end of file diff --git a/UE.Toolkit.Core/Types/Unreal/Common/FunctionParam/IntParam.cs b/UE.Toolkit.Core/Types/Unreal/Common/FunctionParam/IntParam.cs new file mode 100644 index 0000000..24c74d4 --- /dev/null +++ b/UE.Toolkit.Core/Types/Unreal/Common/FunctionParam/IntParam.cs @@ -0,0 +1,6 @@ +using UE.Toolkit.Core.Types.Interfaces; + +namespace UE.Toolkit.Core.Types.Unreal.Common.FunctionParam; + +public class IntParam(Ptr rvalue, IUnrealMemoryInternal? memory = null) + : FunctionParamCopyable(rvalue, "IntProperty", memory); \ No newline at end of file diff --git a/UE.Toolkit.Core/Types/Unreal/Common/FunctionParam/InterfaceParam.cs b/UE.Toolkit.Core/Types/Unreal/Common/FunctionParam/InterfaceParam.cs new file mode 100644 index 0000000..17ecfb7 --- /dev/null +++ b/UE.Toolkit.Core/Types/Unreal/Common/FunctionParam/InterfaceParam.cs @@ -0,0 +1,7 @@ +using UE.Toolkit.Core.Types.Interfaces; +using UE.Toolkit.Core.Types.Unreal.UE5_4_4; + +namespace UE.Toolkit.Core.Types.Unreal.Common.FunctionParam; + +public class InterfaceParam(Ptr> rvalue, IUnrealMemoryInternal? memory = null) + : FunctionParamCopyable>(rvalue, "InterfaceProperty", memory); \ No newline at end of file diff --git a/UE.Toolkit.Core/Types/Unreal/Common/FunctionParam/MapParam.cs b/UE.Toolkit.Core/Types/Unreal/Common/FunctionParam/MapParam.cs new file mode 100644 index 0000000..7920cbb --- /dev/null +++ b/UE.Toolkit.Core/Types/Unreal/Common/FunctionParam/MapParam.cs @@ -0,0 +1,7 @@ +using UE.Toolkit.Core.Types.Interfaces; +using UE.Toolkit.Core.Types.Unreal.UE5_4_4; + +namespace UE.Toolkit.Core.Types.Unreal.Common.FunctionParam; + +public class MapParam(Ptr> rvalue, IUnrealMemoryInternal? memory = null) + : FunctionParamCopyable>(rvalue, "MapProperty", memory); \ No newline at end of file diff --git a/UE.Toolkit.Core/Types/Unreal/Common/FunctionParam/MulticastDelegateParam.cs b/UE.Toolkit.Core/Types/Unreal/Common/FunctionParam/MulticastDelegateParam.cs new file mode 100644 index 0000000..289f984 --- /dev/null +++ b/UE.Toolkit.Core/Types/Unreal/Common/FunctionParam/MulticastDelegateParam.cs @@ -0,0 +1,10 @@ +using UE.Toolkit.Core.Types.Interfaces; +using UE.Toolkit.Core.Types.Unreal.UE5_4_4; + +namespace UE.Toolkit.Core.Types.Unreal.Common.FunctionParam; + +public class MulticastInlineDelegateParam(Ptr rvalue, IUnrealMemoryInternal? memory = null) + : FunctionParamCopyable(rvalue, "MulticastInlineDelegateProperty", memory); + +public class MulticastSparseDelegateParam(Ptr rvalue, IUnrealMemoryInternal? memory = null) + : FunctionParamCopyable(rvalue, "MulticastSparseDelegateProperty", memory); \ No newline at end of file diff --git a/UE.Toolkit.Core/Types/Unreal/Common/FunctionParam/NameParam.cs b/UE.Toolkit.Core/Types/Unreal/Common/FunctionParam/NameParam.cs new file mode 100644 index 0000000..4ea956b --- /dev/null +++ b/UE.Toolkit.Core/Types/Unreal/Common/FunctionParam/NameParam.cs @@ -0,0 +1,7 @@ +using UE.Toolkit.Core.Types.Interfaces; +using UE.Toolkit.Core.Types.Unreal.UE5_4_4; + +namespace UE.Toolkit.Core.Types.Unreal.Common.FunctionParam; + +public class NameParam(Ptr rvalue, IUnrealMemoryInternal? memory = null) + : FunctionParamCopyable(rvalue, "NameProperty", memory); \ No newline at end of file diff --git a/UE.Toolkit.Core/Types/Unreal/Common/FunctionParam/ObjectParam.cs b/UE.Toolkit.Core/Types/Unreal/Common/FunctionParam/ObjectParam.cs new file mode 100644 index 0000000..646fdfb --- /dev/null +++ b/UE.Toolkit.Core/Types/Unreal/Common/FunctionParam/ObjectParam.cs @@ -0,0 +1,6 @@ +using UE.Toolkit.Core.Types.Interfaces; + +namespace UE.Toolkit.Core.Types.Unreal.Common.FunctionParam; + +public class ObjectParam(Ptr rvalue, IUnrealMemoryInternal? memory = null) + : FunctionParamCopyable(rvalue, "ObjectProperty", memory); \ No newline at end of file diff --git a/UE.Toolkit.Core/Types/Unreal/Common/FunctionParam/SetParam.cs b/UE.Toolkit.Core/Types/Unreal/Common/FunctionParam/SetParam.cs new file mode 100644 index 0000000..adf5203 --- /dev/null +++ b/UE.Toolkit.Core/Types/Unreal/Common/FunctionParam/SetParam.cs @@ -0,0 +1,7 @@ +using UE.Toolkit.Core.Types.Interfaces; +using UE.Toolkit.Core.Types.Unreal.UE5_4_4; + +namespace UE.Toolkit.Core.Types.Unreal.Common.FunctionParam; + +public class SetParam(Ptr> rvalue, IUnrealMemoryInternal? memory = null) + : FunctionParamCopyable>(rvalue, "SetProperty", memory); \ No newline at end of file diff --git a/UE.Toolkit.Core/Types/Unreal/Common/FunctionParam/SoftClassParam.cs b/UE.Toolkit.Core/Types/Unreal/Common/FunctionParam/SoftClassParam.cs new file mode 100644 index 0000000..7c30737 --- /dev/null +++ b/UE.Toolkit.Core/Types/Unreal/Common/FunctionParam/SoftClassParam.cs @@ -0,0 +1,7 @@ +using UE.Toolkit.Core.Types.Interfaces; +using UE.Toolkit.Core.Types.Unreal.UE5_4_4; + +namespace UE.Toolkit.Core.Types.Unreal.Common.FunctionParam; + +public class SoftClassParam(Ptr> rvalue, IUnrealMemoryInternal? memory = null) + : FunctionParamCopyable>(rvalue, "SoftClassProperty", memory); \ No newline at end of file diff --git a/UE.Toolkit.Core/Types/Unreal/Common/FunctionParam/SoftObjectParam.cs b/UE.Toolkit.Core/Types/Unreal/Common/FunctionParam/SoftObjectParam.cs new file mode 100644 index 0000000..6a49269 --- /dev/null +++ b/UE.Toolkit.Core/Types/Unreal/Common/FunctionParam/SoftObjectParam.cs @@ -0,0 +1,7 @@ +using UE.Toolkit.Core.Types.Interfaces; +using UE.Toolkit.Core.Types.Unreal.UE5_4_4; + +namespace UE.Toolkit.Core.Types.Unreal.Common.FunctionParam; + +public class SoftObjectParam(Ptr> rvalue, IUnrealMemoryInternal? memory = null) + : FunctionParamCopyable>(rvalue, "SoftObjectProperty", memory); \ No newline at end of file diff --git a/UE.Toolkit.Core/Types/Unreal/Common/FunctionParam/StringParam.cs b/UE.Toolkit.Core/Types/Unreal/Common/FunctionParam/StringParam.cs new file mode 100644 index 0000000..7d8b541 --- /dev/null +++ b/UE.Toolkit.Core/Types/Unreal/Common/FunctionParam/StringParam.cs @@ -0,0 +1,7 @@ +using UE.Toolkit.Core.Types.Interfaces; +using UE.Toolkit.Core.Types.Unreal.UE5_4_4; + +namespace UE.Toolkit.Core.Types.Unreal.Common.FunctionParam; + +public class StringParam(Ptr rvalue, IUnrealMemoryInternal? memory = null) + : FunctionParamCopyable(rvalue, "StrProperty", memory); \ No newline at end of file diff --git a/UE.Toolkit.Core/Types/Unreal/Common/FunctionParam/StructParam.cs b/UE.Toolkit.Core/Types/Unreal/Common/FunctionParam/StructParam.cs new file mode 100644 index 0000000..e085f8d --- /dev/null +++ b/UE.Toolkit.Core/Types/Unreal/Common/FunctionParam/StructParam.cs @@ -0,0 +1,41 @@ +using System.Runtime.InteropServices; +using UE.Toolkit.Core.Types.Interfaces; + +namespace UE.Toolkit.Core.Types.Unreal.Common.FunctionParam; + +public class StructParam(nint ptr, int size, IUnrealMemoryInternal? memory = null) : IFunctionParam, IDisposable +{ + public string PropertyType => "StructProperty"; + + private int Size => size; + + private nint Ptr => ptr; + + private IUnrealMemoryInternal? Memory => memory; + + private unsafe void Copy(nint source, nint destination) + => NativeMemory.Copy((void*)source, (void*)destination, (nuint)Size); + + public void Write(nint Destination) => Copy(Ptr, Destination); + public void Read(nint Destination) => Copy(Destination, Ptr); + + private bool IsDisposed; + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (!IsDisposed) + { + if (disposing) { } + Memory?.Free(Ptr); + IsDisposed = true; + } + } + + ~StructParam() => Dispose(false); +} \ No newline at end of file diff --git a/UE.Toolkit.Core/Types/Unreal/Common/FunctionParam/TextParam.cs b/UE.Toolkit.Core/Types/Unreal/Common/FunctionParam/TextParam.cs new file mode 100644 index 0000000..bae8d77 --- /dev/null +++ b/UE.Toolkit.Core/Types/Unreal/Common/FunctionParam/TextParam.cs @@ -0,0 +1,43 @@ +using System.Runtime.InteropServices; +using UE.Toolkit.Core.Types.Interfaces; + +namespace UE.Toolkit.Core.Types.Unreal.Common.FunctionParam; + +public class TextParam(nint value, int ftextSize, IUnrealMemoryInternal? memory = null) + : IFunctionParam, IDisposable +{ + public unsafe nint Value => value; + + protected IUnrealMemoryInternal? Memory => memory; + + public string PropertyType => "TextProperty"; + + private int FTextSize => ftextSize; + + private unsafe void Copy(nint source, nint destination) => + NativeMemory.Copy((void*)source, (void*)destination, (nuint)FTextSize); + + public void Write(nint Destination) => Copy(Value, Destination); + + public void Read(nint Destination) => Copy(Destination, Value); + + protected bool IsDisposed; + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (!IsDisposed) + { + if (disposing) { } + Memory?.Free(Value); + IsDisposed = true; + } + } + + ~TextParam() => Dispose(false); +} \ No newline at end of file diff --git a/UE.Toolkit.Core/Types/Unreal/Common/FunctionParam/UInt16Param.cs b/UE.Toolkit.Core/Types/Unreal/Common/FunctionParam/UInt16Param.cs new file mode 100644 index 0000000..198d2b1 --- /dev/null +++ b/UE.Toolkit.Core/Types/Unreal/Common/FunctionParam/UInt16Param.cs @@ -0,0 +1,6 @@ +using UE.Toolkit.Core.Types.Interfaces; + +namespace UE.Toolkit.Core.Types.Unreal.Common.FunctionParam; + +public class UInt16Param(Ptr rvalue, IUnrealMemoryInternal? memory = null) + : FunctionParamCopyable(rvalue, "UInt16Property", memory); \ No newline at end of file diff --git a/UE.Toolkit.Core/Types/Unreal/Common/FunctionParam/UInt32Param.cs b/UE.Toolkit.Core/Types/Unreal/Common/FunctionParam/UInt32Param.cs new file mode 100644 index 0000000..54c048a --- /dev/null +++ b/UE.Toolkit.Core/Types/Unreal/Common/FunctionParam/UInt32Param.cs @@ -0,0 +1,6 @@ +using UE.Toolkit.Core.Types.Interfaces; + +namespace UE.Toolkit.Core.Types.Unreal.Common.FunctionParam; + +public class UInt32Param(Ptr rvalue, IUnrealMemoryInternal? memory = null) + : FunctionParamCopyable(rvalue, "UInt32Property", memory); \ No newline at end of file diff --git a/UE.Toolkit.Core/Types/Unreal/Common/FunctionParam/UInt64Param.cs b/UE.Toolkit.Core/Types/Unreal/Common/FunctionParam/UInt64Param.cs new file mode 100644 index 0000000..a80b94e --- /dev/null +++ b/UE.Toolkit.Core/Types/Unreal/Common/FunctionParam/UInt64Param.cs @@ -0,0 +1,6 @@ +using UE.Toolkit.Core.Types.Interfaces; + +namespace UE.Toolkit.Core.Types.Unreal.Common.FunctionParam; + +public class UInt64Param(Ptr rvalue, IUnrealMemoryInternal? memory = null) + : FunctionParamCopyable(rvalue, "UInt64Property", memory); \ No newline at end of file diff --git a/UE.Toolkit.Core/Types/Unreal/Common/FunctionParam/Utf8StringParam.cs b/UE.Toolkit.Core/Types/Unreal/Common/FunctionParam/Utf8StringParam.cs new file mode 100644 index 0000000..a84e284 --- /dev/null +++ b/UE.Toolkit.Core/Types/Unreal/Common/FunctionParam/Utf8StringParam.cs @@ -0,0 +1,7 @@ +using UE.Toolkit.Core.Types.Interfaces; +using UE.Toolkit.Core.Types.Unreal.UE5_6_1; + +namespace UE.Toolkit.Core.Types.Unreal.Common.FunctionParam; + +public class Utf8StringParam(Ptr rvalue, IUnrealMemoryInternal? memory = null) + : FunctionParamCopyable(rvalue, "Utf8StrProperty", memory); \ No newline at end of file diff --git a/UE.Toolkit.Core/Types/Unreal/Factories/BaseUnrealFactory.cs b/UE.Toolkit.Core/Types/Unreal/Factories/BaseUnrealFactory.cs index 61192ee..035d819 100644 --- a/UE.Toolkit.Core/Types/Unreal/Factories/BaseUnrealFactory.cs +++ b/UE.Toolkit.Core/Types/Unreal/Factories/BaseUnrealFactory.cs @@ -7,6 +7,8 @@ public abstract class BaseUnrealFactory : IUnrealFactory { public IUnrealMemoryInternal? Memory { get; set; } + public Action? ProcessEvent { get; set; } + public Func? CreateReturnParam { get; set; } public T Cast(IPtr obj) { @@ -100,6 +102,7 @@ public nint GetAlignment(IFProperty prop) public abstract IFFieldClass CreateFFieldClass(nint ptr); public abstract IFField CreateFField(nint ptr); + public abstract IFFieldVariant CreateFFieldVariant(nint ptr); public abstract IFStructParams CreateFStructParams(nint ptr); public abstract IFPropertyParams CreateFPropertyParams(nint ptr); diff --git a/UE.Toolkit.Core/Types/Unreal/Factories/IUnrealFactory.cs b/UE.Toolkit.Core/Types/Unreal/Factories/IUnrealFactory.cs index e9a5d67..50ba330 100644 --- a/UE.Toolkit.Core/Types/Unreal/Factories/IUnrealFactory.cs +++ b/UE.Toolkit.Core/Types/Unreal/Factories/IUnrealFactory.cs @@ -13,6 +13,8 @@ public interface IUnrealFactory nint GetAlignment(IFProperty prop); IUnrealMemoryInternal? Memory { get; set; } + Action? ProcessEvent { get; set; } + Func? CreateReturnParam { get; set; } IFProperty CreateFProperty(nint ptr); IFBoolProperty CreateFBoolProperty(nint ptr); @@ -42,6 +44,7 @@ public interface IUnrealFactory IFFieldClass CreateFFieldClass(nint ptr); IFField CreateFField(nint ptr); + IFFieldVariant CreateFFieldVariant(nint ptr); IFStructParams CreateFStructParams(nint ptr); IFPropertyParams CreateFPropertyParams(nint ptr); diff --git a/UE.Toolkit.Core/Types/Unreal/Factories/Interfaces/IFField.cs b/UE.Toolkit.Core/Types/Unreal/Factories/Interfaces/IFField.cs index 42bd13b..99f757c 100644 --- a/UE.Toolkit.Core/Types/Unreal/Factories/Interfaces/IFField.cs +++ b/UE.Toolkit.Core/Types/Unreal/Factories/Interfaces/IFField.cs @@ -6,8 +6,11 @@ public interface IFField : IPtr { nint VTable { get; } IFFieldClass ClassPrivate { get; } - FFieldObjectUnion Owner { get; } + IFFieldVariant Owner { get; } IFField? Next { get; } string NamePrivate { get; } EObjectFlags FlagsPrivate { get; } + + void SetOwnerUObject(IUObject owner); + void SetOwnerFField(IFField owner); } \ No newline at end of file diff --git a/UE.Toolkit.Core/Types/Unreal/Factories/Interfaces/IFFieldVariant.cs b/UE.Toolkit.Core/Types/Unreal/Factories/Interfaces/IFFieldVariant.cs new file mode 100644 index 0000000..d039c87 --- /dev/null +++ b/UE.Toolkit.Core/Types/Unreal/Factories/Interfaces/IFFieldVariant.cs @@ -0,0 +1,8 @@ +namespace UE.Toolkit.Core.Types.Unreal.Factories.Interfaces; + +public interface IFFieldVariant : IPtr +{ + IFField? Field { get; } + IUObject? Object { get; } + bool IsObject { get; } +} \ No newline at end of file diff --git a/UE.Toolkit.Core/Types/Unreal/Factories/Interfaces/IUClass.cs b/UE.Toolkit.Core/Types/Unreal/Factories/Interfaces/IUClass.cs index e9a1136..f14f2db 100644 --- a/UE.Toolkit.Core/Types/Unreal/Factories/Interfaces/IUClass.cs +++ b/UE.Toolkit.Core/Types/Unreal/Factories/Interfaces/IUClass.cs @@ -8,9 +8,13 @@ public interface IUClass : IUStruct IUFunction? GetFunction(string Name); + IEnumerable GetFunctions(); + IUObject? ClassDefaultObject { get; } nint Constructor { get; } EClassFlags ClassFlags { get; } + + EClassCastFlags ClassCastFlags { get; } } \ No newline at end of file diff --git a/UE.Toolkit.Core/Types/Unreal/Factories/Interfaces/IUObject.cs b/UE.Toolkit.Core/Types/Unreal/Factories/Interfaces/IUObject.cs index 08f7a2a..b41de37 100644 --- a/UE.Toolkit.Core/Types/Unreal/Factories/Interfaces/IUObject.cs +++ b/UE.Toolkit.Core/Types/Unreal/Factories/Interfaces/IUObject.cs @@ -1,3 +1,5 @@ +using System.Runtime.InteropServices; +using UE.Toolkit.Core.Types.Interfaces; using UE.Toolkit.Core.Types.Unreal.UE5_4_4; namespace UE.Toolkit.Core.Types.Unreal.Factories.Interfaces; @@ -31,4 +33,91 @@ public interface IUObject : IPtr string GetPathName(); // IUObject GetWorld(); + + ProcessEventResult ProcessEvent(string Name, List Params, out IFunctionParam? Return); + + IUnrealFactory GetFactory(); +} + +public abstract unsafe class BaseUObject(nint ptr, IUnrealFactory factory, IUnrealMemoryInternal memory) + : IUObject where TUObjectBase : unmanaged +{ + protected readonly TUObjectBase* _self = (TUObjectBase*)ptr; + protected readonly IUnrealFactory _factory = factory; + protected readonly IUnrealMemoryInternal _memory = memory; + + public IUnrealFactory GetFactory() => _factory; + + public nint Ptr => (nint)_self; + + public abstract nint VTable { get; } + public abstract EObjectFlags ObjectFlags { get; } + public abstract int InternalIndex { get; } + public abstract IUClass ClassPrivate { get; } + public abstract FName NamePrivate { get; } + public abstract IUObject? OuterPrivate { get; } + + public abstract bool IsChildOf(string type); + + public abstract IUObject GetOutermost(); + + public abstract string GetNativeName(); + + public abstract string GetPathName(); + + public ProcessEventResult ProcessEvent(string Name, List Params, out IFunctionParam? Return) + { + Return = null; + // var Function = ClassPrivate.GetFunction(Name); + var CurrentClass = ClassPrivate; + IUFunction? Function = null; + while (Function == null && CurrentClass != null) + { + Function = CurrentClass.GetFunction(Name); + CurrentClass = CurrentClass.GetSuperClass(); + } + if (Function == null) + { + return ProcessEventResult.CouldNotFindFunction; + } + var Alloc = Function.GetTotalParameterSize() switch + { + 0 => nint.Zero, var SizeOf => _memory.Malloc(SizeOf) + }; + foreach (var (Index, Field) in Function.ChildProperties.Select((x, i) => (i, x))) + { + var Property = _factory.CreateFProperty(Field.Ptr); + if (Property.PropertyFlags.HasFlag(EPropertyFlags.CPF_ReturnParm)) + { + NativeMemory.Clear((void*)(Alloc + Property.Offset_Internal), (nuint)Property.ElementSize); + break; + } + var Parameter = Params[Index]; + if (Property.ClassPrivate.Name != Parameter.PropertyType) + { + return ProcessEventResult.ParameterTypeMismatch; + } + Parameter.Write(Alloc + Property.Offset_Internal); + } + _factory.ProcessEvent!(Ptr, Function, Alloc); + foreach (var (Index, Field) in Function.ChildProperties.Select((x, i) => (i, x))) + { + var Property = _factory.CreateFProperty(Field.Ptr); + if (Property.PropertyFlags.HasFlag(EPropertyFlags.CPF_ReturnParm)) + { + Return = _factory.CreateReturnParam!(Property); + Return.Read(Alloc + Property.Offset_Internal); + break; + } + if (Property.PropertyFlags.HasFlag(EPropertyFlags.CPF_OutParm)) + { + Params[Index].Read(Alloc + Property.Offset_Internal); + } + } + if (Alloc != nint.Zero) + { + _memory.Free(Alloc); + } + return ProcessEventResult.Success; + } } \ No newline at end of file diff --git a/UE.Toolkit.Core/Types/Unreal/Factories/UE4_27_2/UnrealFactory.cs b/UE.Toolkit.Core/Types/Unreal/Factories/UE4_27_2/UnrealFactory.cs index a1463ae..ea14f3e 100644 --- a/UE.Toolkit.Core/Types/Unreal/Factories/UE4_27_2/UnrealFactory.cs +++ b/UE.Toolkit.Core/Types/Unreal/Factories/UE4_27_2/UnrealFactory.cs @@ -2,13 +2,14 @@ using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; using UE.Toolkit.Core.Common; +using UE.Toolkit.Core.Types.Interfaces; using UE.Toolkit.Core.Types.Unreal.Factories.Interfaces; using UE.Toolkit.Core.Types.Unreal.UE5_4_4; using EFunctionFlags = UE.Toolkit.Core.Types.Unreal.UE5_4_4.EFunctionFlags; using EPropertyFlags = UE.Toolkit.Core.Types.Unreal.UE5_4_4.EPropertyFlags; using EPropertyGenFlags = UE.Toolkit.Core.Types.Unreal.UE5_4_4.EPropertyGenFlags; using EClassFlags = UE.Toolkit.Core.Types.Unreal.UE5_4_4.EClassFlags; -using FFieldObjectUnion = UE.Toolkit.Core.Types.Unreal.UE5_4_4.FFieldObjectUnion; +// using FFieldObjectUnion = UE.Toolkit.Core.Types.Unreal.UE5_4_4.FFieldObjectUnion; using FUObjectArray_Pack4 = UE.Toolkit.Core.Types.Unreal.UE5_4_4.FUObjectArray_Pack4; using FName = UE.Toolkit.Core.Types.Unreal.UE5_4_4.FName; using EStructFlags = UE.Toolkit.Core.Types.Unreal.UE5_4_4.EStructFlags; @@ -22,6 +23,7 @@ using FEnumProperty = UE.Toolkit.Core.Types.Unreal.UE4_27_2.FEnumProperty; using FField = UE.Toolkit.Core.Types.Unreal.UE4_27_2.FField; using FFieldClass = UE.Toolkit.Core.Types.Unreal.UE4_27_2.FFieldClass; +using FFieldObjectUnion = UE.Toolkit.Core.Types.Unreal.UE4_27_2.FFieldObjectUnion; using FGenericPropertyParams = UE.Toolkit.Core.Types.Unreal.UE4_27_2.FGenericPropertyParams; using FMapProperty = UE.Toolkit.Core.Types.Unreal.UE4_27_2.FMapProperty; using FObjectProperty = UE.Toolkit.Core.Types.Unreal.UE4_27_2.FObjectProperty; @@ -110,26 +112,28 @@ public override nint SizeOf() public override IUObjectArray CreateUObjectArray(nint ptr) => new UObjectArrayUE4_27_2(ptr, this); - public override IUObject CreateUObject(nint ptr) => new UObjectUE4_27_2(ptr, this); + public override IUObject CreateUObject(nint ptr) => new UObjectUE4_27_2(ptr, this, Memory); - public override IUClass CreateUClass(nint ptr) => new UClassUE4_27_2(ptr, this); + public override IUClass CreateUClass(nint ptr) => new UClassUE4_27_2(ptr, this, Memory); - public override IUScriptStruct CreateUScriptStruct(nint ptr) => new UScriptStructUE4_27_2(ptr, this); + public override IUScriptStruct CreateUScriptStruct(nint ptr) => new UScriptStructUE4_27_2(ptr, this, Memory); - public override IUEnum CreateUEnum(nint ptr) => new UEnumUE4_27_2(ptr, this); + public override IUEnum CreateUEnum(nint ptr) => new UEnumUE4_27_2(ptr, this, Memory); - public override IUField CreateUField(nint ptr) => new UFieldUE4_27_2(ptr, this); + public override IUField CreateUField(nint ptr) => new UFieldUE4_27_2(ptr, this, Memory); - public override IUStruct CreateUStruct(nint ptr) => new UStructUE4_27_2(ptr, this); + public override IUStruct CreateUStruct(nint ptr) => new UStructUE4_27_2(ptr, this, Memory); - public override IUUserDefinedEnum CreateUUserDefinedEnum(nint ptr) => new UUserDefinedEnumUE4_27_2(ptr, this); + public override IUUserDefinedEnum CreateUUserDefinedEnum(nint ptr) => new UUserDefinedEnumUE4_27_2(ptr, this, Memory); - public override IUFunction CreateUFunction(nint ptr) => new UFunctionUE4_27_2(ptr, this); + public override IUFunction CreateUFunction(nint ptr) => new UFunctionUE4_27_2(ptr, this, Memory); public override IFFieldClass CreateFFieldClass(nint ptr) => new FFieldClassUE4_27_2(ptr, this); public override IFField CreateFField(nint ptr) => new FFieldUE4_27_2(ptr, this); + public override IFFieldVariant CreateFFieldVariant(nint ptr) => new FFieldVariantUE4_27_2(ptr, this); + public override IFStructParams CreateFStructParams(nint ptr) => new FStructParamsUE4_27_2(ptr, this); public override IFPropertyParams CreateFPropertyParams(nint ptr) => new FPropertyParamsUE4_27_2(ptr, this); @@ -138,9 +142,9 @@ public override nint SizeOf() public override IFWorldContext CreateFWorldContext(nint ptr) => new FWorldContextUE4_27_2(ptr, this); - public override IUEngine CreateUEngine(nint ptr) => new UEngineUE4_27_2(ptr, this); + public override IUEngine CreateUEngine(nint ptr) => new UEngineUE4_27_2(ptr, this, Memory); - public override IUGameInstance CreateUGameInstance(nint ptr) => new UGameInstanceUE4_27_2(ptr, this); + public override IUGameInstance CreateUGameInstance(nint ptr) => new UGameInstanceUE4_27_2(ptr, this, Memory); public override IFStaticConstructObjectParameters CreateFStaticConstructObjectParameters() => new FStaticConstructObjectParametersUE4_27_2(this); @@ -232,10 +236,34 @@ public unsafe class FFieldUE4_27_2(nint ptr, IUnrealFactory factory) public nint Ptr => ptr; public nint VTable => _self->_vtable; public IFFieldClass ClassPrivate => _factory.CreateFFieldClass((nint)_self->class_private); - public FFieldObjectUnion Owner => throw new NotSupportedException(); + public IFFieldVariant Owner => factory.CreateFFieldVariant((nint)(&_self->owner)); public IFField? Next => _self->next != null ? _factory.CreateFField((nint)_self->next) : null; public string NamePrivate => _self->name_private.ToString(); public EObjectFlags FlagsPrivate => _self->flags_private; + + public void SetOwnerUObject(IUObject owner) + { + _self->owner.Object = (UObjectBase*)owner.Ptr; + _self->owner.bIsUObject = true; + } + + public void SetOwnerFField(IFField owner) + { + _self->owner.Field = (FField*)owner.Ptr; + _self->owner.bIsUObject = false; + } +} + +public unsafe class FFieldVariantUE4_27_2(nint ptr, IUnrealFactory factory) + : IFFieldVariant +{ + private readonly FFieldObjectUnion* _self = (FFieldObjectUnion*)ptr; + protected readonly IUnrealFactory _factory = factory; + + public nint Ptr => ptr; + public IFField? Field => _self->Field != null ? _factory.CreateFField((nint)_self->Field) : null; + public IUObject? Object => _self->Object != null ? _factory.CreateUObject((nint)_self->Object) : null; + public bool IsObject => _self->bIsUObject; } public unsafe class FPropertyUE4_27_2(nint ptr, IUnrealFactory factory) @@ -328,14 +356,14 @@ public unsafe class FBytePropertyUE4_27_2(nint ptr, IUnrealFactory factory) public IUEnum? Enum => ((FByteProperty*)Ptr)->enum_data != null ? _factory.CreateUEnum((nint)((FByteProperty*)Ptr)->enum_data) : null; } -public unsafe class UUserDefinedEnumUE4_27_2(nint ptr, IUnrealFactory factory) - : UEnumUE4_27_2(ptr, factory), IUUserDefinedEnum +public unsafe class UUserDefinedEnumUE4_27_2(nint ptr, IUnrealFactory factory, IUnrealMemoryInternal memory) + : UEnumUE4_27_2(ptr, factory, memory), IUUserDefinedEnum { public TMap DisplayNameMap => *(TMap*)(&((UUserDefinedEnum*)ptr)->DisplayNameMap); } -public unsafe class UEnumUE4_27_2(nint ptr, IUnrealFactory factory) - : UFieldUE4_27_2(ptr, factory), IUEnum +public unsafe class UEnumUE4_27_2(nint ptr, IUnrealFactory factory, IUnrealMemoryInternal memory) + : UFieldUE4_27_2(ptr, factory, memory), IUEnum { private readonly UEnum* _self = (UEnum*)ptr; public string CppType => _self->cpp_type.ToString(); @@ -365,8 +393,8 @@ public bool TryParse(string name, bool ignoreCase, [NotNullWhen(true)] out long? } } -public unsafe class UScriptStructUE4_27_2(nint ptr, IUnrealFactory factory) - : UStructUE4_27_2(ptr, factory), IUScriptStruct +public unsafe class UScriptStructUE4_27_2(nint ptr, IUnrealFactory factory, IUnrealMemoryInternal memory) + : UStructUE4_27_2(ptr, factory, memory), IUScriptStruct { private readonly UScriptStruct* _self = (UScriptStruct*)ptr; public EStructFlags StructFlags => (EStructFlags)_self->flags; @@ -374,8 +402,8 @@ public unsafe class UScriptStructUE4_27_2(nint ptr, IUnrealFactory factory) public nint CppStructOps => _self->cpp_struct_ops; } -public unsafe class UStructUE4_27_2(nint ptr, IUnrealFactory factory) - : UFieldUE4_27_2(ptr, factory), IUStruct +public unsafe class UStructUE4_27_2(nint ptr, IUnrealFactory factory, IUnrealMemoryInternal memory) + : UFieldUE4_27_2(ptr, factory, memory), IUStruct { private readonly UStruct* _self = (UStruct*)ptr; @@ -440,7 +468,6 @@ public class IUFieldEnumerable(IUField? initial) { private IUField? _current = initial; private bool isInitial = true; - public bool MoveNext() { if (isInitial) @@ -466,8 +493,8 @@ public void Dispose() { } IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); } -public unsafe class UFieldUE4_27_2(nint ptr, IUnrealFactory factory) - : UObjectUE4_27_2(ptr, factory), IUField +public unsafe class UFieldUE4_27_2(nint ptr, IUnrealFactory factory, IUnrealMemoryInternal memory) + : UObjectUE4_27_2(ptr, factory, memory), IUField { private readonly UField* _self = (UField*)ptr; @@ -475,36 +502,32 @@ public IUField? Next => _self->next != null ? _factory.CreateUField((nint)_self->next) : null; } -public unsafe class UObjectUE4_27_2(nint ptr, IUnrealFactory factory) : IUObject +public unsafe class UObjectUE4_27_2(nint ptr, IUnrealFactory factory, IUnrealMemoryInternal memory) + : BaseUObject(ptr, factory, memory) { - private readonly UObjectBase* _self = (UObjectBase*)ptr; - protected readonly IUnrealFactory _factory = factory; + public override nint VTable => _self->_vtable; - public nint Ptr => (nint)_self; + public override EObjectFlags ObjectFlags => _self->ObjectFlags; - public nint VTable => _self->_vtable; + public override int InternalIndex => (int)_self->InternalIndex; - public EObjectFlags ObjectFlags => _self->ObjectFlags; + public override IUClass ClassPrivate => _factory.CreateUClass((nint)_self->ClassPrivate); - public int InternalIndex => (int)_self->InternalIndex; + public override FName NamePrivate => _self->NamePrivate; - public IUClass ClassPrivate => _factory.CreateUClass((nint)_self->ClassPrivate); + public override IUObject? OuterPrivate => _self->OuterPrivate != null ? _factory.CreateUObject((nint)_self->OuterPrivate) : null; - public FName NamePrivate => _self->NamePrivate; + public override bool IsChildOf(string type) => _self->IsChildOf(type); - public IUObject? OuterPrivate => _self->OuterPrivate != null ? _factory.CreateUObject((nint)_self->OuterPrivate) : null; + public override IUObject GetOutermost() => _factory.CreateUObject((nint)_self->GetOutermost()); - public bool IsChildOf(string type) => _self->IsChildOf(type); + public override string GetNativeName() => ToolkitUtils.GetNativeName(this); - public IUObject GetOutermost() => _factory.CreateUObject((nint)_self->GetOutermost()); - - public string GetNativeName() => ToolkitUtils.GetNativeName(this); - - public string GetPathName() => ToolkitUtils.GetPathName(this); + public override string GetPathName() => ToolkitUtils.GetPathName(this); } -public unsafe class UClassUE4_27_2(nint ptr, IUnrealFactory factory) - : UStructUE4_27_2(ptr, factory), IUClass +public unsafe class UClassUE4_27_2(nint ptr, IUnrealFactory factory, IUnrealMemoryInternal memory) + : UStructUE4_27_2(ptr, factory, memory), IUClass { private readonly UClass* _self = (UClass*)ptr; @@ -522,16 +545,27 @@ public unsafe class UClassUE4_27_2(nint ptr, IUnrealFactory factory) : null; } + public IEnumerable GetFunctions() + { + var FuncMapDict = new TMapDictionary>( + (TMap>*)(&_self->func_map), + _factory.Memory + ); + return FuncMapDict.Values.Select(x => _factory.CreateUFunction((nint)x.Value->Value)); + } + public IUObject? ClassDefaultObject => _self->class_default_obj != null ? factory.CreateUObject((nint)_self->class_default_obj) : null; public nint Constructor => _self->class_ctor; public EClassFlags ClassFlags => _self->class_flags; + + public EClassCastFlags ClassCastFlags => _self->class_cast_flags; } -public unsafe class UFunctionUE4_27_2(nint ptr, IUnrealFactory factory) - : UStructUE4_27_2(ptr, factory), IUFunction +public unsafe class UFunctionUE4_27_2(nint ptr, IUnrealFactory factory, IUnrealMemoryInternal memory) + : UStructUE4_27_2(ptr, factory, memory), IUFunction { private readonly UFunction* _self = (UFunction*)ptr; @@ -543,7 +577,7 @@ public unsafe class UFunctionUE4_27_2(nint ptr, IUnrealFactory factory) public int GetTotalParameterSize() { var LastProperty = ChildProperties.Any() ? _factory.CreateFProperty(ChildProperties.Last().Ptr) : null; - return LastProperty != null ? LastProperty!.Offset_Internal + LastProperty!.ElementSize : 0; + return LastProperty != null ? LastProperty.Offset_Internal + LastProperty.ElementSize : 0; } public nint FunctionPtr => _self->exec_func_ptr; @@ -693,8 +727,8 @@ public void Dispose() {} #endregion } -public unsafe class UEngineUE4_27_2(nint ptr, IUnrealFactory factory) - : UObjectUE4_27_2(ptr, factory), IUEngine +public unsafe class UEngineUE4_27_2(nint ptr, IUnrealFactory factory, IUnrealMemoryInternal memory) + : UObjectUE4_27_2(ptr, factory, memory), IUEngine { private readonly UEngine* _self = (UEngine*)ptr; @@ -783,8 +817,8 @@ protected virtual void Disposing() #endregion } -public unsafe class UGameInstanceUE4_27_2(nint ptr, IUnrealFactory factory) - : UObjectUE4_27_2(ptr, factory), IUGameInstance +public unsafe class UGameInstanceUE4_27_2(nint ptr, IUnrealFactory factory, IUnrealMemoryInternal memory) + : UObjectUE4_27_2(ptr, factory, memory), IUGameInstance { private readonly UGameInstance* _self = (UGameInstance*)ptr; diff --git a/UE.Toolkit.Core/Types/Unreal/Factories/UE5_0_3/UnrealFactory.cs b/UE.Toolkit.Core/Types/Unreal/Factories/UE5_0_3/UnrealFactory.cs index 9e492fc..fc2ccdd 100644 --- a/UE.Toolkit.Core/Types/Unreal/Factories/UE5_0_3/UnrealFactory.cs +++ b/UE.Toolkit.Core/Types/Unreal/Factories/UE5_0_3/UnrealFactory.cs @@ -1,176 +1,47 @@ +using UE.Toolkit.Core.Types.Interfaces; using UE.Toolkit.Core.Types.Unreal.Factories.Interfaces; +using UE.Toolkit.Core.Types.Unreal.Factories.UE5_2_1; +using UE.Toolkit.Core.Types.Unreal.UE5_4_4; +using UClass = UE.Toolkit.Core.Types.Unreal.UE5_0_3.UClass; +using UFunction = UE.Toolkit.Core.Types.Unreal.UE4_27_2.UFunction; namespace UE.Toolkit.Core.Types.Unreal.Factories.UE5_0_3; -public class UnrealFactory : BaseUnrealFactory +public class UnrealFactory : UE.Toolkit.Core.Types.Unreal.Factories.UE5_2_1.UnrealFactory { - public override IntPtr SizeOf() - { - throw new NotImplementedException(); - } - - public override IFProperty CreateFProperty(IntPtr ptr) - { - throw new NotImplementedException(); - } - - public override IFBoolProperty CreateFBoolProperty(IntPtr ptr) - { - throw new NotImplementedException(); - } - - public override IFByteProperty CreateFByteProperty(IntPtr ptr) - { - throw new NotImplementedException(); - } - - public override IFEnumProperty CreateFEnumProperty(IntPtr ptr) - { - throw new NotImplementedException(); - } - - public override IFObjectProperty CreateFObjectProperty(IntPtr ptr) - { - throw new NotImplementedException(); - } - - public override IFSoftClassProperty CreateFSoftClassProperty(IntPtr ptr) - { - throw new NotImplementedException(); - } - - public override IFClassProperty CreateFClassProperty(IntPtr ptr) - { - throw new NotImplementedException(); - } - - public override IFStructProperty CreateFStructProperty(IntPtr ptr) - { - throw new NotImplementedException(); - } + public override IUClass CreateUClass(nint ptr) => new UClass_UE5_0_3(ptr, this, Memory); +} - public override IFMapProperty CreateFMapProperty(IntPtr ptr) - { - throw new NotImplementedException(); - } - - public override IFInterfaceProperty CreateFInterfaceProperty(IntPtr ptr) - { - throw new NotImplementedException(); - } - - public override IFArrayProperty CreateFArrayProperty(IntPtr ptr) - { - throw new NotImplementedException(); - } - - public override IFSetProperty CreateFSetProperty(IntPtr ptr) - { - throw new NotImplementedException(); - } - - public override IFOptionalProperty CreateFOptionalProperty(IntPtr ptr) - { - throw new NotImplementedException(); - } - - public override IFDelegateProperty CreateFDelegateProperty(IntPtr ptr) - { - throw new NotImplementedException(); - } - - public override IUObjectArray CreateUObjectArray(IntPtr ptr) - { - throw new NotImplementedException(); - } - - public override IUObject CreateUObject(IntPtr ptr) - { - throw new NotImplementedException(); - } - - public override IUClass CreateUClass(IntPtr ptr) - { - throw new NotImplementedException(); - } - - public override IUScriptStruct CreateUScriptStruct(IntPtr ptr) - { - throw new NotImplementedException(); - } - - public override IUEnum CreateUEnum(IntPtr ptr) - { - throw new NotImplementedException(); - } - - public override IUField CreateUField(IntPtr ptr) - { - throw new NotImplementedException(); - } - - public override IUStruct CreateUStruct(IntPtr ptr) - { - throw new NotImplementedException(); - } - - public override IUUserDefinedEnum CreateUUserDefinedEnum(IntPtr ptr) - { - throw new NotImplementedException(); - } - - public override IUFunction CreateUFunction(IntPtr ptr) - { - throw new NotImplementedException(); - } - - public override IFFieldClass CreateFFieldClass(IntPtr ptr) - { - throw new NotImplementedException(); - } - - public override IFField CreateFField(IntPtr ptr) - { - throw new NotImplementedException(); - } - - public override IFStructParams CreateFStructParams(IntPtr ptr) - { - throw new NotImplementedException(); - } - - public override IFPropertyParams CreateFPropertyParams(IntPtr ptr) - { - throw new NotImplementedException(); - } - - public override IFGenericPropertyParams CreateFGenericPropertyParams(IntPtr ptr) - { - throw new NotImplementedException(); - } - - public override IFWorldContext CreateFWorldContext(IntPtr ptr) - { - throw new NotImplementedException(); - } - - public override IUEngine CreateUEngine(IntPtr ptr) - { - throw new NotImplementedException(); - } - - public override IUGameInstance CreateUGameInstance(IntPtr ptr) - { - throw new NotImplementedException(); - } - - public override IFStaticConstructObjectParameters CreateFStaticConstructObjectParameters() - { - throw new NotImplementedException(); - } - - public override IFActorSpawnParameters CreateFActorSpawnParameters() - { - throw new NotImplementedException(); - } +public unsafe class UClass_UE5_0_3(nint ptr, IUnrealFactory factory, IUnrealMemoryInternal memory) + : UStruct_UE5_2_1(ptr, factory, memory), IUClass +{ + private readonly UClass* _self = (UClass*)ptr; + + public IUClass? GetSuperClass() + => _self->_super.super_struct != null ? _factory.CreateUClass((nint)_self->_super.super_struct) : null; + + public IUFunction? GetFunction(string Name) + { + var FuncMapDict = new TMapDictionary>( + (TMap>*)(&_self->func_map), factory.Memory + ); + return FuncMapDict.TryGetValue(new(Name), out var Function) + ? factory.CreateUFunction((nint)Function.Value->Value) + : null; + } + + public IEnumerable GetFunctions() + { + var FuncMapDict = new TMapDictionary>( + (TMap>*)(&_self->func_map), _factory.Memory + ); + return FuncMapDict.Values.Select(x => _factory.CreateUFunction((nint)x.Value->Value)); + } + + public IUObject? ClassDefaultObject + => _self->class_default_obj != null ? factory.CreateUObject((nint)_self->class_default_obj) : null; + + public nint Constructor => _self->class_ctor; + public EClassFlags ClassFlags => _self->class_flags; + public EClassCastFlags ClassCastFlags => _self->class_cast_flags; } \ No newline at end of file diff --git a/UE.Toolkit.Core/Types/Unreal/Factories/UE5_1_1/UnrealFactory.cs b/UE.Toolkit.Core/Types/Unreal/Factories/UE5_1_1/UnrealFactory.cs index 38dc2bd..2cea2dd 100644 --- a/UE.Toolkit.Core/Types/Unreal/Factories/UE5_1_1/UnrealFactory.cs +++ b/UE.Toolkit.Core/Types/Unreal/Factories/UE5_1_1/UnrealFactory.cs @@ -134,6 +134,11 @@ public override IFField CreateFField(IntPtr ptr) throw new NotImplementedException(); } + public override IFFieldVariant CreateFFieldVariant(IntPtr ptr) + { + throw new NotImplementedException(); + } + public override IFStructParams CreateFStructParams(IntPtr ptr) { throw new NotImplementedException(); diff --git a/UE.Toolkit.Core/Types/Unreal/Factories/UE5_2_1/UnrealFactory.cs b/UE.Toolkit.Core/Types/Unreal/Factories/UE5_2_1/UnrealFactory.cs index 0e6a0ce..60689ef 100644 --- a/UE.Toolkit.Core/Types/Unreal/Factories/UE5_2_1/UnrealFactory.cs +++ b/UE.Toolkit.Core/Types/Unreal/Factories/UE5_2_1/UnrealFactory.cs @@ -1,4 +1,5 @@ using System.Runtime.InteropServices; +using UE.Toolkit.Core.Types.Interfaces; using UE.Toolkit.Core.Types.Unreal.Factories.Interfaces; using UE.Toolkit.Core.Types.Unreal.Factories.UE5_4_4; using UE.Toolkit.Core.Types.Unreal.UE5_4_4; @@ -21,6 +22,8 @@ using FPropertyParamsBase = UE.Toolkit.Core.Types.Unreal.UE4_27_2.FPropertyParamsBase; using FStructParams = UE.Toolkit.Core.Types.Unreal.UE4_27_2.FStructParams; +using FField = UE.Toolkit.Core.Types.Unreal.UE4_27_2.FField; + namespace UE.Toolkit.Core.Types.Unreal.Factories.UE5_2_1; public class UnrealFactory : BaseUnrealFactory @@ -73,30 +76,31 @@ public override nint SizeOf() public override IFOptionalProperty CreateFOptionalProperty(nint ptr) => throw new NotSupportedException(); public override IFDelegateProperty CreateFDelegateProperty(nint ptr) => new UE4_27_2.FDelegatePropertyUE4_27_2(ptr, this); public override IUObjectArray CreateUObjectArray(nint ptr) => new UObjectArray_UE5_4_4(ptr, this); - public override IUObject CreateUObject(nint ptr) => new UObject_UE5_4_4(ptr, this); - public override IUClass CreateUClass(nint ptr) => new UClass_UE5_2_1(ptr, this); - public override IUScriptStruct CreateUScriptStruct(nint ptr) => new UScriptStruct_UE5_2_1(ptr, this); - public override IUEnum CreateUEnum(nint ptr) => new UEnum_UE5_4_4(ptr, this); - public override IUField CreateUField(nint ptr) => new UField_UE5_4_4(ptr, this); - public override IUStruct CreateUStruct(nint ptr) => new UStruct_UE5_2_1(ptr, this); - public override IUUserDefinedEnum CreateUUserDefinedEnum(nint ptr) => new UUserDefinedEnum_UE5_4_4(ptr, this); - public override IUFunction CreateUFunction(nint ptr) => new UFunction_UE5_4_4(ptr, this); + public override IUObject CreateUObject(nint ptr) => new UObject_UE5_4_4(ptr, this, Memory); + public override IUClass CreateUClass(nint ptr) => new UClass_UE5_2_1(ptr, this, Memory); + public override IUScriptStruct CreateUScriptStruct(nint ptr) => new UScriptStruct_UE5_2_1(ptr, this, Memory); + public override IUEnum CreateUEnum(nint ptr) => new UEnum_UE5_4_4(ptr, this, Memory); + public override IUField CreateUField(nint ptr) => new UField_UE5_4_4(ptr, this, Memory); + public override IUStruct CreateUStruct(nint ptr) => new UStruct_UE5_2_1(ptr, this, Memory); + public override IUUserDefinedEnum CreateUUserDefinedEnum(nint ptr) => new UUserDefinedEnum_UE5_4_4(ptr, this, Memory); + public override IUFunction CreateUFunction(nint ptr) => new UFunction_UE5_4_4(ptr, this, Memory); public override IFFieldClass CreateFFieldClass(nint ptr) => new FFieldClass_UE5_4_4(ptr, this); - public override IFField CreateFField(nint ptr) => new FField_UE5_4_4(ptr, this); + public override IFField CreateFField(nint ptr) => new FField_UE5_2_1(ptr, this); + public override IFFieldVariant CreateFFieldVariant(nint ptr) => new UE4_27_2.FFieldVariantUE4_27_2(ptr, this); public override IFStructParams CreateFStructParams(nint ptr) => new FStructParams_UE5_2_1(ptr, this); public override IFPropertyParams CreateFPropertyParams(nint ptr) => new FPropertyParams_UE5_2_1(ptr, this); public override IFGenericPropertyParams CreateFGenericPropertyParams(nint ptr) => new FGenericPropertyParams_UE5_2_1(ptr, this); public override IFWorldContext CreateFWorldContext(nint ptr) => new FWorldContext_UE5_4_4(ptr, this); - public override IUEngine CreateUEngine(nint ptr) => new UEngine_UE5_4_4(ptr, this); - public override IUGameInstance CreateUGameInstance(nint ptr) => new UGameInstance_UE5_4_4(ptr, this); + public override IUEngine CreateUEngine(nint ptr) => new UEngine_UE5_4_4(ptr, this, Memory); + public override IUGameInstance CreateUGameInstance(nint ptr) => new UGameInstance_UE5_4_4(ptr, this, Memory); public override IFStaticConstructObjectParameters CreateFStaticConstructObjectParameters() => new FStaticConstructObjectParameters_UE5_4_4(this); public override IFActorSpawnParameters CreateFActorSpawnParameters() => new FActorSpawnParameters_UE5_4_4(this); } -public unsafe class UScriptStruct_UE5_2_1(nint ptr, IUnrealFactory factory) - : UStruct_UE5_2_1(ptr, factory), IUScriptStruct +public unsafe class UScriptStruct_UE5_2_1(nint ptr, IUnrealFactory factory, IUnrealMemoryInternal memory) + : UStruct_UE5_2_1(ptr, factory, memory), IUScriptStruct { private readonly UScriptStruct* _self = (UScriptStruct*)ptr; public EStructFlags StructFlags => _self->StructFlags; @@ -104,8 +108,8 @@ public unsafe class UScriptStruct_UE5_2_1(nint ptr, IUnrealFactory factory) public nint CppStructOps => _self->CppStructOps; } -public unsafe class UStruct_UE5_2_1(nint ptr, IUnrealFactory factory) - : UField_UE5_4_4(ptr, factory), IUStruct +public unsafe class UStruct_UE5_2_1(nint ptr, IUnrealFactory factory, IUnrealMemoryInternal memory) + : UField_UE5_4_4(ptr, factory, memory), IUStruct { private readonly UStruct* _self = (UStruct*)ptr; @@ -134,8 +138,8 @@ public IEnumerable PostConstructLink _factory); } -public unsafe class UClass_UE5_2_1(nint ptr, IUnrealFactory factory) - : UStruct_UE5_2_1(ptr, factory), IUClass +public unsafe class UClass_UE5_2_1(nint ptr, IUnrealFactory factory, IUnrealMemoryInternal memory) + : UStruct_UE5_2_1(ptr, factory, memory), IUClass { private readonly UClass* _self = (UClass*)ptr; @@ -144,19 +148,29 @@ public unsafe class UClass_UE5_2_1(nint ptr, IUnrealFactory factory) public IUFunction? GetFunction(string Name) { - var FuncMapDict = new TMapDictionary( - (TMap*)(&_self->FuncMap), factory.Memory + var FuncMapDict = new TMapDictionary>( + (TMap>*)(&_self->FuncMap), factory.Memory ); return FuncMapDict.TryGetValue(new(Name), out var Function) - ? factory.CreateUFunction((nint)Function.Value) + ? factory.CreateUFunction((nint)Function.Value->Value) : null; } + public IEnumerable GetFunctions() + { + var FuncMapDict = new TMapDictionary>( + (TMap>*)(&_self->FuncMap), + _factory.Memory + ); + return FuncMapDict.Values.Select(x => _factory.CreateUFunction((nint)x.Value->Value)); + } + public IUObject? ClassDefaultObject => _self->ClassDefaultObject != null ? factory.CreateUObject((nint)_self->ClassDefaultObject ) : null; public nint Constructor => _self->ClassConstructor; public EClassFlags ClassFlags => _self->ClassFlags; + public EClassCastFlags ClassCastFlags => _self->ClassCastFlags; } public unsafe class FStructParams_UE5_2_1(nint ptr, IUnrealFactory factory) : IFStructParams @@ -203,4 +217,31 @@ public unsafe class FGenericPropertyParams_UE5_2_1(nint ptr, IUnrealFactory fact public int ArrayDim => _self->Super.ArrayDim; public int Offset => _self->Super.Offset; +} + +public unsafe class FField_UE5_2_1(nint ptr, IUnrealFactory factory) + : IFField +{ + private readonly FField* _self = (FField*)ptr; + protected readonly IUnrealFactory _factory = factory; + + public nint Ptr => ptr; + public nint VTable => _self->_vtable; + public IFFieldClass ClassPrivate => _factory.CreateFFieldClass((nint)_self->class_private); + public IFFieldVariant Owner => factory.CreateFFieldVariant((nint)(&_self->owner)); + public IFField? Next => _self->next != null ? _factory.CreateFField((nint)_self->next) : null; + public string NamePrivate => _self->name_private.ToString(); + public EObjectFlags FlagsPrivate => _self->flags_private; + + public void SetOwnerUObject(IUObject owner) + { + _self->owner.Object = (Unreal.UE4_27_2.UObjectBase*)owner.Ptr; + _self->owner.bIsUObject = true; + } + + public void SetOwnerFField(IFField owner) + { + _self->owner.Field = (FField*)owner.Ptr; + _self->owner.bIsUObject = false; + } } \ No newline at end of file diff --git a/UE.Toolkit.Core/Types/Unreal/Factories/UE5_3_2/UnrealFactory.cs b/UE.Toolkit.Core/Types/Unreal/Factories/UE5_3_2/UnrealFactory.cs index 315ef45..681b6a5 100644 --- a/UE.Toolkit.Core/Types/Unreal/Factories/UE5_3_2/UnrealFactory.cs +++ b/UE.Toolkit.Core/Types/Unreal/Factories/UE5_3_2/UnrealFactory.cs @@ -134,6 +134,11 @@ public override IFField CreateFField(IntPtr ptr) throw new NotImplementedException(); } + public override IFFieldVariant CreateFFieldVariant(IntPtr ptr) + { + throw new NotImplementedException(); + } + public override IFStructParams CreateFStructParams(IntPtr ptr) { throw new NotImplementedException(); diff --git a/UE.Toolkit.Core/Types/Unreal/Factories/UE5_4_4/UnrealFactory.cs b/UE.Toolkit.Core/Types/Unreal/Factories/UE5_4_4/UnrealFactory.cs index c517688..c0dc7b9 100644 --- a/UE.Toolkit.Core/Types/Unreal/Factories/UE5_4_4/UnrealFactory.cs +++ b/UE.Toolkit.Core/Types/Unreal/Factories/UE5_4_4/UnrealFactory.cs @@ -2,6 +2,7 @@ using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; using UE.Toolkit.Core.Common; +using UE.Toolkit.Core.Types.Interfaces; using UE.Toolkit.Core.Types.Unreal.Factories.Interfaces; using UE.Toolkit.Core.Types.Unreal.UE5_4_4; @@ -58,22 +59,23 @@ public override nint SizeOf() public override IFOptionalProperty CreateFOptionalProperty(nint ptr) => new FOptionalProperty_UE5_4_4(ptr, this); public override IFDelegateProperty CreateFDelegateProperty(nint ptr) => new FDelegateProperty_UE5_4_4(ptr, this); public override IUObjectArray CreateUObjectArray(nint ptr) => new UObjectArray_UE5_4_4(ptr, this); - public override IUObject CreateUObject(nint ptr) => new UObject_UE5_4_4(ptr, this); - public override IUClass CreateUClass(nint ptr) => new UClass_UE5_4_4(ptr, this); - public override IUScriptStruct CreateUScriptStruct(nint ptr) => new UScriptStruct_UE5_4_4(ptr, this); - public override IUEnum CreateUEnum(nint ptr) => new UEnum_UE5_4_4(ptr, this); - public override IUField CreateUField(nint ptr) => new UField_UE5_4_4(ptr, this); - public override IUStruct CreateUStruct(nint ptr) => new UStruct_UE5_4_4(ptr, this); - public override IUUserDefinedEnum CreateUUserDefinedEnum(nint ptr) => new UUserDefinedEnum_UE5_4_4(ptr, this); - public override IUFunction CreateUFunction(nint ptr) => new UFunction_UE5_4_4(ptr, this); + public override IUObject CreateUObject(nint ptr) => new UObject_UE5_4_4(ptr, this, Memory); + public override IUClass CreateUClass(nint ptr) => new UClass_UE5_4_4(ptr, this, Memory); + public override IUScriptStruct CreateUScriptStruct(nint ptr) => new UScriptStruct_UE5_4_4(ptr, this, Memory); + public override IUEnum CreateUEnum(nint ptr) => new UEnum_UE5_4_4(ptr, this, Memory); + public override IUField CreateUField(nint ptr) => new UField_UE5_4_4(ptr, this, Memory); + public override IUStruct CreateUStruct(nint ptr) => new UStruct_UE5_4_4(ptr, this, Memory); + public override IUUserDefinedEnum CreateUUserDefinedEnum(nint ptr) => new UUserDefinedEnum_UE5_4_4(ptr, this, Memory); + public override IUFunction CreateUFunction(nint ptr) => new UFunction_UE5_4_4(ptr, this, Memory); public override IFFieldClass CreateFFieldClass(nint ptr) => new FFieldClass_UE5_4_4(ptr, this); public override IFField CreateFField(nint ptr) => new FField_UE5_4_4(ptr, this); + public override IFFieldVariant CreateFFieldVariant(nint ptr) => new FFieldVariantUE5_4_4(ptr, this); public override IFStructParams CreateFStructParams(nint ptr) => new FStructParams_UE5_4_4(ptr, this); public override IFPropertyParams CreateFPropertyParams(nint ptr) => new FPropertyParams_UE5_4_4(ptr, this); public override IFGenericPropertyParams CreateFGenericPropertyParams(nint ptr) => new FGenericPropertyParams_UE5_4_4(ptr, this); public override IFWorldContext CreateFWorldContext(nint ptr) => new FWorldContext_UE5_4_4(ptr, this); - public override IUEngine CreateUEngine(nint ptr) => new UEngine_UE5_4_4(ptr, this); - public override IUGameInstance CreateUGameInstance(nint ptr) => new UGameInstance_UE5_4_4(ptr, this); + public override IUEngine CreateUEngine(nint ptr) => new UEngine_UE5_4_4(ptr, this, Memory); + public override IUGameInstance CreateUGameInstance(nint ptr) => new UGameInstance_UE5_4_4(ptr, this, Memory); public override IFStaticConstructObjectParameters CreateFStaticConstructObjectParameters() => new FStaticConstructObjectParameters_UE5_4_4(this); public override IFActorSpawnParameters CreateFActorSpawnParameters() @@ -169,10 +171,26 @@ public unsafe class FField_UE5_4_4(nint ptr, IUnrealFactory factory) public nint Ptr => ptr; public nint VTable => _self->VTable; public IFFieldClass ClassPrivate => _factory.CreateFFieldClass((nint)_self->ClassPrivate); - public FFieldObjectUnion Owner => _self->Owner; + public IFFieldVariant Owner => factory.CreateFFieldVariant((nint)(&_self->Owner)); public IFField? Next => _self->Next != null ? _factory.CreateFField((nint)_self->Next) : null; public string NamePrivate => _self->NamePrivate.ToString(); public EObjectFlags FlagsPrivate => _self->FlagsPrivate; + + public void SetOwnerUObject(IUObject owner) => _self->Owner.Object = (UObjectBase*)(owner.Ptr + 1); + + public void SetOwnerFField(IFField owner) => _self->Owner.Field = (FField*)owner.Ptr; +} + +public unsafe class FFieldVariantUE5_4_4(nint ptr, IUnrealFactory factory) + : IFFieldVariant +{ + private readonly FFieldObjectUnion* _self = (FFieldObjectUnion*)ptr; + protected readonly IUnrealFactory _factory = factory; + + public nint Ptr => ptr; + public IFField? Field => _self->Field != null ? _factory.CreateFField((nint)_self->Field) : null; + public IUObject? Object => _self->Object != null ? _factory.CreateUObject((nint)(_self->Object) + 1) : null; + public bool IsObject => ((nint)_self->Object & 1) != 0; } public unsafe class FProperty_UE5_4_4(nint ptr, IUnrealFactory factory) @@ -265,14 +283,14 @@ public unsafe class FByteProperty_UE5_4_4(nint ptr, IUnrealFactory factory) public IUEnum? Enum => ((FByteProperty*)Ptr)->Enum != null ? _factory.CreateUEnum((nint)((FByteProperty*)Ptr)->Enum) : null; } -public unsafe class UUserDefinedEnum_UE5_4_4(nint ptr, IUnrealFactory factory) - : UEnum_UE5_4_4(ptr, factory), IUUserDefinedEnum +public unsafe class UUserDefinedEnum_UE5_4_4(nint ptr, IUnrealFactory factory, IUnrealMemoryInternal memory) + : UEnum_UE5_4_4(ptr, factory, memory), IUUserDefinedEnum { public TMap DisplayNameMap => ((UUserDefinedEnum*)Ptr)->DisplayNameMap; } -public unsafe class UEnum_UE5_4_4(nint ptr, IUnrealFactory factory) - : UField_UE5_4_4(ptr, factory), IUEnum +public unsafe class UEnum_UE5_4_4(nint ptr, IUnrealFactory factory, IUnrealMemoryInternal memory) + : UField_UE5_4_4(ptr, factory, memory), IUEnum { private readonly UEnum* _self = (UEnum*)ptr; public string CppType => _self->CppType.ToString(); @@ -302,8 +320,8 @@ public bool TryParse(string name, bool ignoreCase, [NotNullWhen(true)] out long? } } -public unsafe class UScriptStruct_UE5_4_4(nint ptr, IUnrealFactory factory) - : UStruct_UE5_4_4(ptr, factory), IUScriptStruct +public unsafe class UScriptStruct_UE5_4_4(nint ptr, IUnrealFactory factory, IUnrealMemoryInternal memory) + : UStruct_UE5_4_4(ptr, factory, memory), IUScriptStruct { private readonly UScriptStruct* _self = (UScriptStruct*)ptr; public EStructFlags StructFlags => _self->StructFlags; @@ -311,8 +329,8 @@ public unsafe class UScriptStruct_UE5_4_4(nint ptr, IUnrealFactory factory) public nint CppStructOps => _self->CppStructOps; } -public unsafe class UStruct_UE5_4_4(nint ptr, IUnrealFactory factory) - : UField_UE5_4_4(ptr, factory), IUStruct +public unsafe class UStruct_UE5_4_4(nint ptr, IUnrealFactory factory, IUnrealMemoryInternal memory) + : UField_UE5_4_4(ptr, factory, memory), IUStruct { private readonly UStruct* _self = (UStruct*)ptr; @@ -405,8 +423,8 @@ public void Dispose() { } IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); } -public unsafe class UField_UE5_4_4(nint ptr, IUnrealFactory factory) - : UObject_UE5_4_4(ptr, factory), IUField +public unsafe class UField_UE5_4_4(nint ptr, IUnrealFactory factory, IUnrealMemoryInternal memory) + : UObject_UE5_4_4(ptr, factory, memory), IUField { private readonly UField* _self = (UField*)ptr; @@ -414,36 +432,32 @@ public IUField? Next => _self->Next != null ? _factory.CreateUField((nint)_self->Next) : null; } -public unsafe class UObject_UE5_4_4(nint ptr, IUnrealFactory factory) : IUObject +public unsafe class UObject_UE5_4_4(nint ptr, IUnrealFactory factory, IUnrealMemoryInternal memory) + : BaseUObject(ptr, factory, memory) { - private readonly UObjectBase* _self = (UObjectBase*)ptr; - protected readonly IUnrealFactory _factory = factory; + public override nint VTable => _self->VTable; - public nint Ptr => (nint)_self; - - public nint VTable => _self->VTable; - - public EObjectFlags ObjectFlags => _self->ObjectFlags; + public override EObjectFlags ObjectFlags => _self->ObjectFlags; - public int InternalIndex => _self->InternalIndex; + public override int InternalIndex => _self->InternalIndex; - public IUClass ClassPrivate => _factory.CreateUClass((nint)_self->ClassPrivate); + public override IUClass ClassPrivate => _factory.CreateUClass((nint)_self->ClassPrivate); - public FName NamePrivate => _self->NamePrivate; + public override FName NamePrivate => _self->NamePrivate; - public IUObject? OuterPrivate => _self->OuterPrivate != null ? _factory.CreateUObject((nint)_self->OuterPrivate) : null; + public override IUObject? OuterPrivate => _self->OuterPrivate != null ? _factory.CreateUObject((nint)_self->OuterPrivate) : null; - public bool IsChildOf(string type) => _self->IsChildOf(type); + public override bool IsChildOf(string type) => _self->IsChildOf(type); - public IUObject GetOutermost() => _factory.CreateUObject((nint)_self->GetOutermost()); + public override IUObject GetOutermost() => _factory.CreateUObject((nint)_self->GetOutermost()); - public string GetNativeName() => ToolkitUtils.GetNativeName(this); + public override string GetNativeName() => ToolkitUtils.GetNativeName(this); - public string GetPathName() => ToolkitUtils.GetPathName(this); + public override string GetPathName() => ToolkitUtils.GetPathName(this); } -public unsafe class UClass_UE5_4_4(nint ptr, IUnrealFactory factory) - : UStruct_UE5_4_4(ptr, factory), IUClass +public unsafe class UClass_UE5_4_4(nint ptr, IUnrealFactory factory, IUnrealMemoryInternal memory) + : UStruct_UE5_4_4(ptr, factory, memory), IUClass { private readonly UClass* _self = (UClass*)ptr; @@ -452,23 +466,33 @@ public unsafe class UClass_UE5_4_4(nint ptr, IUnrealFactory factory) public IUFunction? GetFunction(string Name) { - var FuncMapDict = new TMapDictionary( - (TMap*)(&_self->FuncMap), factory.Memory + var FuncMapDict = new TMapDictionary>( + (TMap>*)(&_self->FuncMap), factory.Memory ); return FuncMapDict.TryGetValue(new(Name), out var Function) - ? factory.CreateUFunction((nint)Function.Value) + ? factory.CreateUFunction((nint)Function.Value->Value) : null; } + public IEnumerable GetFunctions() + { + var FuncMapDict = new TMapDictionary>( + (TMap>*)(&_self->FuncMap), + _factory.Memory + ); + return FuncMapDict.Values.Select(x => _factory.CreateUFunction((nint)x.Value->Value)); + } + public IUObject? ClassDefaultObject => _self->ClassDefaultObject != null ? factory.CreateUObject((nint)_self->ClassDefaultObject ) : null; public nint Constructor => _self->ClassConstructor; public EClassFlags ClassFlags => _self->ClassFlags; + public EClassCastFlags ClassCastFlags => _self->ClassCastFlags; } -public unsafe class UFunction_UE5_4_4(nint ptr, IUnrealFactory factory) - : UStruct_UE5_4_4(ptr, factory), IUFunction +public unsafe class UFunction_UE5_4_4(nint ptr, IUnrealFactory factory, IUnrealMemoryInternal memory) + : UStruct_UE5_4_4(ptr, factory, memory), IUFunction { private readonly UFunction* _self = (UFunction*)ptr; @@ -480,7 +504,7 @@ public unsafe class UFunction_UE5_4_4(nint ptr, IUnrealFactory factory) public int GetTotalParameterSize() { var LastProperty = ChildProperties.Any() ? _factory.CreateFProperty(ChildProperties.Last().Ptr) : null; - return LastProperty != null ? LastProperty!.Offset_Internal + LastProperty!.ElementSize : 0; + return LastProperty != null ? LastProperty.Offset_Internal + LastProperty.ElementSize : 0; } public nint FunctionPtr => (nint)_self->Func; @@ -629,8 +653,8 @@ public void Dispose() {} #endregion } -public unsafe class UEngine_UE5_4_4(nint ptr, IUnrealFactory factory) - : UObject_UE5_4_4(ptr, factory), IUEngine +public unsafe class UEngine_UE5_4_4(nint ptr, IUnrealFactory factory, IUnrealMemoryInternal memory) + : UObject_UE5_4_4(ptr, factory, memory), IUEngine { private readonly UEngine* _self = (UEngine*)ptr; @@ -719,8 +743,8 @@ protected virtual void Disposing() #endregion } -public unsafe class UGameInstance_UE5_4_4(nint ptr, IUnrealFactory factory) - : UObject_UE5_4_4(ptr, factory), IUGameInstance +public unsafe class UGameInstance_UE5_4_4(nint ptr, IUnrealFactory factory, IUnrealMemoryInternal memory) + : UObject_UE5_4_4(ptr, factory, memory), IUGameInstance { private readonly UGameInstance* _self = (UGameInstance*)ptr; diff --git a/UE.Toolkit.Core/Types/Unreal/Factories/UE5_5_4/UnrealFactory.cs b/UE.Toolkit.Core/Types/Unreal/Factories/UE5_5_4/UnrealFactory.cs index d468253..74b001b 100644 --- a/UE.Toolkit.Core/Types/Unreal/Factories/UE5_5_4/UnrealFactory.cs +++ b/UE.Toolkit.Core/Types/Unreal/Factories/UE5_5_4/UnrealFactory.cs @@ -134,6 +134,11 @@ public override IFField CreateFField(IntPtr ptr) throw new NotImplementedException(); } + public override IFFieldVariant CreateFFieldVariant(IntPtr ptr) + { + throw new NotImplementedException(); + } + public override IFStructParams CreateFStructParams(IntPtr ptr) { throw new NotImplementedException(); diff --git a/UE.Toolkit.Core/Types/Unreal/Factories/UE5_6_1/UnrealFactory.cs b/UE.Toolkit.Core/Types/Unreal/Factories/UE5_6_1/UnrealFactory.cs index fee2b12..8f79910 100644 --- a/UE.Toolkit.Core/Types/Unreal/Factories/UE5_6_1/UnrealFactory.cs +++ b/UE.Toolkit.Core/Types/Unreal/Factories/UE5_6_1/UnrealFactory.cs @@ -1,3 +1,4 @@ +using UE.Toolkit.Core.Types.Interfaces; using UE.Toolkit.Core.Types.Unreal.Factories.Interfaces; using UE.Toolkit.Core.Types.Unreal.Factories.UE5_4_4; using UE.Toolkit.Core.Types.Unreal.UE5_4_4; @@ -54,30 +55,31 @@ public override nint SizeOf() public override IFOptionalProperty CreateFOptionalProperty(nint ptr) => new FOptionalProperty_UE5_4_4(ptr, this); public override IFDelegateProperty CreateFDelegateProperty(nint ptr) => new FDelegateProperty_UE5_4_4(ptr, this); public override IUObjectArray CreateUObjectArray(nint ptr) => new UObjectArray_UE5_4_4(ptr, this); - public override IUObject CreateUObject(nint ptr) => new UObject_UE5_4_4(ptr, this); - public override IUClass CreateUClass(nint ptr) => new UClass_UE5_6_1(ptr, this); - public override IUScriptStruct CreateUScriptStruct(nint ptr) => new UScriptStruct_UE5_6_1(ptr, this); - public override IUEnum CreateUEnum(nint ptr) => new UEnum_UE5_4_4(ptr, this); - public override IUField CreateUField(nint ptr) => new UField_UE5_4_4(ptr, this); - public override IUStruct CreateUStruct(nint ptr) => new UStruct_UE5_6_1(ptr, this); - public override IUUserDefinedEnum CreateUUserDefinedEnum(nint ptr) => new UUserDefinedEnum_UE5_4_4(ptr, this); - public override IUFunction CreateUFunction(nint ptr) => new UFunction_UE5_4_4(ptr, this); + public override IUObject CreateUObject(nint ptr) => new UObject_UE5_4_4(ptr, this, Memory); + public override IUClass CreateUClass(nint ptr) => new UClass_UE5_6_1(ptr, this, Memory); + public override IUScriptStruct CreateUScriptStruct(nint ptr) => new UScriptStruct_UE5_6_1(ptr, this, Memory); + public override IUEnum CreateUEnum(nint ptr) => new UEnum_UE5_4_4(ptr, this, Memory); + public override IUField CreateUField(nint ptr) => new UField_UE5_4_4(ptr, this, Memory); + public override IUStruct CreateUStruct(nint ptr) => new UStruct_UE5_6_1(ptr, this, Memory); + public override IUUserDefinedEnum CreateUUserDefinedEnum(nint ptr) => new UUserDefinedEnum_UE5_4_4(ptr, this, Memory); + public override IUFunction CreateUFunction(nint ptr) => new UFunction_UE5_6_1(ptr, this, Memory); public override IFFieldClass CreateFFieldClass(nint ptr) => new FFieldClass_UE5_4_4(ptr, this); public override IFField CreateFField(nint ptr) => new FField_UE5_4_4(ptr, this); + public override IFFieldVariant CreateFFieldVariant(nint ptr) => new FFieldVariantUE5_4_4(ptr, this); public override IFStructParams CreateFStructParams(nint ptr) => new FStructParams_UE5_4_4(ptr, this); public override IFPropertyParams CreateFPropertyParams(nint ptr) => new FPropertyParams_UE5_4_4(ptr, this); public override IFGenericPropertyParams CreateFGenericPropertyParams(nint ptr) => new FGenericPropertyParams_UE5_4_4(ptr, this); public override IFWorldContext CreateFWorldContext(nint ptr) => new FWorldContext_UE5_4_4(ptr, this); - public override IUEngine CreateUEngine(nint ptr) => new UEngine_UE5_4_4(ptr, this); - public override IUGameInstance CreateUGameInstance(nint ptr) => new UGameInstance_UE5_4_4(ptr, this); + public override IUEngine CreateUEngine(nint ptr) => new UEngine_UE5_4_4(ptr, this, Memory); + public override IUGameInstance CreateUGameInstance(nint ptr) => new UGameInstance_UE5_4_4(ptr, this, Memory); public override IFStaticConstructObjectParameters CreateFStaticConstructObjectParameters() => new FStaticConstructObjectParameters_UE5_4_4(this); public override IFActorSpawnParameters CreateFActorSpawnParameters() => new FActorSpawnParameters_UE5_4_4(this); } -public unsafe class UStruct_UE5_6_1(nint ptr, IUnrealFactory factory) - : UField_UE5_4_4(ptr, factory), IUStruct +public unsafe class UStruct_UE5_6_1(nint ptr, IUnrealFactory factory, IUnrealMemoryInternal memory) + : UField_UE5_4_4(ptr, factory, memory), IUStruct { private readonly UStruct* _self = (UStruct*)ptr; @@ -106,8 +108,8 @@ public IEnumerable PostConstructLink _factory); } -public unsafe class UScriptStruct_UE5_6_1(nint ptr, IUnrealFactory factory) - : UStruct_UE5_6_1(ptr, factory), IUScriptStruct +public unsafe class UScriptStruct_UE5_6_1(nint ptr, IUnrealFactory factory, IUnrealMemoryInternal memory) + : UStruct_UE5_6_1(ptr, factory, memory), IUScriptStruct { private readonly UScriptStruct* _self = (UScriptStruct*)ptr; public EStructFlags StructFlags => _self->StructFlags; @@ -115,8 +117,8 @@ public unsafe class UScriptStruct_UE5_6_1(nint ptr, IUnrealFactory factory) public nint CppStructOps => _self->CppStructOps; } -public unsafe class UClass_UE5_6_1(nint ptr, IUnrealFactory factory) - : UStruct_UE5_6_1(ptr, factory), IUClass +public unsafe class UClass_UE5_6_1(nint ptr, IUnrealFactory factory, IUnrealMemoryInternal memory) + : UStruct_UE5_6_1(ptr, factory, memory), IUClass { private readonly UClass* _self = (UClass*)ptr; @@ -125,17 +127,46 @@ public unsafe class UClass_UE5_6_1(nint ptr, IUnrealFactory factory) public IUFunction? GetFunction(string Name) { - var FuncMapDict = new TMapDictionary( - (TMap*)(&_self->FuncMap), factory.Memory + var FuncMapDict = new TMapDictionary>( + (TMap>*)(&_self->FuncMap), factory.Memory ); return FuncMapDict.TryGetValue(new(Name), out var Function) - ? factory.CreateUFunction((nint)Function.Value) + ? factory.CreateUFunction((nint)Function.Value->Value) : null; } + public IEnumerable GetFunctions() + { + var FuncMapDict = new TMapDictionary>( + (TMap>*)(&_self->FuncMap), + _factory.Memory + ); + return FuncMapDict.Values.Select(x => _factory.CreateUFunction((nint)x.Value->Value)); + } + public IUObject? ClassDefaultObject => _self->ClassDefaultObject != null ? factory.CreateUObject((nint)_self->ClassDefaultObject ) : null; public nint Constructor => _self->ClassConstructor; public EClassFlags ClassFlags => _self->ClassFlags; + public EClassCastFlags ClassCastFlags => _self->ClassCastFlags; +} + +public unsafe class UFunction_UE5_6_1(nint ptr, IUnrealFactory factory, IUnrealMemoryInternal memory) + : UStruct_UE5_6_1(ptr, factory, memory), IUFunction +{ + private readonly UFunction* _self = (UFunction*)ptr; + + public EFunctionFlags FunctionFlags => _self->FunctionFlags; + public int ParamCount => _self->NumParms; + public int ParamSize => _self->ParmsSize; + public int ReturnValueOffset => _self->ReturnValueOffset; + + public int GetTotalParameterSize() + { + var LastProperty = ChildProperties.Any() ? _factory.CreateFProperty(ChildProperties.Last().Ptr) : null; + return LastProperty != null ? LastProperty.Offset_Internal + LastProperty.ElementSize : 0; + } + + public nint FunctionPtr => (nint)_self->Func; } \ No newline at end of file diff --git a/UE.Toolkit.Core/Types/Unreal/Factories/UE5_7_4/UnrealFactory.cs b/UE.Toolkit.Core/Types/Unreal/Factories/UE5_7_4/UnrealFactory.cs index 266f10f..d3f218f 100644 --- a/UE.Toolkit.Core/Types/Unreal/Factories/UE5_7_4/UnrealFactory.cs +++ b/UE.Toolkit.Core/Types/Unreal/Factories/UE5_7_4/UnrealFactory.cs @@ -5,6 +5,7 @@ using UE.Toolkit.Core.Types.Unreal.Factories.UE5_4_4; using UE.Toolkit.Core.Types.Unreal.UE5_4_4; using FFieldClass = UE.Toolkit.Core.Types.Unreal.UE5_7_4.FFieldClass; +using UClass = UE.Toolkit.Core.Types.Unreal.UE5_7_4.UClass; namespace UE.Toolkit.Core.Types.Unreal.Factories.UE5_7_4; @@ -56,22 +57,23 @@ public override nint SizeOf() public override IFOptionalProperty CreateFOptionalProperty(nint ptr) => new FOptionalProperty_UE5_4_4(ptr, this); public override IFDelegateProperty CreateFDelegateProperty(nint ptr) => new FDelegateProperty_UE5_4_4(ptr, this); public override IUObjectArray CreateUObjectArray(nint ptr) => new UObjectArray_UE5_7_4(ptr, this); - public override IUObject CreateUObject(nint ptr) => new UObject_UE5_4_4(ptr, this); - public override IUClass CreateUClass(nint ptr) => new UE5_6_1.UClass_UE5_6_1(ptr, this); - public override IUScriptStruct CreateUScriptStruct(nint ptr) => new UE5_6_1.UScriptStruct_UE5_6_1(ptr, this); - public override IUEnum CreateUEnum(nint ptr) => new UEnum_UE5_7_4(ptr, this); - public override IUField CreateUField(nint ptr) => new UField_UE5_4_4(ptr, this); - public override IUStruct CreateUStruct(nint ptr) => new UE5_6_1.UStruct_UE5_6_1(ptr, this); - public override IUUserDefinedEnum CreateUUserDefinedEnum(nint ptr) => new UUserDefinedEnum_UE5_4_4(ptr, this); - public override IUFunction CreateUFunction(nint ptr) => new UFunction_UE5_4_4(ptr, this); + public override IUObject CreateUObject(nint ptr) => new UObject_UE5_4_4(ptr, this, Memory); + public override IUClass CreateUClass(nint ptr) => new UClass_UE5_7_4(ptr, this, Memory); + public override IUScriptStruct CreateUScriptStruct(nint ptr) => new UE5_6_1.UScriptStruct_UE5_6_1(ptr, this, Memory); + public override IUEnum CreateUEnum(nint ptr) => new UEnum_UE5_7_4(ptr, this, Memory); + public override IUField CreateUField(nint ptr) => new UField_UE5_4_4(ptr, this, Memory); + public override IUStruct CreateUStruct(nint ptr) => new UE5_6_1.UStruct_UE5_6_1(ptr, this, Memory); + public override IUUserDefinedEnum CreateUUserDefinedEnum(nint ptr) => new UUserDefinedEnum_UE5_4_4(ptr, this, Memory); + public override IUFunction CreateUFunction(nint ptr) => new UE5_6_1.UFunction_UE5_6_1(ptr, this, Memory); public override IFFieldClass CreateFFieldClass(nint ptr) => new FFieldClass_UE5_7_4(ptr, this); public override IFField CreateFField(nint ptr) => new FField_UE5_4_4(ptr, this); + public override IFFieldVariant CreateFFieldVariant(nint ptr) => new FFieldVariantUE5_4_4(ptr, this); public override IFStructParams CreateFStructParams(nint ptr) => new FStructParams_UE5_4_4(ptr, this); public override IFPropertyParams CreateFPropertyParams(nint ptr) => new FPropertyParams_UE5_4_4(ptr, this); public override IFGenericPropertyParams CreateFGenericPropertyParams(nint ptr) => new FGenericPropertyParams_UE5_4_4(ptr, this); public override IFWorldContext CreateFWorldContext(nint ptr) => new FWorldContext_UE5_4_4(ptr, this); - public override IUEngine CreateUEngine(nint ptr) => new UEngine_UE5_4_4(ptr, this); - public override IUGameInstance CreateUGameInstance(nint ptr) => new UGameInstance_UE5_4_4(ptr, this); + public override IUEngine CreateUEngine(nint ptr) => new UEngine_UE5_4_4(ptr, this, Memory); + public override IUGameInstance CreateUGameInstance(nint ptr) => new UGameInstance_UE5_4_4(ptr, this, Memory); public override IFStaticConstructObjectParameters CreateFStaticConstructObjectParameters() => new FStaticConstructObjectParameters_UE5_4_4(this); public override IFActorSpawnParameters CreateFActorSpawnParameters() @@ -126,8 +128,8 @@ public void RemoveFromRootSet(int idx) } } -public unsafe class UEnum_UE5_7_4(nint ptr, IUnrealFactory factory) - : UField_UE5_4_4(ptr, factory), IUEnum, IDisposable +public unsafe class UEnum_UE5_7_4(nint ptr, IUnrealFactory factory, IUnrealMemoryInternal memory) + : UField_UE5_4_4(ptr, factory, memory), IUEnum, IDisposable { private readonly Unreal.UE5_7_4.UEnum* _self = (Unreal.UE5_7_4.UEnum*)ptr; public string CppType => _self->CppType.ToString(); @@ -199,4 +201,39 @@ protected virtual void Dispose(bool disposing) if (disposing && CachedNames.Value.AllocatorInstance != null) _factory.Memory.Free((nint)CachedNames.Value.AllocatorInstance); } +} + +public unsafe class UClass_UE5_7_4(nint ptr, IUnrealFactory factory, IUnrealMemoryInternal memory) + : UE5_6_1.UStruct_UE5_6_1(ptr, factory, memory), IUClass +{ + private readonly UClass* _self = (UClass*)ptr; + + public IUClass? GetSuperClass() + => _self->GetSuperClass() != null ? _factory.CreateUClass((nint)_self->GetSuperClass()) : null; + + public IUFunction? GetFunction(string Name) + { + var FuncMapDict = new TMapDictionary>( + (TMap>*)(&_self->FuncMap), factory.Memory + ); + return FuncMapDict.TryGetValue(new(Name), out var Function) + ? factory.CreateUFunction((nint)Function.Value->Value) + : null; + } + + public IEnumerable GetFunctions() + { + var FuncMapDict = new TMapDictionary>( + (TMap>*)(&_self->FuncMap), + _factory.Memory + ); + return FuncMapDict.Values.Select(x => _factory.CreateUFunction((nint)x.Value->Value)); + } + + public IUObject? ClassDefaultObject + => _self->ClassDefaultObject != null ? factory.CreateUObject((nint)_self->ClassDefaultObject ) : null; + + public nint Constructor => _self->ClassConstructor; + public EClassFlags ClassFlags => _self->ClassFlags; + public EClassCastFlags ClassCastFlags => _self->ClassCastFlags; } \ No newline at end of file diff --git a/UE.Toolkit.Core/Types/Unreal/UE4_27_2/Unreal.cs b/UE.Toolkit.Core/Types/Unreal/UE4_27_2/Unreal.cs index 51ed573..0caf212 100644 --- a/UE.Toolkit.Core/Types/Unreal/UE4_27_2/Unreal.cs +++ b/UE.Toolkit.Core/Types/Unreal/UE4_27_2/Unreal.cs @@ -210,6 +210,7 @@ public unsafe struct FFieldObjectUnion { [FieldOffset(0x0)] public FField* Field; [FieldOffset(0x0)] public UObjectBase* Object; + [FieldOffset(0x8)] public bool bIsUObject; } [StructLayout(LayoutKind.Sequential, Size = 0x78)] diff --git a/UE.Toolkit.Core/Types/Unreal/UE5_0_3/UClass.cs b/UE.Toolkit.Core/Types/Unreal/UE5_0_3/UClass.cs new file mode 100644 index 0000000..95b8052 --- /dev/null +++ b/UE.Toolkit.Core/Types/Unreal/UE5_0_3/UClass.cs @@ -0,0 +1,34 @@ +using System.Runtime.InteropServices; +using UE.Toolkit.Core.Types.Unreal.UE4_27_2; +using UE.Toolkit.Core.Types.Unreal.UE5_4_4; +using UField = UE.Toolkit.Core.Types.Unreal.UE4_27_2.UField; +using UObjectBase = UE.Toolkit.Core.Types.Unreal.UE4_27_2.UObjectBase; +using UScriptStruct = UE.Toolkit.Core.Types.Unreal.UE4_27_2.UScriptStruct; +using UStruct = UE.Toolkit.Core.Types.Unreal.UE4_27_2.UStruct; + +namespace UE.Toolkit.Core.Types.Unreal.UE5_0_3; + +[StructLayout(LayoutKind.Explicit, Size = 0x230)] +public unsafe struct UClass +{ + [FieldOffset(0x0)] public UStruct _super; + [FieldOffset(0xb0)] public IntPtr class_ctor; // InternalConstructor => UClassName::UClassName + [FieldOffset(0xb8)] public IntPtr class_vtable_helper_ctor_caller; + [FieldOffset(0xc0)] public IntPtr class_add_ref_objects; + [FieldOffset(0xc8)] public uint class_status; // ClassUnique : 31, bCooked : 1 + [FieldOffset(0xcc)] public uint FirstOwnedClassRep; + [FieldOffset(0xd0)] public bool bCooked; + [FieldOffset(0xd1)] public bool bLayoutChanging; + [FieldOffset(0xd4)] public EClassFlags class_flags; + [FieldOffset(0xd8)] public EClassCastFlags class_cast_flags; + [FieldOffset(0xe0)] public UClass* class_within; // type of object containing the current object + [FieldOffset(0xe8)] public FName class_conf_name; + [FieldOffset(0x100)] public TArray net_fields; + [FieldOffset(0x110)] public UObjectBase* class_default_obj; // Default object of type described in UClass instance + [FieldOffset(0x118)] public nint sparse_class_data; + [FieldOffset(0x120)] public UScriptStruct* sparse_class_data_struct; + [FieldOffset(0x128)] public TMap func_map; + [FieldOffset(0x178)] public TMap super_func_map; + [FieldOffset(0x1d0)] public TArray interfaces; + [FieldOffset(0x220)] public TArray native_func_lookup; +} \ No newline at end of file diff --git a/UE.Toolkit.Core/Types/Unreal/UE5_2_1/UClass.cs b/UE.Toolkit.Core/Types/Unreal/UE5_2_1/UClass.cs new file mode 100644 index 0000000..d0f89d0 --- /dev/null +++ b/UE.Toolkit.Core/Types/Unreal/UE5_2_1/UClass.cs @@ -0,0 +1,34 @@ +using System.Runtime.InteropServices; +using UE.Toolkit.Core.Types.Unreal.UE4_27_2; +using UE.Toolkit.Core.Types.Unreal.UE5_4_4; +using UField = UE.Toolkit.Core.Types.Unreal.UE4_27_2.UField; +using UObjectBase = UE.Toolkit.Core.Types.Unreal.UE4_27_2.UObjectBase; +using UScriptStruct = UE.Toolkit.Core.Types.Unreal.UE4_27_2.UScriptStruct; +using UStruct = UE.Toolkit.Core.Types.Unreal.UE4_27_2.UStruct; + +namespace UE.Toolkit.Core.Types.Unreal.UE5_2_1; + +[StructLayout(LayoutKind.Explicit, Size = 0x220)] +public unsafe struct UClass +{ + [FieldOffset(0x0)] public UStruct _super; + [FieldOffset(0xb0)] public IntPtr class_ctor; // InternalConstructor => UClassName::UClassName + [FieldOffset(0xb8)] public IntPtr class_vtable_helper_ctor_caller; + [FieldOffset(0xc0)] public IntPtr class_add_ref_objects; + [FieldOffset(0xc8)] public uint class_status; // ClassUnique : 31, bCooked : 1 + [FieldOffset(0xcc)] public uint FirstOwnedClassRep; + [FieldOffset(0xd0)] public bool bCooked; + [FieldOffset(0xd1)] public bool bLayoutChanging; + [FieldOffset(0xd4)] public EClassFlags class_flags; + [FieldOffset(0xd8)] public EClassCastFlags class_cast_flags; + [FieldOffset(0xe0)] public UClass* class_within; // type of object containing the current object + [FieldOffset(0xe8)] public FName class_conf_name; + [FieldOffset(0x100)] public TArray net_fields; + [FieldOffset(0x110)] public UObjectBase* class_default_obj; // Default object of type described in UClass instance + [FieldOffset(0x118)] public nint sparse_class_data; + [FieldOffset(0x120)] public UScriptStruct* sparse_class_data_struct; + [FieldOffset(0x128)] public TMap func_map; + [FieldOffset(0x180)] public TMap super_func_map; + [FieldOffset(0x1d8)] public TArray interfaces; + [FieldOffset(0x210)] public TArray native_func_lookup; +} \ No newline at end of file diff --git a/UE.Toolkit.Core/Types/Unreal/UE5_4_4/FString.cs b/UE.Toolkit.Core/Types/Unreal/UE5_4_4/FString.cs index 5bed2e0..93bad21 100644 --- a/UE.Toolkit.Core/Types/Unreal/UE5_4_4/FString.cs +++ b/UE.Toolkit.Core/Types/Unreal/UE5_4_4/FString.cs @@ -5,8 +5,7 @@ namespace UE.Toolkit.Core.Types.Unreal.UE5_4_4; [StructLayout(LayoutKind.Sequential)] public unsafe struct FString : IMapHashable { - - private static uint[] CRC_HASH = + public static uint[] CRC_HASH = [ 0x00000000, 0x04C11DB7, 0x09823B6E, 0x0D4326D9, 0x130476DC, 0x17C56B6B, 0x1A864DB2, 0x1E475005, 0x2608EDB8, 0x22C9F00F, 0x2F8AD6D6, 0x2B4BCB61, 0x350C9B64, 0x31CD86D3, 0x3C8EA00A, 0x384FBDBD, 0x4C11DB70, 0x48D0C6C7, 0x4593E01E, 0x4152FDA9, 0x5F15ADAC, 0x5BD4B01B, 0x569796C2, 0x52568B75, 0x6A1936C8, 0x6ED82B7F, 0x639B0DA6, 0x675A1011, 0x791D4014, 0x7DDC5DA3, 0x709F7B7A, 0x745E66CD, diff --git a/UE.Toolkit.Core/Types/Unreal/UE5_4_4/TArray.cs b/UE.Toolkit.Core/Types/Unreal/UE5_4_4/TArray.cs index 8065fa0..1c69ec2 100644 --- a/UE.Toolkit.Core/Types/Unreal/UE5_4_4/TArray.cs +++ b/UE.Toolkit.Core/Types/Unreal/UE5_4_4/TArray.cs @@ -12,6 +12,11 @@ public unsafe struct TArray where T : unmanaged public T* AllocatorInstance; public int ArrayNum; public int ArrayMax; + + public TArrayList ToManaged(IUnrealMemoryInternal Memory) + { + fixed (TArray* self = &this) return new TArrayList(self, Memory); + } } public unsafe class TArrayListStatic diff --git a/UE.Toolkit.Core/Types/Unreal/UE5_4_4/TBitArray.cs b/UE.Toolkit.Core/Types/Unreal/UE5_4_4/TBitArray.cs index 683f624..0b3a6df 100644 --- a/UE.Toolkit.Core/Types/Unreal/UE5_4_4/TBitArray.cs +++ b/UE.Toolkit.Core/Types/Unreal/UE5_4_4/TBitArray.cs @@ -40,18 +40,21 @@ public unsafe class TBitArrayList : IDisposable, IList private int InlineAllocatorSize; protected bool OwnsInstance; protected bool Disposed = false; + protected bool InlineGoesFirst; /// /// Wraps a TArrayList around an existing TBitArray created in C++ /// /// Pointer to an existing TBitArray /// The Unreal allocator, used for methods that modify the TBitArray - public TBitArrayList(byte* _Self, IUnrealMemoryInternal _Allocator, int _InlineAllocatorSize = TBitArrayConstants.DEFAULT_ALLOCATOR_SIZE) + public TBitArrayList(byte* _Self, IUnrealMemoryInternal _Allocator, int _InlineAllocatorSize = TBitArrayConstants.DEFAULT_ALLOCATOR_SIZE, + bool inlineGoesFirst = true) { Allocator = _Allocator; InlineAllocatorSize = _InlineAllocatorSize; Self = _Self; OwnsInstance = false; + InlineGoesFirst = inlineGoesFirst; } /// @@ -65,19 +68,20 @@ public TBitArrayList(IUnrealMemoryInternal _Allocator, int _InlineAllocatorSize Self = (byte*)Allocator.MallocZeroed(GetStructSize()); ArrayMax = InlineBits; OwnsInstance = true; + InlineGoesFirst = true; } protected byte* Inline { - get => Self; + get => Self + (InlineGoesFirst ? 0 : InlineAllocatorSize); } internal int InlineBits => InlineAllocatorSize * TBitArrayConstants.BITS_PER_BYTE; protected byte* Allocation { - get => *(byte**)(Self + InlineAllocatorSize); - set => *(byte**)(Self + InlineAllocatorSize) = value; + get => *(byte**)(Self + (InlineGoesFirst ? InlineAllocatorSize : 0)); + set => *(byte**)(Self + (InlineGoesFirst ? InlineAllocatorSize : 0)) = value; } protected byte* Data @@ -94,17 +98,17 @@ protected byte* Data public int ArrayNum { - get => *(int*)(Self + InlineAllocatorSize + sizeof(nint)); - protected set => *(int*)(Self + InlineAllocatorSize + sizeof(nint)) = value; + get => *(int*)(Self + (InlineGoesFirst ? InlineAllocatorSize : 0) + sizeof(nint)); + protected set => *(int*)(Self + (InlineGoesFirst ? InlineAllocatorSize : 0) + sizeof(nint)) = value; } public int ArrayMax { - get => *(int*)(Self + InlineAllocatorSize + sizeof(nint) + sizeof(int)); - protected set => *(int*)(Self + InlineAllocatorSize + sizeof(nint) + sizeof(int)) = value; + get => *(int*)(Self + (InlineGoesFirst ? InlineAllocatorSize : 0) + sizeof(nint) + sizeof(int)); + protected set => *(int*)(Self + (InlineGoesFirst ? InlineAllocatorSize : 0) + sizeof(nint) + sizeof(int)) = value; } - bool InBounds(int index) => index is >= 0 && index < ArrayNum; + bool InBounds(int index) => index >= 0 && index < ArrayNum; bool InBoundsForInsertion(int index) => index >= 0 && index <= ArrayNum; /// /// Relinquish ownership of this TArray. This is used in cases where you know that Unreal will deallocate it or it otherwise diff --git a/UE.Toolkit.Core/Types/Unreal/UE5_4_4/TMap.cs b/UE.Toolkit.Core/Types/Unreal/UE5_4_4/TMap.cs index 6ae1f71..dfebc2a 100644 --- a/UE.Toolkit.Core/Types/Unreal/UE5_4_4/TMap.cs +++ b/UE.Toolkit.Core/Types/Unreal/UE5_4_4/TMap.cs @@ -396,13 +396,13 @@ private int HashSize /// /// Pointer to an existing TMap /// The Unreal allocator, used for methods that modify the TMap - public TMapDictionary(TMap* _Self, IUnrealMemoryInternal _Allocator, Action? _DebugCallback = null) + public TMapDictionary(TMap* _Self, IUnrealMemoryInternal _Allocator, Action? _DebugCallback = null, bool inlineGoesFirst = true) { Self = (nint)_Self; Allocator = _Allocator; Elements = new(ElementsRaw, Allocator); OwnsInstance = false; - BitAllocator = new(BitAllocatorRaw, Allocator); + BitAllocator = new(BitAllocatorRaw, Allocator, TBitArrayConstants.DEFAULT_ALLOCATOR_SIZE, inlineGoesFirst); DebugCallback = _DebugCallback; } @@ -411,13 +411,13 @@ public TMapDictionary(TMap* _Self, IUnrealMemoryInternal _ /// taken out of scope. /// /// The Unreal allocator, used for methods that modify the TMap - public TMapDictionary(IUnrealMemoryInternal _Allocator) + public TMapDictionary(IUnrealMemoryInternal _Allocator, bool inlineGoesFirst = true) { Self = _Allocator.MallocZeroed(SizeOf); Allocator = _Allocator; Elements = new(ElementsRaw, Allocator); OwnsInstance = true; - BitAllocator = new(BitAllocatorRaw, Allocator); + BitAllocator = new(BitAllocatorRaw, Allocator, TBitArrayConstants.DEFAULT_ALLOCATOR_SIZE, inlineGoesFirst); // Sets ArrayMax for BitAllocator to number of inline bits (128) BitAllocator.Clear(); } diff --git a/UE.Toolkit.Core/Types/Unreal/UE5_6_1/FAnsiString.cs b/UE.Toolkit.Core/Types/Unreal/UE5_6_1/FAnsiString.cs new file mode 100644 index 0000000..559416d --- /dev/null +++ b/UE.Toolkit.Core/Types/Unreal/UE5_6_1/FAnsiString.cs @@ -0,0 +1,23 @@ +using System.Runtime.InteropServices; +using System.Text; +using UE.Toolkit.Core.Types.Unreal.UE5_4_4; + +namespace UE.Toolkit.Core.Types.Unreal.UE5_6_1; + +[StructLayout(LayoutKind.Sequential)] +public unsafe struct FAnsiString : IMapHashable +{ + public TArray Data; + + public override string ToString() + => Data.ArrayNum > 0 ? Marshal.PtrToStringAnsi((nint)Data.AllocatorInstance, Data.ArrayNum - 1) : string.Empty; + + public uint GetTypeHash() + { + var Bytes = Encoding.ASCII.GetBytes(ToString()); + uint Hash = 0; + foreach (var Byte in Bytes) + Hash = ((Hash >> 8) & 0xFFFFFF) ^ FString.CRC_HASH[(Hash ^ Byte) & 0xFF]; + return Hash; + } +} \ No newline at end of file diff --git a/UE.Toolkit.Core/Types/Unreal/UE5_6_1/FUtf8String.cs b/UE.Toolkit.Core/Types/Unreal/UE5_6_1/FUtf8String.cs new file mode 100644 index 0000000..e83c518 --- /dev/null +++ b/UE.Toolkit.Core/Types/Unreal/UE5_6_1/FUtf8String.cs @@ -0,0 +1,23 @@ +using System.Runtime.InteropServices; +using System.Text; +using UE.Toolkit.Core.Types.Unreal.UE5_4_4; + +namespace UE.Toolkit.Core.Types.Unreal.UE5_6_1; + +[StructLayout(LayoutKind.Sequential)] +public unsafe struct FUtf8String : IMapHashable +{ + public TArray Data; + + public override string ToString() + => Data.ArrayNum > 0 ? Marshal.PtrToStringUTF8((nint)Data.AllocatorInstance, Data.ArrayNum - 1) : string.Empty; + + public uint GetTypeHash() + { + var Bytes = Encoding.UTF8.GetBytes(ToString()); + uint Hash = 0; + foreach (var Byte in Bytes) + Hash = ((Hash >> 8) & 0xFFFFFF) ^ FString.CRC_HASH[(Hash ^ Byte) & 0xFF]; + return Hash; + } +} \ No newline at end of file diff --git a/UE.Toolkit.Core/Types/Unreal/UE5_7_4/UClass.cs b/UE.Toolkit.Core/Types/Unreal/UE5_7_4/UClass.cs new file mode 100644 index 0000000..41dd27e --- /dev/null +++ b/UE.Toolkit.Core/Types/Unreal/UE5_7_4/UClass.cs @@ -0,0 +1,32 @@ +using System.Runtime.InteropServices; +using UE.Toolkit.Core.Types.Unreal.UE5_4_4; + +namespace UE.Toolkit.Core.Types.Unreal.UE5_7_4; + +[StructLayout(LayoutKind.Sequential, Size = 0x208)] +public unsafe struct UClass +{ + public UStruct Super; + public nint ClassConstructor; + public nint ClassVTableHelperCtorCaller; + public nint CppClassStaticFunctions; + public int ClassUnique; + public int FirstOwnedClassRep; + public bool bCooked; + public bool bLayoutChanging; + public EClassFlags ClassFlags; + public EClassCastFlags ClassCastFlags; + public UClass* ClassWithin; + //public UObjectBase* ClassGeneratedBy; // WITH_EDITORONLY_DATA + //public FField* PropertiesPendingDestruction; // WITH_EDITORONLY_DATA + public FName ClassConfigName; + public TArray ClassReps; + public TArray NetFields; + public UObjectBase* ClassDefaultObject; + public nint SparseClassData; + public UScriptStruct* SparseClassDataStruct; + public bool bNeedsDynamicSubobjectInstancing; + public TMap FuncMap; + + public readonly UClass* GetSuperClass() => (UClass*)Super.SuperStruct; +} \ No newline at end of file diff --git a/UE.Toolkit.Core/UE.Toolkit.Core.csproj b/UE.Toolkit.Core/UE.Toolkit.Core.csproj index 0d00bf1..5779283 100644 --- a/UE.Toolkit.Core/UE.Toolkit.Core.csproj +++ b/UE.Toolkit.Core/UE.Toolkit.Core.csproj @@ -6,7 +6,7 @@ enable true https://github.com/RyoTune/UE.Toolkit - 1.9.0 + 1.10.0 diff --git a/UE.Toolkit.DumperMod/Config.cs b/UE.Toolkit.DumperMod/Config.cs index 81007cf..b6a9ee7 100644 --- a/UE.Toolkit.DumperMod/Config.cs +++ b/UE.Toolkit.DumperMod/Config.cs @@ -11,8 +11,14 @@ public class Config : Configurable public LogLevel LogLevel { get; set; } = LogLevel.Information; [DisplayName("Dump Mode")] + [Description("Defines how the dump will be saved onto the file system")] [DefaultValue(DumpFileMode.SingleFile)] public DumpFileMode Mode { get; set; } = DumpFileMode.SingleFile; + + [DisplayName("Dump Schema")] + [Description("Defines the format for the type dump")] + [DefaultValue(DumpSchema.Dynamic)] + public DumpSchema Schema { get; set; } = DumpSchema.Dynamic; [DisplayName("File Namespace")] [DefaultValue("")] @@ -25,6 +31,10 @@ public class Config : Configurable [DisplayName("Single-File File Name")] [DefaultValue("")] public string SingleFileOutputName { get; set; } = string.Empty; + + [DisplayName("Dump Functions")] + [DefaultValue(true)] + public bool DumpFunctions { get; set; } = true; } public enum DumpFileMode @@ -39,6 +49,14 @@ public enum DumpFileMode FilePerModule, } +public enum DumpSchema +{ + [Display(Name = "Structs Only")] + Static, + [Display(Name = "Structs and Classes")] + Dynamic, +} + /// /// Allows you to override certain aspects of the configuration creation process (e.g. create multiple configurations). /// Override elements in for finer control. diff --git a/UE.Toolkit.DumperMod/Context.cs b/UE.Toolkit.DumperMod/Context.cs new file mode 100644 index 0000000..304eece --- /dev/null +++ b/UE.Toolkit.DumperMod/Context.cs @@ -0,0 +1,32 @@ +using UE.Toolkit.Core.Types.Unreal.Factories; +using UE.Toolkit.DumperMod.Definitions; +using UE.Toolkit.Interfaces; +using UnrealEssentials.Interfaces; + +namespace UE.Toolkit.DumperMod; + +public class Context +{ + public Context(IUnrealFactory factory, IUnrealObjects uobjs, IUnrealStrings strs, IUnrealClasses classes, + string dumpDir, IUnrealEssentials essentials) + { + DumpDirectory = dumpDir; + Objects = uobjs; + Strings = strs; + Factory = factory; + Classes = classes; + Essentials = essentials; + Builtins = new(essentials); + Registry = new(this); + } + + public string DumpDirectory { get; } + + public IUnrealObjects Objects { get; } + public IUnrealStrings Strings { get; } + public IUnrealFactory Factory { get; } + public IUnrealClasses Classes { get; } + public IUnrealEssentials Essentials { get; } + public Builtins Builtins { get; } + public Registry Registry { get; } +} \ No newline at end of file diff --git a/UE.Toolkit.DumperMod/Definitions/Base.cs b/UE.Toolkit.DumperMod/Definitions/Base.cs new file mode 100644 index 0000000..442a550 --- /dev/null +++ b/UE.Toolkit.DumperMod/Definitions/Base.cs @@ -0,0 +1,19 @@ +namespace UE.Toolkit.DumperMod.Definitions; + +public interface IObjectFactory +{ + void Register(); +} + +public interface ISerializable +{ + string Serialize(Context context); +} + +public abstract class BaseObjectFactory(Context context, ObjectType objectType) : IObjectFactory +{ + protected Context Context = context; + protected ObjectType ObjectType = objectType; + + public abstract void Register(); +} \ No newline at end of file diff --git a/UE.Toolkit.DumperMod/Definitions/Builtins.cs b/UE.Toolkit.DumperMod/Definitions/Builtins.cs new file mode 100644 index 0000000..1bed411 --- /dev/null +++ b/UE.Toolkit.DumperMod/Definitions/Builtins.cs @@ -0,0 +1,161 @@ +using System.Runtime.CompilerServices; +using System.Text; +using UnrealEssentials.Interfaces; + +namespace UE.Toolkit.DumperMod.Definitions; + +public class Builtins(IUnrealEssentials essentials) +{ + private IUnrealEssentials Essentials = essentials; + + private List GetDefaultUsings() + { + List Usings = []; + if (Mod.Config.Schema == DumpSchema.Dynamic) + Usings.Add("System.Runtime.CompilerServices"); + Usings.AddRange([ + "System.Runtime.InteropServices", + "UE.Toolkit.Core.Types", + "UE.Toolkit.Core.Types.Unreal.UE5_4_4", + ]); + if (Mod.Config.Schema == DumpSchema.Dynamic) + Usings.AddRange([ + "UE.Toolkit.Core.Types.Unreal.Factories", + "UE.Toolkit.Core.Types.Unreal.Factories.Interfaces", + "UE.Toolkit.Core.Types.Unreal.Common.FunctionParam", + ]); + var VerParts = Essentials.GetEngineVersion().Split("-")[^1].Split("."); + // FText definition is different for versions below UE 5.4 + if (int.Parse(VerParts[0]) < 5 || int.Parse(VerParts[1]) < 4) + Usings.Add("FText = UE.Toolkit.Core.Types.Unreal.UE4_27_2.FText"); + // Added FAnsiString and FUtf8String for UE 5.6+ + if (int.Parse(VerParts[0]) == 5 && int.Parse(VerParts[1]) >= 6) + { + Usings.Add("FAnsiString = UE.Toolkit.Core.Types.Unreal.UE5_6_1.FAnsiString"); + Usings.Add("FUtf8String = UE.Toolkit.Core.Types.Unreal.UE5_6_1.FUtf8String"); + } + return Usings; + } + + public void AddHeader(StringBuilder sb) + { + sb.AppendLine(""" +/* Generated with UE Toolkit: Dumper (1.10.0) */ +/* GitHub: https://github.com/RyoTune/UE.Toolkit */ +/* Author: RyoTune and Rirurin */ +/* Special thanks to UE4SS team whose code was */ +/* used for reference. */ + +"""); + + foreach (var use in GetDefaultUsings()) + sb.AppendLine($"using {use};"); + + if (!string.IsNullOrEmpty(Mod.Config.FileUsings)) + { + var usings = Mod.Config.FileUsings.Split(';', + StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries) + .Select(x => x.Replace("using ", string.Empty)); + foreach (var use in usings) sb.AppendLine($"using {use};"); + } + + sb.AppendLine(); + if (!string.IsNullOrEmpty(Mod.Config.FileNamespace)) + { + sb.AppendLine($"namespace {Mod.Config.FileNamespace.TrimEnd(';').Replace("namespace ", string.Empty)};"); + sb.AppendLine(); + } + } + + public void AddBaseObjectDefinition(StringBuilder sb) + { +sb.AppendLine(""" +public interface ITypeRepr where TRepr: unmanaged +{ + unsafe TRepr* Repr { get; } +} + +public abstract class ObjectImpl(IUObject inner) +{ + public IUObject Inner { get; } = inner; + + protected Dictionary CreateFieldOffsets() + { + Dictionary Result = []; + foreach (var Prop in Inner.ClassPrivate.PropertyLink) + if (!Result.ContainsKey(Prop.NamePrivate)) + Result[Prop.NamePrivate] = Prop.Offset_Internal; + return Result; + } + + protected abstract int GetFieldOffset(string Name); +} + +"""); + } + + public static string SanitizeName(string name) + { + var parts = name.Split('_'); + if (parts.Last().Length == 32 && parts.Length > 2) + { + name = string.Join(string.Empty, parts[..^2]); + // SMT5V: Property that's a sequence of underscores becomes an empty string + if (name == string.Empty) name = "EMPTY"; + } + + name = name.Replace(' ', '_'); + name = name.Replace('-', '_'); + name = name.Replace('/', '_'); + name = name.Replace("?", string.Empty); + name = name.Replace("&", string.Empty); + name = name.Replace('(', '_'); + name = name.Replace(')', '_'); + name = name.Replace('[', '_'); + name = name.Replace(']', '_'); + name = name.Replace("+", "_"); + name = name.Replace("'", "_"); + //name = name.Replace('>', '_'); + if (name == "object") name = "_object"; + + // name = SanitizeForParam(name); + + if (char.IsDigit(name[0])) + { + name = '_' + name; + } + + return name; + } + + // Extra sanitization step to prevent C# treating a parameter named after a primitive data type as a data type + public static string SanitizeForTypename(string name) + { + return name switch + { + "base" => "Base", + "bool" => "Bool", + "float" => "Float", + "double" => "Double", + "ref" => "Ref", + "int" => "Int", + "return" => "Return", + "string" => "String", + "Inner" => "Inner_", + _ => name + }; + } + + public static string SanitizeForFunctionName(string name) + { + name = name.Replace(".", "_"); + name = name.Replace(">", "_"); + return name; + } + + public static string SanitizeForEnum(string name) + { + name = name.Replace(".", "_"); + return name; + } +} \ No newline at end of file diff --git a/UE.Toolkit.DumperMod/Definitions/Class.cs b/UE.Toolkit.DumperMod/Definitions/Class.cs new file mode 100644 index 0000000..7b05317 --- /dev/null +++ b/UE.Toolkit.DumperMod/Definitions/Class.cs @@ -0,0 +1,125 @@ +using System.Text; +using UE.Toolkit.Core.Types.Unreal.Factories.Interfaces; +using UE.Toolkit.Core.Types.Unreal.UE5_4_4; + +namespace UE.Toolkit.DumperMod.Definitions; + +public class ClassFactory(Context context, ObjectType objectType, IUClass uclass) : BaseObjectFactory(context, objectType) +{ + public override void Register() { + var innerName = uclass.NamePrivate.ToString(); + // TODO: Fix GetNativeName on UE4 to retrieve AActor attribute from classes + var displayName = (uclass.ClassCastFlags.HasFlag(EClassCastFlags.AActor) ? "A" : "U") + innerName; + var size = uclass.PropertiesSize; + var alignment = uclass.MinAlignment; + + var super = uclass.GetSuperClass(); + var superLastProp = super?.PropertyLink.MaxBy(x => x.Offset_Internal); + var superSize = superLastProp?.Offset_Internal + superLastProp?.ElementSize ?? 0; + // var superSize = super?.PropertiesSize ?? 0; + var superName = super?.NamePrivate.ToString(); + + // TODO: Generate delegates. + + var propClass = new PropertyClassFactory(Context).ResolveProperties(uclass.PropertyLink, superSize); + var propStruct = new PropertyStructFactory(Context).ResolveProperties(uclass.PropertyLink, superSize); + + var functions = Mod.Config.DumpFunctions ? new FunctionFactory(Context).ResolveFunctions(uclass) : []; + Context.Registry.Structs[innerName] = + new ClassDefinition(innerName, displayName, size, alignment, propClass, propStruct, functions, superName); + } +} + +public class ClassFactoryStatic(Context context, ObjectType objectType, IUClass uclass) + : BaseObjectFactory(context, objectType) +{ + public override void Register() { + var innerName = uclass.NamePrivate.ToString(); + var displayName = (uclass.ClassCastFlags.HasFlag(EClassCastFlags.AActor) ? "A" : "U") + innerName; + var size = uclass.PropertiesSize; + var alignment = uclass.MinAlignment; + + var super = uclass.GetSuperClass(); + var superSize = super?.PropertiesSize ?? 0; + var superName = super?.NamePrivate.ToString(); + + var propStruct = new PropertyStructFactory(Context).ResolveProperties(uclass.PropertyLink, superSize); + Context.Registry.Structs[innerName] = new StructDefinition(innerName, displayName, size, alignment, propStruct, superName); + } +} + +public class ClassDefinition( + string internalName, + string displayName, + int size, + int alignment, + List propClass, + List propStruct, + List functions, + string? superInternalName) + : StructDefinition(internalName, displayName, size, alignment, propClass, superInternalName) +{ + private List PropStruct => propStruct; + private List Functions => functions; + + public override string Serialize(Context context) + { + var sb = new StringBuilder(); + if (Mod.Config.Mode == DumpFileMode.FilePerType) context.Builtins.AddHeader(sb); + var DisplayNameCS = Builtins.SanitizeName(DisplayName); + var DisplayNameRepr = $"{DisplayNameCS}_Repr"; + StructDefinition? SuperDef = null; + if (SuperInternalName != null) context.Registry.Structs.TryGetValue(SuperInternalName, out SuperDef); + var SuperDefName = SuperDef != null ? Builtins.SanitizeName(SuperDef.DisplayName) : "ObjectImpl"; + // sb.AppendLine($"public class {DisplayNameCS}(IUObject inner) : {SuperDefName}(inner), ITypeRepr<{DisplayNameRepr}>\n{{"); + sb.AppendLine($"public class {DisplayNameCS} : {SuperDefName}, ITypeRepr<{DisplayNameRepr}>\n{{"); + sb.AppendLine("\tprivate static Dictionary? FieldOffsets;"); + var callBaseCtor = SuperDef != null ? "base(inner, false)" : "base(inner)"; + sb.AppendLine($"\tpublic {DisplayNameCS}(IUObject inner, bool genOffsets = true) : {callBaseCtor}\n\t{{"); + sb.AppendLine("\t\tif (genOffsets) FieldOffsets ??= CreateFieldOffsets();"); + sb.AppendLine("\t}\n"); + sb.AppendLine("\tprotected override int GetFieldOffset(string Name) => FieldOffsets![Name];\n"); + var ReprNewModifier = SuperDef != null ? "new " : string.Empty; + sb.AppendLine($"\tpublic {ReprNewModifier}unsafe {DisplayNameRepr}* Repr => ({DisplayNameRepr}*)Inner.Ptr;\n"); + foreach (var prop in Properties) + sb.AppendLine(prop.Serialize(context)); + foreach (var func in Functions) + sb.AppendLine(func.Serialize(context)); + sb.AppendLine("}\n"); + var reprDef = new StructDefinitionRepr(InternalName, DisplayName, Size, Alignment, PropStruct, SuperInternalName); + sb.AppendLine(reprDef.Serialize(context)); + return sb.ToString(); + } + + public override ObjectType Type => ObjectType.Class; + + public override string GetUnmanagedTypeName() => DisplayName + "_Repr"; +} + +public class StructDefinitionRepr( + string internalName, + string displayName, + int size, + int alignment, + List properties, + string? superInternalName) + : StructDefinition(internalName, displayName, size, alignment, properties, superInternalName) +{ + public override string Serialize(Context context) + { + var sb = new StringBuilder(); + + if (Mod.Config.Mode == DumpFileMode.FilePerType) context.Builtins.AddHeader(sb); + + var DisplayNameCS = Builtins.SanitizeName(DisplayName); + var DisplayNameRepr = $"{DisplayNameCS}_Repr"; + var (superName, superSize) = GetSuperInfo(context); + var superNameFmt = superName != null ? $"{superName}_Repr" : null; + WriteStructBase(sb, DisplayNameRepr, superNameFmt, superSize, context); + var sep = Properties.Count > 0 ? "\n" : string.Empty; + sb.AppendLine($"{sep}\tpublic {DisplayNameCS} ToManaged(IUnrealFactory factory)\n\t{{"); + sb.AppendLine($"\t\tfixed ({DisplayNameRepr}* self = &this) return new(factory.CreateUObject((nint)self));"); + sb.AppendLine("\t}\n}"); + return sb.ToString(); + } +} \ No newline at end of file diff --git a/UE.Toolkit.DumperMod/Definitions/Enum.cs b/UE.Toolkit.DumperMod/Definitions/Enum.cs new file mode 100644 index 0000000..a707241 --- /dev/null +++ b/UE.Toolkit.DumperMod/Definitions/Enum.cs @@ -0,0 +1,115 @@ +using System.Text; +using UE.Toolkit.Core.Types.Unreal.Factories.Interfaces; +using UE.Toolkit.Core.Types.Unreal.UE5_4_4; + +namespace UE.Toolkit.DumperMod.Definitions; + +public class EnumFactory(Context context, ObjectType objectType, IUEnum uenum, string? knownType = null) + : BaseObjectFactory(context, objectType) +{ + public override void Register() + { + var name = uenum.NamePrivate.ToString(); + if (Context.Registry.Enums.ContainsKey(name) && knownType == null) return; + + var entries = new Dictionary(); + + var dispNames = new Dictionary(); + if (uenum.IsChildOf()) + { + var userEnum = Context.Factory.Cast(uenum); + for (var i = 0; i < uenum.Names.ArrayNum; i++) + { + var dispName = Context.Strings.UEnumGetDisplayNameTextByIndex(userEnum.Ptr, i); + dispNames[i] = $"{name}::{dispName}"; + } + } + + long bigEntryValue = 0; + var bigEntryName = string.Empty; + for (var i = 0; i < uenum.Names.ArrayNum; i++) + { + unsafe + { + var entry = &uenum.Names.AllocatorInstance[i]; + + if (!dispNames.TryGetValue(i, out var entryName)) + { + entryName = entry->Key.ToString(); + } + + var entryValue = entry->Value; + entries[entryName] = entryValue; + + if (bigEntryValue < entryValue) + { + bigEntryValue = entryValue; + bigEntryName = entryName; + } + } + } + + var entryConstant = $"{name}::{name}_MAX"; + if (entries.TryGetValue(entryConstant, out var entryConstantValue) && entryConstantValue == bigEntryValue) + { + entries.Remove(entryConstant); + } + + if (bigEntryValue == 256 && bigEntryName.EndsWith("_MAX")) entries.Remove(bigEntryName); + + var underlyingType = knownType ?? bigEntryValue switch + { + <= byte.MaxValue => "byte", + <= short.MaxValue => "short", + <= int.MaxValue => "int", + <= long.MaxValue => "long", + }; + + var hasNegativeValue = entries.Any(x => x.Value < 0); + if (underlyingType == "byte" && hasNegativeValue) underlyingType = "sbyte"; + if (underlyingType != "byte" && !hasNegativeValue && !underlyingType.StartsWith('u')) underlyingType = $"u{underlyingType}"; + + Context.Registry.Enums[name] = new EnumDefinition(name, underlyingType, entries); + } +} + +public class EnumDefinition(string name, string underlyingType, Dictionary entries) : ISerializable +{ + private string Name = name; + private string UnderlyingType = underlyingType; + private Dictionary Entries = entries; + + public string Serialize(Context context) + { + var sb = new StringBuilder(); + + if (Mod.Config.Mode == DumpFileMode.FilePerType) + { + context.Builtins.AddHeader(sb); + } + + sb.AppendLine($"public enum {Builtins.SanitizeName(Name)} : {UnderlyingType}\n{{"); + Dictionary UsageCount = []; + foreach (var entry in Entries) + { + var variantName = SanitizeEntryName(entry.Key); + if (UsageCount.TryGetValue(variantName, out var count)) + { + variantName += $"_{count}"; + UsageCount[variantName] = count + 1; + } + else + { + UsageCount[variantName] = 1; + } + sb.AppendLine($" {variantName} = {entry.Value},"); + } + + sb.AppendLine("}"); + return sb.ToString(); + } + + public ObjectType Type => ObjectType.Enum; + + private static string SanitizeEntryName(string name) => Builtins.SanitizeForEnum(Builtins.SanitizeName(name.Split("::").Last())); +} \ No newline at end of file diff --git a/UE.Toolkit.DumperMod/Definitions/Function.cs b/UE.Toolkit.DumperMod/Definitions/Function.cs new file mode 100644 index 0000000..ba40e99 --- /dev/null +++ b/UE.Toolkit.DumperMod/Definitions/Function.cs @@ -0,0 +1,215 @@ +using System.Text; +using UE.Toolkit.Core.Types.Interfaces; +using UE.Toolkit.Core.Types.Unreal.Factories.Interfaces; +using UE.Toolkit.Core.Types.Unreal.UE5_4_4; + +namespace UE.Toolkit.DumperMod.Definitions; + +public abstract class ParameterDefinition(string name, Func propTypeName, IFProperty meta) : ISerializable +{ + public string Name { get; } = name; + public Func PropTypeName { get; } = propTypeName; + public IFProperty Meta { get; } = meta; + + public bool IsReference => Meta.PropertyFlags.HasFlag(EPropertyFlags.CPF_OutParm); + + public abstract string Serialize(Context context); +} + +public class ParameterHeadDefinition(string name, Func propTypeName, IFProperty meta) + : ParameterDefinition(name, propTypeName, meta) +{ + public override string Serialize(Context context) => $"{(IsReference ? "ref" : string.Empty)} {PropTypeName()} {Name}"; +} + +public class ParameterBodyDefinition(string name, Func propTypeName, IFProperty meta, bool isLast) + : ParameterDefinition(name, propTypeName, meta) +{ + public bool IsLast { get; set; } = isLast; + + public override string Serialize(Context context) + { + var typeName = propTypeName(); + var paramTypeName = FunctionParamFactory.GetParamNameFromProperty(Meta, context.Factory, context.Classes); + if (paramTypeName == null) return $"// PARAM TODO {typeName}"; + typeName = Meta.ClassPrivate.Name switch + { + "ArrayProperty" => "TArray", + "MapProperty" => "TMap", + "SetProperty" => "TSet", + "ByteProperty" => "byte", + "InterfaceProperty" => "TScriptInterface", + "SoftClassProperty" => "TSoftClassPtr", + "SoftObjectProperty" => "TSoftObjectPtr", + _ => typeName + }; + var next = IsLast ? string.Empty : ","; + if (Meta.ClassPrivate.Name is "ObjectProperty" or "ClassProperty" or "ClassPtrProperty") + return $"new {paramTypeName}(new(&{Name + "_Ptr"})){next}"; + var ptrCast = IsReference ? $"({typeName}*)Unsafe.AsPointer(ref {Name})" : $"&{Name}"; + if (!IsReference) + { + ptrCast = Meta.ClassPrivate.Name switch + { + "ByteProperty" => $"(byte*)(&{Name})", + "ArrayProperty" => $"(TArray*)(&{Name})", + "MapProperty" => $"(TMap*)(&{Name})", + "SetProperty" => $"(TSet*)(&{Name})", + "InterfaceProperty" => $"(TScriptInterface*)(&{Name})", + "SoftClassProperty" => $"(TSoftClassPtr*)(&{Name})", + "SoftObjectProperty" => $"(TSoftObjectPtr*)(&{Name})", + _ => ptrCast + }; + } + var paramDecl = Meta.ClassPrivate.Name switch + { + "BoolProperty" => $"new {paramTypeName}(new({ptrCast}), {context.Factory.CreateFBoolProperty(Meta.Ptr).FieldMask})", + "StructProperty" => $"new {paramTypeName}(new({ptrCast}), {context.Factory.CreateFStructProperty(Meta.Ptr).Struct.PropertiesSize})", + "EnumProperty" => $"new {paramTypeName}(new({ptrCast}), {Meta.ElementSize})", + "TextProperty" => $"new {paramTypeName}(new({ptrCast}), {context.Classes.GetFTextSize()})", + _ => $"new {paramTypeName}(new({ptrCast}))" + }; + return $"{paramDecl}{next}"; + } +} + +public class ReturnValueDefinition(Func typeName, string metaName, string? paramTypeName) : ISerializable +{ + public Func TypeName => typeName; + public string MetaName => metaName; + public string? ParamTypeName => paramTypeName; + + private string CreateStructPropertyReturn() + { + var Result = $"{TypeName()} ReturnValue;"; + Result += $"\n\t\t(({ParamTypeName}?)Return)!.Write((nint)(&ReturnValue));"; + Result += "\n\t\treturn ReturnValue;"; + return Result; + } + + private string CreateSingleLineReturn() + { + var ConstructValue = MetaName switch + { + "ObjectProperty" or "ClassProperty" or "ClassPtrProperty" + => $"new(Inner.GetFactory().CreateUObject((({ParamTypeName}?)Return)!.Value))", + "ByteProperty" => $"({TypeName()})((({ParamTypeName}?)Return)!.Value)", + _ => $"(({ParamTypeName}?)Return)!.Value" + }; + return $"return {ConstructValue};"; + } + + public string Serialize(Context context) + { + if (ParamTypeName == null) return $"return null; // RETURN VALUE TODO {TypeName()}"; + return MetaName switch + { + "StructProperty" or "EnumProperty" or "TextProperty" or "ArrayProperty" + or "MapProperty" or "SetProperty" or "InterfaceProperty" + or "SoftClassProperty" or "SoftObjectProperty" or "DelegateProperty" + or "MulticastInlineDelegateProperty" or "MulticastSparseDelegateProperty" + => CreateStructPropertyReturn(), + _ => CreateSingleLineReturn() + }; + } +} + +public class FunctionFactory(Context context) +{ + public List ResolveFunctions(IUClass uclass) + { + var PropFactory = new PropertyClassFactory(context); + return uclass.GetFunctions() + .Where(x => + { + var Name = x.NamePrivate.ToString(); + return !(Name.StartsWith("ExecuteUbergraph") || Name.StartsWith("EvaluateGraphExposedInputs")); + }) + .Select(x => + { + List HeadParams = []; + List BodyParams = []; + List BodyPrefix = []; + List BodyPostfix = []; + ReturnValueDefinition? ReturnValue = null; + Func? returnTypeName = null; + Dictionary nameUse = []; + foreach (var Field in x.ChildProperties) + { + var Param = context.Factory.CreateFProperty(Field.Ptr); + if (Param.PropertyFlags.HasFlag(EPropertyFlags.CPF_ReturnParm)) + { + returnTypeName = PropFactory.GetPropTypenameFunctionParam(Param); + var returnParamName = FunctionParamFactory.GetParamNameFromProperty(Param, context.Factory, context.Classes); + ReturnValue = new(returnTypeName, Param.ClassPrivate.Name, returnParamName); + break; + } + var paramName = Builtins.SanitizeForTypename(Builtins.SanitizeName(Param.NamePrivate)); + if (nameUse.TryGetValue(paramName, out var useCount)) + { + paramName += $"_{useCount}"; + nameUse[paramName] = useCount + 1; + } + else + { + nameUse[paramName] = 1; + } + var propTypeName = PropFactory.GetPropTypenameFunctionParam(Param); + if (propTypeName == null) + { + Log.Error($"{nameof(ResolveFunctions)} || Could not determine data types for all parameters in '{x.NamePrivate}'"); + return null; + } + HeadParams.Add(new ParameterHeadDefinition(paramName, propTypeName, Param )); + BodyParams.Add(new ParameterBodyDefinition(paramName, propTypeName, Param, false )); + if (Param.ClassPrivate.Name is "ObjectProperty" or "ClassProperty" or "ClassPtrProperty") + { + BodyPrefix.Add($"nint {paramName}_Ptr = {paramName}.Inner.Ptr;"); + if (Param.PropertyFlags.HasFlag(EPropertyFlags.CPF_OutParm)) + BodyPostfix.Add($"{paramName} = new(Inner.GetFactory().CreateUObject({paramName}_Ptr));"); + } + } + if (BodyParams.Count > 0) BodyParams.Last().IsLast = true; + var funcName = x.NamePrivate.ToString(); + var funcNameSanitized = Builtins.SanitizeForFunctionName(Builtins.SanitizeName(funcName)); + return new FunctionDefinition(funcNameSanitized, funcName, returnTypeName, HeadParams, BodyParams, ReturnValue, BodyPrefix, BodyPostfix); + }) + .Where(x => x != null) + .ToList(); + } +} + +public class FunctionDefinition(string name, string rawName, Func? returnTypeName, List headParams, + List bodyParams, ReturnValueDefinition? returnParam, List bodyPrefix, List bodyPostfix) + : ISerializable +{ + public string Name { get; } = name; + public string RawName { get; } = rawName; + public Func? ReturnTypeName { get; } = returnTypeName; + public List HeadParams { get; } = headParams; + public List BodyParams { get; } = bodyParams; + public ReturnValueDefinition? ReturnParam { get; } = returnParam; + public List BodyPrefix { get; } = bodyPrefix; + public List BodyPostfix { get; } = bodyPostfix; + + public string Serialize(Context context) + { + var sb = new StringBuilder(); + var returnType = ReturnTypeName?.Invoke() ?? "void"; + sb.AppendLine($"\tpublic unsafe {returnType} {Name}({string.Join(",", HeadParams.Select(x => x.Serialize(context)))})"); + sb.AppendLine("\t{"); + foreach (var preLine in BodyPrefix) sb.AppendLine($"\t\t{preLine}"); + var outVar = (ReturnTypeName != null ? "var Return" : "_"); + if (BodyParams.Count > 0) + { + sb.AppendLine($"\t\t_ = Inner.ProcessEvent(\"{RawName}\", ["); + foreach (var bodyParam in BodyParams) sb.AppendLine($"\t\t\t{bodyParam.Serialize(context)}"); + sb.AppendLine($"\t\t], out {outVar});"); + } + else sb.AppendLine($"\t\t_ = Inner.ProcessEvent(\"{RawName}\", [], out {outVar});"); + foreach (var postLine in BodyPostfix) sb.AppendLine($"\t\t{postLine}"); + if (ReturnParam != null) sb.AppendLine($"\t\t{ReturnParam.Serialize(context)}"); + sb.AppendLine("\t}"); + return sb.ToString(); + } +} \ No newline at end of file diff --git a/UE.Toolkit.DumperMod/Definitions/Property.cs b/UE.Toolkit.DumperMod/Definitions/Property.cs new file mode 100644 index 0000000..015d8e3 --- /dev/null +++ b/UE.Toolkit.DumperMod/Definitions/Property.cs @@ -0,0 +1,390 @@ +using System.Text; +using UE.Toolkit.Core.Types.Unreal.Factories.Interfaces; + +namespace UE.Toolkit.DumperMod.Definitions; + +public abstract class BasePropertyDefintion(string name, int size, int offset, Func propTypeName) : ISerializable +{ + public string Name { get; set; } = name; + public int Size { get; set; } = size; + public int Offset { get; set; } = offset; + public Func PropTypeName { get; } = propTypeName; + + public abstract string Serialize(Context context); +} + +public class PropertyStructDefinition(string name, int size, int offset, Func propTypeName) + : BasePropertyDefintion(name, size, offset, propTypeName) +{ + public override string Serialize(Context context) => $"[FieldOffset(0x{Offset:X})] public {PropTypeName()} {Name}; // Size: 0x{Size:X}"; +} + +public class PropertyClassDefinition(string name, string rawName, int size, int offset, Func propTypeName, + Func accessor, Func? mutator) + : BasePropertyDefintion(name, size, offset, propTypeName) +{ + private string RawName => rawName; + private Func Accessor => accessor; + private Func? Mutator => mutator; + + public override string Serialize(Context context) + { + var propName = Name; + if (propName == "Inner") propName += "_"; + var sb = new StringBuilder(); + sb.AppendLine($"\tpublic unsafe {PropTypeName()} {propName}"); + sb.AppendLine("\t{"); + sb.AppendLine($"\t\t{Accessor(Name, RawName)}"); + if (Mutator != null) sb.AppendLine($"\t\t{Mutator(Name, RawName)}"); + sb.AppendLine("\t}"); + return sb.ToString(); + } +} + +public abstract class BasePropertyFactory(Context context) +{ + protected virtual bool AllowGenerationForProperty(IFProperty prop) => true; + + public List ResolveProperties(IEnumerable propLink, int SuperStructEnd) + { + List props = []; + foreach (var prop in propLink) + { + // Stop when we find a property with an offset lower than the size of the super struct. + // PropertyLink contains a list of fields declared by object in ascending order, then from it's super + // object and so on. + if (prop.Offset_Internal < SuperStructEnd) break; + if (!AllowGenerationForProperty(prop)) continue; + var newProp = ResolveProperty(prop); + if (newProp == null) continue; + var numSameName = props.Count(x => x.Name.StartsWith(newProp.Name)); // Compare against sanitized name, since that's what props are using. + if (numSameName > 0) newProp.Name = $"{newProp.Name}_{numSameName + 1}"; + props.Add(newProp); + } + + return props; + } + + protected abstract BasePropertyDefintion? ResolveProperty(IFProperty prop); + + private static string SafelyCreateGenericType(string Type, bool makeGeneric) + => makeGeneric ? Type : $"nint /* {Type} */"; + + private static string SafelyCreatePointerType(string Type, bool makeGeneric) + => makeGeneric ? $"Ptr<{Type}>" : $"nint /* Ptr<{Type}> */"; + + /// + /// Gets the property type name, such as byte for ByteProperty. + /// This is done lazily since we only have the internal names in + /// when we want their C++/C# equivalent, which isn't known until object registrations finish. + /// + /// + /// C++/C# property type name. + public Func? GetPropTypenameStruct(IFProperty prop, bool makeGenerics) + { + var className = prop.ClassPrivate.Name; + switch (className) + { + case "BoolProperty": + return () => "bool"; + case "ByteProperty": + var byteProp = context.Factory.Cast(prop); + if (byteProp.Enum != null) + { + var byteEnumName = byteProp.Enum.NamePrivate.ToString(); + new EnumFactory(context, ObjectType.Enum, context.Factory.Cast(byteProp.Enum), "byte").Register(); + return () => Builtins.SanitizeName(byteEnumName); + } + + return () => "byte"; + case "Int8Property": + return () => "byte"; + case "Int16Property": + return () => "short"; + case "UInt16Property": + return () => "ushort"; + case "IntProperty": + return () => "int"; + case "UInt32Property": + return () => "uint"; + case "Int64Property": + return () => "long"; + case "UInt64Property": + return () => "ulong"; + case "FloatProperty": + return () => "float"; + case "DoubleProperty": + return () => "double"; + case "NameProperty": + return () => "FName"; + case "StrProperty": + return () => "FString"; + case "TextProperty": + return () => "FText"; + case "DataTableRowHandle": + return () => "FDataTableRowHandle"; + case "DelegateProperty": + return () => "FScriptDelegate"; + case "MulticastInlineDelegateProperty": + case "MulticastSparseDelegateProperty": + return () => "FMulticastScriptDelegate"; + case "WeakObjectProperty": + return () => "FWeakObjectPtr"; + case "ObjectProperty": + var propClass = context.Factory.Cast(prop).PropertyClass; + if (propClass.Ptr == nint.Zero) + { + Log.Error($"{nameof(GetPropTypenameStruct)} || {prop.NamePrivate}->PropertyClass (0x{prop.Ptr:x}) is null"); + return null; + } + var objPropType = propClass.NamePrivate.ToString(); + return () => Builtins.SanitizeName(context.Registry.Structs.TryGetValue(objPropType, out var knownStruct) ? $"{knownStruct.GetUnmanagedTypeName()}*" : $"{objPropType}*"); + case "SoftObjectProperty": + var softObjPropType = context.Factory.Cast(prop).PropertyClass.NamePrivate.ToString(); + // return () => Builtins.SanitizeName(context.Registry.Structs.TryGetValue(softObjPropType, out var knownStruct) ? $"TSoftObjectPtr<{knownStruct.GetUnmanagedTypeName()}>" : $"TSoftObjectPtr<{softObjPropType}>"); + return () => context.Registry.Structs.TryGetValue(softObjPropType, out var knownStruct) ? + $"TSoftObjectPtr<{SafelyCreateGenericType(knownStruct.GetUnmanagedTypeName(), makeGenerics)}>" : + $"TSoftObjectPtr<{SafelyCreateGenericType(Builtins.SanitizeName(softObjPropType), makeGenerics)}>"; + case "SoftClassProperty": + var softClassPropType = context.Factory.Cast(prop).MetaClass.NamePrivate.ToString(); + return () => context.Registry.Structs.TryGetValue(softClassPropType, out var knownStruct) ? + $"TSoftClassPtr<{SafelyCreateGenericType(knownStruct.GetUnmanagedTypeName(), makeGenerics)}>" : + $"TSoftClassPtr<{SafelyCreateGenericType(Builtins.SanitizeName(softClassPropType), makeGenerics)}>"; + case "StructProperty": + var structPropType = context.Factory.Cast(prop).Struct.NamePrivate.ToString(); + return () => Builtins.SanitizeName(context.Registry.Structs.TryGetValue(structPropType, out var knownStruct) ? knownStruct.GetUnmanagedTypeName() : structPropType); + case "ClassProperty": + case "ClassPtrProperty": + var classPropClass = context.Factory.Cast(prop).MetaClass; + var classPropType = classPropClass != null ? classPropClass.NamePrivate.ToString() : "UClass*"; + return () => Builtins.SanitizeName(context.Registry.Structs.TryGetValue(classPropType, out var knownStruct) ? $"{knownStruct.GetUnmanagedTypeName()}*" : classPropType); + case "EnumProperty": + var enumProp = context.Factory.Cast(prop); + var enumClass = enumProp.Enum; + if (enumClass.Ptr == nint.Zero) + { + Log.Error($"{nameof(GetPropTypenameStruct)} || {prop.NamePrivate}->Enum (0x{prop.Ptr:x}) is null"); + return null; + } + var enumPropName = enumClass.NamePrivate.ToString(); + new EnumFactory(context, ObjectType.Enum, enumClass, context.Classes.GetPropertyTypeName(enumProp.UnderlyingProp)).Register(); + return () => Builtins.SanitizeName(enumPropName); + case "MapProperty": + var mapProp = context.Factory.Cast(prop); + return () => + { + var mapPropKeyType = GetPropTypenameStruct(mapProp.KeyProp, makeGenerics)(); + var mapPropValueType = GetPropTypenameStruct(mapProp.ValueProp, makeGenerics)(); + var isKeyPtr = mapPropKeyType.EndsWith('*') || mapPropKeyType.Contains('<'); // Use nint for pointers and generic types. + var isValuePtr = mapPropValueType.EndsWith('*') || mapPropValueType.Contains('<'); + + var keyName = Builtins.SanitizeName(mapPropKeyType.TrimEnd('*')); + var valueName = Builtins.SanitizeName(mapPropValueType.TrimEnd('*')); + + var keyType = isKeyPtr ? SafelyCreatePointerType(keyName, makeGenerics) : keyName; + var valueType = isValuePtr ? SafelyCreatePointerType(valueName, makeGenerics) : valueName; + + return $"TMap<{keyType}, {valueType}>"; + }; + case "InterfaceProperty": + var intPropType = context.Factory.Cast(prop).InterfaceClass.NamePrivate.ToString(); + return () => Builtins.SanitizeName(context.Registry.Structs.TryGetValue(intPropType, out var knownStruct) ? $"TScriptInterface<{knownStruct.GetUnmanagedTypeName()}>" : $"TScriptInterface<{intPropType}>"); + case "ArrayProperty": + return () => + { + var arrayPropType = GetPropTypenameStruct(context.Factory.Cast(prop).Inner, makeGenerics)(); + var isPtrType = arrayPropType.EndsWith('*') || arrayPropType.Contains('<'); // Use nint for pointers and generic types. + var arrTypeSanitized = Builtins.SanitizeName(arrayPropType.TrimEnd('*')); + return isPtrType ? + $"TArray<{SafelyCreatePointerType(arrTypeSanitized, makeGenerics)}>" : + $"TArray<{arrTypeSanitized}>"; + }; + case "SetProperty": + return () => + { + var setPropType = GetPropTypenameStruct(context.Factory.Cast(prop).ElementProp, makeGenerics)(); + var isPtrType = setPropType.EndsWith('*') || setPropType.Contains('<'); // Use nint for pointers and generic types.; + var setPropTypeSanitized = Builtins.SanitizeName(setPropType.TrimEnd('*')); + return isPtrType ? + $"TSet<{SafelyCreatePointerType(setPropTypeSanitized, makeGenerics)}>" : + $"TSet<{setPropTypeSanitized}>"; + }; + case "OptionalProperty": + return () => + { + var optionalType = GetPropTypenameStruct(context.Factory.Cast(prop).ValueProperty, makeGenerics)(); + if (context.Registry.Structs.TryGetValue(optionalType, out var knownOptType)) + optionalType = knownOptType.GetUnmanagedTypeName(); + + return $"TOptional<{Builtins.SanitizeName(optionalType)}>"; + }; + case "FieldPathProperty": + return () => "FFieldPath"; + case "LazyObjectProperty": + var lazyObjType = context.Factory.Cast(prop).PropertyClass.NamePrivate.ToString(); + return () => + { + if (context.Registry.Structs.TryGetValue(lazyObjType, out var knownLazyType)) + lazyObjType = knownLazyType.GetUnmanagedTypeName(); + + return $"TLazyObjectPtr<{SafelyCreateGenericType(Builtins.SanitizeName(lazyObjType), makeGenerics)}>"; + }; + case "Utf8StrProperty": + return () => "FUtf8String"; + case "AnsiStrProperty": + return () => "FAnsiString"; + default: + Log.Warning($"Unknown Property: {className}"); + return () => className; + } + } + + protected (string Name, int Size, int Offset, string ClassName) GetBaseInfo(IFProperty prop) + { + var name = Builtins.SanitizeForTypename(Builtins.SanitizeName(prop.NamePrivate)); + var size = prop.ElementSize; + var offset = prop.Offset_Internal; + var className = prop.ClassPrivate.Name; + // name = Builtins.SanitizeForParam(name); + return (name, size, offset, className); + } +} + +public class PropertyStructFactory(Context context) : BasePropertyFactory(context) +{ + protected override BasePropertyDefintion? ResolveProperty(IFProperty prop) + { + var (name, size, offset, _) = GetBaseInfo(prop); + var typename = GetPropTypenameStruct(prop, false); + return typename != null ? new PropertyStructDefinition(name, size, offset, typename) : null; + } +} + +public class PropertyClassFactory(Context context) : BasePropertyFactory(context) +{ + private Func GetPropAccessor(IFProperty prop, Func getTypeName) + { + var className = prop.ClassPrivate.Name; + switch (className) + { + // Pass by value + case "ByteProperty" or "Int8Property" or "Int16Property" or "UInt16Property" or "IntProperty" + or "UInt32Property" or "Int64Property" or "UInt64Property" or "FloatProperty" or "DoubleProperty" + or "NameProperty" or "EnumProperty" : + return (_, raw) => $"get => *({getTypeName()}*)(Inner.Ptr + GetFieldOffset(\"{raw}\"));"; + // Pass by reference + case "StructProperty" or "StrProperty" or "ArrayProperty" or "MapProperty" + or "SoftObjectProperty" or "SoftClassProperty" or "TextProperty" + or "WeakObjectProperty" or "SetProperty" or "DelegateProprety" + or "MulticastInlineDelegateProperty" or "MulticastSparseDelegateProperty": + return (_, raw) => $"get => ({getTypeName()})(Inner.Ptr + GetFieldOffset(\"{raw}\"));"; + case "BoolProperty": + var BoolProp = context.Factory.CreateFBoolProperty(prop.Ptr); + return (BoolProp.FieldMask == byte.MaxValue) switch + { + true => (_, raw) => $"get => *(bool*)(Inner.Ptr + GetFieldOffset(\"{raw}\"));", + false => (_, raw) => $"get => (*(byte*)(Inner.Ptr + GetFieldOffset(\"{raw}\")) & {BoolProp.FieldMask}) == 0;" + }; + case "ObjectProperty" or "ClassProperty" or "ClassPtrProperty": + return (_, raw) => + $"get => new(Inner.GetFactory().CreateUObject(*(nint*)(Inner.Ptr + GetFieldOffset(\"{raw}\"))));"; + default: + return (_, _) => $"get => throw new NotSupportedException(\"!! GET TODO {className} !!\");"; + } + } + + private Func? GetPropMutator(IFProperty prop, Func getTypeName) + { + var className = prop.ClassPrivate.Name; + switch (className) + { + // Pass by value + case "ByteProperty" or "Int8Property" or "Int16Property" or "UInt16Property" or "IntProperty" + or "UInt32Property" or "Int64Property" or "UInt64Property" or "FloatProperty" or "DoubleProperty" + or "NameProperty" or "EnumProperty": + return (_, raw) => $"set => *({getTypeName()}*)(Inner.Ptr + GetFieldOffset(\"{raw}\")) = value;"; + // Pass by reference, don't create mutator + case "StructProperty" or "StrProperty" or "ArrayProperty" or "MapProperty" + or "SoftObjectProperty" or "SoftClassProperty" or "TextProperty" + or "WeakObjectProperty" or "SetProperty" or "DelegateProprety" + or "MulticastInlineDelegateProperty" or "MulticastSparseDelegateProperty": + return null; + case "BoolProperty": + var BoolProp = context.Factory.CreateFBoolProperty(prop.Ptr); + return (BoolProp.FieldMask == byte.MaxValue) switch + { + true => (_, raw) => $"set => *(bool*)(Inner.Ptr + GetFieldOffset(\"{raw}\")) = value;", + false => (param, raw) => $"set => *(byte*)(Inner.Ptr + GetFieldOffset(\"{raw}\")) ^= (byte)(Convert.ToByte({param} != value) * {BoolProp.FieldMask});" + }; + case "ObjectProperty" or "ClassProperty" or "ClassPtrProperty": + return (_, raw) => $"set => *(nint*)(Inner.Ptr + GetFieldOffset(\"{raw}\")) = value.Inner.Ptr;"; + default: + return (_, _) => $"set => throw new NotSupportedException(\"!! SET TODO {className} !!\");"; + } + } + + private Func GetClassPropTypenameManaged(IUClass classPropClass) + { + var classPropType = classPropClass != null ? classPropClass.NamePrivate.ToString() : "UClass"; + return () => Builtins.SanitizeName(context.Registry.Structs.TryGetValue(classPropType, out var knownStruct) ? $"{knownStruct.DisplayName}" : classPropType); + } + + private Func? GetPropTypenameClass(IFProperty prop) + { + var className = prop.ClassPrivate.Name; + switch (className) + { + // Passed by reference + case "StructProperty" or "StrProperty" or "ArrayProperty" or "MapProperty" + or "SoftObjectProperty" or "SoftClassProperty" or "TextProperty" + or "WeakObjectProperty" or "SetProperty" or "DelegateProprety" + or "MulticastInlineDelegateProperty" or "MulticastSparseDelegateProperty": + return () => GetPropTypenameStruct(prop, true)() + "*"; + case "ClassProperty" or "ClassPtrProperty": + return GetClassPropTypenameManaged(context.Factory.Cast(prop).MetaClass); + case "ObjectProperty": + var propClass = context.Factory.Cast(prop).PropertyClass; + if (propClass.Ptr == nint.Zero) + { + Log.Error($"{nameof(GetPropTypenameClass)} || {prop.NamePrivate}->PropertyClass (0x{prop.Ptr:x}) is null"); + return null; + } + var objPropType = propClass.NamePrivate.ToString(); + return () => Builtins.SanitizeName(context.Registry.Structs.TryGetValue(objPropType, out var knownStruct) ? $"{knownStruct.DisplayName}" : $"{objPropType}"); + default: + return GetPropTypenameStruct(prop, true); + } + } + + internal Func? GetPropTypenameFunctionParam(IFProperty prop) + { + var className = prop.ClassPrivate.Name; + switch (className) + { + case "ClassProperty" or "ClassPtrProperty": + return GetClassPropTypenameManaged(context.Factory.Cast(prop).MetaClass); + case "ObjectProperty": + var propClass = context.Factory.Cast(prop).PropertyClass; + if (propClass.Ptr == nint.Zero) + { + Log.Error($"{nameof(GetPropTypenameClass)} || {prop.NamePrivate}->PropertyClass (0x{prop.Ptr:x}) is null"); + return null; + } + var objPropType = propClass.NamePrivate.ToString(); + return () => Builtins.SanitizeName(context.Registry.Structs.TryGetValue(objPropType, out var knownStruct) ? $"{knownStruct.DisplayName}" : $"{objPropType}"); + default: + return GetPropTypenameStruct(prop, true); + } + } + + protected override BasePropertyDefintion? ResolveProperty(IFProperty prop) + { + var (name, size, offset, _) = GetBaseInfo(prop); + var propTypename = GetPropTypenameClass(prop); + // Cannot continue + if (propTypename == null) return null; + var getAccessor = GetPropAccessor(prop, propTypename); + var getMutator = GetPropMutator(prop, propTypename); + return new PropertyClassDefinition(name, prop.NamePrivate, size, offset, propTypename, getAccessor, getMutator); + } +} \ No newline at end of file diff --git a/UE.Toolkit.DumperMod/Definitions/Registry.cs b/UE.Toolkit.DumperMod/Definitions/Registry.cs new file mode 100644 index 0000000..55b8b63 --- /dev/null +++ b/UE.Toolkit.DumperMod/Definitions/Registry.cs @@ -0,0 +1,90 @@ +using System.Text; +using UE.Toolkit.Core.Types.Unreal.Factories.Interfaces; +using UE.Toolkit.Core.Types.Unreal.UE5_4_4; + +namespace UE.Toolkit.DumperMod.Definitions; + +[Flags] +public enum ObjectType +{ + None = 0, + Class = 1 << 0, // inherits from UClass + Struct = 1 << 1, // inherits from UScriptStruct + Enum = 1 << 2, // inherits from UEnum + Interface = 1 << 3, // inherits from UInterface + Function = 1 << 5, // inherits from UFunction +} + +public class Registry(Context context) +{ + private Context Context = context; + + public Dictionary Structs = []; + public Dictionary Enums = []; + + private IObjectFactory? GetObjectFactory(IUObject obj) + { + if (obj.IsChildOf()) + { + var objectType = ObjectType.Class; + if (obj.IsChildOf()) objectType |= ObjectType.Interface; + return Mod.Config.Schema switch + { + DumpSchema.Static => new ClassFactoryStatic(Context, objectType, Context.Factory.Cast(obj)), + DumpSchema.Dynamic => new ClassFactory(Context, objectType, Context.Factory.Cast(obj)), + }; + } + if (obj.IsChildOf()) + return new StructFactory(Context, ObjectType.Struct, Context.Factory.Cast(obj)); + if (obj.IsChildOf()) + return new EnumFactory(Context, ObjectType.Enum, Context.Factory.Cast(obj)); + return null; + } + + public void Register() + { + var objectArray = Context.Objects.GUObjectArray; + for (var i = 0; i < objectArray.NumElements; i++) + { + var obj = objectArray.IndexToObject(i); + if (obj == null) continue; + // Interfaces? (Interface) + GetObjectFactory(obj)?.Register(); + } + } + + private void SerializeDefinition(string Name, ISerializable ser, StringBuilder? sb, ref int numDumped) + { + if (Mod.Config.Mode == DumpFileMode.FilePerType) + { + var outputFile = Path.Join(Context.DumpDirectory, $"{Name}.cs"); + File.WriteAllText(outputFile, ser.Serialize(Context)); + } + else sb?.AppendLine(ser.Serialize(Context)); + numDumped++; + } + + public void Serialize(StringBuilder? sb, ref int numDumped) + { + foreach (var (_, Definition) in Context.Registry.Structs) + SerializeDefinition(Definition.DisplayName, Definition, sb, ref numDumped); + foreach (var (Name, Definition) in Context.Registry.Enums) + SerializeDefinition(Name, Definition, sb, ref numDumped); + } + + private static string GetModuleNameForPackage(IUObject package) + { + if (package.OuterPrivate != null) + { + throw new("Encountered a package with an outer object set"); + } + + var packageName = package.NamePrivate.ToString(); + if (!packageName.StartsWith("/Script/")) + { + return string.Empty; + } + + return packageName["/Script/".Length..]; + } +} \ No newline at end of file diff --git a/UE.Toolkit.DumperMod/Definitions/Struct.cs b/UE.Toolkit.DumperMod/Definitions/Struct.cs new file mode 100644 index 0000000..f34e999 --- /dev/null +++ b/UE.Toolkit.DumperMod/Definitions/Struct.cs @@ -0,0 +1,106 @@ +using System.Text; +using UE.Toolkit.Core.Types.Unreal.Factories.Interfaces; + +namespace UE.Toolkit.DumperMod.Definitions; + +public class StructFactory(Context context, ObjectType objectType, IUScriptStruct scriptStruct) : BaseObjectFactory(context, objectType) +{ + public override void Register() + { + var structName = scriptStruct.NamePrivate.ToString(); + var structNativeName = "F" + structName; + var alignment = scriptStruct.MinAlignment; + var align = alignment - 1; + var size = (scriptStruct.PropertiesSize + align) & ~align; + var super = scriptStruct.SuperStruct; + var superLastProp = super?.PropertyLink.MaxBy(x => x.Offset_Internal); + var superSize = superLastProp?.Offset_Internal + superLastProp?.ElementSize ?? 0; + // var superSize = super?.PropertiesSize ?? 0; + var superName = super?.NamePrivate.ToString(); + if ((superName ?? string.Empty) == structName) + { + Log.Warning($"{nameof(StructFactory)} || '{structNativeName}' is recursive"); + return; + } + var props = new PropertyStructFactory(Context).ResolveProperties(scriptStruct.PropertyLink, superSize); + Context.Registry.Structs[structName] = new StructDefinition(structName, structNativeName, size, alignment, props, superName); + } +} + +public abstract class BaseStructDefinition( + string internalName, + string displayName, + int size, + int alignment, + List properties, + string? superInternalName) : ISerializable +{ + public string InternalName { get; } = internalName; + public string DisplayName { get; } = displayName; + public int Size { get; } = size; + public int Alignment { get; } = alignment; + public List Properties { get; } = properties; + public string? SuperInternalName { get; } = superInternalName; + + public abstract string Serialize(Context context); +} + +public class StructDefinition( + string internalName, + string displayName, + int size, + int alignment, + List propClass, + string? superInternalName) : BaseStructDefinition( + internalName, displayName, size, alignment, propClass, superInternalName) +{ + + protected void WriteStructBase(StringBuilder sb, string StructName, string? SuperName, int SuperSize, Context context) + { + sb.AppendLine($"[StructLayout(LayoutKind.Explicit, Pack = {Alignment}, Size = 0x{Size:X})]"); + sb.AppendLine($"public unsafe struct {StructName}\n{{"); + if (SuperName != null) + { + sb.AppendLine($"\t[FieldOffset(0x0)] public {SuperName} Super; // Size: 0x{SuperSize:X}"); + } + foreach (var prop in Properties) + sb.AppendLine($"\t{prop.Serialize(context)}"); + } + + protected (string?, int) GetSuperInfo(Context context) + { + string? superName = null; + var superSize = 0; + if (SuperInternalName != null) + { + if (context.Registry.Structs.TryGetValue(SuperInternalName, out var super)) + { + superName = Builtins.SanitizeName(super.DisplayName); + superSize = super.Size; + } + else + { + Log.Warning($"Failed to get super: {SuperInternalName}"); + } + } + return (superName, superSize); + } + + public override string Serialize(Context context) + { + var sb = new StringBuilder(); + + if (Mod.Config.Mode == DumpFileMode.FilePerType) context.Builtins.AddHeader(sb); + + var structName = Builtins.SanitizeName(DisplayName); + + var (superName, superSize) = GetSuperInfo(context); + WriteStructBase(sb, structName, superName, superSize, context); + sb.AppendLine("}"); + return sb.ToString(); + } + + public virtual ObjectType Type => ObjectType.Struct; + + public virtual string GetUnmanagedTypeName() => DisplayName; +} \ No newline at end of file diff --git a/UE.Toolkit.DumperMod/Dumper.cs b/UE.Toolkit.DumperMod/Dumper.cs index 3d3039f..3dc5bcf 100644 --- a/UE.Toolkit.DumperMod/Dumper.cs +++ b/UE.Toolkit.DumperMod/Dumper.cs @@ -1,633 +1,61 @@ -using System.Diagnostics; +using System.Diagnostics; using System.Text; using UE.Toolkit.Core.Types.Unreal.Factories; -using UE.Toolkit.Core.Types.Unreal.Factories.Interfaces; -using UE.Toolkit.Core.Types.Unreal.UE5_4_4; +using UE.Toolkit.DumperMod.Definitions; using UE.Toolkit.Interfaces; - -// ReSharper disable InconsistentNaming +using UnrealEssentials.Interfaces; namespace UE.Toolkit.DumperMod; -public unsafe class Dumper +public class Dumper( + IUnrealFactory factory, + IUnrealObjects uobjs, + IUnrealStrings strs, + IUnrealClasses classes, + string dumpDir, + IUnrealEssentials essentials) { - private record PropertyDefinition(string Name, int Size, int Offset, Func PropTypeName) : ICsharpText - { - public string GetCsharpText() - { - return $"[FieldOffset(0x{Offset:X})] public {PropTypeName()} {SanitizeName(Name)}; // Size: 0x{Size:X}"; - } - } - - private record UStructDefinition(string InternalName, string DisplayName, int Size, int Alignment, PropertyDefinition[] Properties, string? SuperInternalName) : ICsharpText - { - public string Name => SanitizeName(DisplayName); - - public string GetCsharpText() - { - var sb = new StringBuilder(); - - if (Mod.Config.Mode == DumpFileMode.FilePerType) - { - AddHeader(sb); - } - - sb.AppendLine($"[StructLayout(LayoutKind.Explicit, Pack = {Alignment}, Size = 0x{Size:X})]"); - sb.AppendLine($"public unsafe struct {SanitizeName(DisplayName)}\n{{"); - if (SuperInternalName != null) - { - if (_UStructDefinitions.TryGetValue(SuperInternalName, out var super)) - { - sb.AppendLine($" [FieldOffset(0x0)] public {SanitizeName(super.DisplayName)} Super; // Size: 0x{super.Size:X}"); - } - else - { - Log.Warning($"Failed to get super: {SuperInternalName}"); - } - } - - foreach (var prop in Properties) - { - sb.AppendLine($" {prop.GetCsharpText()}"); - } - - sb.AppendLine("}"); - return sb.ToString(); - } - } - - private record UEnumDefinition(string Name, string UnderlyingType, Dictionary Entries) : ICsharpText - { - public string GetCsharpText() - { - var sb = new StringBuilder(); - - if (Mod.Config.Mode == DumpFileMode.FilePerType) - { - AddHeader(sb); - } - - sb.AppendLine($"public enum {SanitizeName(Name)} : {UnderlyingType}\n{{"); - foreach (var entry in Entries) - { - sb.AppendLine($" {SanitizeEntryName(entry.Key)} = {entry.Value},"); - } - - sb.AppendLine("}"); - return sb.ToString(); - } - - private static string SanitizeEntryName(string name) => SanitizeName(name.Split("::").Last()); - } - - private static readonly Dictionary _UStructDefinitions = []; - private readonly Dictionary _UEnumDefinitions = []; - private readonly string _dumpDir; - private readonly IUnrealObjects _uobjs; - private readonly IUnrealStrings _strs; - private readonly IUnrealFactory _factory; - private readonly IUnrealClasses _classes; - - public Dumper(IUnrealFactory factory, IUnrealObjects uobjs, IUnrealStrings strs, IUnrealClasses classes, string dumpDir) - { - _uobjs = uobjs; - _strs = strs; - _dumpDir = dumpDir; - _factory = factory; - _classes = classes; - - if (Directory.Exists(dumpDir)) Directory.Delete(dumpDir, true); - Directory.CreateDirectory(dumpDir); - } + private Context Context = new(factory, uobjs, strs, classes, dumpDir, essentials); public void DumpObjects() { Log.Information("Dumping objects..."); var sw = new Stopwatch(); - sw.Start(); - RegisterObjects(); - + Context.Registry.Register(); + sw.Stop(); + StringBuilder? sb = null; if (Mod.Config.Mode == DumpFileMode.SingleFile) { sb = new(); - AddHeader(sb); - AddPtrDefinition(sb); + Context.Builtins.AddHeader(sb); + if (Mod.Config.Schema == DumpSchema.Dynamic) Context.Builtins.AddBaseObjectDefinition(sb); } else { - var outputFile = Path.Join(_dumpDir, "Builtin_Ptr.cs"); - var sbPtr = new StringBuilder(); - AddHeader(sbPtr); - AddPtrDefinition(sbPtr); - File.WriteAllText(outputFile, sbPtr.ToString()); - } - - var numDumped = 0; - foreach (var item in _UStructDefinitions) - { - if (Mod.Config.Mode == DumpFileMode.FilePerType) - { - var outputFile = Path.Join(_dumpDir, $"{item.Value.DisplayName}.cs"); - File.WriteAllText(outputFile, item.Value.GetCsharpText()); - } - else - { - sb?.AppendLine(item.Value.GetCsharpText()); - } - - numDumped++; + var outputFile = Path.Join(Context.DumpDirectory, "UObjectImpl.cs"); + var implWriter = new StringBuilder(); + Context.Builtins.AddHeader(implWriter); + if (Mod.Config.Schema == DumpSchema.Dynamic) Context.Builtins.AddBaseObjectDefinition(implWriter); + File.WriteAllText(outputFile, implWriter.ToString()); } - foreach (var item in _UEnumDefinitions) - { - if (Mod.Config.Mode == DumpFileMode.FilePerType) - { - var outputFile = Path.Join(_dumpDir, $"{item.Key}"); - File.WriteAllText(outputFile, item.Value.GetCsharpText()); - } - else - { - sb?.AppendLine(item.Value.GetCsharpText()); - } - - numDumped++; - } - + var numDumped = 0; + Context.Registry.Serialize(sb, ref numDumped); sw.Stop(); if (Mod.Config.Mode == DumpFileMode.SingleFile) { var singleFileOutput = string.IsNullOrEmpty(Mod.Config.SingleFileOutputName) - ? Path.Join(_dumpDir, "Types.cs") - : Path.Join(_dumpDir, $"{Mod.Config.SingleFileOutputName.Replace(".cs", string.Empty)}.cs"); - + ? Path.Join(Context.DumpDirectory, "Types.cs") + : Path.Join(Context.DumpDirectory, $"{Mod.Config.SingleFileOutputName.Replace(".cs", string.Empty)}.cs"); File.WriteAllText(singleFileOutput, sb!.ToString()); Log.Information($"{numDumped} objects dumped in {sw.ElapsedMilliseconds}ms.\nOutput File: {singleFileOutput}"); } else { - Log.Information($"{numDumped} objects dumped in {sw.ElapsedMilliseconds}ms.\nOutput Folder: {_dumpDir}"); - } - } - - private void RegisterObjects() - { - var objArray = _uobjs.GUObjectArray; - for (int i = 0; i < _uobjs.GUObjectArray.NumElements; i++) - { - //if (i > _uobjs.GUObjectArray.ObjLastNonGCIndex) break; - - var obj = _uobjs.GUObjectArray.IndexToObject(i); - if (obj == null) continue; - - // var uclass = (Core.Types.Unreal.UE4_27_2.UClass*)obj.Ptr; - // continue; - var moduleName = GetModuleNameForPackage(obj.GetOutermost()); - var fileBaseName = GetHeaderNameForObject(obj); - - if (obj.IsChildOf()) - { - var uclass = _factory.Cast(obj); - if (obj.IsChildOf()) - { - // TODO: - var interfaceName = obj.NamePrivate.ToString(); - _UStructDefinitions[interfaceName] = new(interfaceName, interfaceName, 0, 0, [], null); - Log.Debug($"Interface: {interfaceName}"); - } - else - { - GenerateObjectDefinition(uclass); - } - } - else if (obj.IsChildOf()) - { - GenerateStructDefinition(_factory.Cast(obj)); - } - else if (obj.IsChildOf()) - { - GenerateEnumDefinition(_factory.Cast(obj)); - } - } - } - - private static string GetModuleNameForPackage(IUObject package) - { - if (package.OuterPrivate != null) - { - throw new("Encountered a package with an outer object set"); - } - - var packageName = package.NamePrivate.ToString(); - if (!packageName.StartsWith("/Script/")) - { - return string.Empty; - } - - return packageName["/Script/".Length..]; - } - - private static string GetHeaderNameForObject(IUObject obj) - { - string? headerName = null; - UObjectBase* finalObj; - - if (obj.IsA() || obj.IsA()) - { - headerName = obj.NamePrivate.ToString(); - } - else if (obj.IsA()) - { - headerName = obj.NamePrivate.ToString(); - } - else - { - // TODO: UFunction stuff; - } - - // TODO: Other stuff? - return headerName; - } - - private static void AddHeader(StringBuilder sb) - { - sb.AppendLine("/* Generated with UE Toolkit: Dumper (1.9.0) */"); - sb.AppendLine("/* GitHub: https://github.com/RyoTune/UE.Toolkit */"); - sb.AppendLine("/* Author: RyoTune */"); - sb.AppendLine("/* Special thanks to UE4SS team and Rirurin */"); - sb.AppendLine("/* whose code was used for reference. */"); - sb.AppendLine(); - - sb.AppendLine("using System.Runtime.InteropServices;"); - - if (!string.IsNullOrEmpty(Mod.Config.FileUsings)) - { - var usings = Mod.Config.FileUsings.Split(';', - StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries) - .Select(x => x.Replace("using ", string.Empty)); - foreach (var use in usings) sb.AppendLine($"using {use};"); - } - - sb.AppendLine(); - if (!string.IsNullOrEmpty(Mod.Config.FileNamespace)) - { - sb.AppendLine($"namespace {Mod.Config.FileNamespace.TrimEnd(';').Replace("namespace ", string.Empty)};"); - sb.AppendLine(); + Log.Information($"{numDumped} objects dumped in {sw.ElapsedMilliseconds}ms.\nOutput Folder: {Context.DumpDirectory}"); } } - - private static void AddPtrDefinition(StringBuilder sb) - { - sb.AppendLine("public readonly unsafe struct Ptr(T* value) : IEquatable>"); - sb.AppendLine(" where T : unmanaged"); - sb.AppendLine("{"); - sb.AppendLine(" public readonly T* Value = value;"); - sb.AppendLine(); - sb.AppendLine(" public bool Equals(Ptr other) => Value == other.Value;"); - sb.AppendLine(" public static bool operator ==(Ptr a, Ptr b) => a.Equals(b);"); - sb.AppendLine(" public static bool operator !=(Ptr a, Ptr b) => !a.Equals(b);"); - sb.AppendLine("}"); - sb.AppendLine(); - } - - private void GenerateObjectDefinition(IUClass uclass) - { - var className = uclass.NamePrivate.ToString(); - var classNativeName = uclass.GetNativeName(); - var size = uclass.PropertiesSize; - var alignment = uclass.MinAlignment; - - // TODO: Flag stuff? - - var super = uclass.GetSuperClass(); - var superSize = super?.PropertiesSize ?? 0; - var superName = super?.NamePrivate.ToString(); - //var superNativeName = super != null ? GetNativeClassName(super) : "UObjectBaseUtility"; - - // TODO: Add super header data. - - // TODO: Generate delegates. - - var properties = ResolveProperties(uclass.PropertyLink, superSize); - - // TODO: Generate functions. - - _UStructDefinitions[className] = - new(className, classNativeName, size, alignment, properties, superName); - - Log.Debug($"UObject: {classNativeName}"); - } - - private void GenerateStructDefinition(IUScriptStruct scriptStruct) - { - var structName = scriptStruct.NamePrivate.ToString(); - var structNativeName = scriptStruct.GetNativeName(); - var size = scriptStruct.PropertiesSize; - var alignment = scriptStruct.MinAlignment; - var super = scriptStruct.SuperStruct; - var superSize = super?.PropertiesSize ?? 0; - var superName = super?.NamePrivate.ToString(); - //var superNativeName = super != null ? GetNativeStructName((UScriptStruct*)super) : null; - - var props = ResolveProperties(scriptStruct.PropertyLink, superSize); - - _UStructDefinitions[structName] = new(structName, structNativeName, size, alignment, props, superName); - Log.Debug($"UScriptStruct: {structNativeName}"); - } - - private void GenerateEnumDefinition(IUEnum uenum, string? knownType = null) - { - var name = uenum.NamePrivate.ToString(); - if (_UEnumDefinitions.ContainsKey(name) && knownType == null) return; - - var entries = new Dictionary(); - - var dispNames = new Dictionary(); - if (uenum.IsChildOf()) - { - var userEnum = _factory.Cast(uenum); - for (var i = 0; i < uenum.Names.ArrayNum; i++) - { - var dispName = _strs.UEnumGetDisplayNameTextByIndex(userEnum.Ptr, i); - dispNames[i] = $"{name}::{dispName}"; - } - } - - long bigEntryValue = 0; - string bigEntryName = string.Empty; - for (int i = 0; i < uenum.Names.ArrayNum; i++) - { - var entry = &uenum.Names.AllocatorInstance[i]; - - if (!dispNames.TryGetValue(i, out var entryName)) - { - entryName = entry->Key.ToString(); - } - - var entryValue = entry->Value; - entries[entryName] = entryValue; - - if (bigEntryValue < entryValue) - { - bigEntryValue = entryValue; - bigEntryName = entryName; - } - } - - var entryConstant = $"{name}::{name}_MAX"; - if (entries.TryGetValue(entryConstant, out var entryConstantValue) && entryConstantValue == bigEntryValue) - { - entries.Remove(entryConstant); - } - - if (bigEntryValue == 256 && bigEntryName.EndsWith("_MAX")) entries.Remove(bigEntryName); - - var underlyingType = knownType ?? bigEntryValue switch - { - <= byte.MaxValue => "byte", - <= short.MaxValue => "short", - <= int.MaxValue => "int", - <= long.MaxValue => "long", - }; - - bool hasNegativeValue = entries.Any(x => x.Value < 0); - if (underlyingType == "byte" && hasNegativeValue) underlyingType = "sbyte"; - if (underlyingType != "byte" && !hasNegativeValue && !underlyingType.StartsWith('u')) underlyingType = $"u{underlyingType}"; - - _UEnumDefinitions[name] = new(name, underlyingType, entries); - } - - private PropertyDefinition[] ResolveProperties(IEnumerable propLink, int SuperStructEnd) - { - var props = new List(); - foreach (var prop in propLink) - { - // Stop when we find a property with an offset lower than the size of the super struct. - // PropertyLink contains a list of fields declared by object in ascending order, then from it's super - // object and so on. - if (prop.Offset_Internal < SuperStructEnd) - break; - var newProp = ResolveProperty(prop); - var numSameName = props.Count(x => x.Name.StartsWith(newProp.Name)); // Compare against sanitized name, since that's what props are using. - - // Handle multiple properties with the same name. - if (numSameName == 0) - { - props.Add(newProp); - } - else - { - props.Add(newProp with { Name = $"{newProp.Name}_{numSameName + 1}" }); - } - } - - return props.ToArray(); - } - - private PropertyDefinition ResolveProperty(IFProperty prop) - { - var (name, size, offset, _) = GetBaseInfo(prop); - if (name == "bool" || name == "float") name += '_'; - - var resProp = new PropertyDefinition(SanitizeName(name), size, offset, GetPropertyTypeNameLazy(prop)); - return resProp; - } - - /// - /// Gets the property type name, such as byte for ByteProperty. - /// This is done lazily since we only have the internal names in - /// when we want their C++/C# equivalent, which isn't known until object registrations finish. - /// - /// - /// C++/C# property type name. - private Func GetPropertyTypeNameLazy(IFProperty prop) - { - var className = prop.ClassPrivate.Name; - switch (className) - { - case "BoolProperty": - return () => "bool"; - case "ByteProperty": - var byteProp = _factory.Cast(prop); - if (byteProp.Enum != null) - { - var byteEnumName = byteProp.Enum.NamePrivate.ToString(); - GenerateEnumDefinition(_factory.Cast(byteProp.Enum), "byte"); - return () => SanitizeName(byteEnumName); - } - - return () => "byte"; - case "Int8Property": - return () => "byte"; - case "Int16Property": - return () => "short"; - case "UInt16Property": - return () => "ushort"; - case "IntProperty": - return () => "int"; - case "UInt32Property": - return () => "uint"; - case "Int64Property": - return () => "long"; - case "UInt64Property": - return () => "ulong"; - case "FloatProperty": - return () => "float"; - case "DoubleProperty": - return () => "double"; - case "NameProperty": - return () => "FName"; - case "StrProperty": - return () => "FString"; - case "TextProperty": - return () => "FText"; - case "DataTableRowHandle": - return () => "FDataTableRowHandle"; - case "DelegateProperty": - return () => "FScriptDelegate"; - case "MulticastInlineDelegateProperty": - case "MulticastSparseDelegateProperty": - return () => "FMulticastScriptDelegate"; - case "WeakObjectProperty": - return () => "FWeakObjectPtr"; - case "ObjectProperty": - var objPropType = _factory.Cast(prop).PropertyClass.NamePrivate.ToString(); - return () => SanitizeName(_UStructDefinitions.TryGetValue(objPropType, out var knownStruct) ? $"{knownStruct.DisplayName}*" : $"{objPropType}*"); - case "SoftObjectProperty": - var softObjPropType = _factory.Cast(prop).PropertyClass.NamePrivate.ToString(); - return () => SanitizeName(_UStructDefinitions.TryGetValue(softObjPropType, out var knownStruct) ? $"TSoftObjectPtr<{knownStruct.DisplayName}>" : $"TSoftObjectPtr<{softObjPropType}>"); - case "SoftClassProperty": - var softClassPropType = _factory.Cast(prop).MetaClass.NamePrivate.ToString(); - return () => SanitizeName(_UStructDefinitions.TryGetValue(softClassPropType, out var knownStruct) ? $"TSoftClassPtr<{knownStruct.DisplayName}>" : $"TSoftClassPtr<{softClassPropType}>"); - case "StructProperty": - var structPropType = _factory.Cast(prop).Struct.NamePrivate.ToString(); - return () => SanitizeName(_UStructDefinitions.TryGetValue(structPropType, out var knownStruct) ? knownStruct.DisplayName : structPropType); - case "ClassProperty": - case "ClassPtrProperty": - var classPropClass = _factory.Cast(prop).MetaClass; - var classPropType = classPropClass != null ? classPropClass.NamePrivate.ToString() : "UClass*"; - return () => SanitizeName(_UStructDefinitions.TryGetValue(classPropType, out var knownStruct) ? $"{knownStruct.DisplayName}*" : classPropType); - case "EnumProperty": - var enumProp = _factory.Cast(prop); - var enumPropName = enumProp.Enum.NamePrivate.ToString(); - GenerateEnumDefinition(enumProp.Enum, _classes.GetPropertyTypeName(enumProp.UnderlyingProp)); - return () => SanitizeName(enumPropName); - case "MapProperty": - var mapProp = _factory.Cast(prop); - var mapPropKeyType = _classes.GetPropertyTypeName(mapProp.KeyProp); - var mapPropValueType = _classes.GetPropertyTypeName(mapProp.ValueProp); - return () => - { - var isKeyPtr = mapPropKeyType.EndsWith('*') || mapPropKeyType.Contains('<'); // Use nint for pointers and generic types. - var isValuePtr = mapPropValueType.EndsWith('*') || mapPropValueType.Contains('<'); - - _UStructDefinitions.TryGetValue(mapPropKeyType.TrimEnd('*'), out var knownKeyStruct); - _UStructDefinitions.TryGetValue(mapPropValueType.TrimEnd('*'), out var knownValueStruct); - - var keyName = SanitizeName(knownKeyStruct?.DisplayName ?? mapPropKeyType); - var valueName = SanitizeName(knownValueStruct?.DisplayName ?? mapPropValueType); - - var keyType = isKeyPtr ? $"Ptr<{keyName}>" : keyName; - var valueType = isValuePtr ? $"Ptr<{valueName}>" : valueName; - - return $"TMap<{keyType}, {valueType}>"; - }; - case "InterfaceProperty": - var intPropType = _factory.Cast(prop).InterfaceClass.NamePrivate.ToString(); - return () => SanitizeName(_UStructDefinitions.TryGetValue(intPropType, out var knownStruct) ? $"TScriptInterface<{knownStruct.DisplayName}>" : $"TScriptInterface<{intPropType}>"); - case "ArrayProperty": - var arrayPropType = _classes.GetPropertyTypeName(_factory.Cast(prop).Inner); - return () => - { - var isPtrType = arrayPropType.EndsWith('*') || arrayPropType.Contains('<'); // Use nint for pointers and generic types. - _UStructDefinitions.TryGetValue(arrayPropType.TrimEnd('*'), out var knownStruct); - var arrTypeSanitized = SanitizeName(knownStruct?.DisplayName ?? arrayPropType); - return isPtrType ? - $"TArray>" : - $"TArray<{arrTypeSanitized}>"; - }; - case "SetProperty": - var setPropType = _classes.GetPropertyTypeName(_factory.Cast(prop).ElementProp); - return () => - { - var isPtrType = setPropType.EndsWith('*') || setPropType.Contains('<'); // Use nint for pointers and generic types.; - _UStructDefinitions.TryGetValue(setPropType.TrimEnd('*'), out var knownStruct); - return isPtrType - ? $"TSet /* TSet<{setPropType}> */" - : $"TSet<{SanitizeName(knownStruct?.DisplayName ?? setPropType)}>"; - }; - case "OptionalProperty": - var optionalType = _classes.GetPropertyTypeName(_factory.Cast(prop).ValueProperty); - return () => - { - if (_UStructDefinitions.TryGetValue(optionalType, out var knownOptType)) - optionalType = knownOptType.DisplayName; - - return $"TOptional<{SanitizeName(optionalType)}>"; - }; - case "FieldPathProperty": - return () => "FFieldPath"; - case "LazyObjectProperty": - var lazyObjType = _factory.Cast(prop).PropertyClass.NamePrivate.ToString(); - return () => - { - if (_UStructDefinitions.TryGetValue(lazyObjType, out var knownLazyType)) - lazyObjType = knownLazyType.DisplayName; - - return $"TLazyObjectPtr<{SanitizeName(lazyObjType)}>"; - }; - case "Utf8StrProperty": - return () => "FUtf8String"; - case "AnsiStrProperty": - return () => "FAnsiString"; - default: - Log.Warning($"Unknown Property: {className}"); - return () => className; - } - } - - private (string Name, int Size, int Offset, string ClassName) GetBaseInfo(IFProperty prop) - { - var name = SanitizeName(prop.NamePrivate); - var size = prop.ElementSize; - var offset = prop.Offset_Internal; - var className = prop.ClassPrivate.Name; - return (name, size, offset, className); - } - - private static string SanitizeName(string name) - { - var parts = name.Split('_'); - if (parts.Last().Length == 32 && parts.Length > 2) - { - name = string.Join(string.Empty, parts[..^2]); - } - - name = name.Replace(' ', '_'); - name = name.Replace('-', '_'); - name = name.Replace('/', '_'); - name = name.Replace("?", string.Empty); - name = name.Replace("&", string.Empty); - name = name.Replace('(', '_'); - name = name.Replace(')', '_'); - name = name.Replace('[', '_'); - name = name.Replace(']', '_'); - if (name == "object") name = "_object"; - - if (char.IsDigit(name[0])) - { - name = '_' + name; - } - - return name; - } - - private interface ICsharpText - { - string Name { get; } - - string GetCsharpText(); - } } \ No newline at end of file diff --git a/UE.Toolkit.DumperMod/Mod.cs b/UE.Toolkit.DumperMod/Mod.cs index 926b6d9..11ae6b6 100644 --- a/UE.Toolkit.DumperMod/Mod.cs +++ b/UE.Toolkit.DumperMod/Mod.cs @@ -6,6 +6,7 @@ using UE.Toolkit.Core.Types.Unreal.Factories; using UE.Toolkit.DumperMod.Template; using UE.Toolkit.Interfaces; +using UnrealEssentials.Interfaces; namespace UE.Toolkit.DumperMod; @@ -33,6 +34,12 @@ public Mod(ModContext context) #endif Project.Initialize(_modConfig, _modLoader, _log, true); Log.LogLevel = Config.LogLevel; + + if (!_modLoader.GetController().TryGetTarget(out var _essentials)) + { + throw new Exception( + "Unreal Essentials is missing! Download the latest version from https://github.com/AnimatedSwine37/UnrealEssentials/releases"); + } _modLoader.GetController().TryGetTarget(out var objs); _modLoader.GetController().TryGetTarget(out var strs); @@ -41,7 +48,11 @@ public Mod(ModContext context) var dumpDir = Path.Join(_modLoader.GetDirectoryForModId(_modConfig.ModId), "dump", _modLoader.GetAppConfig().AppId); - _dumper = new(factory!, objs!, strs!, classes!, dumpDir); + if (!Directory.Exists(dumpDir)) + { + Directory.CreateDirectory(dumpDir); + } + _dumper = new(factory!, objs!, strs!, classes!, dumpDir, _essentials); } #region Standard Overrides diff --git a/UE.Toolkit.DumperMod/ModConfig.json b/UE.Toolkit.DumperMod/ModConfig.json index ab9294e..1789cfb 100644 --- a/UE.Toolkit.DumperMod/ModConfig.json +++ b/UE.Toolkit.DumperMod/ModConfig.json @@ -1,8 +1,8 @@ { "ModId": "UE.Toolkit.DumperMod", "ModName": "UE Toolkit: Dumper", - "ModAuthor": "RyoTune", - "ModVersion": "1.9.0", + "ModAuthor": "RyoTune, Rirurin", + "ModVersion": "1.10.0", "ModDescription": "Unreal Engine object dumper to C# types.", "ModDll": "UE.Toolkit.DumperMod.dll", "ModIcon": "Preview.png", @@ -44,6 +44,15 @@ "AssetFileName": "Mod.zip" }, "ReleaseMetadataName": "UE.Toolkit.Reloaded.ReleaseMetadata.json" + }, + "UnrealEssentials": { + "Config": { + "UserName": "AnimatedSwine37", + "RepositoryName": "UnrealEssentials", + "UseReleaseTag": false, + "AssetFileName": "Mod.zip" + }, + "ReleaseMetadataName": "UnrealEssentials.ReleaseMetadata.json" } } }, @@ -58,7 +67,8 @@ "ModDependencies": [ "reloaded.sharedlib.hooks", "Reloaded.Memory.SigScan.ReloadedII", - "UE.Toolkit.Reloaded" + "UE.Toolkit.Reloaded", + "UnrealEssentials" ], "OptionalDependencies": [], "SupportedAppId": [ diff --git a/UE.Toolkit.DumperMod/UE.Toolkit.DumperMod.csproj b/UE.Toolkit.DumperMod/UE.Toolkit.DumperMod.csproj index 9547de9..03cbc41 100644 --- a/UE.Toolkit.DumperMod/UE.Toolkit.DumperMod.csproj +++ b/UE.Toolkit.DumperMod/UE.Toolkit.DumperMod.csproj @@ -1,10 +1,10 @@  - net8.0-windows + net9.0 false true - 12.0 + 13.0 enable True $(RELOADEDIIMODS)/UE.Toolkit.DumperMod @@ -47,6 +47,7 @@ + diff --git a/UE.Toolkit.Interfaces/ITypeReflection.cs b/UE.Toolkit.Interfaces/ITypeReflection.cs index 6119f96..58e849e 100644 --- a/UE.Toolkit.Interfaces/ITypeReflection.cs +++ b/UE.Toolkit.Interfaces/ITypeReflection.cs @@ -1,4 +1,5 @@ -using UE.Toolkit.Core.Types.Unreal.Common; +using UE.Toolkit.Core.Types.Interfaces; +using UE.Toolkit.Core.Types.Unreal.Common; using UE.Toolkit.Core.Types.Unreal.Factories.Interfaces; namespace UE.Toolkit.Interfaces; @@ -6,26 +7,8 @@ namespace UE.Toolkit.Interfaces; /// /// API for obtaining special type reflection info which cannot be obtained entirely through the runtime reflection system. /// -public interface ITypeReflection +public interface ITypeReflection : ITypeReflectionInternal { - - #region FText - - /// - /// Get the FText type used by the currently running version of the engine. - /// UE 5.4 and later have a significantly different FText implement compared to earlier versions. - /// - /// Type information for the FText. - Type GetFText(); - /// - /// Get the size of the FText type used by the currently running version of the engine. - /// UE 5.4 and later have a significantly different FText implement compared to earlier versions. - /// - /// Size of FText. - int GetFTextSize(); - - #endregion - #region FSoftObjectPath /// diff --git a/UE.Toolkit.Interfaces/IUnrealClasses.cs b/UE.Toolkit.Interfaces/IUnrealClasses.cs index cfcfc49..467fead 100644 --- a/UE.Toolkit.Interfaces/IUnrealClasses.cs +++ b/UE.Toolkit.Interfaces/IUnrealClasses.cs @@ -67,7 +67,7 @@ public interface IUnrealClasses : IUnrealClassesInternal, ITypeReflection #endregion - #region Struct Field Extension Methods + #region Struct Field Extension Methods (parented to object) /// /// Listen for the creation of an object's class, then extend it's allocation size and call a custom constructor @@ -283,7 +283,7 @@ public bool AddClassProperty(string Name, int Offset, out IFCla public bool AddTextProperty(string Name, int Offset, out IFProperty? Out) where TObject : unmanaged; /// - /// Add a Array (TArray) containing elememts of the property defined in Inner to the object's class with the + /// Add a Array (TArray) containing elements of the property defined in Inner to the object's class with the /// specified name and offset. This will make the field exposable to blueprints and Object XML. /// /// Name of the new field. @@ -294,6 +294,188 @@ public bool AddClassProperty(string Name, int Offset, out IFCla public bool AddArrayProperty(string Name, int Offset, IFProperty Inner, out IFArrayProperty? Property) where TObject : unmanaged; + /* + /// + /// Add a map (TMap) with it's key and value types defined in Key and Value, and with the + /// specified name and offset. This will make the field exposable to blueprints and Object XML. + /// + /// Name of the new field. + /// Offset of the new field. + /// The property used for each key in the map. + /// The property used for each value in the map. + /// Return value. + /// Object type. + public bool AddMapProperty(string Name, int Offset, + IFProperty Key, IFProperty Value, out IFArrayProperty? Property) where TObject : unmanaged; + */ + + #endregion + + #region Struct Field Extension Methods (no parent) + + /// + /// Add an Int8 property to the object's class with the specified name and offset. This will make the field + /// exposable to blueprints and Object XML. + /// + /// Name of the new field. + /// Offset of the new field. + /// Return value. + public bool AddI8Property(string Name, int Offset, out IFProperty? Out) ; + + /// + /// Add a Int16 property to the object's class with the specified name and offset. This will make the field + /// exposable to blueprints and Object XML. + /// + /// Name of the new field. + /// Offset of the new field. + /// Return value. + public bool AddI16Property(string Name, int Offset, out IFProperty? Out) ; + + /// + /// Add a Int32 property to the object's class with the specified name and offset. This will make the field + /// exposable to blueprints and Object XML. + /// + /// Name of the new field. + /// Offset of the new field. + /// Return value. + public bool AddI32Property(string Name, int Offset, out IFProperty? Out) ; + + /// + /// Add a Int64 property to the object's class with the specified name and offset. This will make the field + /// exposable to blueprints and Object XML. + /// + /// Name of the new field. + /// Offset of the new field. + /// Return value. + public bool AddI64Property(string Name, int Offset, out IFProperty? Out) ; + + /// + /// Add a UInt8 property to the object's class with the specified name and offset. This will make the field + /// exposable to blueprints and Object XML. + /// + /// Name of the new field. + /// Offset of the new field. + /// Return value. + public bool AddU8Property(string Name, int Offset, out IFProperty? Out) ; + + /// + /// Add a UInt16 property to the object's class with the specified name and offset. This will make the field + /// exposable to blueprints and Object XML. + /// + /// Name of the new field. + /// Offset of the new field. + /// Return value. + public bool AddU16Property(string Name, int Offset, out IFProperty? Out) ; + + /// + /// Add a UInt32 property to the object's class with the specified name and offset. This will make the field + /// exposable to blueprints and Object XML. + /// + /// Name of the new field. + /// Offset of the new field. + /// Return value. + public bool AddU32Property(string Name, int Offset, out IFProperty? Out) ; + + /// + /// Add a UInt64 property to the object's class with the specified name and offset. This will make the field + /// exposable to blueprints and Object XML. + /// + /// Name of the new field. + /// Offset of the new field. + /// Return value. + public bool AddU64Property(string Name, int Offset, out IFProperty? Out) ; + + /// + /// Add a float property to the object's class with the specified name and offset. This will make the field + /// exposable to blueprints and Object XML. + /// + /// Name of the new field. + /// Offset of the new field. + /// Return value. + public bool AddF32Property(string Name, int Offset, out IFProperty? Out) ; + + /// + /// Add a double property to the object's class with the specified name and offset. This will make the field + /// exposable to blueprints and Object XML. + /// + /// Name of the new field. + /// Offset of the new field. + /// Return value. + public bool AddF64Property(string Name, int Offset, out IFProperty? Out) ; + + /// + /// Add a by-value struct to the object's class with the specified name and offset. This will make the field + /// exposable to blueprints and Object XML. + /// + /// Name of the new field. + /// Offset of the new field. + /// Return value. + /// Field type. + public bool AddStructProperty(string Name, int Offset, out IFStructProperty? Out) + where TField : unmanaged; + + /// + /// Add a by-value struct to the object's class with the specified name and offset. This will make the field + /// exposable to blueprints and Object XML. + /// + /// Name of the new field. + /// Field type. + /// Offset of the new field. + /// Return value. + public bool AddStructProperty(string Name, string TypeName, int Offset, out IFStructProperty? Out); + + /// + /// Add a by-reference struct to the object's class with the specified name and offset. This will make the field + /// exposable to blueprints and Object XML. + /// This is constructed as an ObjectProperty, but with the object type set to a UScriptStruct instead of a UClass + /// to make the underlying table in a DataTable viewable by the type reflection system (big hack, but needed for + /// data table debugging tools). + /// + /// Name of the new field. + /// Field type. + /// Offset of the new field. + /// Return value. + public bool AddStructProperty_DataTableSpecial(string Name, string TypeName, int Offset, out IFObjectProperty? Out); + + /// + /// Add a FName to the object's class with the specified name and offset. This will make the field + /// exposable to blueprints and Object XML. + /// + /// Name of the new field. + /// Offset of the new field. + /// Return value. + public bool AddNameProperty(string Name, int Offset, out IFProperty? Out) ; + + /// + /// Add a FString to the object's class with the specified name and offset. This will make the field + /// exposable to blueprints and Object XML. + /// + /// Name of the new field. + /// Offset of the new field. + /// Return value. + public bool AddStringProperty(string Name, int Offset, out IFProperty? Out) ; + + /// + /// Add a FText to the object's class with the specified name and offset. This will make the field + /// exposable to blueprints and Object XML. + /// + /// Name of the new field. + /// Offset of the new field. + /// Return value. + public bool AddTextProperty(string Name, int Offset, out IFProperty? Out) ; + + + /// + /// Add a map (TMap) with it's key and value types defined in Key and Value, and with the + /// specified name and offset. This will make the field exposable to blueprints and Object XML. + /// + /// Name of the new field. + /// Offset of the new field. + /// The property used for each key in the map. + /// The property used for each value in the map. + /// Return value. + public bool AddMapProperty(string Name, int Offset, + IFProperty Key, IFProperty Value, out IFMapProperty? Property); #endregion #region New Struct Construction diff --git a/UE.Toolkit.Interfaces/UE.Toolkit.Interfaces.csproj b/UE.Toolkit.Interfaces/UE.Toolkit.Interfaces.csproj index b1e6b90..9032814 100644 --- a/UE.Toolkit.Interfaces/UE.Toolkit.Interfaces.csproj +++ b/UE.Toolkit.Interfaces/UE.Toolkit.Interfaces.csproj @@ -6,7 +6,7 @@ enable true https://github.com/RyoTune/UE.Toolkit - 1.9.0 + 1.10.0 diff --git a/UE.Toolkit.Reloaded/Common/DynamicMap/String.cs b/UE.Toolkit.Reloaded/Common/DynamicMap/String.cs index 48351db..774d59c 100644 --- a/UE.Toolkit.Reloaded/Common/DynamicMap/String.cs +++ b/UE.Toolkit.Reloaded/Common/DynamicMap/String.cs @@ -17,7 +17,9 @@ public class StringDynamicMapKeyType(IFMapProperty property, IUnrealFactory fact public override unsafe bool FromString(string text, [NotNullWhen(true)] out IDynamicMapKey? key) { - key = new StringDynamicMapKey(*Objects.CreateFString(text), Memory); + var pString = Objects.CreateFString(text); + key = new StringDynamicMapKey(*pString, Memory); + Memory.Free((nint)pString); return true; } diff --git a/UE.Toolkit.Reloaded/Common/GameConfigs/GameConfig.cs b/UE.Toolkit.Reloaded/Common/GameConfigs/GameConfig.cs index 64f7729..8d056a0 100644 --- a/UE.Toolkit.Reloaded/Common/GameConfigs/GameConfig.cs +++ b/UE.Toolkit.Reloaded/Common/GameConfigs/GameConfig.cs @@ -36,7 +36,8 @@ public static void SetGame(string appId, IUnrealEssentials essentials) { "++UE4+Release-4.27" => new UE4_27_2_P3R(), "++UE5+Release-5.0" => new UE5_0_3(), - "++UE5+Release-5.1" or "++UE5+Release-5.2" => new UE5_2_1(), + "++UE5+Release-5.1" => new UE5_1_1(), + "++UE5+Release-5.2" => new UE5_2_1(), "++UE5+Release-5.3" => new UE5_3_2(), "++UE5+Release-5.6" => new UE5_6_1(), "++UE5+Release-5.7" => new UE5_7_4(), diff --git a/UE.Toolkit.Reloaded/Common/GameConfigs/Games/UE5_0_3.cs b/UE.Toolkit.Reloaded/Common/GameConfigs/Games/UE5_0_3.cs index 58b7a22..daf302f 100644 --- a/UE.Toolkit.Reloaded/Common/GameConfigs/Games/UE5_0_3.cs +++ b/UE.Toolkit.Reloaded/Common/GameConfigs/Games/UE5_0_3.cs @@ -1,6 +1,6 @@ using UE.Toolkit.Core.Types.Unreal.Common; using UE.Toolkit.Core.Types.Unreal.Factories; -using UE.Toolkit.Core.Types.Unreal.Factories.UE5_2_1; +using UE.Toolkit.Core.Types.Unreal.Factories.UE5_0_3; using UE.Toolkit.Interfaces; using UE.Toolkit.Reloaded.Reflection; using UE.Toolkit.Reloaded.Reflection.UE5_2_1; diff --git a/UE.Toolkit.Reloaded/Common/GameConfigs/Games/UE5_1_1.cs b/UE.Toolkit.Reloaded/Common/GameConfigs/Games/UE5_1_1.cs new file mode 100644 index 0000000..167b41f --- /dev/null +++ b/UE.Toolkit.Reloaded/Common/GameConfigs/Games/UE5_1_1.cs @@ -0,0 +1,26 @@ +using UE.Toolkit.Core.Types.Unreal.Factories; +using UE.Toolkit.Core.Types.Unreal.Factories.UE5_0_3; +using UE.Toolkit.Interfaces; +using UE.Toolkit.Reloaded.Reflection; +using UE.Toolkit.Reloaded.Reflection.UE5_2_1; +using UE.Toolkit.Reloaded.Unreal; + +namespace UE.Toolkit.Reloaded.Common.GameConfigs.Games; + +public class UE5_1_1 : UE5_4_4_ClairObscur +{ + public override string Id => "UE5_1_1"; + public override IUnrealFactory Factory { get; } = new UnrealFactory(); + public override IUnrealMemory Memory { get; } = new UnrealMemory(); + public override IPropertyFlagsBuilder FlagsBuilder { get; } = new PropertyFlagsBuilder(); + + public override BasePropertyFactory PropertyFactory(IUnrealClasses classes) + => new PropertyFactory(Factory, Memory, classes, FlagsBuilder); + + public override BaseTypeFactory TypeFactory(IUnrealClasses classes) + => new TypeFactory(Factory, Memory, classes, FlagsBuilder); + + public override Type GetFText() => typeof(UE.Toolkit.Core.Types.Unreal.UE4_27_2.FText); + + public override unsafe int GetFTextSize() => sizeof(UE.Toolkit.Core.Types.Unreal.UE4_27_2.FText); +} \ No newline at end of file diff --git a/UE.Toolkit.Reloaded/Mod.cs b/UE.Toolkit.Reloaded/Mod.cs index d57ecda..4a285c2 100644 --- a/UE.Toolkit.Reloaded/Mod.cs +++ b/UE.Toolkit.Reloaded/Mod.cs @@ -87,6 +87,8 @@ public Mod(ModContext context) _address = new(); _classes = new(_factory, _memory, _objects, _hooks, _address); _methods = new(_factory, _memory, _classes, _objects, _hooks); + _factory.ProcessEvent = _methods.CallProcessEvent; + _factory.CreateReturnParam = _methods.CreateReturnParam; _state = new(_factory, _classes); _spawning = new(_classes, _factory, _state); _writer = new(_objects, _tables, _memory, _classes, _factory); diff --git a/UE.Toolkit.Reloaded/ModConfig.json b/UE.Toolkit.Reloaded/ModConfig.json index c7ee7a4..4dedf14 100644 --- a/UE.Toolkit.Reloaded/ModConfig.json +++ b/UE.Toolkit.Reloaded/ModConfig.json @@ -2,7 +2,7 @@ "ModId": "UE.Toolkit.Reloaded", "ModName": "Unreal Toolkit", "ModAuthor": "RyoTune, Rirurin", - "ModVersion": "1.9.1", + "ModVersion": "1.10.0", "ModDescription": "Modding toolkit for Unreal Engine games.\r\nSupports games between UE 4.27 and UE 5.7", "ModDll": "UE.Toolkit.Reloaded.dll", "ModIcon": "Preview.png", diff --git a/UE.Toolkit.Reloaded/ObjectWriters/Nodes/NodeFactory.cs b/UE.Toolkit.Reloaded/ObjectWriters/Nodes/NodeFactory.cs index 3b3ff5b..50a0796 100644 --- a/UE.Toolkit.Reloaded/ObjectWriters/Nodes/NodeFactory.cs +++ b/UE.Toolkit.Reloaded/ObjectWriters/Nodes/NodeFactory.cs @@ -44,7 +44,7 @@ public unsafe IFieldNode Create(IFProperty property, nint fieldPtr) "FloatProperty" => new FloatNode(property, new((float*)fieldPtr)), "DoubleProperty" => new DoubleNode(property, new((double*)fieldPtr)), "NameProperty" => new NameNode(property, new((FName*)fieldPtr)), - "StrProperty" => new StrNode(property, new((FString*)fieldPtr), Objects), + "StrProperty" => new StrNode(property, new((FString*)fieldPtr), Objects, Memory), "TextProperty" => new TextNode(property, new((FText*)fieldPtr), Objects), "ObjectProperty" => new ObjectNode(Factory.CreateFObjectProperty(property.Ptr), fieldPtr, this), "SoftObjectProperty" => new SoftObjectNode(property, new((FSoftObjectPtr*)fieldPtr), Classes), diff --git a/UE.Toolkit.Reloaded/ObjectWriters/Nodes/StrNode.cs b/UE.Toolkit.Reloaded/ObjectWriters/Nodes/StrNode.cs index 8153dd7..541bad5 100644 --- a/UE.Toolkit.Reloaded/ObjectWriters/Nodes/StrNode.cs +++ b/UE.Toolkit.Reloaded/ObjectWriters/Nodes/StrNode.cs @@ -1,20 +1,23 @@ using System.Runtime.InteropServices; using UE.Toolkit.Core.Types; +using UE.Toolkit.Core.Types.Interfaces; using UE.Toolkit.Core.Types.Unreal.Factories.Interfaces; using UE.Toolkit.Core.Types.Unreal.UE5_4_4; using UE.Toolkit.Interfaces; namespace UE.Toolkit.Reloaded.ObjectWriters.Nodes; -public class StrNode(IFProperty property, Ptr value, IUnrealObjects unrealObjects) +public class StrNode(IFProperty property, Ptr value, IUnrealObjects unrealObjects, IUnrealMemoryInternal unrealMemory) : TextPrimitiveNode(property, value) { private IUnrealObjects UnrealObjects => unrealObjects; + private IUnrealMemoryInternal UnrealMemory => unrealMemory; protected override unsafe void SetField(string text) { var fstring = UnrealObjects.CreateFString(text); *Value.Value = *fstring; + UnrealMemory.Free((nint)fstring); } protected override unsafe void SetInitialValue() diff --git a/UE.Toolkit.Reloaded/Project/UE.Toolkit.Reloaded/chronos-win64-shipping/unreal.ini b/UE.Toolkit.Reloaded/Project/UE.Toolkit.Reloaded/chronos-win64-shipping/unreal.ini index 99fd744..9e43853 100644 --- a/UE.Toolkit.Reloaded/Project/UE.Toolkit.Reloaded/chronos-win64-shipping/unreal.ini +++ b/UE.Toolkit.Reloaded/Project/UE.Toolkit.Reloaded/chronos-win64-shipping/unreal.ini @@ -11,7 +11,7 @@ QuantizeSize=0x48 ProcessEvent=0x268 [UScriptStruct] -GetCustomGuid=0x378 +GetCustomGuid=0x380 [UPackage] GamePackage=/Script/Chronos diff --git a/UE.Toolkit.Reloaded/Project/UE.Toolkit.Reloaded/iostoretest_50-win64-shipping/unreal.ini b/UE.Toolkit.Reloaded/Project/UE.Toolkit.Reloaded/iostoretest_50-win64-shipping/unreal.ini index 071aafa..42abbbd 100644 --- a/UE.Toolkit.Reloaded/Project/UE.Toolkit.Reloaded/iostoretest_50-win64-shipping/unreal.ini +++ b/UE.Toolkit.Reloaded/Project/UE.Toolkit.Reloaded/iostoretest_50-win64-shipping/unreal.ini @@ -8,10 +8,10 @@ Realloc=0x20 QuantizeSize=0x38 [UObject] -ProcessEvent=0x268 +ProcessEvent=0x258 [UScriptStruct] -GetCustomGuid=0x378 +GetCustomGuid=0x370 [UPackage] GamePackage=/Script/IOStoreTest_50 diff --git a/UE.Toolkit.Reloaded/Project/UE.Toolkit.Reloaded/iostoretest_51-win64-shipping/unreal.ini b/UE.Toolkit.Reloaded/Project/UE.Toolkit.Reloaded/iostoretest_51-win64-shipping/unreal.ini index dd33289..d6e2a24 100644 --- a/UE.Toolkit.Reloaded/Project/UE.Toolkit.Reloaded/iostoretest_51-win64-shipping/unreal.ini +++ b/UE.Toolkit.Reloaded/Project/UE.Toolkit.Reloaded/iostoretest_51-win64-shipping/unreal.ini @@ -8,7 +8,7 @@ Realloc=0x20 QuantizeSize=0x38 [UObject] -ProcessEvent=0x268 +ProcessEvent=0x260 [UScriptStruct] GetCustomGuid=0x378 diff --git a/UE.Toolkit.Reloaded/Project/UE.Toolkit.Reloaded/iostoretest_52-win64-shipping/unreal.ini b/UE.Toolkit.Reloaded/Project/UE.Toolkit.Reloaded/iostoretest_52-win64-shipping/unreal.ini index 1a1ed15..7f4b396 100644 --- a/UE.Toolkit.Reloaded/Project/UE.Toolkit.Reloaded/iostoretest_52-win64-shipping/unreal.ini +++ b/UE.Toolkit.Reloaded/Project/UE.Toolkit.Reloaded/iostoretest_52-win64-shipping/unreal.ini @@ -11,7 +11,7 @@ QuantizeSize=0x48 ProcessEvent=0x268 [UScriptStruct] -GetCustomGuid=0x378 +GetCustomGuid=0x380 [UPackage] GamePackage=/Script/IOStoreTest_52 diff --git a/UE.Toolkit.Reloaded/Project/UE.Toolkit.Reloaded/iostoretest_55-win64-shipping/unreal.ini b/UE.Toolkit.Reloaded/Project/UE.Toolkit.Reloaded/iostoretest_55-win64-shipping/unreal.ini index f0a1ad4..c1646cd 100644 --- a/UE.Toolkit.Reloaded/Project/UE.Toolkit.Reloaded/iostoretest_55-win64-shipping/unreal.ini +++ b/UE.Toolkit.Reloaded/Project/UE.Toolkit.Reloaded/iostoretest_55-win64-shipping/unreal.ini @@ -8,10 +8,10 @@ Realloc=0x38 QuantizeSize=0x60 [UObject] -ProcessEvent=0x268 +ProcessEvent=0x278 [UScriptStruct] -GetCustomGuid=0x378 +GetCustomGuid=0x398 [UPackage] GamePackage=/Script/IOStoreTest_55 diff --git a/UE.Toolkit.Reloaded/Project/UE.Toolkit.Reloaded/iostoretest_56-win64-shipping/unreal.ini b/UE.Toolkit.Reloaded/Project/UE.Toolkit.Reloaded/iostoretest_56-win64-shipping/unreal.ini index 15a830b..735ae61 100644 --- a/UE.Toolkit.Reloaded/Project/UE.Toolkit.Reloaded/iostoretest_56-win64-shipping/unreal.ini +++ b/UE.Toolkit.Reloaded/Project/UE.Toolkit.Reloaded/iostoretest_56-win64-shipping/unreal.ini @@ -8,10 +8,10 @@ Realloc=0x38 QuantizeSize=0x60 [UObject] -ProcessEvent=0x268 +ProcessEvent=0x260 [UScriptStruct] -GetCustomGuid=0x378 +GetCustomGuid=0x380 [UPackage] GamePackage=/Script/IOStoreTest_56 diff --git a/UE.Toolkit.Reloaded/Project/UE.Toolkit.Reloaded/iostoretest_57-win64-shipping/unreal.ini b/UE.Toolkit.Reloaded/Project/UE.Toolkit.Reloaded/iostoretest_57-win64-shipping/unreal.ini index 887d641..14ff3fc 100644 --- a/UE.Toolkit.Reloaded/Project/UE.Toolkit.Reloaded/iostoretest_57-win64-shipping/unreal.ini +++ b/UE.Toolkit.Reloaded/Project/UE.Toolkit.Reloaded/iostoretest_57-win64-shipping/unreal.ini @@ -8,10 +8,10 @@ Realloc=0x38 QuantizeSize=0x60 [UObject] -ProcessEvent=0x268 +ProcessEvent=0x260 [UScriptStruct] -GetCustomGuid=0x378 +GetCustomGuid=0x380 [UPackage] GamePackage=/Script/IOStoreTest_57 diff --git a/UE.Toolkit.Reloaded/Reflection/PropertyFactory.cs b/UE.Toolkit.Reloaded/Reflection/PropertyFactory.cs index af15891..472bcde 100644 --- a/UE.Toolkit.Reloaded/Reflection/PropertyFactory.cs +++ b/UE.Toolkit.Reloaded/Reflection/PropertyFactory.cs @@ -53,7 +53,7 @@ public bool CheckPropertyEquality(string Name, uint OtherValue) return Value.ComparisonIndex.Value == OtherValue; } - private bool GetProperty(string Name, out FieldClassGlobal? FieldClass) + protected bool GetProperty(string Name, out FieldClassGlobal? FieldClass) { FieldClass = null; PropertyNames ??= InitializePropertyNames(); @@ -72,7 +72,9 @@ protected bool TryGetClassAndProperty(string PropertyName, out IUClass? #region INTERNAL INTERFACE - protected abstract void LinkToPropertyList(IFProperty Property, IUClass Reflect); + protected abstract void LinkToPropertyList(IFProperty Property, IUClass? Reflect); + + #region Properties Owned by a Class protected abstract void SetPropertySuperFields(IFField Field, string Name, IUClass ClassReflection, FieldClassGlobal PropertyClass); @@ -126,6 +128,54 @@ protected bool CreateTextPropertyInner(out IFProperty where TProperty : unmanaged => CreatePropertyInner(out NewProperty, Name, Offset, PropertyName, Visibility, SetTextPropertyFields); + + #endregion + + // Used in cases where we're constructing a type parameter for a generic type such as an array or map, + // so we don't want the element linked to a class. Set no parent initially, then let the array/map + // property initializer set the owners for the type params. + #region Unowned Properties + + protected abstract void SetPropertySuperFieldsNoOwner(IFField Field, string Name, FieldClassGlobal PropertyClass); + + private bool CreatePropertyInner(out IFProperty? NewProperty, + string Name, int Offset, string PropertyName, PropertyVisibility Visibility, + Action Callback) + where TProperty : unmanaged + { + NewProperty = null; + if (!GetProperty(PropertyName, out var PropertyClass)) + return false; + var Alloc = Memory.Malloc(Marshal.SizeOf(), FIELD_ALIGNMENT); + SetPropertySuperFieldsNoOwner(Factory.CreateFField(Alloc), Name, PropertyClass!); + NewProperty = Factory.CreateFProperty(Alloc); + Callback(NewProperty, Offset, Visibility); + LinkToPropertyList(NewProperty, null); + return true; + } + + protected bool CreateCopyPropertyInner(out IFProperty? NewProperty, + string Name, int Offset, string PropertyName, PropertyVisibility Visibility) + where TField : unmanaged + where TProperty : unmanaged + => CreatePropertyInner(out NewProperty, Name, + Offset, PropertyName, Visibility, SetCopyPropertyFields); + + protected bool CreateStringPropertyInner(out IFProperty? NewProperty, + string Name, int Offset, string PropertyName, PropertyVisibility Visibility) + where TField : unmanaged + where TProperty : unmanaged + => CreatePropertyInner(out NewProperty, Name, + Offset, PropertyName, Visibility, SetStringPropertyFields); + + protected bool CreateTextPropertyInner(out IFProperty? NewProperty, + string Name, int Offset, string PropertyName, PropertyVisibility Visibility) + where TField : unmanaged + where TProperty : unmanaged + => CreatePropertyInner(out NewProperty, Name, + Offset, PropertyName, Visibility, SetTextPropertyFields); + + #endregion protected abstract void SetBoolPropertyFields(IFBoolProperty Property, BooleanMask Mask); @@ -197,6 +247,36 @@ public abstract bool CreateF32(out IFProperty? NewProperty, string Name, public abstract bool CreateF64(out IFProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility) where TOwner: unmanaged; + public abstract bool CreateI8(out IFProperty? NewProperty, string Name, int Offset, + PropertyVisibility Visibility); + + public abstract bool CreateI16(out IFProperty? NewProperty, string Name, int Offset, + PropertyVisibility Visibility); + + public abstract bool CreateI32(out IFProperty? NewProperty, string Name, int Offset, + PropertyVisibility Visibility); + + public abstract bool CreateI64(out IFProperty? NewProperty, string Name, int Offset, + PropertyVisibility Visibility); + + public abstract bool CreateU8(out IFProperty? NewProperty, string Name, int Offset, + PropertyVisibility Visibility); + + public abstract bool CreateU16(out IFProperty? NewProperty, string Name, int Offset, + PropertyVisibility Visibility); + + public abstract bool CreateU32(out IFProperty? NewProperty, string Name, int Offset, + PropertyVisibility Visibility); + + public abstract bool CreateU64(out IFProperty? NewProperty, string Name, int Offset, + PropertyVisibility Visibility); + + public abstract bool CreateF32(out IFProperty? NewProperty, string Name, int Offset, + PropertyVisibility Visibility); + + public abstract bool CreateF64(out IFProperty? NewProperty, string Name, int Offset, + PropertyVisibility Visibility); + public bool CreateCBool(out IFBoolProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility) where TOwner: unmanaged => CreateBoolPropertyInner(out NewProperty, Name, Offset, Visibility, new(1, 255)); @@ -223,6 +303,16 @@ public abstract bool CreateStruct(out IFStructProperty? NewPrope where TOwner : unmanaged where TField : unmanaged; + public abstract bool CreateStruct(out IFStructProperty? NewProperty, + string Name, int Offset, PropertyVisibility Visibility) + where TField : unmanaged; + + public abstract bool CreateStruct(out IFStructProperty? NewProperty, + string Name, string TypeName, int Offset, PropertyVisibility Visibility); + + public abstract bool CreateStructDTSpecial(out IFObjectProperty? NewProperty, + string Name, string TypeName, int Offset, PropertyVisibility Visibility); + public abstract bool CreateObject(out IFObjectProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility) where TOwner : unmanaged @@ -248,10 +338,24 @@ public abstract bool CreateString(out IFProperty? NewProperty, string Na public abstract bool CreateText(out IFProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility) where TOwner: unmanaged; + + public abstract bool CreateName(out IFProperty? NewProperty, string Name, int Offset, + PropertyVisibility Visibility) ; + + public abstract bool CreateString(out IFProperty? NewProperty, string Name, int Offset, + PropertyVisibility Visibility) ; + + public abstract bool CreateText(out IFProperty? NewProperty, string Name, int Offset, + PropertyVisibility Visibility) ; public abstract bool CreateArray(out IFArrayProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility, IFProperty Inner) where TObject : unmanaged; + // public abstract bool CreateMap(out IFArrayProperty? NewProperty, string Name, int Offset, + // PropertyVisibility Visibility, IFProperty Key, IFProperty Value) where TObject : unmanaged; + + public abstract bool CreateMap(out IFMapProperty? NewProperty, string Name, int Offset, + PropertyVisibility Visibility, IFProperty Key, IFProperty Value); #endregion protected readonly IUnrealFactory Factory = factory; diff --git a/UE.Toolkit.Reloaded/Reflection/UE4_27_2/PropertyFactory.cs b/UE.Toolkit.Reloaded/Reflection/UE4_27_2/PropertyFactory.cs index 5218a63..24d72f7 100644 --- a/UE.Toolkit.Reloaded/Reflection/UE4_27_2/PropertyFactory.cs +++ b/UE.Toolkit.Reloaded/Reflection/UE4_27_2/PropertyFactory.cs @@ -20,14 +20,18 @@ public class PropertyFactory(IUnrealFactory factory, IUnrealMemory memory, : BasePropertyFactory(factory, memory, classes, flags) { - protected override unsafe void LinkToPropertyList(IFProperty Property, IUClass Reflect) + protected override unsafe void LinkToPropertyList(IFProperty Property, IUClass? Reflect) { var pProperty = (FProperty*)Property.Ptr; pProperty->prop_link_next = null; pProperty->next_ref = null; pProperty->dtor_link_next = null; pProperty->post_ct_link_next = null; - + + if (Reflect == null) + { + return; + } var pClass = (UClass*)Reflect.Ptr; if (((UStruct*)pClass)->prop_link == null) { @@ -47,21 +51,31 @@ protected override unsafe void LinkToPropertyList(IFProperty Property, IUClass R pProperty->prop_link_next = pNextProp; ((FField*)pProperty)->next = (FField*)pNextProp; } - } + } } - - protected override unsafe void SetPropertySuperFields(IFField Field, string Name, IUClass ClassReflection, - FieldClassGlobal PropertyClass) + + protected override unsafe void SetPropertySuperFieldsNoOwner(IFField Field, string Name, FieldClassGlobal PropertyClass) { var pField = (FField*)Field.Ptr; pField->_vtable = PropertyClass.Vtable; pField->class_private = (FFieldClass*)PropertyClass.Params.Ptr; - pField->owner.Object = (UObjectBase*)ClassReflection.Ptr; // UClass* pField->next = null; pField->name_private = new FName(Name); pField->flags_private = EObjectFlags.RF_Public | EObjectFlags.RF_MarkAsNative | EObjectFlags.RF_Transient; } + private unsafe void SetPropertySuperFieldsUObject(IFField Field, string Name, IUClass ClassReflection, + FieldClassGlobal PropertyClass) + { + SetPropertySuperFieldsNoOwner(Field, Name, PropertyClass); + var pField = (FField*)Field.Ptr; + pField->owner.Object = (UObjectBase*)ClassReflection.Ptr; // UClass* + pField->owner.bIsUObject = true; + } + + protected override void SetPropertySuperFields(IFField Field, string Name, IUClass ClassReflection, + FieldClassGlobal PropertyClass) => SetPropertySuperFieldsUObject(Field, Name, ClassReflection, PropertyClass); + private unsafe void SetPropertyFieldDefaults(FProperty* pProperty, int Offset) { pProperty->rep_index = 0; @@ -80,7 +94,7 @@ private unsafe void SetPropertyFieldsInner(IFProperty Property, int Offset, SetPropertyFieldDefaults(pProperty, Offset); } - protected override unsafe void SetCopyPropertyFields(IFProperty Property, int Offset, + protected override void SetCopyPropertyFields(IFProperty Property, int Offset, PropertyVisibility Visibility) { var PropertyFlags = PropertyBuilderFlags.NoCtor | PropertyBuilderFlags.Copy | PropertyBuilderFlags.NoDtor; @@ -133,6 +147,36 @@ public override bool CreateF32(out IFProperty? NewProperty, string Name, public override bool CreateF64(out IFProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility) => CreateCopyPropertyInner(out NewProperty, Name, Offset, "DoubleProperty", Visibility); + + public override bool CreateI8(out IFProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility) + => CreateCopyPropertyInner(out NewProperty, Name, Offset, "Int8Property", Visibility); + + public override bool CreateI16(out IFProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility) + => CreateCopyPropertyInner(out NewProperty, Name, Offset, "Int16Property", Visibility); + + public override bool CreateI32(out IFProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility) + => CreateCopyPropertyInner(out NewProperty, Name, Offset, "IntProperty", Visibility); + + public override bool CreateI64(out IFProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility) + => CreateCopyPropertyInner(out NewProperty, Name, Offset, "Int64Property", Visibility); + + public override bool CreateU8(out IFProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility) + => CreateCopyPropertyInner(out NewProperty, Name, Offset, "UInt8Property", Visibility); + + public override bool CreateU16(out IFProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility) + => CreateCopyPropertyInner(out NewProperty, Name, Offset, "UInt16Property", Visibility); + + public override bool CreateU32(out IFProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility) + => CreateCopyPropertyInner(out NewProperty, Name, Offset, "UInt32Property", Visibility); + + public override bool CreateU64(out IFProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility) + => CreateCopyPropertyInner(out NewProperty, Name, Offset, "UInt64Property", Visibility); + + public override bool CreateF32(out IFProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility) + => CreateCopyPropertyInner(out NewProperty, Name, Offset, "FloatProperty", Visibility); + + public override bool CreateF64(out IFProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility) + => CreateCopyPropertyInner(out NewProperty, Name, Offset, "DoubleProperty", Visibility); public override bool CreateStruct(out IFStructProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility) @@ -157,6 +201,75 @@ public override bool CreateStruct(out IFStructProperty? NewPrope return true; } + public override bool CreateStruct(out IFStructProperty? NewProperty, string Name, int Offset, + PropertyVisibility Visibility) + { + NewProperty = null; + if (!GetProperty("StructProperty", out var PropertyClass) + || !Classes.GetScriptStructInfoFromType(out var ScriptStruct)) + return false; + var Alloc = Memory.Malloc(Marshal.SizeOf(), FIELD_ALIGNMENT); + NewProperty = Factory.CreateFStructProperty(Alloc); + SetPropertySuperFieldsNoOwner(Factory.CreateFField(Alloc), Name, PropertyClass!); + unsafe + { + var pProperty = (FProperty*)Alloc; + pProperty->array_dim = 1; + pProperty->element_size = ScriptStruct!.PropertiesSize; // FExampleStruct mExampleField; + pProperty->property_flags = Flags.CreatePropertyFlags(Visibility, PropertyBuilderFlags.None); + SetPropertyFieldDefaults(pProperty, Offset); + } + LinkToPropertyList(NewProperty, null); + unsafe { ((FStructProperty*)NewProperty.Ptr)->struct_data = (UScriptStruct*)ScriptStruct.Ptr; } + return true; + } + + public override bool CreateStruct(out IFStructProperty? NewProperty, string Name, string TypeName, int Offset, + PropertyVisibility Visibility) + { + NewProperty = null; + if (!GetProperty("StructProperty", out var PropertyClass) + || !Classes.GetScriptStructInfoFromName($"F{TypeName}", out var ScriptStruct)) + return false; + var Alloc = Memory.Malloc(Marshal.SizeOf(), FIELD_ALIGNMENT); + NewProperty = Factory.CreateFStructProperty(Alloc); + SetPropertySuperFieldsNoOwner(Factory.CreateFField(Alloc), Name, PropertyClass!); + unsafe + { + var pProperty = (FProperty*)Alloc; + pProperty->array_dim = 1; + pProperty->element_size = ScriptStruct!.PropertiesSize; // FExampleStruct mExampleField; + pProperty->property_flags = Flags.CreatePropertyFlags(Visibility, PropertyBuilderFlags.None); + SetPropertyFieldDefaults(pProperty, Offset); + } + LinkToPropertyList(NewProperty, null); + unsafe { ((FStructProperty*)NewProperty.Ptr)->struct_data = (UScriptStruct*)ScriptStruct.Ptr; } + return true; + } + + public override bool CreateStructDTSpecial(out IFObjectProperty? NewProperty, + string Name, string TypeName, int Offset, PropertyVisibility Visibility) + { + NewProperty = null; + if (!GetProperty("ObjectProperty", out var PropertyClass) + || !Classes.GetScriptStructInfoFromName($"F{TypeName}", out var FieldClass)) + return false; + var Alloc = Memory.Malloc(Marshal.SizeOf(), FIELD_ALIGNMENT); + NewProperty = Factory.CreateFObjectProperty(Alloc); + SetPropertySuperFieldsNoOwner(Factory.CreateFField(Alloc), Name, PropertyClass!); + unsafe + { + var pProperty = (FProperty*)Alloc; + pProperty->array_dim = 1; + pProperty->element_size = Marshal.SizeOf(); + pProperty->property_flags = Flags.CreatePropertyFlags(Visibility, PropertyBuilderFlags.None); + SetPropertyFieldDefaults(pProperty, Offset); + } + LinkToPropertyList(NewProperty, null); + unsafe { ((FObjectProperty*)NewProperty.Ptr)->prop_class = (UClass*)FieldClass!.Ptr; } // Our "class" + return true; + } + public override bool CreateObject(out IFObjectProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility) { @@ -190,6 +303,15 @@ public override bool CreateString(out IFProperty? NewProperty, string Na public override bool CreateText(out IFProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility) => CreateTextPropertyInner(out NewProperty, Name, Offset, "TextProperty", Visibility); + + public override bool CreateName(out IFProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility) + => CreateCopyPropertyInner(out NewProperty, Name, Offset, "NameProperty", Visibility); + + public override bool CreateString(out IFProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility) + => CreateStringPropertyInner(out NewProperty, Name, Offset, "StrProperty", Visibility); + + public override bool CreateText(out IFProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility) + => CreateTextPropertyInner(out NewProperty, Name, Offset, "TextProperty", Visibility); public override bool CreateArray(out IFArrayProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility, IFProperty Inner) @@ -212,4 +334,29 @@ public override bool CreateArray(out IFArrayProperty? NewProperty, strin unsafe { ((FArrayProperty*)Alloc)->inner = (FProperty*)Inner.Ptr; } return true; } + + public override bool CreateMap(out IFMapProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility, + IFProperty Key, IFProperty Value) + { + NewProperty = null; + if (!GetProperty("MapProperty", out var PropertyClass)) + return false; + var Alloc = Memory.Malloc(Marshal.SizeOf(), FIELD_ALIGNMENT); + NewProperty = Factory.CreateFMapProperty(Alloc); + SetPropertySuperFieldsNoOwner(Factory.CreateFField(Alloc), Name, PropertyClass!); + unsafe + { + var pProperty = (FProperty*)Alloc; + pProperty->array_dim = 1; + pProperty->element_size = 0x50; // sizeof(TMap), usually + pProperty->property_flags = Flags.CreatePropertyFlags(Visibility, PropertyBuilderFlags.NoCtor); + SetPropertyFieldDefaults(pProperty, Offset); + } + LinkToPropertyList(NewProperty, null); + unsafe { ((FMapProperty*)Alloc)->key_prop = (FProperty*)Key.Ptr; } + unsafe { ((FMapProperty*)Alloc)->value_prop = (FProperty*)Value.Ptr; } + Key.SetOwnerFField(NewProperty); + Value.SetOwnerFField(NewProperty); + return true; + } } \ No newline at end of file diff --git a/UE.Toolkit.Reloaded/Reflection/UE5_2_1/PropertyFactory.cs b/UE.Toolkit.Reloaded/Reflection/UE5_2_1/PropertyFactory.cs index 407c684..9e14234 100644 --- a/UE.Toolkit.Reloaded/Reflection/UE5_2_1/PropertyFactory.cs +++ b/UE.Toolkit.Reloaded/Reflection/UE5_2_1/PropertyFactory.cs @@ -17,13 +17,18 @@ public class PropertyFactory(IUnrealFactory factory, IUnrealMemory memory, : BasePropertyFactory(factory, memory, classes, flags) { - protected override unsafe void LinkToPropertyList(IFProperty Property, IUClass Reflect) + protected override unsafe void LinkToPropertyList(IFProperty Property, IUClass? Reflect) { var pProperty = (FProperty*)Property.Ptr; pProperty->prop_link_next = null; pProperty->next_ref = null; pProperty->dtor_link_next = null; pProperty->post_ct_link_next = null; + + if (Reflect == null) + { + return; + } var pClass = (UClass*)Reflect.Ptr; if (((UStruct*)pClass)->PropertyLink == null) @@ -47,17 +52,27 @@ protected override unsafe void LinkToPropertyList(IFProperty Property, IUClass R } } - protected override unsafe void SetPropertySuperFields(IFField Field, string Name, IUClass ClassReflection, - FieldClassGlobal PropertyClass) + protected override unsafe void SetPropertySuperFieldsNoOwner(IFField Field, string Name, FieldClassGlobal PropertyClass) { var pField = (FField*)Field.Ptr; pField->_vtable = PropertyClass.Vtable; pField->class_private = (FFieldClass*)PropertyClass.Params.Ptr; - pField->owner.Object = (UObjectBase*)ClassReflection.Ptr; // UClass* pField->next = null; pField->name_private = new FName(Name); pField->flags_private = EObjectFlags.RF_Public | EObjectFlags.RF_MarkAsNative | EObjectFlags.RF_Transient; } + + private unsafe void SetPropertySuperFieldsUObject(IFField Field, string Name, IUClass ClassReflection, + FieldClassGlobal PropertyClass) + { + SetPropertySuperFieldsNoOwner(Field, Name, PropertyClass); + var pField = (FField*)Field.Ptr; + pField->owner.Object = (UObjectBase*)ClassReflection.Ptr; // UClass* + pField->owner.bIsUObject = true; + } + + protected override void SetPropertySuperFields(IFField Field, string Name, IUClass ClassReflection, + FieldClassGlobal PropertyClass) => SetPropertySuperFieldsUObject(Field, Name, ClassReflection, PropertyClass); private unsafe void SetPropertyFieldDefaults(FProperty* pProperty, int Offset) { @@ -129,6 +144,36 @@ public override bool CreateF32(out IFProperty? NewProperty, string Name, public override bool CreateF64(out IFProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility) => CreateCopyPropertyInner(out NewProperty, Name, Offset, "FDoubleProperty", Visibility); + + public override bool CreateI8(out IFProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility) + => CreateCopyPropertyInner(out NewProperty, Name, Offset, "Int8Property", Visibility); + + public override bool CreateI16(out IFProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility) + => CreateCopyPropertyInner(out NewProperty, Name, Offset, "Int16Property", Visibility); + + public override bool CreateI32(out IFProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility) + => CreateCopyPropertyInner(out NewProperty, Name, Offset, "IntProperty", Visibility); + + public override bool CreateI64(out IFProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility) + => CreateCopyPropertyInner(out NewProperty, Name, Offset, "Int64Property", Visibility); + + public override bool CreateU8(out IFProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility) + => CreateCopyPropertyInner(out NewProperty, Name, Offset, "UInt8Property", Visibility); + + public override bool CreateU16(out IFProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility) + => CreateCopyPropertyInner(out NewProperty, Name, Offset, "UInt16Property", Visibility); + + public override bool CreateU32(out IFProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility) + => CreateCopyPropertyInner(out NewProperty, Name, Offset, "UInt32Property", Visibility); + + public override bool CreateU64(out IFProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility) + => CreateCopyPropertyInner(out NewProperty, Name, Offset, "UInt64Property", Visibility); + + public override bool CreateF32(out IFProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility) + => CreateCopyPropertyInner(out NewProperty, Name, Offset, "FFloatProperty", Visibility); + + public override bool CreateF64(out IFProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility) + => CreateCopyPropertyInner(out NewProperty, Name, Offset, "FDoubleProperty", Visibility); public override bool CreateStruct(out IFStructProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility) @@ -152,6 +197,75 @@ public override bool CreateStruct(out IFStructProperty? NewPrope unsafe { ((FStructProperty*)NewProperty.Ptr)->Struct = (UScriptStruct*)ScriptStruct.Ptr; } return true; } + + public override bool CreateStruct(out IFStructProperty? NewProperty, string Name, int Offset, + PropertyVisibility Visibility) + { + NewProperty = null; + if (!GetProperty("StructProperty", out var PropertyClass) + || !Classes.GetScriptStructInfoFromType(out var ScriptStruct)) + return false; + var Alloc = Memory.Malloc(Marshal.SizeOf(), FIELD_ALIGNMENT); + NewProperty = Factory.CreateFStructProperty(Alloc); + SetPropertySuperFieldsNoOwner(Factory.CreateFField(Alloc), Name, PropertyClass!); + unsafe + { + var pProperty = (FProperty*)Alloc; + pProperty->array_dim = 1; + pProperty->element_size = ScriptStruct!.PropertiesSize; // FExampleStruct mExampleField; + pProperty->property_flags = Flags.CreatePropertyFlags(Visibility, PropertyBuilderFlags.None); + SetPropertyFieldDefaults(pProperty, Offset); + } + LinkToPropertyList(NewProperty, null); + unsafe { ((FStructProperty*)NewProperty.Ptr)->Struct = (UScriptStruct*)ScriptStruct.Ptr; } + return true; + } + + public override bool CreateStruct(out IFStructProperty? NewProperty, string Name, string TypeName, int Offset, + PropertyVisibility Visibility) + { + NewProperty = null; + if (!GetProperty("StructProperty", out var PropertyClass) + || !Classes.GetScriptStructInfoFromName($"F{TypeName}", out var ScriptStruct)) + return false; + var Alloc = Memory.Malloc(Marshal.SizeOf(), FIELD_ALIGNMENT); + NewProperty = Factory.CreateFStructProperty(Alloc); + SetPropertySuperFieldsNoOwner(Factory.CreateFField(Alloc), Name, PropertyClass!); + unsafe + { + var pProperty = (FProperty*)Alloc; + pProperty->array_dim = 1; + pProperty->element_size = ScriptStruct!.PropertiesSize; // FExampleStruct mExampleField; + pProperty->property_flags = Flags.CreatePropertyFlags(Visibility, PropertyBuilderFlags.None); + SetPropertyFieldDefaults(pProperty, Offset); + } + LinkToPropertyList(NewProperty, null); + unsafe { ((FStructProperty*)NewProperty.Ptr)->Struct = (UScriptStruct*)ScriptStruct.Ptr; } + return true; + } + + public override bool CreateStructDTSpecial(out IFObjectProperty? NewProperty, + string Name, string TypeName, int Offset, PropertyVisibility Visibility) + { + NewProperty = null; + if (!GetProperty("ObjectProperty", out var PropertyClass) + || !Classes.GetScriptStructInfoFromName($"F{TypeName}", out var FieldClass)) + return false; + var Alloc = Memory.Malloc(Marshal.SizeOf(), FIELD_ALIGNMENT); + NewProperty = Factory.CreateFObjectProperty(Alloc); + SetPropertySuperFieldsNoOwner(Factory.CreateFField(Alloc), Name, PropertyClass!); + unsafe + { + var pProperty = (FProperty*)Alloc; + pProperty->array_dim = 1; + pProperty->element_size = Marshal.SizeOf(); + pProperty->property_flags = Flags.CreatePropertyFlags(Visibility, PropertyBuilderFlags.None); + SetPropertyFieldDefaults(pProperty, Offset); + } + LinkToPropertyList(NewProperty, null); + unsafe { ((FObjectProperty*)NewProperty.Ptr)->PropertyClass = (UClass*)FieldClass!.Ptr; } // Our "class" + return true; + } public override bool CreateObject(out IFObjectProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility) @@ -186,6 +300,15 @@ public override bool CreateString(out IFProperty? NewProperty, string Na public override bool CreateText(out IFProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility) => CreateTextPropertyInner(out NewProperty, Name, Offset, "TextProperty", Visibility); + + public override bool CreateName(out IFProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility) + => CreateCopyPropertyInner(out NewProperty, Name, Offset, "NameProperty", Visibility); + + public override bool CreateString(out IFProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility) + => CreateStringPropertyInner(out NewProperty, Name, Offset, "StrProperty", Visibility); + + public override bool CreateText(out IFProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility) + => CreateTextPropertyInner(out NewProperty, Name, Offset, "TextProperty", Visibility); public override bool CreateArray(out IFArrayProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility, IFProperty Inner) @@ -208,4 +331,29 @@ public override bool CreateArray(out IFArrayProperty? NewProperty, strin unsafe { ((FArrayProperty*)Alloc)->Inner = (UE.Toolkit.Core.Types.Unreal.UE5_4_4.FProperty*)Inner.Ptr; } return true; } + + public override bool CreateMap(out IFMapProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility, + IFProperty Key, IFProperty Value) + { + NewProperty = null; + if (!GetProperty("MapProperty", out var PropertyClass)) + return false; + var Alloc = Memory.Malloc(Marshal.SizeOf(), FIELD_ALIGNMENT); + NewProperty = Factory.CreateFMapProperty(Alloc); + SetPropertySuperFieldsNoOwner(Factory.CreateFField(Alloc), Name, PropertyClass!); + unsafe + { + var pProperty = (FProperty*)Alloc; + pProperty->array_dim = 1; + pProperty->element_size = 0x50; // sizeof(TMap), usually + pProperty->property_flags = Flags.CreatePropertyFlags(Visibility, PropertyBuilderFlags.NoCtor); + SetPropertyFieldDefaults(pProperty, Offset); + } + LinkToPropertyList(NewProperty, null); + unsafe { ((FMapProperty*)Alloc)->KeyProp = (UE.Toolkit.Core.Types.Unreal.UE5_4_4.FProperty*)Key.Ptr; } + unsafe { ((FMapProperty*)Alloc)->ValueProp = (UE.Toolkit.Core.Types.Unreal.UE5_4_4.FProperty*)Value.Ptr; } + Key.SetOwnerFField(NewProperty); + Value.SetOwnerFField(NewProperty); + return true; + } } \ No newline at end of file diff --git a/UE.Toolkit.Reloaded/Reflection/UE5_4_4/PropertyFactory.cs b/UE.Toolkit.Reloaded/Reflection/UE5_4_4/PropertyFactory.cs index 9b3ee32..e076e6a 100644 --- a/UE.Toolkit.Reloaded/Reflection/UE5_4_4/PropertyFactory.cs +++ b/UE.Toolkit.Reloaded/Reflection/UE5_4_4/PropertyFactory.cs @@ -12,7 +12,7 @@ public class PropertyFactory(IUnrealFactory factory, IUnrealMemory memory, : BasePropertyFactory(factory, memory, classes, flags) { - protected override unsafe void LinkToPropertyList(IFProperty Property, IUClass Reflect) + protected override unsafe void LinkToPropertyList(IFProperty Property, IUClass? Reflect) { var pProperty = (FProperty*)Property.Ptr; pProperty->PropertyLinkNext = null; @@ -20,6 +20,11 @@ protected override unsafe void LinkToPropertyList(IFProperty Property, IUClass R pProperty->DestructorLinkNext = null; pProperty->PostConstructLinkNext = null; + if (Reflect == null) + { + return; + } + var pClass = (UClass*)Reflect.Ptr; // Is this the only field? if (((UStruct*)pClass)->PropertyLink == null) @@ -43,17 +48,26 @@ protected override unsafe void LinkToPropertyList(IFProperty Property, IUClass R } } - protected override unsafe void SetPropertySuperFields(IFField Field, string Name, IUClass ClassReflection, - FieldClassGlobal PropertyClass) + protected override unsafe void SetPropertySuperFieldsNoOwner(IFField Field, string Name, FieldClassGlobal PropertyClass) { var pField = (FField*)Field.Ptr; pField->VTable = PropertyClass.Vtable; pField->ClassPrivate = (FFieldClass*)PropertyClass.Params.Ptr; - pField->Owner.Object = (UObjectBase*)ClassReflection.Ptr; // UClass* pField->Next = null; pField->NamePrivate = new FName(Name); pField->FlagsPrivate = EObjectFlags.RF_Public | EObjectFlags.RF_MarkAsNative | EObjectFlags.RF_Transient; } + + private unsafe void SetPropertySuperFieldsUObject(IFField Field, string Name, IUClass ClassReflection, + FieldClassGlobal PropertyClass) + { + SetPropertySuperFieldsNoOwner(Field, Name, PropertyClass); + var pField = (FField*)Field.Ptr; + pField->Owner.Object = (UObjectBase*)(ClassReflection.Ptr + 1); // UClass* + } + + protected override void SetPropertySuperFields(IFField Field, string Name, IUClass ClassReflection, + FieldClassGlobal PropertyClass) => SetPropertySuperFieldsUObject(Field, Name, ClassReflection, PropertyClass); private unsafe void SetPropertyFieldDefaults(FProperty* pProperty, int Offset) { @@ -125,6 +139,36 @@ public override bool CreateF32(out IFProperty? NewProperty, string Name, public override bool CreateF64(out IFProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility) => CreateCopyPropertyInner(out NewProperty, Name, Offset, "FDoubleProperty", Visibility); + + public override bool CreateI8(out IFProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility) + => CreateCopyPropertyInner(out NewProperty, Name, Offset, "Int8Property", Visibility); + + public override bool CreateI16(out IFProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility) + => CreateCopyPropertyInner(out NewProperty, Name, Offset, "Int16Property", Visibility); + + public override bool CreateI32(out IFProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility) + => CreateCopyPropertyInner(out NewProperty, Name, Offset, "IntProperty", Visibility); + + public override bool CreateI64(out IFProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility) + => CreateCopyPropertyInner(out NewProperty, Name, Offset, "Int64Property", Visibility); + + public override bool CreateU8(out IFProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility) + => CreateCopyPropertyInner(out NewProperty, Name, Offset, "UInt8Property", Visibility); + + public override bool CreateU16(out IFProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility) + => CreateCopyPropertyInner(out NewProperty, Name, Offset, "UInt16Property", Visibility); + + public override bool CreateU32(out IFProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility) + => CreateCopyPropertyInner(out NewProperty, Name, Offset, "UInt32Property", Visibility); + + public override bool CreateU64(out IFProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility) + => CreateCopyPropertyInner(out NewProperty, Name, Offset, "UInt64Property", Visibility); + + public override bool CreateF32(out IFProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility) + => CreateCopyPropertyInner(out NewProperty, Name, Offset, "FFloatProperty", Visibility); + + public override bool CreateF64(out IFProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility) + => CreateCopyPropertyInner(out NewProperty, Name, Offset, "FDoubleProperty", Visibility); public override bool CreateStruct(out IFStructProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility) @@ -148,6 +192,75 @@ public override bool CreateStruct(out IFStructProperty? NewPrope unsafe { ((FStructProperty*)NewProperty.Ptr)->Struct = (UScriptStruct*)ScriptStruct.Ptr; } return true; } + + public override bool CreateStruct(out IFStructProperty? NewProperty, string Name, int Offset, + PropertyVisibility Visibility) + { + NewProperty = null; + if (!GetProperty("StructProperty", out var PropertyClass) + || !Classes.GetScriptStructInfoFromType(out var ScriptStruct)) + return false; + var Alloc = Memory.Malloc(Marshal.SizeOf(), FIELD_ALIGNMENT); + NewProperty = Factory.CreateFStructProperty(Alloc); + SetPropertySuperFieldsNoOwner(Factory.CreateFField(Alloc), Name, PropertyClass!); + unsafe + { + var pProperty = (FProperty*)Alloc; + pProperty->ArrayDim = 1; + pProperty->ElementSize = ScriptStruct!.PropertiesSize; // FExampleStruct mExampleField; + pProperty->PropertyFlags = Flags.CreatePropertyFlags(Visibility, PropertyBuilderFlags.None); + SetPropertyFieldDefaults(pProperty, Offset); + } + LinkToPropertyList(NewProperty, null); + unsafe { ((FStructProperty*)NewProperty.Ptr)->Struct = (UScriptStruct*)ScriptStruct.Ptr; } + return true; + } + + public override bool CreateStruct(out IFStructProperty? NewProperty, string Name, string TypeName, int Offset, + PropertyVisibility Visibility) + { + NewProperty = null; + if (!GetProperty("StructProperty", out var PropertyClass) + || !Classes.GetScriptStructInfoFromName($"F{TypeName}", out var ScriptStruct)) + return false; + var Alloc = Memory.Malloc(Marshal.SizeOf(), FIELD_ALIGNMENT); + NewProperty = Factory.CreateFStructProperty(Alloc); + SetPropertySuperFieldsNoOwner(Factory.CreateFField(Alloc), Name, PropertyClass!); + unsafe + { + var pProperty = (FProperty*)Alloc; + pProperty->ArrayDim = 1; + pProperty->ElementSize = ScriptStruct!.PropertiesSize; // FExampleStruct mExampleField; + pProperty->PropertyFlags = Flags.CreatePropertyFlags(Visibility, PropertyBuilderFlags.None); + SetPropertyFieldDefaults(pProperty, Offset); + } + LinkToPropertyList(NewProperty, null); + unsafe { ((FStructProperty*)NewProperty.Ptr)->Struct = (UScriptStruct*)ScriptStruct.Ptr; } + return true; + } + + public override bool CreateStructDTSpecial(out IFObjectProperty? NewProperty, + string Name, string TypeName, int Offset, PropertyVisibility Visibility) + { + NewProperty = null; + if (!GetProperty("ObjectProperty", out var PropertyClass) + || !Classes.GetScriptStructInfoFromName($"F{TypeName}", out var FieldClass)) + return false; + var Alloc = Memory.Malloc(Marshal.SizeOf(), FIELD_ALIGNMENT); + NewProperty = Factory.CreateFObjectProperty(Alloc); + SetPropertySuperFieldsNoOwner(Factory.CreateFField(Alloc), Name, PropertyClass!); + unsafe + { + var pProperty = (FProperty*)Alloc; + pProperty->ArrayDim = 1; + pProperty->ElementSize = Marshal.SizeOf(); + pProperty->PropertyFlags = Flags.CreatePropertyFlags(Visibility, PropertyBuilderFlags.None); + SetPropertyFieldDefaults(pProperty, Offset); + } + LinkToPropertyList(NewProperty, null); + unsafe { ((FObjectProperty*)NewProperty.Ptr)->PropertyClass = (UClass*)FieldClass!.Ptr; } // Our "class" + return true; + } public override bool CreateObject(out IFObjectProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility) @@ -182,6 +295,15 @@ public override bool CreateString(out IFProperty? NewProperty, string Na public override bool CreateText(out IFProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility) => CreateTextPropertyInner(out NewProperty, Name, Offset, "TextProperty", Visibility); + + public override bool CreateName(out IFProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility) + => CreateCopyPropertyInner(out NewProperty, Name, Offset, "NameProperty", Visibility); + + public override bool CreateString(out IFProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility) + => CreateStringPropertyInner(out NewProperty, Name, Offset, "StrProperty", Visibility); + + public override bool CreateText(out IFProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility) + => CreateTextPropertyInner(out NewProperty, Name, Offset, "TextProperty", Visibility); public override bool CreateArray(out IFArrayProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility, IFProperty Inner) @@ -204,4 +326,29 @@ public override bool CreateArray(out IFArrayProperty? NewProperty, strin unsafe { ((FArrayProperty*)Alloc)->Inner = (FProperty*)Inner.Ptr; } return true; } + + public override bool CreateMap(out IFMapProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility, + IFProperty Key, IFProperty Value) + { + NewProperty = null; + if (!GetProperty("MapProperty", out var PropertyClass)) + return false; + var Alloc = Memory.Malloc(Marshal.SizeOf(), FIELD_ALIGNMENT); + NewProperty = Factory.CreateFMapProperty(Alloc); + SetPropertySuperFieldsNoOwner(Factory.CreateFField(Alloc), Name, PropertyClass!); + unsafe + { + var pProperty = (FProperty*)Alloc; + pProperty->ArrayDim = 1; + pProperty->ElementSize = 0x50; // sizeof(TMap), usually + pProperty->PropertyFlags = Flags.CreatePropertyFlags(Visibility, PropertyBuilderFlags.NoCtor); + SetPropertyFieldDefaults(pProperty, Offset); + } + LinkToPropertyList(NewProperty, null); + unsafe { ((FMapProperty*)Alloc)->KeyProp = (FProperty*)Key.Ptr; } + unsafe { ((FMapProperty*)Alloc)->ValueProp = (FProperty*)Value.Ptr; } + Key.SetOwnerFField(NewProperty); + Value.SetOwnerFField(NewProperty); + return true; + } } \ No newline at end of file diff --git a/UE.Toolkit.Reloaded/Reflection/UE5_6_1/PropertyFactory.cs b/UE.Toolkit.Reloaded/Reflection/UE5_6_1/PropertyFactory.cs index 0263442..a620da4 100644 --- a/UE.Toolkit.Reloaded/Reflection/UE5_6_1/PropertyFactory.cs +++ b/UE.Toolkit.Reloaded/Reflection/UE5_6_1/PropertyFactory.cs @@ -15,7 +15,7 @@ public class PropertyFactory(IUnrealFactory factory, IUnrealMemory memory, : BasePropertyFactory(factory, memory, classes, flags) { - protected override unsafe void LinkToPropertyList(IFProperty Property, IUClass Reflect) + protected override unsafe void LinkToPropertyList(IFProperty Property, IUClass? Reflect) { var pProperty = (FProperty*)Property.Ptr; pProperty->PropertyLinkNext = null; @@ -23,6 +23,11 @@ protected override unsafe void LinkToPropertyList(IFProperty Property, IUClass R pProperty->DestructorLinkNext = null; pProperty->PostConstructLinkNext = null; + if (Reflect == null) + { + return; + } + var pClass = (UClass*)Reflect.Ptr; // Is this the only field? if (((UStruct*)pClass)->PropertyLink == null) @@ -46,17 +51,26 @@ protected override unsafe void LinkToPropertyList(IFProperty Property, IUClass R } } - protected override unsafe void SetPropertySuperFields(IFField Field, string Name, IUClass ClassReflection, - FieldClassGlobal PropertyClass) + protected override unsafe void SetPropertySuperFieldsNoOwner(IFField Field, string Name, FieldClassGlobal PropertyClass) { var pField = (FField*)Field.Ptr; pField->VTable = PropertyClass.Vtable; pField->ClassPrivate = (FFieldClass*)PropertyClass.Params.Ptr; - pField->Owner.Object = (UObjectBase*)ClassReflection.Ptr; // UClass* pField->Next = null; pField->NamePrivate = new FName(Name); pField->FlagsPrivate = EObjectFlags.RF_Public | EObjectFlags.RF_MarkAsNative | EObjectFlags.RF_Transient; } + + private unsafe void SetPropertySuperFieldsUObject(IFField Field, string Name, IUClass ClassReflection, + FieldClassGlobal PropertyClass) + { + SetPropertySuperFieldsNoOwner(Field, Name, PropertyClass); + var pField = (FField*)Field.Ptr; + pField->Owner.Object = (UObjectBase*)(ClassReflection.Ptr + 1); // UClass* + } + + protected override void SetPropertySuperFields(IFField Field, string Name, IUClass ClassReflection, + FieldClassGlobal PropertyClass) => SetPropertySuperFieldsUObject(Field, Name, ClassReflection, PropertyClass); private unsafe void SetPropertyFieldDefaults(FProperty* pProperty, int Offset) { @@ -128,6 +142,36 @@ public override bool CreateF32(out IFProperty? NewProperty, string Name, public override bool CreateF64(out IFProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility) => CreateCopyPropertyInner(out NewProperty, Name, Offset, "FDoubleProperty", Visibility); + + public override bool CreateI8(out IFProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility) + => CreateCopyPropertyInner(out NewProperty, Name, Offset, "Int8Property", Visibility); + + public override bool CreateI16(out IFProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility) + => CreateCopyPropertyInner(out NewProperty, Name, Offset, "Int16Property", Visibility); + + public override bool CreateI32(out IFProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility) + => CreateCopyPropertyInner(out NewProperty, Name, Offset, "IntProperty", Visibility); + + public override bool CreateI64(out IFProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility) + => CreateCopyPropertyInner(out NewProperty, Name, Offset, "Int64Property", Visibility); + + public override bool CreateU8(out IFProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility) + => CreateCopyPropertyInner(out NewProperty, Name, Offset, "UInt8Property", Visibility); + + public override bool CreateU16(out IFProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility) + => CreateCopyPropertyInner(out NewProperty, Name, Offset, "UInt16Property", Visibility); + + public override bool CreateU32(out IFProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility) + => CreateCopyPropertyInner(out NewProperty, Name, Offset, "UInt32Property", Visibility); + + public override bool CreateU64(out IFProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility) + => CreateCopyPropertyInner(out NewProperty, Name, Offset, "UInt64Property", Visibility); + + public override bool CreateF32(out IFProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility) + => CreateCopyPropertyInner(out NewProperty, Name, Offset, "FFloatProperty", Visibility); + + public override bool CreateF64(out IFProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility) + => CreateCopyPropertyInner(out NewProperty, Name, Offset, "FDoubleProperty", Visibility); public override bool CreateStruct(out IFStructProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility) @@ -151,6 +195,75 @@ public override bool CreateStruct(out IFStructProperty? NewPrope unsafe { ((FStructProperty*)NewProperty.Ptr)->Struct = (UScriptStruct*)ScriptStruct.Ptr; } return true; } + + public override bool CreateStruct(out IFStructProperty? NewProperty, string Name, int Offset, + PropertyVisibility Visibility) + { + NewProperty = null; + if (!GetProperty("StructProperty", out var PropertyClass) + || !Classes.GetScriptStructInfoFromType(out var ScriptStruct)) + return false; + var Alloc = Memory.Malloc(Marshal.SizeOf(), FIELD_ALIGNMENT); + NewProperty = Factory.CreateFStructProperty(Alloc); + SetPropertySuperFieldsNoOwner(Factory.CreateFField(Alloc), Name, PropertyClass!); + unsafe + { + var pProperty = (FProperty*)Alloc; + pProperty->ArrayDim = 1; + pProperty->ElementSize = ScriptStruct!.PropertiesSize; // FExampleStruct mExampleField; + pProperty->PropertyFlags = Flags.CreatePropertyFlags(Visibility, PropertyBuilderFlags.None); + SetPropertyFieldDefaults(pProperty, Offset); + } + LinkToPropertyList(NewProperty, null); + unsafe { ((FStructProperty*)NewProperty.Ptr)->Struct = (UScriptStruct*)ScriptStruct.Ptr; } + return true; + } + + public override bool CreateStruct(out IFStructProperty? NewProperty, string Name, string TypeName, int Offset, + PropertyVisibility Visibility) + { + NewProperty = null; + if (!GetProperty("StructProperty", out var PropertyClass) + || !Classes.GetScriptStructInfoFromName($"F{TypeName}", out var ScriptStruct)) + return false; + var Alloc = Memory.Malloc(Marshal.SizeOf(), FIELD_ALIGNMENT); + NewProperty = Factory.CreateFStructProperty(Alloc); + SetPropertySuperFieldsNoOwner(Factory.CreateFField(Alloc), Name, PropertyClass!); + unsafe + { + var pProperty = (FProperty*)Alloc; + pProperty->ArrayDim = 1; + pProperty->ElementSize = ScriptStruct!.PropertiesSize; // FExampleStruct mExampleField; + pProperty->PropertyFlags = Flags.CreatePropertyFlags(Visibility, PropertyBuilderFlags.None); + SetPropertyFieldDefaults(pProperty, Offset); + } + LinkToPropertyList(NewProperty, null); + unsafe { ((FStructProperty*)NewProperty.Ptr)->Struct = (UScriptStruct*)ScriptStruct.Ptr; } + return true; + } + + public override bool CreateStructDTSpecial(out IFObjectProperty? NewProperty, + string Name, string TypeName, int Offset, PropertyVisibility Visibility) + { + NewProperty = null; + if (!GetProperty("ObjectProperty", out var PropertyClass) + || !Classes.GetScriptStructInfoFromName($"F{TypeName}", out var FieldClass)) + return false; + var Alloc = Memory.Malloc(Marshal.SizeOf(), FIELD_ALIGNMENT); + NewProperty = Factory.CreateFObjectProperty(Alloc); + SetPropertySuperFieldsNoOwner(Factory.CreateFField(Alloc), Name, PropertyClass!); + unsafe + { + var pProperty = (FProperty*)Alloc; + pProperty->ArrayDim = 1; + pProperty->ElementSize = Marshal.SizeOf(); + pProperty->PropertyFlags = Flags.CreatePropertyFlags(Visibility, PropertyBuilderFlags.None); + SetPropertyFieldDefaults(pProperty, Offset); + } + LinkToPropertyList(NewProperty, null); + unsafe { ((FObjectProperty*)NewProperty.Ptr)->PropertyClass = (UClass*)FieldClass!.Ptr; } // Our "class" + return true; + } public override bool CreateObject(out IFObjectProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility) @@ -185,6 +298,15 @@ public override bool CreateString(out IFProperty? NewProperty, string Na public override bool CreateText(out IFProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility) => CreateTextPropertyInner(out NewProperty, Name, Offset, "TextProperty", Visibility); + + public override bool CreateName(out IFProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility) + => CreateCopyPropertyInner(out NewProperty, Name, Offset, "NameProperty", Visibility); + + public override bool CreateString(out IFProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility) + => CreateStringPropertyInner(out NewProperty, Name, Offset, "StrProperty", Visibility); + + public override bool CreateText(out IFProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility) + => CreateTextPropertyInner(out NewProperty, Name, Offset, "TextProperty", Visibility); public override bool CreateArray(out IFArrayProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility, IFProperty Inner) @@ -207,4 +329,29 @@ public override bool CreateArray(out IFArrayProperty? NewProperty, strin unsafe { ((FArrayProperty*)Alloc)->Inner = (FProperty*)Inner.Ptr; } return true; } + + public override bool CreateMap(out IFMapProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility, + IFProperty Key, IFProperty Value) + { + NewProperty = null; + if (!GetProperty("MapProperty", out var PropertyClass)) + return false; + var Alloc = Memory.Malloc(Marshal.SizeOf(), FIELD_ALIGNMENT); + NewProperty = Factory.CreateFMapProperty(Alloc); + SetPropertySuperFieldsNoOwner(Factory.CreateFField(Alloc), Name, PropertyClass!); + unsafe + { + var pProperty = (FProperty*)Alloc; + pProperty->ArrayDim = 1; + pProperty->ElementSize = 0x50; // sizeof(TMap), usually + pProperty->PropertyFlags = Flags.CreatePropertyFlags(Visibility, PropertyBuilderFlags.NoCtor); + SetPropertyFieldDefaults(pProperty, Offset); + } + LinkToPropertyList(NewProperty, null); + unsafe { ((FMapProperty*)Alloc)->KeyProp = (FProperty*)Key.Ptr; } + unsafe { ((FMapProperty*)Alloc)->ValueProp = (FProperty*)Value.Ptr; } + Key.SetOwnerFField(NewProperty); + Value.SetOwnerFField(NewProperty); + return true; + } } \ No newline at end of file diff --git a/UE.Toolkit.Reloaded/Reflection/UE5_7_4/PropertyFactory.cs b/UE.Toolkit.Reloaded/Reflection/UE5_7_4/PropertyFactory.cs index e24db84..81634c1 100644 --- a/UE.Toolkit.Reloaded/Reflection/UE5_7_4/PropertyFactory.cs +++ b/UE.Toolkit.Reloaded/Reflection/UE5_7_4/PropertyFactory.cs @@ -18,7 +18,7 @@ public class PropertyFactory(IUnrealFactory factory, IUnrealMemory memory, : BasePropertyFactory(factory, memory, classes, flags) { - protected override unsafe void LinkToPropertyList(IFProperty Property, IUClass Reflect) + protected override unsafe void LinkToPropertyList(IFProperty Property, IUClass? Reflect) { var pProperty = (FProperty*)Property.Ptr; pProperty->PropertyLinkNext = null; @@ -26,6 +26,11 @@ protected override unsafe void LinkToPropertyList(IFProperty Property, IUClass R pProperty->DestructorLinkNext = null; pProperty->PostConstructLinkNext = null; + if (Reflect == null) + { + return; + } + var pClass = (UClass*)Reflect.Ptr; if (((UStruct*)pClass)->PropertyLink == null) { @@ -48,17 +53,26 @@ protected override unsafe void LinkToPropertyList(IFProperty Property, IUClass R } } - protected override unsafe void SetPropertySuperFields(IFField Field, string Name, IUClass ClassReflection, - FieldClassGlobal PropertyClass) + protected override unsafe void SetPropertySuperFieldsNoOwner(IFField Field, string Name, FieldClassGlobal PropertyClass) { var pField = (FField*)Field.Ptr; pField->VTable = PropertyClass.Vtable; pField->ClassPrivate = (FFieldClass*)PropertyClass.Params.Ptr; - pField->Owner.Object = (UObjectBase*)ClassReflection.Ptr; // UClass* pField->Next = null; pField->NamePrivate = new FName(Name); pField->FlagsPrivate = EObjectFlags.RF_Public | EObjectFlags.RF_MarkAsNative | EObjectFlags.RF_Transient; } + + private unsafe void SetPropertySuperFieldsUObject(IFField Field, string Name, IUClass ClassReflection, + FieldClassGlobal PropertyClass) + { + SetPropertySuperFieldsNoOwner(Field, Name, PropertyClass); + var pField = (FField*)Field.Ptr; + pField->Owner.Object = (UObjectBase*)(ClassReflection.Ptr + 1); // UClass* + } + + protected override void SetPropertySuperFields(IFField Field, string Name, IUClass ClassReflection, + FieldClassGlobal PropertyClass) => SetPropertySuperFieldsUObject(Field, Name, ClassReflection, PropertyClass); private unsafe void SetPropertyFieldDefaults(FProperty* pProperty, int Offset) { @@ -130,6 +144,36 @@ public override bool CreateF32(out IFProperty? NewProperty, string Name, public override bool CreateF64(out IFProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility) => CreateCopyPropertyInner(out NewProperty, Name, Offset, "FDoubleProperty", Visibility); + + public override bool CreateI8(out IFProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility) + => CreateCopyPropertyInner(out NewProperty, Name, Offset, "Int8Property", Visibility); + + public override bool CreateI16(out IFProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility) + => CreateCopyPropertyInner(out NewProperty, Name, Offset, "Int16Property", Visibility); + + public override bool CreateI32(out IFProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility) + => CreateCopyPropertyInner(out NewProperty, Name, Offset, "IntProperty", Visibility); + + public override bool CreateI64(out IFProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility) + => CreateCopyPropertyInner(out NewProperty, Name, Offset, "Int64Property", Visibility); + + public override bool CreateU8(out IFProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility) + => CreateCopyPropertyInner(out NewProperty, Name, Offset, "UInt8Property", Visibility); + + public override bool CreateU16(out IFProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility) + => CreateCopyPropertyInner(out NewProperty, Name, Offset, "UInt16Property", Visibility); + + public override bool CreateU32(out IFProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility) + => CreateCopyPropertyInner(out NewProperty, Name, Offset, "UInt32Property", Visibility); + + public override bool CreateU64(out IFProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility) + => CreateCopyPropertyInner(out NewProperty, Name, Offset, "UInt64Property", Visibility); + + public override bool CreateF32(out IFProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility) + => CreateCopyPropertyInner(out NewProperty, Name, Offset, "FFloatProperty", Visibility); + + public override bool CreateF64(out IFProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility) + => CreateCopyPropertyInner(out NewProperty, Name, Offset, "FDoubleProperty", Visibility); public override bool CreateStruct(out IFStructProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility) @@ -153,6 +197,75 @@ public override bool CreateStruct(out IFStructProperty? NewPrope unsafe { ((FStructProperty*)NewProperty.Ptr)->Struct = (UScriptStruct*)ScriptStruct.Ptr; } return true; } + + public override bool CreateStruct(out IFStructProperty? NewProperty, string Name, int Offset, + PropertyVisibility Visibility) + { + NewProperty = null; + if (!GetProperty("StructProperty", out var PropertyClass) + || !Classes.GetScriptStructInfoFromType(out var ScriptStruct)) + return false; + var Alloc = Memory.Malloc(Marshal.SizeOf(), FIELD_ALIGNMENT); + NewProperty = Factory.CreateFStructProperty(Alloc); + SetPropertySuperFieldsNoOwner(Factory.CreateFField(Alloc), Name, PropertyClass!); + unsafe + { + var pProperty = (FProperty*)Alloc; + pProperty->ArrayDim = 1; + pProperty->ElementSize = ScriptStruct!.PropertiesSize; // FExampleStruct mExampleField; + pProperty->PropertyFlags = Flags.CreatePropertyFlags(Visibility, PropertyBuilderFlags.None); + SetPropertyFieldDefaults(pProperty, Offset); + } + LinkToPropertyList(NewProperty, null); + unsafe { ((FStructProperty*)NewProperty.Ptr)->Struct = (UScriptStruct*)ScriptStruct.Ptr; } + return true; + } + + public override bool CreateStruct(out IFStructProperty? NewProperty, string Name, string TypeName, int Offset, + PropertyVisibility Visibility) + { + NewProperty = null; + if (!GetProperty("StructProperty", out var PropertyClass) + || !Classes.GetScriptStructInfoFromName($"F{TypeName}", out var ScriptStruct)) + return false; + var Alloc = Memory.Malloc(Marshal.SizeOf(), FIELD_ALIGNMENT); + NewProperty = Factory.CreateFStructProperty(Alloc); + SetPropertySuperFieldsNoOwner(Factory.CreateFField(Alloc), Name, PropertyClass!); + unsafe + { + var pProperty = (FProperty*)Alloc; + pProperty->ArrayDim = 1; + pProperty->ElementSize = ScriptStruct!.PropertiesSize; // FExampleStruct mExampleField; + pProperty->PropertyFlags = Flags.CreatePropertyFlags(Visibility, PropertyBuilderFlags.None); + SetPropertyFieldDefaults(pProperty, Offset); + } + LinkToPropertyList(NewProperty, null); + unsafe { ((FStructProperty*)NewProperty.Ptr)->Struct = (UScriptStruct*)ScriptStruct.Ptr; } + return true; + } + + public override bool CreateStructDTSpecial(out IFObjectProperty? NewProperty, + string Name, string TypeName, int Offset, PropertyVisibility Visibility) + { + NewProperty = null; + if (!GetProperty("ObjectProperty", out var PropertyClass) + || !Classes.GetScriptStructInfoFromName($"F{TypeName}", out var FieldClass)) + return false; + var Alloc = Memory.Malloc(Marshal.SizeOf(), FIELD_ALIGNMENT); + NewProperty = Factory.CreateFObjectProperty(Alloc); + SetPropertySuperFieldsNoOwner(Factory.CreateFField(Alloc), Name, PropertyClass!); + unsafe + { + var pProperty = (FProperty*)Alloc; + pProperty->ArrayDim = 1; + pProperty->ElementSize = Marshal.SizeOf(); + pProperty->PropertyFlags = Flags.CreatePropertyFlags(Visibility, PropertyBuilderFlags.None); + SetPropertyFieldDefaults(pProperty, Offset); + } + LinkToPropertyList(NewProperty, null); + unsafe { ((FObjectProperty*)NewProperty.Ptr)->PropertyClass = (UClass*)FieldClass!.Ptr; } // Our "class" + return true; + } public override bool CreateObject(out IFObjectProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility) @@ -187,6 +300,15 @@ public override bool CreateString(out IFProperty? NewProperty, string Na public override bool CreateText(out IFProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility) => CreateTextPropertyInner(out NewProperty, Name, Offset, "TextProperty", Visibility); + + public override bool CreateName(out IFProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility) + => CreateCopyPropertyInner(out NewProperty, Name, Offset, "NameProperty", Visibility); + + public override bool CreateString(out IFProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility) + => CreateStringPropertyInner(out NewProperty, Name, Offset, "StrProperty", Visibility); + + public override bool CreateText(out IFProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility) + => CreateTextPropertyInner(out NewProperty, Name, Offset, "TextProperty", Visibility); public override bool CreateArray(out IFArrayProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility, IFProperty Inner) @@ -209,4 +331,29 @@ public override bool CreateArray(out IFArrayProperty? NewProperty, strin unsafe { ((FArrayProperty*)Alloc)->Inner = (FProperty*)Inner.Ptr; } return true; } + + public override bool CreateMap(out IFMapProperty? NewProperty, string Name, int Offset, PropertyVisibility Visibility, + IFProperty Key, IFProperty Value) + { + NewProperty = null; + if (!GetProperty("MapProperty", out var PropertyClass)) + return false; + var Alloc = Memory.Malloc(Marshal.SizeOf(), FIELD_ALIGNMENT); + NewProperty = Factory.CreateFMapProperty(Alloc); + SetPropertySuperFieldsNoOwner(Factory.CreateFField(Alloc), Name, PropertyClass!); + unsafe + { + var pProperty = (FProperty*)Alloc; + pProperty->ArrayDim = 1; + pProperty->ElementSize = 0x50; // sizeof(TMap), usually + pProperty->PropertyFlags = Flags.CreatePropertyFlags(Visibility, PropertyBuilderFlags.NoCtor); + SetPropertyFieldDefaults(pProperty, Offset); + } + LinkToPropertyList(NewProperty, null); + unsafe { ((FMapProperty*)Alloc)->KeyProp = (FProperty*)Key.Ptr; } + unsafe { ((FMapProperty*)Alloc)->ValueProp = (FProperty*)Value.Ptr; } + Key.SetOwnerFField(NewProperty); + Value.SetOwnerFField(NewProperty); + return true; + } } \ No newline at end of file diff --git a/UE.Toolkit.Reloaded/Unreal/UnrealClasses.cs b/UE.Toolkit.Reloaded/Unreal/UnrealClasses.cs index a14486e..f3deaae 100644 --- a/UE.Toolkit.Reloaded/Unreal/UnrealClasses.cs +++ b/UE.Toolkit.Reloaded/Unreal/UnrealClasses.cs @@ -301,56 +301,124 @@ public bool AddI32Property(string Name, int Offset, out IFProperty? Pro where TObject : unmanaged { Property = null; - return PropertyFactory.CreateI32(out Property, Name, Offset, PropertyVisibility.Public); + return PropertyFactory.CreateI32(out Property, Name, Offset, PropertyVisibility.Public); } public bool AddI64Property(string Name, int Offset, out IFProperty? Property) where TObject : unmanaged { Property = null; - return PropertyFactory.CreateI64(out Property, Name, Offset, PropertyVisibility.Public); + return PropertyFactory.CreateI64(out Property, Name, Offset, PropertyVisibility.Public); } public bool AddU8Property(string Name, int Offset, out IFProperty? Property) where TObject : unmanaged { Property = null; - return PropertyFactory.CreateU8(out Property, Name, Offset, PropertyVisibility.Public); + return PropertyFactory.CreateU8(out Property, Name, Offset, PropertyVisibility.Public); } public bool AddU16Property(string Name, int Offset, out IFProperty? Property) where TObject : unmanaged { Property = null; - return PropertyFactory.CreateU16(out Property, Name, Offset, PropertyVisibility.Public); + return PropertyFactory.CreateU16(out Property, Name, Offset, PropertyVisibility.Public); } public bool AddU32Property(string Name, int Offset, out IFProperty? Property) where TObject : unmanaged { Property = null; - return PropertyFactory.CreateU32(out Property, Name, Offset, PropertyVisibility.Public); + return PropertyFactory.CreateU32(out Property, Name, Offset, PropertyVisibility.Public); } public bool AddU64Property(string Name, int Offset, out IFProperty? Property) where TObject : unmanaged { Property = null; - return PropertyFactory.CreateU64(out Property, Name, Offset, PropertyVisibility.Public); + return PropertyFactory.CreateU64(out Property, Name, Offset, PropertyVisibility.Public); } public bool AddF32Property(string Name, int Offset, out IFProperty? Property) where TObject : unmanaged { Property = null; - return PropertyFactory.CreateF32(out Property, Name, Offset, PropertyVisibility.Public); + return PropertyFactory.CreateF32(out Property, Name, Offset, PropertyVisibility.Public); } public bool AddF64Property(string Name, int Offset, out IFProperty? Property) where TObject : unmanaged { Property = null; - return PropertyFactory.CreateF64(out Property, Name, Offset, PropertyVisibility.Public); + return PropertyFactory.CreateF64(out Property, Name, Offset, PropertyVisibility.Public); + } + + public bool AddI8Property(string Name, int Offset, out IFProperty? Property) + { + Property = null; + return PropertyFactory.CreateI8(out Property, Name, Offset, PropertyVisibility.Public); + } + + public bool AddI16Property(string Name, int Offset, out IFProperty? Property) + { + Property = null; + return PropertyFactory.CreateI16(out Property, Name, Offset, PropertyVisibility.Public); + } + + public bool AddI32Property(string Name, int Offset, out IFProperty? Property) + + { + Property = null; + return PropertyFactory.CreateI32(out Property, Name, Offset, PropertyVisibility.Public); + } + + public bool AddI64Property(string Name, int Offset, out IFProperty? Property) + + { + Property = null; + return PropertyFactory.CreateI64(out Property, Name, Offset, PropertyVisibility.Public); + } + + public bool AddU8Property(string Name, int Offset, out IFProperty? Property) + + { + Property = null; + return PropertyFactory.CreateU8(out Property, Name, Offset, PropertyVisibility.Public); + } + + public bool AddU16Property(string Name, int Offset, out IFProperty? Property) + + { + Property = null; + return PropertyFactory.CreateU16(out Property, Name, Offset, PropertyVisibility.Public); + } + + public bool AddU32Property(string Name, int Offset, out IFProperty? Property) + + { + Property = null; + return PropertyFactory.CreateU32(out Property, Name, Offset, PropertyVisibility.Public); + } + + public bool AddU64Property(string Name, int Offset, out IFProperty? Property) + + { + Property = null; + return PropertyFactory.CreateU64(out Property, Name, Offset, PropertyVisibility.Public); + } + + public bool AddF32Property(string Name, int Offset, out IFProperty? Property) + + { + Property = null; + return PropertyFactory.CreateF32(out Property, Name, Offset, PropertyVisibility.Public); + } + + public bool AddF64Property(string Name, int Offset, out IFProperty? Property) + + { + Property = null; + return PropertyFactory.CreateF64(out Property, Name, Offset, PropertyVisibility.Public); } public bool AddCBoolProperty(string Name, int Offset, out IFBoolProperty? Property) @@ -420,6 +488,15 @@ public bool AddArrayProperty(string Name, int Offset, IFProperty Inner, return PropertyFactory.CreateArray(out Property, Name, Offset, PropertyVisibility.Public, Inner); } + /* + public bool AddMapProperty(string Name, int Offset, + IFProperty Key, IFProperty Value, out IFMapProperty? Property) where TObject : unmanaged + { + Property = null; + return PropertyFactory.CreateMap(out Property, Name, Offset, PropertyVisibility.Public, Key, Value); + } + */ + public IFGenericPropertyParams? CreateI8Param(string Name, int Offset) => TypeFactory.CreateI8Param(Name, Offset, out var Out) ? Out : null; @@ -449,6 +526,53 @@ public bool AddArrayProperty(string Name, int Offset, IFProperty Inner, public IFGenericPropertyParams? CreateF64Param(string Name, int Offset) => TypeFactory.CreateF64Param(Name, Offset, out var Out) ? Out : null; + + public bool AddStructProperty(string Name, int Offset, out IFStructProperty? Property) + where TField : unmanaged + { + Property = null; + return PropertyFactory.CreateStruct(out Property, Name, Offset, PropertyVisibility.Public); + } + + public bool AddStructProperty(string Name, string TypeName, int Offset, out IFStructProperty? Property) + { + Property = null; + return PropertyFactory.CreateStruct(out Property, Name, TypeName, Offset, PropertyVisibility.Public); + } + + public bool AddStructProperty_DataTableSpecial(string Name, string TypeName, int Offset, out IFObjectProperty? Property) + { + Property = null; + return PropertyFactory.CreateStructDTSpecial(out Property, Name, TypeName, Offset, PropertyVisibility.Public); + } + + public bool AddNameProperty(string Name, int Offset, out IFProperty? Property) + + { + Property = null; + return PropertyFactory.CreateName(out Property, Name, Offset, PropertyVisibility.Public); + } + + public bool AddStringProperty(string String, int Offset, out IFProperty? Property) + + { + Property = null; + return PropertyFactory.CreateString(out Property, String, Offset, PropertyVisibility.Public); + } + + public bool AddTextProperty(string Text, int Offset, out IFProperty? Property) + + { + Property = null; + return PropertyFactory.CreateText(out Property, Text, Offset, PropertyVisibility.Public); + } + + public bool AddMapProperty(string Name, int Offset, + IFProperty Key, IFProperty Value, out IFMapProperty? Property) + { + Property = null; + return PropertyFactory.CreateMap(out Property, Name, Offset, PropertyVisibility.Public, Key, Value); + } public bool CreateScriptStruct(string Name, int Size, List Fields, out IUScriptStruct? Out) { diff --git a/UE.Toolkit.Reloaded/Unreal/UnrealMethods.cs b/UE.Toolkit.Reloaded/Unreal/UnrealMethods.cs index 70f33c0..26f11f5 100644 --- a/UE.Toolkit.Reloaded/Unreal/UnrealMethods.cs +++ b/UE.Toolkit.Reloaded/Unreal/UnrealMethods.cs @@ -2,6 +2,7 @@ using Reloaded.Hooks.Definitions; using UE.Toolkit.Core.Types; using UE.Toolkit.Core.Types.Interfaces; +using UE.Toolkit.Core.Types.Unreal.Common.FunctionParam; using UE.Toolkit.Core.Types.Unreal.Factories; using UE.Toolkit.Core.Types.Unreal.Factories.Interfaces; using EPropertyFlags = UE.Toolkit.Core.Types.Unreal.UE5_4_4.EPropertyFlags; @@ -142,7 +143,7 @@ public unsafe void FromAlloc(nint pAlloc) public class UnrealMethods : IUnrealMethods { - #region Function Invocation Parameters + #region Function Invocation Parameters (OLD) public IInvocationParameter CreateI8Param(sbyte Value = 0) => new I8InvocationParameter(Value); public IInvocationParameter CreateI16Param(short Value = 0) => new I16InvocationParameter(Value); @@ -160,7 +161,7 @@ public class UnrealMethods : IUnrealMethods #endregion - #region Function Invocation Execute + #region Function Invocation Execute (OLD) private delegate void UObject_ProcessEvent(nint Object, nint TargetFunction, nint Params); private uint UObject_ProcessEvent_Offset; @@ -177,6 +178,7 @@ private bool ProcessEventInner(ToolkitUObject Object, string N ref List Parameters, out IUFunction? Function, out nint Alloc, ExecutionFlags Flags) where TObject : unmanaged { + Log.Warning("IUnrealMethods::ProcessEvent is deprecated! Use IUObject::ProcessEvent instead!\n"); // Get type reflection for object type Function = null; Alloc = nint.Zero; @@ -223,11 +225,8 @@ private bool ProcessEventInner(ToolkitUObject Object, string N } Parameter.ToAlloc(Alloc + Property.Offset_Internal); } - unsafe - { - var ProcessEventWrapper = Hooks.CreateWrapper(*(nint*)(Function.VTable + UObject_ProcessEvent_Offset), out _); - ProcessEventWrapper((nint)Object.Self, Function.Ptr, Alloc); - } + + unsafe { CallProcessEvent((nint)Object.Self, Function, Alloc); } return true; } @@ -332,6 +331,15 @@ public TReturnType ProcessEvent(ToolkitUObject Ob } #endregion + + internal unsafe void CallProcessEvent(nint Object, IUFunction Function, nint Alloc) + { + var ProcessEventWrapper = Hooks.CreateWrapper(*(nint*)(Function.VTable + UObject_ProcessEvent_Offset), out _); + ProcessEventWrapper(Object, Function.Ptr, Alloc); + } + + internal IFunctionParam CreateReturnParam(IFProperty property) + => FunctionParamFactory.CreateParam(property, Factory, Classes, Memory); #region Unreal Toolkit API References diff --git a/UE.Toolkit.Reloaded/Unreal/UnrealObjects.cs b/UE.Toolkit.Reloaded/Unreal/UnrealObjects.cs index c0e746c..db4830c 100644 --- a/UE.Toolkit.Reloaded/Unreal/UnrealObjects.cs +++ b/UE.Toolkit.Reloaded/Unreal/UnrealObjects.cs @@ -86,6 +86,13 @@ public UnrealObjects(IUnrealFactory factory) public IUObjectArray GUObjectArray { get; private set; } = null!; + // Remove ending _Repr from object types, to handle class based object dumps created in UE Toolkit 1.10+ + private static string GetObjectTypeName() where TObject : unmanaged + { + var Name = typeof(TObject).Name; + return Name.EndsWith("_Repr") ? Name[1..^5] : Name[1..]; + } + public void OnObjectLoadedByName(string objName, Action> callback) where TObject : unmanaged { @@ -101,7 +108,7 @@ public void OnObjectLoadedByName(string objName, Action(Action> callback) - where TObject : unmanaged => OnObjectLoadedByName(typeof(TObject).Name, callback); + where TObject : unmanaged => OnObjectLoadedByName(GetObjectTypeName(), callback); public void OnObjectLoadedByClass(string objClass, Action> callback) where TObject : unmanaged @@ -113,7 +120,7 @@ public void OnObjectLoadedByClass(string objClass, Action(Action> callback) - where TObject : unmanaged => OnObjectLoadedByClass(typeof(TObject).Name, callback); + where TObject : unmanaged => OnObjectLoadedByClass(GetObjectTypeName(), callback); public void OnObjectLoadedByPath(string objectPath, Action> callback) where TObject : unmanaged @@ -148,7 +155,7 @@ private void ForEachObject(Func Callback) public ToolkitUObject? FindObjectByName(string objectName) where TObject : unmanaged { - var Object = FindObjectByName(objectName, typeof(TObject).Name); + var Object = FindObjectByName(objectName, GetObjectTypeName()); return Object != null ? new ToolkitUObject((TObject*)Object.Ptr) : null; } @@ -165,7 +172,7 @@ private void ForEachObject(Func Callback) public ToolkitUObject? FindObjectByClass() where TObject : unmanaged { - var Object = FindObjectByClass(typeof(TObject).Name); + var Object = FindObjectByClass(GetObjectTypeName()); return Object != null ? new ToolkitUObject((TObject*)Object.Ptr) : null; }