From 809d23d54531336f149f744fcdb4a7f2d14a03c4 Mon Sep 17 00:00:00 2001 From: ApfelTeeSaft <91074565+ApfelTeeSaft@users.noreply.github.com> Date: Thu, 18 Jul 2024 15:31:51 +0200 Subject: [PATCH] attempt at fly logic --- F4Menu/Classes.cpp | 132 +++++ F4Menu/Classes.hpp | 170 +++++++ F4Menu/Containers.h | 925 ++++++++++++++++++++++++++++++++++ F4Menu/F4Menu.vcxproj | 9 + F4Menu/F4Menu.vcxproj.filters | 30 ++ F4Menu/Game.cpp | 79 +++ F4Menu/Game.h | 28 + F4Menu/GuiManager.cpp | 16 +- F4Menu/Logic.cpp | 23 + F4Menu/Logic.hpp | 8 + F4Menu/UE4.cpp | 47 ++ F4Menu/UE4.hpp | 875 ++++++++++++++++++++++++++++++++ F4Menu/framework.h | 3 + 13 files changed, 2332 insertions(+), 13 deletions(-) create mode 100644 F4Menu/Classes.cpp create mode 100644 F4Menu/Classes.hpp create mode 100644 F4Menu/Containers.h create mode 100644 F4Menu/Game.cpp create mode 100644 F4Menu/Game.h create mode 100644 F4Menu/Logic.cpp create mode 100644 F4Menu/Logic.hpp create mode 100644 F4Menu/UE4.cpp create mode 100644 F4Menu/UE4.hpp diff --git a/F4Menu/Classes.cpp b/F4Menu/Classes.cpp new file mode 100644 index 000000000..43a0758ae --- /dev/null +++ b/F4Menu/Classes.cpp @@ -0,0 +1,132 @@ + +#include "UE4.hpp" + +#include "Classes.hpp" + +namespace UE4 +{ + class UObject* UObject::FindObjectFastImpl(const std::string& Name, EClassCastFlags RequiredType) + { + int ObjectNum = GObjects ? GObjects->Num() : GObjectsNew->Num(); + bool bOldGObj = GObjects ? true : false; + + for (int i = 0; i < ObjectNum; ++i) + { + UObject* Object = nullptr; + if (bOldGObj) + Object = GObjects->GetByIndex(i); + else + Object = GObjectsNew->GetByIndex(i); + + if (!Object) + continue; + + if (Object->HasTypeFlag(RequiredType) && Object->GetName() == Name) + return Object; + } + + return nullptr; + } + + class UObject* UObject::FindObjectImpl(const std::string& FullName, EClassCastFlags RequiredType) + { + int ObjectNum = GObjects.GetTypedPtr()->GetByIndex(0) ? GObjects->Num() : GObjectsNew->Num(); + bool bOldGObj = GObjects.GetTypedPtr()->GetByIndex(0) ? true : false; + + for (int i = 0; i < ObjectNum; ++i) + { + UObject* Object = nullptr; + + if (bOldGObj) + Object = GObjects->GetByIndex(i); + else + Object = GObjectsNew->GetByIndex(i); + + if (!Object) + continue; + + if (Object->HasTypeFlag(RequiredType) && Object->GetFullName() == FullName) + return Object; + } + + return nullptr; + } + + std::string UObject::GetFullName() const + { + if (this && Class) + { + std::string Temp; + + for (UObject* NextOuter = Outer; NextOuter; NextOuter = NextOuter->Outer) + { + Temp = NextOuter->GetName() + "." + Temp; + } + + std::string Name = Class->GetName(); + Name += " "; + Name += Temp; + Name += GetName(); + + return Name; + } + + return "None"; + } + + std::string UObject::GetName() const + { + return this ? Name.ToString() : "None"; + } + + bool UObject::HasTypeFlag(EClassCastFlags TypeFlags) const + { + return (Class->CastFlags & TypeFlags); + } + + bool UObject::IsA(EClassCastFlags TypeFlags) const + { + return (Class->CastFlags & TypeFlags); + } + + bool UObject::IsA(class UClass* TypeClass) const + { + return Class->IsSubclassOf(TypeClass); + } + + bool UObject::IsDefaultObject() const + { + return (Flags & EObjectFlags::ClassDefaultObject); + } + + bool UStruct::IsSubclassOf(const UStruct* Base) const + { + if (!Base) + return false; + + for (const UStruct* Struct = this; Struct; Struct = Struct->Super) + { + if (Struct == Base) + return true; + } + + return false; + } + + class UFunction* UClass::GetFunction(const std::string& ClassName, const std::string& FuncName) const + { + for (const UStruct* Clss = this; Clss; Clss = Clss->Super) + { + if (Clss->GetName() != ClassName) + continue; + + for (UField* Field = Clss->Children; Field; Field = Field->Next) + { + if (Field->HasTypeFlag(EClassCastFlags::Function) && Field->GetName() == FuncName) + return static_cast(Field); + } + } + + return nullptr; + } +} \ No newline at end of file diff --git a/F4Menu/Classes.hpp b/F4Menu/Classes.hpp new file mode 100644 index 000000000..34b6d68e6 --- /dev/null +++ b/F4Menu/Classes.hpp @@ -0,0 +1,170 @@ +#pragma once +#include "UE4.hpp" +#include "Containers.h" + +namespace UE4 +{ + class UObject + { + public: + static inline class TUObjectArrayWrapper GObjects; + static inline class TUObjectArrayNew* GObjectsNew; + + void* VTable; + EObjectFlags Flags; + int32 Index; + class UClass* Class; + class FName Name; + class UObject* Outer; + + public: + static class UObject* FindObjectFastImpl(const std::string& Name, EClassCastFlags RequiredType = EClassCastFlags::None); + static class UObject* FindObjectImpl(const std::string& FullName, EClassCastFlags RequiredType = EClassCastFlags::None); + + std::string GetFullName() const; + std::string GetName() const; + bool HasTypeFlag(EClassCastFlags TypeFlags) const; + bool IsA(EClassCastFlags TypeFlags) const; + bool IsA(class UClass* TypeClass) const; + bool IsDefaultObject() const; + + public: + static class UClass* FindClass(const std::string& ClassFullName) + { + return FindObject(ClassFullName, EClassCastFlags::Class); + } + static class UClass* FindClassFast(const std::string& ClassName) + { + return FindObjectFast(ClassName, EClassCastFlags::Class); + } + + template + static UEType* FindObject(const std::string& Name, EClassCastFlags RequiredType = EClassCastFlags::None) + { + return static_cast(FindObjectImpl(Name, RequiredType)); + } + template + static UEType* FindObjectFast(const std::string& Name, EClassCastFlags RequiredType = EClassCastFlags::None) + { + return static_cast(FindObjectFastImpl(Name, RequiredType)); + } + + void ProcessEvent(class UFunction* Function, void* Parms) const + { + InSDKUtils::CallGameFunction(InSDKUtils::GetVirtualFunction(this, Offsets::ProcessEventIdx), this, Function, Parms); + } + + static class UClass* StaticClass() + { + return StaticClassImpl<"Object">(); + } + static class UObject* GetDefaultObj() + { + return GetDefaultObjImpl(); + } + }; + + + class UField : public UObject + { + public: + class UField* Next; + + public: + static class UClass* StaticClass() + { + return StaticClassImpl<"Field">(); + } + static class UField* GetDefaultObj() + { + return GetDefaultObjImpl(); + } + }; + + class UProperty : public UField + { + public: + int32 ArrayDim; + int32 ElementSize; + uint64 PropertyFlags; + uint8 Pad_20[0x4]; + int32 Offset; + uint8 Pad_21[0x28]; + + public: + static class UClass* StaticClass() + { + return StaticClassImpl<"Property">(); + } + static class UProperty* GetDefaultObj() + { + return GetDefaultObjImpl(); + } + }; + + + class UStruct : public UField + { + public: + class UStruct* Super; + class UField* Children; + int32 Size; + int32 MinAlignemnt; + uint8 Pad_1D[0x40]; + + public: + bool IsSubclassOf(const UStruct* Base) const; + + public: + static class UClass* StaticClass() + { + return StaticClassImpl<"Struct">(); + } + static class UStruct* GetDefaultObj() + { + return GetDefaultObjImpl(); + } + }; + + class UClass : public UStruct + { + public: + uint8 Pad_24[0x30]; + enum class EClassCastFlags CastFlags; + uint8 Pad_25[0x38]; + class UObject* DefaultObject; + uint8 Pad_26[0xF8]; + public: + class UFunction* GetFunction(const std::string& ClassName, const std::string& FuncName) const; + + public: + static class UClass* StaticClass() + { + return StaticClassImpl<"Class">(); + } + static class UClass* GetDefaultObj() + { + return GetDefaultObjImpl(); + } + }; + + class UFunction : public UStruct + { + public: + using FNativeFuncPtr = void (*)(void* Context, void* TheStack, void* Result); + + uint32 FunctionFlags; + uint8 Pad_27[0x20]; + FNativeFuncPtr ExecFunction; + + public: + static class UClass* StaticClass() + { + return StaticClassImpl<"Function">(); + } + static class UFunction* GetDefaultObj() + { + return GetDefaultObjImpl(); + } + }; +} \ No newline at end of file diff --git a/F4Menu/Containers.h b/F4Menu/Containers.h new file mode 100644 index 000000000..6f969d15b --- /dev/null +++ b/F4Menu/Containers.h @@ -0,0 +1,925 @@ +#pragma once +#include +#include +#include +#include + +namespace UE4 +{ + namespace Containers + { + typedef int8_t int8; + typedef int16_t int16; + typedef int32_t int32; + typedef int64_t int64; + + typedef uint8_t uint8; + typedef uint16_t uint16; + typedef uint32_t uint32; + typedef uint64_t uint64; + + + namespace FMemory + { + inline void* (*Realloc)(void* Memory, int64_t NewSize, uint32_t Alignment); + inline void* (*Free)(void* Memory); + } + + template + class TArray; + + template + class TSparseArray; + + template + class TSet; + + template + class TMap; + + template + class TPair; + + namespace Iterators + { + class FSetBitIterator; + + template + class TArrayIterator; + + template + class TContainerIterator; + + template + using TSparseArrayIterator = TContainerIterator>; + + template + using TSetIterator = TContainerIterator>; + + template + using TMapIterator = TContainerIterator>; + } + + + namespace ContainerImpl + { + namespace HelperFunctions + { + inline uint32 FloorLog2(uint32 Value) + { + uint32 pos = 0; + if (Value >= 1 << 16) { Value >>= 16; pos += 16; } + if (Value >= 1 << 8) { Value >>= 8; pos += 8; } + if (Value >= 1 << 4) { Value >>= 4; pos += 4; } + if (Value >= 1 << 2) { Value >>= 2; pos += 2; } + if (Value >= 1 << 1) { pos += 1; } + return pos; + } + + inline uint32 CountLeadingZeros(uint32 Value) + { + if (Value == 0) + return 32; + + return 31 - FloorLog2(Value); + } + } + + template + struct TAlignedBytes + { + alignas(Alignment) uint8 Pad[Size]; + }; + + template + class TInlineAllocator + { + public: + template + class ForElementType + { + private: + static constexpr int32 ElementSize = sizeof(ElementType); + static constexpr int32 ElementAlign = alignof(ElementType); + + static constexpr int32 InlineDataSizeBytes = NumInlineElements * ElementSize; + + private: + TAlignedBytes InlineData[NumInlineElements]; + ElementType* SecondaryData; + + public: + ForElementType() + : InlineData{ 0x0 }, SecondaryData(nullptr) + { + } + + ForElementType(ForElementType&&) = default; + ForElementType(const ForElementType&) = default; + + public: + ForElementType& operator=(ForElementType&&) = default; + ForElementType& operator=(const ForElementType&) = default; + + public: + inline const ElementType* GetAllocation() const { return SecondaryData ? SecondaryData : reinterpret_cast(&InlineData); } + + inline uint32 GetNumInlineBytes() const { return NumInlineElements; } + }; + }; + + class FBitArray + { + protected: + static constexpr int32 NumBitsPerDWORD = 32; + static constexpr int32 NumBitsPerDWORDLogTwo = 5; + + private: + TInlineAllocator<4>::ForElementType Data; + int32 NumBits; + int32 MaxBits; + + public: + FBitArray() + : NumBits(0), MaxBits(Data.GetNumInlineBytes()* NumBitsPerDWORD) + { + } + + FBitArray(const FBitArray&) = default; + + FBitArray(FBitArray&&) = default; + + public: + FBitArray& operator=(FBitArray&&) = default; + + FBitArray& operator=(const FBitArray& Other) = default; + + private: + inline void VerifyIndex(int32 Index) const { if (!IsValidIndex(Index)) throw std::out_of_range("Index was out of range!"); } + + public: + inline int32 Num() const { return NumBits; } + inline int32 Max() const { return MaxBits; } + + inline const uint32* GetData() const { return reinterpret_cast(Data.GetAllocation()); } + + inline bool IsValidIndex(int32 Index) const { return Index >= 0 && Index < NumBits; } + + inline bool IsValid() const { return GetData() && NumBits > 0; } + + public: + inline bool operator[](int32 Index) const { VerifyIndex(Index); return GetData()[Index / NumBitsPerDWORD] & (1 << (Index & (NumBitsPerDWORD - 1))); } + + inline bool operator==(const FBitArray& Other) const { return NumBits == Other.NumBits && GetData() == Other.GetData(); } + inline bool operator!=(const FBitArray& Other) const { return NumBits != Other.NumBits || GetData() != Other.GetData(); } + + public: + friend Iterators::FSetBitIterator begin(const FBitArray& Array); + friend Iterators::FSetBitIterator end(const FBitArray& Array); + }; + + template + union TSparseArrayElementOrFreeListLink + { + SparseArrayType ElementData; + + struct + { + int32 PrevFreeIndex; + int32 NextFreeIndex; + }; + }; + + template + class SetElement + { + private: + template + friend class TSet; + + private: + SetType Value; + int32 HashNextId; + int32 HashIndex; + }; + } + + + template + class TPair + { + private: + KeyType First; + ValueType Second; + + public: + TPair(KeyType Key, ValueType Value) + : First(Key), Second(Value) + { + } + + public: + inline KeyType& Key() { return First; } + inline const KeyType& Key() const { return First; } + + inline ValueType& Value() { return Second; } + inline const ValueType& Value() const { return Second; } + }; + + template + class TArray + { + private: + template + friend class TAllocatedArray; + + template + friend class TSparseArray; + + protected: + static constexpr uint64 ElementAlign = alignof(ArrayElementType); + static constexpr uint64 ElementSize = sizeof(ArrayElementType); + + public: + ArrayElementType* Data; + int32 NumElements; + int32 MaxElements; + + TArray() + : Data(nullptr), NumElements(0), MaxElements(0) + { + } + + TArray(const TArray&) = default; + + TArray(TArray&&) = default; + + public: + TArray& operator=(TArray&&) = default; + TArray& operator=(const TArray&) = default; + + private: + inline int32 GetSlack() const { return MaxElements - NumElements; } + + inline void VerifyIndex(int32 Index) const { if (!IsValidIndex(Index)) throw std::out_of_range("Index was out of range!"); } + + inline ArrayElementType& GetUnsafe(int32 Index) { return Data[Index]; } + inline const ArrayElementType& GetUnsafe(int32 Index) const { return Data[Index]; } + + public: + inline void Reserve(const int Num) + { + Data = (ArrayElementType*)FMemory::Realloc(Data, (MaxElements = Num + NumElements) * sizeof(ArrayElementType), 0); + } + + inline void Free() + { + if (Data) + FMemory::Free(Data); + + MaxElements = 0; + NumElements = 0; + } + + inline ArrayElementType& Add(const ArrayElementType& InData) + { + Reserve(1); + + Data[NumElements] = InData; + ++NumElements; + + return Data[NumElements - 1]; + } + + void AddWithSize(size_t SizeOfElement, void* ElementPointer) + { + Data = (ArrayElementType*)FMemory::Realloc(Data, SizeOfElement * (NumElements + 1), 0); + + memcpy((Data + ((SizeOfElement - sizeof(ArrayElementType)) * NumElements) + NumElements++), ElementPointer, SizeOfElement); + + MaxElements = NumElements; + } + + inline bool Remove(int Index) + { + if (Index < NumElements) + { + if (Index != NumElements - 1) + { + Data[Index] = Data[NumElements - 1]; + } + + --NumElements; + return true; + } + return false; + } + + inline void Clear() + { + NumElements = 0; + + if (!Data) + memset(Data, 0, NumElements * ElementSize); + } + + public: + inline int32 Num() const { return NumElements; } + inline int32 Max() const { return MaxElements; } + + inline bool IsValidIndex(int32 Index) const { return Data && Index >= 0 && Index < NumElements; } + + inline bool IsValid() const { return Data && NumElements > 0 && MaxElements >= NumElements; } + + public: + inline ArrayElementType& operator[](int32 Index) { VerifyIndex(Index); return Data[Index]; } + inline const ArrayElementType& operator[](int32 Index) const { VerifyIndex(Index); return Data[Index]; } + + inline bool operator==(const TArray& Other) const { return Data == Other.Data; } + inline bool operator!=(const TArray& Other) const { return Data != Other.Data; } + + inline explicit operator bool() const { return IsValid(); }; + + public: + template friend Iterators::TArrayIterator begin(const TArray& Array); + template friend Iterators::TArrayIterator end(const TArray& Array); + }; + + class FString : public TArray + { + public: + using TArray::TArray; + + FString(const wchar_t* Str) + { + const uint32 NullTerminatedLength = static_cast(wcslen(Str) + 0x1); + + Data = const_cast(Str); + NumElements = NullTerminatedLength; + MaxElements = NullTerminatedLength; + } + + public: + inline std::string ToString() const + { + if (*this) + { + std::wstring WData(Data); +#pragma warning(suppress: 4244) + return std::string(WData.begin(), WData.end()); + } + + return ""; + } + + inline std::wstring ToWString() const + { + if (*this) + return std::wstring(Data); + + return L""; + } + + public: + inline wchar_t* CStr() { return Data; } + inline const wchar_t* CStr() const { return Data; } + + public: + inline bool operator==(const FString& Other) const { return Other ? NumElements == Other.NumElements && wcscmp(Data, Other.Data) == 0 : false; } + inline bool operator!=(const FString& Other) const { return Other ? NumElements != Other.NumElements || wcscmp(Data, Other.Data) != 0 : true; } + }; + template + class TAllocatedArray : public TArray + { + public: + TAllocatedArray() = delete; + + public: + TAllocatedArray(int32 Size) + { + this->Data = static_cast(malloc(Size * sizeof(ArrayElementType))); + this->NumElements = 0x0; + this->MaxElements = Size; + } + + ~TAllocatedArray() + { + if (this->Data) + free(this->Data); + + this->NumElements = 0x0; + this->MaxElements = 0x0; + } + + public: + inline operator TArray() { return *reinterpret_cast*>(this); } + inline operator const TArray() const { return *reinterpret_cast*>(this); } + }; + class FAllocatedString : public FString + { + public: + FAllocatedString() = delete; + + public: + FAllocatedString(int32 Size) + { + Data = static_cast(malloc(Size * sizeof(wchar_t))); + NumElements = 0x0; + MaxElements = Size; + } + + ~FAllocatedString() + { + if (Data) + free(Data); + + NumElements = 0x0; + MaxElements = 0x0; + } + + public: + inline operator FString() { return *reinterpret_cast(this); } + inline operator const FString() const { return *reinterpret_cast(this); } + }; + template + class TSparseArray + { + private: + static constexpr uint32 ElementAlign = alignof(SparseArrayElementType); + static constexpr uint32 ElementSize = sizeof(SparseArrayElementType); + + private: + using FElementOrFreeListLink = ContainerImpl::TSparseArrayElementOrFreeListLink>; + + private: + TArray Data; + ContainerImpl::FBitArray AllocationFlags; + int32 FirstFreeIndex; + int32 NumFreeIndices; + + public: + TSparseArray() + : FirstFreeIndex(-1), NumFreeIndices(0) + { + } + + TSparseArray(TSparseArray&&) = default; + TSparseArray(const TSparseArray&) = default; + + public: + TSparseArray& operator=(TSparseArray&&) = default; + TSparseArray& operator=(const TSparseArray&) = default; + + private: + inline void VerifyIndex(int32 Index) const { if (!IsValidIndex(Index)) throw std::out_of_range("Index was out of range!"); } + + public: + inline int32 NumAllocated() const { return Data.Num(); } + + inline int32 Num() const { return NumAllocated() - NumFreeIndices; } + inline int32 Max() const { return Data.Max(); } + + inline bool IsValidIndex(int32 Index) const { return Data.IsValidIndex(Index) && AllocationFlags[Index]; } + + inline bool IsValid() const { return Data.IsValid() && AllocationFlags.IsValid(); } + + public: + const ContainerImpl::FBitArray& GetAllocationFlags() const { return AllocationFlags; } + + public: + inline SparseArrayElementType& operator[](int32 Index) { VerifyIndex(Index); return *reinterpret_cast(&Data.GetUnsafe(Index).ElementData); } + inline const SparseArrayElementType& operator[](int32 Index) const { VerifyIndex(Index); return *reinterpret_cast(&Data.GetUnsafe(Index).ElementData); } + + inline bool operator==(const TSparseArray& Other) const { return Data == Other.Data; } + inline bool operator!=(const TSparseArray& Other) const { return Data != Other.Data; } + + public: + template friend Iterators::TSparseArrayIterator begin(const TSparseArray& Array); + template friend Iterators::TSparseArrayIterator end(const TSparseArray& Array); + }; + + template + class TSet + { + private: + static constexpr uint32 ElementAlign = alignof(SetElementType); + static constexpr uint32 ElementSize = sizeof(SetElementType); + + private: + using SetDataType = ContainerImpl::SetElement; + using HashType = ContainerImpl::TInlineAllocator<1>::ForElementType; + + private: + TSparseArray Elements; + HashType Hash; + int32 HashSize; + + public: + TSet() + : HashSize(0) + { + } + + TSet(TSet&&) = default; + TSet(const TSet&) = default; + + public: + TSet& operator=(TSet&&) = default; + TSet& operator=(const TSet&) = default; + + private: + inline void VerifyIndex(int32 Index) const { if (!IsValidIndex(Index)) throw std::out_of_range("Index was out of range!"); } + + public: + inline int32 NumAllocated() const { return Elements.NumAllocated(); } + + inline int32 Num() const { return Elements.Num(); } + inline int32 Max() const { return Elements.Max(); } + + inline bool IsValidIndex(int32 Index) const { return Elements.IsValidIndex(Index); } + + inline bool IsValid() const { return Elements.IsValid(); } + + public: + const ContainerImpl::FBitArray& GetAllocationFlags() const { return Elements.GetAllocationFlags(); } + + public: + inline SetElementType& operator[] (int32 Index) { return Elements[Index].Value; } + inline const SetElementType& operator[] (int32 Index) const { return Elements[Index].Value; } + + inline bool operator==(const TSet& Other) const { return Elements == Other.Elements; } + inline bool operator!=(const TSet& Other) const { return Elements != Other.Elements; } + + public: + template friend Iterators::TSetIterator begin(const TSet& Set); + template friend Iterators::TSetIterator end(const TSet& Set); + }; + + template + class TMap + { + public: + using ElementType = TPair; + + private: + TSet Elements; + + private: + inline void VerifyIndex(int32 Index) const { if (!IsValidIndex(Index)) throw std::out_of_range("Index was out of range!"); } + + public: + inline int32 NumAllocated() const { return Elements.NumAllocated(); } + + inline int32 Num() const { return Elements.Num(); } + inline int32 Max() const { return Elements.Max(); } + + inline bool IsValidIndex(int32 Index) const { return Elements.IsValidIndex(Index); } + + inline bool IsValid() const { return Elements.IsValid(); } + + public: + const ContainerImpl::FBitArray& GetAllocationFlags() const { return Elements.GetAllocationFlags(); } + + public: + inline decltype(auto) Find(const KeyElementType& Key, bool(*Equals)(const KeyElementType& LeftKey, const KeyElementType& RightKey)) + { + for (auto It = begin(*this); It != end(*this); ++It) + { + if (Equals(It->Key(), Key)) + return It; + } + + return end(*this); + } + + public: + inline ElementType& operator[] (int32 Index) { return Elements[Index]; } + inline const ElementType& operator[] (int32 Index) const { return Elements[Index]; } + + inline bool operator==(const TMap& Other) const { return Elements == Other.Elements; } + inline bool operator!=(const TMap& Other) const { return Elements != Other.Elements; } + + public: + template friend Iterators::TMapIterator begin(const TMap& Map); + template friend Iterators::TMapIterator end(const TMap& Map); + }; + + namespace Iterators + { + class FRelativeBitReference + { + protected: + static constexpr int32 NumBitsPerDWORD = 32; + static constexpr int32 NumBitsPerDWORDLogTwo = 5; + + public: + inline explicit FRelativeBitReference(int32 BitIndex) + : WordIndex(BitIndex >> NumBitsPerDWORDLogTwo) + , Mask(1 << (BitIndex & (NumBitsPerDWORD - 1))) + { + } + + int32 WordIndex; + uint32 Mask; + }; + + class FSetBitIterator : public FRelativeBitReference + { + private: + const ContainerImpl::FBitArray& Array; + + uint32 UnvisitedBitMask; + int32 CurrentBitIndex; + int32 BaseBitIndex; + + public: + explicit FSetBitIterator(const ContainerImpl::FBitArray& InArray, int32 StartIndex = 0) + : FRelativeBitReference(StartIndex) + , Array(InArray) + , UnvisitedBitMask((~0U) << (StartIndex & (NumBitsPerDWORD - 1))) + , CurrentBitIndex(StartIndex) + , BaseBitIndex(StartIndex & ~(NumBitsPerDWORD - 1)) + { + if (StartIndex != Array.Num()) + FindFirstSetBit(); + } + + public: + inline FSetBitIterator& operator++() + { + UnvisitedBitMask &= ~this->Mask; + + FindFirstSetBit(); + + return *this; + } + + inline explicit operator bool() const { return CurrentBitIndex < Array.Num(); } + + inline bool operator==(const FSetBitIterator& Rhs) const { return CurrentBitIndex == Rhs.CurrentBitIndex && &Array == &Rhs.Array; } + inline bool operator!=(const FSetBitIterator& Rhs) const { return CurrentBitIndex != Rhs.CurrentBitIndex || &Array != &Rhs.Array; } + + public: + inline int32 GetIndex() { return CurrentBitIndex; } + + void FindFirstSetBit() + { + const uint32* ArrayData = Array.GetData(); + const int32 ArrayNum = Array.Num(); + const int32 LastWordIndex = (ArrayNum - 1) / NumBitsPerDWORD; + + uint32 RemainingBitMask = ArrayData[this->WordIndex] & UnvisitedBitMask; + while (!RemainingBitMask) + { + ++this->WordIndex; + BaseBitIndex += NumBitsPerDWORD; + if (this->WordIndex > LastWordIndex) + { + CurrentBitIndex = ArrayNum; + return; + } + + RemainingBitMask = ArrayData[this->WordIndex]; + UnvisitedBitMask = ~0; + } + + const uint32 NewRemainingBitMask = RemainingBitMask & (RemainingBitMask - 1); + + this->Mask = NewRemainingBitMask ^ RemainingBitMask; + + CurrentBitIndex = BaseBitIndex + NumBitsPerDWORD - 1 - ContainerImpl::HelperFunctions::CountLeadingZeros(this->Mask); + + if (CurrentBitIndex > ArrayNum) + CurrentBitIndex = ArrayNum; + } + }; + + template + class TArrayIterator + { + private: + TArray& IteratedArray; + int32 Index; + + public: + TArrayIterator(const TArray& Array, int32 StartIndex = 0x0) + : IteratedArray(const_cast&>(Array)), Index(StartIndex) + { + } + + public: + inline int32 GetIndex() { return Index; } + + inline int32 IsValid() { return IteratedArray.IsValidIndex(GetIndex()); } + + public: + inline TArrayIterator& operator++() { ++Index; return *this; } + inline TArrayIterator& operator--() { --Index; return *this; } + + inline ArrayType& operator*() { return IteratedArray[GetIndex()]; } + inline const ArrayType& operator*() const { return IteratedArray[GetIndex()]; } + + inline ArrayType* operator->() { return &IteratedArray[GetIndex()]; } + inline const ArrayType* operator->() const { return &IteratedArray[GetIndex()]; } + + inline bool operator==(const TArrayIterator& Other) const { return &IteratedArray == &Other.IteratedArray && Index == Other.Index; } + inline bool operator!=(const TArrayIterator& Other) const { return &IteratedArray != &Other.IteratedArray || Index != Other.Index; } + }; + + template + class TContainerIterator + { + private: + ContainerType& IteratedContainer; + FSetBitIterator BitIterator; + + public: + TContainerIterator(const ContainerType& Container, const ContainerImpl::FBitArray& BitArray, int32 StartIndex = 0x0) + : IteratedContainer(const_cast(Container)), BitIterator(BitArray, StartIndex) + { + } + + public: + inline int32 GetIndex() { return BitIterator.GetIndex(); } + + inline int32 IsValid() { return IteratedContainer.IsValidIndex(GetIndex()); } + + public: + inline TContainerIterator& operator++() { ++BitIterator; return *this; } + inline TContainerIterator& operator--() { --BitIterator; return *this; } + + inline auto& operator*() { return IteratedContainer[GetIndex()]; } + inline const auto& operator*() const { return IteratedContainer[GetIndex()]; } + + inline auto* operator->() { return &IteratedContainer[GetIndex()]; } + inline const auto* operator->() const { return &IteratedContainer[GetIndex()]; } + + inline bool operator==(const TContainerIterator& Other) const { return &IteratedContainer == &Other.IteratedContainer && BitIterator == Other.BitIterator; } + inline bool operator!=(const TContainerIterator& Other) const { return &IteratedContainer != &Other.IteratedContainer || BitIterator != Other.BitIterator; } + }; + } + + inline Iterators::FSetBitIterator begin(const ContainerImpl::FBitArray& Array) { return Iterators::FSetBitIterator(Array, 0); } + inline Iterators::FSetBitIterator end(const ContainerImpl::FBitArray& Array) { return Iterators::FSetBitIterator(Array, Array.Num()); } + + template inline Iterators::TArrayIterator begin(const TArray& Array) { return Iterators::TArrayIterator(Array, 0); } + template inline Iterators::TArrayIterator end(const TArray& Array) { return Iterators::TArrayIterator(Array, Array.Num()); } + + template inline Iterators::TSparseArrayIterator begin(const TSparseArray& Array) { return Iterators::TSparseArrayIterator(Array, Array.GetAllocationFlags(), 0); } + template inline Iterators::TSparseArrayIterator end(const TSparseArray& Array) { return Iterators::TSparseArrayIterator(Array, Array.GetAllocationFlags(), Array.NumAllocated()); } + + template inline Iterators::TSetIterator begin(const TSet& Set) { return Iterators::TSetIterator(Set, Set.GetAllocationFlags(), 0); } + template inline Iterators::TSetIterator end(const TSet& Set) { return Iterators::TSetIterator(Set, Set.GetAllocationFlags(), Set.NumAllocated()); } + + template inline Iterators::TMapIterator begin(const TMap& Map) { return Iterators::TMapIterator(Map, Map.GetAllocationFlags(), 0); } + template inline Iterators::TMapIterator end(const TMap& Map) { return Iterators::TMapIterator(Map, Map.GetAllocationFlags(), Map.NumAllocated()); } + + + struct FVector + { + public: + using UnderlayingType = float; + + float X; + float Y; + float Z; + + public: + FVector& Normalize() + { + *this /= Magnitude(); + return *this; + } + FVector& operator*=(const FVector& Other) + { + *this = *this * Other; + return *this; + } + FVector& operator*=(float Scalar) + { + *this = *this * Scalar; + return *this; + } + FVector& operator+=(const FVector& Other) + { + *this = *this + Other; + return *this; + } + FVector& operator-=(const FVector& Other) + { + *this = *this - Other; + return *this; + } + FVector& operator/=(const FVector& Other) + { + *this = *this / Other; + return *this; + } + FVector& operator/=(float Scalar) + { + *this = *this / Scalar; + return *this; + } + + UnderlayingType Dot(const FVector& Other) const + { + return (X * Other.X) + (Y * Other.Y) + (Z * Other.Z); + } + UnderlayingType GetDistanceTo(const FVector& Other) const + { + FVector DiffVector = Other - *this; + return DiffVector.Magnitude(); + } + UnderlayingType GetDistanceToInMeters(const FVector& Other) const + { + return GetDistanceTo(Other) * 0.01; + } + FVector GetNormalized() const + { + return *this / Magnitude(); + } + bool IsZero() const + { + return X == 0.0 && Y == 0.0 && Z == 0.0; + } + UnderlayingType Magnitude() const + { + return std::sqrt((X * X) + (Y * Y) + (Z * Z)); + } + bool operator!=(const FVector& Other) const + { + return X != Other.X || Y != Other.Y || Z != Other.Z; + } + FVector operator*(const FVector& Other) const + { + return { X * Other.X, Y * Other.Y, Z * Other.Z }; + } + FVector operator*(float Scalar) const + { + return { X * Scalar, Y * Scalar, Z * Scalar }; + } + FVector operator+(const FVector& Other) const + { + return { X + Other.X, Y + Other.Y, Z + Other.Z }; + } + FVector operator-(const FVector& Other) const + { + return { X - Other.X, Y - Other.Y, Z - Other.Z }; + } + FVector operator/(const FVector& Other) const + { + if (Other.X == 0.0f || Other.Y == 0.0f || Other.Z == 0.0f) + return *this; + + return { X / Other.X, Y / Other.Y, Z / Other.Z }; + } + FVector operator/(float Scalar) const + { + if (Scalar == 0.0f) + return *this; + + return { X / Scalar, Y / Scalar, Z / Scalar }; + } + bool operator==(const FVector& Other) const + { + return X == Other.X && Y == Other.Y && Z == Other.Z; + } + }; + + struct FRotator final + { + public: + float Pitch; + float Yaw; + float Roll; + }; + + struct FQuat final + { + public: + float X; // 0x0000(0x0004)(Edit, BlueprintVisible, ZeroConstructor, SaveGame, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic) + float Y; // 0x0004(0x0004)(Edit, BlueprintVisible, ZeroConstructor, SaveGame, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic) + float Z; // 0x0008(0x0004)(Edit, BlueprintVisible, ZeroConstructor, SaveGame, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic) + float W; // 0x000C(0x0004)(Edit, BlueprintVisible, ZeroConstructor, SaveGame, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic) + }; + + struct FTransform final + { + public: + struct FQuat Rotation; // 0x0000(0x0010)(Edit, BlueprintVisible, SaveGame, IsPlainOldData, NoDestructor, NativeAccessSpecifierPublic) + struct FVector Translation; // 0x0010(0x000C)(Edit, BlueprintVisible, SaveGame, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic) + uint8 Pad_16[0x4]; // 0x001C(0x0004)(Fixing Size After Last Property [ Dumper-7 ]) + struct FVector Scale3D; // 0x0020(0x000C)(Edit, BlueprintVisible, SaveGame, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic) + uint8 Pad_17[0x4]; // 0x002C(0x0004)(Fixing Struct Size After Last Property [ Dumper-7 ]) + }; + + struct FGuid final + { + public: + int32 A; // 0x0000(0x0004)(Edit, ZeroConstructor, SaveGame, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic) + int32 B; // 0x0004(0x0004)(Edit, ZeroConstructor, SaveGame, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic) + int32 C; // 0x0008(0x0004)(Edit, ZeroConstructor, SaveGame, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic) + int32 D; // 0x000C(0x0004)(Edit, ZeroConstructor, SaveGame, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic) + }; + } +} \ No newline at end of file diff --git a/F4Menu/F4Menu.vcxproj b/F4Menu/F4Menu.vcxproj index b5dc34889..7be6ca644 100644 --- a/F4Menu/F4Menu.vcxproj +++ b/F4Menu/F4Menu.vcxproj @@ -149,11 +149,15 @@ + + + + @@ -817,11 +821,15 @@ + + + + @@ -1077,6 +1085,7 @@ + diff --git a/F4Menu/F4Menu.vcxproj.filters b/F4Menu/F4Menu.vcxproj.filters index 588729d16..e85e060a0 100644 --- a/F4Menu/F4Menu.vcxproj.filters +++ b/F4Menu/F4Menu.vcxproj.filters @@ -37,6 +37,9 @@ {e26e9c40-97ed-4b77-ab53-dec94227c35c} + + {68d198a5-d4b1-416f-9e54-86c4dbbb69d9} + @@ -2043,6 +2046,21 @@ ThirdParty\imgui + + ALTF4_F + + + ALTF4_F + + + SDK + + + Engine + + + Engine + @@ -2819,6 +2837,18 @@ ThirdParty\imgui + + ALTF4_F + + + SDK + + + Engine + + + ALTF4_F + diff --git a/F4Menu/Game.cpp b/F4Menu/Game.cpp new file mode 100644 index 000000000..f2d63f822 --- /dev/null +++ b/F4Menu/Game.cpp @@ -0,0 +1,79 @@ +#include "Game.h" +#include "Classes.hpp" +#include "UE4.hpp" +#include "SDK/SDK/Engine_classes.hpp" +#include "SDK/SDK/CoreUObject_classes.hpp" + +namespace Game { + UE4::UObject* GetEngine() { + // Assuming there is a method to get the engine instance + return UE4::UObject::FindObject("EngineName"); + } + + UE4::UObject* GetWorld() { + auto GameViewport = GetChild(GetEngine(), "GameViewport"); + auto World = GetChild(GameViewport, "World"); + return World; + } + + UE4::UObject* GetPlayerController() { + auto OwningGameInstance = GetChild(GetWorld(), "OwningGameInstance"); + std::vector LocalPlayers = GetChildAsTArray(OwningGameInstance, "LocalPlayers"); + auto PlayerController = GetChild(LocalPlayers[0], "PlayerController"); + return PlayerController; + } + + UE4::UObject* GetPlayerState() { + auto PlayerState = GetChild(GetPlayerController(), "PlayerState"); + return PlayerState; + } + + UE4::UObject* GetPawn() { + auto Pawn = GetChild(GetPlayerController(), "Pawn"); + return Pawn; + } + + UE4::UObject* GetGameMode() { + auto AuthorityGameMode = GetChild(GetWorld(), "AuthorityGameMode"); + return AuthorityGameMode; + } + + UE4::UObject* GetGameState() { + auto GameState = GetChild(GetGameMode(), "GameState"); + return GameState; + } + + // Utility function implementations + UE4::UObject* GetChild(UE4::UObject* parent, const std::string& name) { + if (parent) { + // Assuming parent->GetChildren() returns a list of child objects + for (auto& child : parent->GetChildren()) { + if (child->GetName() == name) { + return child; + } + } + } + return nullptr; + } + + template + std::vector GetChildAsTArray(UE4::UObject* parent, const std::string& name) { + std::vector children; + if (parent) { + for (auto& child : parent->GetChildren()) { + if (child->GetName() == name) { + if (auto castedChild = dynamic_cast(child)) { + children.push_back(castedChild); + } + } + } + } + return children; + } + + UE4::UClass* StaticClassImpl(const std::string& className) { + return UE4::UObject::FindClass(className); + } +} + +template std::vector Game::GetChildAsTArray(UE4::UObject* parent, const std::string& name); \ No newline at end of file diff --git a/F4Menu/Game.h b/F4Menu/Game.h new file mode 100644 index 000000000..038fddbae --- /dev/null +++ b/F4Menu/Game.h @@ -0,0 +1,28 @@ +#ifndef GAME_H +#define GAME_H + +#include +#include + +namespace UE4 { + class UObject; + class UClass; +} + +namespace Game { + UE4::UObject* GetEngine(); + UE4::UObject* GetWorld(); + UE4::UObject* GetPlayerController(); + UE4::UObject* GetPlayerState(); + UE4::UObject* GetPawn(); + UE4::UObject* GetGameMode(); + UE4::UObject* GetGameState(); + + // Utility functions + UE4::UObject* GetChild(UE4::UObject* parent, const std::string& name); + template + std::vector GetChildAsTArray(UE4::UObject* parent, const std::string& name); + UE4::UClass* StaticClassImpl(const std::string& className); +} + +#endif // GAME_H \ No newline at end of file diff --git a/F4Menu/GuiManager.cpp b/F4Menu/GuiManager.cpp index 54409aebd..b058004fd 100644 --- a/F4Menu/GuiManager.cpp +++ b/F4Menu/GuiManager.cpp @@ -4,6 +4,7 @@ #include "ThirdParty/imgui/imgui_impl_dx11.h" #include #include +#include "Logic.hpp" extern ID3D11Device* g_pd3dDevice; extern ID3D11DeviceContext* g_pd3dDeviceContext; @@ -18,9 +19,8 @@ namespace { void ShowGui() { ImGui::Begin("Menu"); - if (ImGui::Button("Flying")) { - flyingEnabled = !flyingEnabled; - // Add logic to enable/disable flying + if (ImGui::Checkbox("Flying", &flyingEnabled)) { + Logic::ToggleFlyingMode(flyingEnabled); } ImGui::End(); @@ -75,17 +75,7 @@ namespace GuiManager { // Rendering ImGui::Render(); - g_pd3dDeviceContext->OMSetRenderTargets(1, &g_mainRenderTargetView, nullptr); ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData()); } } - - bool IsGuiVisible() { - return guiVisible; - } - - void SetupGui() { - // Initialize ImGui - InitImGui(); - } } \ No newline at end of file diff --git a/F4Menu/Logic.cpp b/F4Menu/Logic.cpp new file mode 100644 index 000000000..646d31c20 --- /dev/null +++ b/F4Menu/Logic.cpp @@ -0,0 +1,23 @@ +#include "Logic.hpp" +#include "Game.h" +#include "Classes.hpp" // Include to ensure UE4::UObject is defined + +namespace Logic { + void ToggleFlyingMode(bool enableFlying) { + auto PlayerController = Game::GetPlayerController(); + if (PlayerController) { + auto Pawn = Game::GetPawn(); + if (Pawn) { + constexpr int MOVE_Flying = 2; + constexpr int MOVE_Walking = 0; + + if (enableFlying) { + Pawn->SetMovementMode(MOVE_Flying); + } + else { + Pawn->SetMovementMode(MOVE_Walking); + } + } + } + } +} \ No newline at end of file diff --git a/F4Menu/Logic.hpp b/F4Menu/Logic.hpp new file mode 100644 index 000000000..0f3fabedf --- /dev/null +++ b/F4Menu/Logic.hpp @@ -0,0 +1,8 @@ +#ifndef LOGIC_HPP +#define LOGIC_HPP + +namespace Logic { + void ToggleFlyingMode(bool enableFlying); +} + +#endif // LOGIC_HPP \ No newline at end of file diff --git a/F4Menu/UE4.cpp b/F4Menu/UE4.cpp new file mode 100644 index 000000000..84fe952ce --- /dev/null +++ b/F4Menu/UE4.cpp @@ -0,0 +1,47 @@ +#include "UE4.hpp" + +#include "Classes.hpp" + +namespace UE4 +{ + class UClass* BasicFilesImpleUtils::FindClassByName(const std::string& Name) + { + return UObject::FindClassFast(Name); + } + + class UClass* BasicFilesImpleUtils::FindClassByFullName(const std::string& Name) + { + return UObject::FindClass(Name); + } + + std::string BasicFilesImpleUtils::GetObjectName(class UClass* Class) + { + return Class->GetName(); + } + + int32 BasicFilesImpleUtils::GetObjectIndex(class UClass* Class) + { + return Class->Index; + } + + class UObject* BasicFilesImpleUtils::GetObjectByIndex(int32 Index) + { + return UObject::GObjects->GetByIndex(Index); + } + + UFunction* BasicFilesImpleUtils::FindFunctionByFName(const FName* Name) + { + for (int i = 0; i < UObject::GObjects->Num(); ++i) + { + UObject* Object = UObject::GObjects->GetByIndex(i); + + if (!Object) + continue; + + if (Object->Name == *Name) + return static_cast(Object); + } + + return nullptr; + } +} \ No newline at end of file diff --git a/F4Menu/UE4.hpp b/F4Menu/UE4.hpp new file mode 100644 index 000000000..a64dd98c0 --- /dev/null +++ b/F4Menu/UE4.hpp @@ -0,0 +1,875 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include "Containers.h" + +namespace UE4 +{ + using namespace Containers; + + + namespace Offsets + { + static uintptr_t GObjects = 0; + static uintptr_t AppendString = 0; + static uintptr_t ProcessEvent = 0; + static uintptr_t ProcessEventIdx = 0; + static uintptr_t GWorld = 0; + } + + namespace InSDKUtils + { + inline uintptr_t GetImageBase() + { + return reinterpret_cast(GetModuleHandle(0)); + } + + template + inline FuncType GetVirtualFunction(const void* ObjectInstance, int32 Index) + { + void** VTable = *reinterpret_cast(const_cast(ObjectInstance)); + + return reinterpret_cast(VTable[Index]); + } + + template + requires std::invocable + inline auto CallGameFunction(FuncType Function, ParamTypes&&... Args) + { + return Function(std::forward(Args)...); + } + } + + + template + struct StringLiteral + { + char Chars[Len]; + + consteval StringLiteral(const char(&String)[Len]) + { + std::copy_n(String, Len, Chars); + } + + operator std::string() const + { + return static_cast(Chars); + } + }; + class UClass; + class UObject; + class UFunction; + + struct FName; + + namespace BasicFilesImpleUtils + { + UClass* FindClassByName(const std::string& Name); + UClass* FindClassByFullName(const std::string& Name); + + std::string GetObjectName(class UClass* Class); + int32 GetObjectIndex(class UClass* Class); + + UObject* GetObjectByIndex(int32 Index); + + UFunction* FindFunctionByFName(const FName* Name); + } + + template + class UClass* StaticClassImpl() + { + static class UClass* Clss = nullptr; + + if (Clss == nullptr) + { + if constexpr (bIsFullName) { + Clss = BasicFilesImpleUtils::FindClassByFullName(Name); + } + else { + Clss = BasicFilesImpleUtils::FindClassByName(Name); + } + } + + return Clss; + } + + template + class UClass* StaticBPGeneratedClassImpl() + { + static auto SetClassIndex = [](UClass* Class, int32& Index) -> UClass* + { + if (Class) + Index = BasicFilesImpleUtils::GetObjectIndex(Class); + + return Class; + }; + + static int32 ClassIdx = 0x0; + if constexpr (bIsFullName) + { + if (ClassIdx == 0x0) + return SetClassIndex(BasicFilesImpleUtils::FindClassByFullName(Name), ClassIdx); + + UClass* ClassObj = static_cast(BasicFilesImpleUtils::GetObjectByIndex(ClassIdx)); + if (!ClassObj || BasicFilesImpleUtils::GetObjectName(ClassObj) != static_cast(Name)) + return SetClassIndex(BasicFilesImpleUtils::FindClassByFullName(Name), ClassIdx); + + return ClassObj; + } + else + { + if (ClassIdx == 0x0) + return SetClassIndex(BasicFilesImpleUtils::FindClassByName(Name), ClassIdx); + + UClass* ClassObj = static_cast(BasicFilesImpleUtils::GetObjectByIndex(ClassIdx)); + if (!ClassObj || BasicFilesImpleUtils::GetObjectName(ClassObj) != static_cast(Name)) + return SetClassIndex(BasicFilesImpleUtils::FindClassByName(Name), ClassIdx); + + return ClassObj; + } + } + + template + ClassType* GetDefaultObjImpl() + { + return static_cast(ClassType::StaticClass()->DefaultObject); + } + struct FUObjectItem final + { + public: + class UObject* Object; + uint8 Pad_0[0x10]; + }; + static_assert(alignof(FUObjectItem) == 0x000008, "Wrong alignment on FUObjectItem"); + static_assert(sizeof(FUObjectItem) == 0x000018, "Wrong size on FUObjectItem"); + static_assert(offsetof(FUObjectItem, Object) == 0x000000, "Member 'FUObjectItem::Object' has a wrong offset!"); + + class TUObjectArrayNew + { + public: + enum + { + ElementsPerChunk = 0x10000, + }; + + public: + static inline auto DecryptPtr = [](void* ObjPtr) -> uint8* + { + return reinterpret_cast(ObjPtr); + }; + + FUObjectItem** Objects; + uint8 Pad_0[0x08]; + int32 MaxElements; + int32 NumElements; + int32 MaxChunks; + int32 NumChunks; + + + public: + // Call InitGObjects() before using these functions + inline int32 Num() const + { + return NumElements; + } + + inline FUObjectItem** GetDecrytedObjPtr() const + { + return reinterpret_cast(DecryptPtr(Objects)); + } + + inline class UObject* GetByIndex(const int32 Index) const + { + if (Index < 0 || Index > NumElements) + return nullptr; + + const int32 ChunkIndex = Index / ElementsPerChunk; + const int32 InChunkIdx = Index % ElementsPerChunk; + + return GetDecrytedObjPtr()[ChunkIndex][InChunkIdx].Object; + } + }; + + class TUObjectArray + { + private: + static inline auto DecryptPtr = [](void* ObjPtr) -> uint8* + { + return reinterpret_cast(ObjPtr); + }; + + public: + FUObjectItem* Objects; + int32 MaxElements; + int32 NumElements; + + public: + inline int Num() const + { + return NumElements; + } + + inline FUObjectItem* GetDecrytedObjPtr() const + { + return reinterpret_cast(DecryptPtr(Objects)); + } + + inline class UObject* GetByIndex(const int32 Index) const + { + if (Index < 0 || Index > NumElements) + return nullptr; + + return GetDecrytedObjPtr()[Index].Object; + } + }; + + class TUObjectArrayWrapper + { + private: + friend class UObject; + + public: + void* GObjectsAddress = nullptr; + + private: + TUObjectArrayWrapper() = default; + + public: + TUObjectArrayWrapper(TUObjectArrayWrapper&&) = delete; + TUObjectArrayWrapper(const TUObjectArrayWrapper&) = delete; + + TUObjectArrayWrapper& operator=(TUObjectArrayWrapper&&) = delete; + TUObjectArrayWrapper& operator=(const TUObjectArrayWrapper&) = delete; + + public: + inline void InitGObjects() + { + + } + + public: + inline class TUObjectArray* operator->() + { + if (!GObjectsAddress) [[unlikely]] + InitGObjects(); + + return reinterpret_cast(GObjectsAddress); + } + + inline operator const void* () + { + if (!GObjectsAddress) [[unlikely]] + InitGObjects(); + + return GObjectsAddress; + } + + inline class TUObjectArray* GetTypedPtr() + { + if (!GObjectsAddress) [[unlikely]] + InitGObjects(); + + return reinterpret_cast(GObjectsAddress); + } + }; + class FName final + { + public: + static inline void* AppendString = nullptr; + + int32 ComparisonIndex; + int32 Number; + + public: + static void InitInternal() + { + AppendString = reinterpret_cast((uintptr_t)GetModuleHandle(0) + Offsets::AppendString); + } + + int32 GetDisplayIndex() const + { + return ComparisonIndex; + } + + std::string GetRawString() const + { + thread_local FAllocatedString TempString(1024); + + if (!AppendString) + InitInternal(); + + InSDKUtils::CallGameFunction(reinterpret_cast(AppendString), this, TempString); + + std::string OutputString = TempString.ToString(); + TempString.Clear(); + + return OutputString; + } + + std::string ToString() const + { + std::string OutputString = GetRawString(); + + size_t pos = OutputString.rfind('/'); + + if (pos == std::string::npos) + return OutputString; + + return OutputString.substr(pos + 1); + } + + bool operator==(const FName& Other) const + { + return ComparisonIndex == Other.ComparisonIndex && Number == Other.Number; + } + bool operator!=(const FName& Other) const + { + return ComparisonIndex != Other.ComparisonIndex || Number != Other.Number; + } + }; + + template + class TSubclassOf + { + class UClass* ClassPtr; + + public: + TSubclassOf() = default; + + inline TSubclassOf(UClass* Class) + : ClassPtr(Class) + { + } + + inline UClass* Get() + { + return ClassPtr; + } + + inline operator UClass* () const + { + return ClassPtr; + } + + template, bool>::type> + inline operator TSubclassOf() const + { + return ClassPtr; + } + + inline UClass* operator->() + { + return ClassPtr; + } + + inline TSubclassOf& operator=(UClass* Class) + { + ClassPtr = Class; + + return *this; + } + + inline bool operator==(const TSubclassOf& Other) const + { + return ClassPtr == Other.ClassPtr; + } + + inline bool operator!=(const TSubclassOf& Other) const + { + return ClassPtr != Other.ClassPtr; + } + + inline bool operator==(UClass* Other) const + { + return ClassPtr == Other; + } + + inline bool operator!=(UClass* Other) const + { + return ClassPtr != Other; + } + }; + class FTextData final + { + public: + uint8 Pad_1[0x28]; + class FString TextSource; + }; + static_assert(alignof(FTextData) == 0x000008, "Wrong alignment on FTextData"); + static_assert(sizeof(FTextData) == 0x000038, "Wrong size on FTextData"); + static_assert(offsetof(FTextData, TextSource) == 0x000028, "Member 'FTextData::TextSource' has a wrong offset!"); + class FText final + { + public: + class FTextData* TextData; + uint8 Pad_2[0x10]; + + public: + const class FString& GetStringRef() const + { + return TextData->TextSource; + } + std::string ToString() const + { + return TextData->TextSource.ToString(); + } + }; + static_assert(alignof(FText) == 0x000008, "Wrong alignment on FText"); + static_assert(sizeof(FText) == 0x000018, "Wrong size on FText"); + static_assert(offsetof(FText, TextData) == 0x000000, "Member 'FText::TextData' has a wrong offset!"); + class FWeakObjectPtr + { + public: + int32 ObjectIndex; + int32 ObjectSerialNumber; + + public: + class UObject* Get() const; + class UObject* operator->() const; + bool operator==(const FWeakObjectPtr& Other) const; + bool operator!=(const FWeakObjectPtr& Other) const; + bool operator==(const class UObject* Other) const; + bool operator!=(const class UObject* Other) const; + }; + static_assert(alignof(FWeakObjectPtr) == 0x000004, "Wrong alignment on FWeakObjectPtr"); + static_assert(sizeof(FWeakObjectPtr) == 0x000008, "Wrong size on FWeakObjectPtr"); + static_assert(offsetof(FWeakObjectPtr, ObjectIndex) == 0x000000, "Member 'FWeakObjectPtr::ObjectIndex' has a wrong offset!"); + static_assert(offsetof(FWeakObjectPtr, ObjectSerialNumber) == 0x000004, "Member 'FWeakObjectPtr::ObjectSerialNumber' has a wrong offset!"); + + template + class TWeakObjectPtr : public FWeakObjectPtr + { + public: + UEType* Get() const + { + return static_cast(FWeakObjectPtr::Get()); + } + + UEType* operator->() const + { + return static_cast(FWeakObjectPtr::Get()); + } + }; + class FUniqueObjectGuid final + { + public: + uint32 A; + uint32 B; + uint32 C; + uint32 D; + }; + static_assert(alignof(FUniqueObjectGuid) == 0x000004, "Wrong alignment on FUniqueObjectGuid"); + static_assert(sizeof(FUniqueObjectGuid) == 0x000010, "Wrong size on FUniqueObjectGuid"); + static_assert(offsetof(FUniqueObjectGuid, A) == 0x000000, "Member 'FUniqueObjectGuid::A' has a wrong offset!"); + static_assert(offsetof(FUniqueObjectGuid, B) == 0x000004, "Member 'FUniqueObjectGuid::B' has a wrong offset!"); + static_assert(offsetof(FUniqueObjectGuid, C) == 0x000008, "Member 'FUniqueObjectGuid::C' has a wrong offset!"); + static_assert(offsetof(FUniqueObjectGuid, D) == 0x00000C, "Member 'FUniqueObjectGuid::D' has a wrong offset!"); + template + class TPersistentObjectPtr + { + public: + FWeakObjectPtr WeakPtr; + int32 TagAtLastTest; + TObjectID ObjectID; + + public: + class UObject* Get() const + { + return WeakPtr.Get(); + } + class UObject* operator->() const + { + return WeakPtr.Get(); + } + }; + + template + class TLazyObjectPtr : public TPersistentObjectPtr + { + public: + UEType* Get() const + { + return static_cast(TPersistentObjectPtr::Get()); + } + UEType* operator->() const + { + return static_cast(TPersistentObjectPtr::Get()); + } + }; + + namespace FakeSoftObjectPtr + { + struct FSoftObjectPath + { + public: + class FName AssetPathName; + class FString SubPathString; + }; + static_assert(alignof(FSoftObjectPath) == 0x000008, "Wrong alignment on FSoftObjectPath"); + static_assert(sizeof(FSoftObjectPath) == 0x000018, "Wrong size on FSoftObjectPath"); + static_assert(offsetof(FSoftObjectPath, AssetPathName) == 0x000000, "Member 'FSoftObjectPath::AssetPathName' has a wrong offset!"); + static_assert(offsetof(FSoftObjectPath, SubPathString) == 0x000008, "Member 'FSoftObjectPath::SubPathString' has a wrong offset!"); + + } + + class FSoftObjectPtr : public TPersistentObjectPtr + { + }; + + template + class TSoftObjectPtr : public FSoftObjectPtr + { + public: + UEType* Get() const + { + return static_cast(TPersistentObjectPtr::Get()); + } + UEType* operator->() const + { + return static_cast(TPersistentObjectPtr::Get()); + } + }; + + template + class TSoftClassPtr : public FSoftObjectPtr + { + public: + UEType* Get() const + { + return static_cast(TPersistentObjectPtr::Get()); + } + UEType* operator->() const + { + return static_cast(TPersistentObjectPtr::Get()); + } + }; + class FScriptInterface + { + public: + UObject* ObjectPointer; + void* InterfacePointer; + + public: + class UObject* GetObjectRef() const + { + return ObjectPointer; + } + + void* GetInterfaceRef() const + { + return InterfacePointer; + } + + }; + static_assert(alignof(FScriptInterface) == 0x000008, "Wrong alignment on FScriptInterface"); + static_assert(sizeof(FScriptInterface) == 0x000010, "Wrong size on FScriptInterface"); + static_assert(offsetof(FScriptInterface, ObjectPointer) == 0x000000, "Member 'FScriptInterface::ObjectPointer' has a wrong offset!"); + static_assert(offsetof(FScriptInterface, InterfacePointer) == 0x000008, "Member 'FScriptInterface::InterfacePointer' has a wrong offset!"); + template + class TScriptInterface final : public FScriptInterface + { + }; + template + class TDelegate + { + public: + struct InvalidUseOfTDelegate TemplateParamIsNotAFunctionSignature; + }; + template + class TDelegate + { + public: + FWeakObjectPtr Object; + FName FunctionName; + }; + +#define UE_ENUM_OPERATORS(EEnumClass) \ + \ +inline constexpr EEnumClass operator|(EEnumClass Left, EEnumClass Right) \ +{ \ + return (EEnumClass)((std::underlying_type::type)(Left) | (std::underlying_type::type)(Right)); \ +} \ + \ +inline constexpr EEnumClass& operator|=(EEnumClass& Left, EEnumClass Right) \ +{ \ + return (EEnumClass&)((std::underlying_type::type&)(Left) |= (std::underlying_type::type)(Right)); \ +} \ + \ +inline bool operator&(EEnumClass Left, EEnumClass Right) \ +{ \ + return (((std::underlying_type::type)(Left) & (std::underlying_type::type)(Right)) == (std::underlying_type::type)(Right)); \ +} + + enum class EObjectFlags : int32 + { + NoFlags = 0x00000000, + + Public = 0x00000001, + Standalone = 0x00000002, + MarkAsNative = 0x00000004, + Transactional = 0x00000008, + ClassDefaultObject = 0x00000010, + ArchetypeObject = 0x00000020, + Transient = 0x00000040, + + MarkAsRootSet = 0x00000080, + TagGarbageTemp = 0x00000100, + + NeedInitialization = 0x00000200, + NeedLoad = 0x00000400, + KeepForCooker = 0x00000800, + NeedPostLoad = 0x00001000, + NeedPostLoadSubobjects = 0x00002000, + NewerVersionExists = 0x00004000, + BeginDestroyed = 0x00008000, + FinishDestroyed = 0x00010000, + + BeingRegenerated = 0x00020000, + DefaultSubObject = 0x00040000, + WasLoaded = 0x00080000, + TextExportTransient = 0x00100000, + LoadCompleted = 0x00200000, + InheritableComponentTemplate = 0x00400000, + DuplicateTransient = 0x00800000, + StrongRefOnFrame = 0x01000000, + NonPIEDuplicateTransient = 0x02000000, + Dynamic = 0x04000000, + WillBeLoaded = 0x08000000, + }; + + enum class EFunctionFlags : uint32 + { + None = 0x00000000, + + Final = 0x00000001, + RequiredAPI = 0x00000002, + BlueprintAuthorityOnly = 0x00000004, + BlueprintCosmetic = 0x00000008, + Net = 0x00000040, + NetReliable = 0x00000080, + NetRequest = 0x00000100, + Exec = 0x00000200, + Native = 0x00000400, + Event = 0x00000800, + NetResponse = 0x00001000, + Static = 0x00002000, + NetMulticast = 0x00004000, + UbergraphFunction = 0x00008000, + MulticastDelegate = 0x00010000, + Public = 0x00020000, + Private = 0x00040000, + Protected = 0x00080000, + Delegate = 0x00100000, + NetServer = 0x00200000, + HasOutParms = 0x00400000, + HasDefaults = 0x00800000, + NetClient = 0x01000000, + DLLImport = 0x02000000, + BlueprintCallable = 0x04000000, + BlueprintEvent = 0x08000000, + BlueprintPure = 0x10000000, + EditorOnly = 0x20000000, + Const = 0x40000000, + NetValidate = 0x80000000, + + AllFlags = 0xFFFFFFFF, + }; + + enum class EClassFlags : int32 + { + CLASS_None = 0x00000000u, + Abstract = 0x00000001u, + DefaultConfig = 0x00000002u, + Config = 0x00000004u, + Transient = 0x00000008u, + Parsed = 0x00000010u, + MatchedSerializers = 0x00000020u, + ProjectUserConfig = 0x00000040u, + Native = 0x00000080u, + NoExport = 0x00000100u, + NotPlaceable = 0x00000200u, + PerObjectConfig = 0x00000400u, + ReplicationDataIsSetUp = 0x00000800u, + EditInlineNew = 0x00001000u, + CollapseCategories = 0x00002000u, + Interface = 0x00004000u, + CustomConstructor = 0x00008000u, + Const = 0x00010000u, + LayoutChanging = 0x00020000u, + CompiledFromBlueprint = 0x00040000u, + MinimalAPI = 0x00080000u, + RequiredAPI = 0x00100000u, + DefaultToInstanced = 0x00200000u, + TokenStreamAssembled = 0x00400000u, + HasInstancedReference = 0x00800000u, + Hidden = 0x01000000u, + Deprecated = 0x02000000u, + HideDropDown = 0x04000000u, + GlobalUserConfig = 0x08000000u, + Intrinsic = 0x10000000u, + Constructed = 0x20000000u, + ConfigDoNotCheckDefaults = 0x40000000u, + NewerVersionExists = 0x80000000u, + }; + + enum class EClassCastFlags : uint64 + { + None = 0x0000000000000000, + + Field = 0x0000000000000001, + Int8Property = 0x0000000000000002, + Enum = 0x0000000000000004, + Struct = 0x0000000000000008, + ScriptStruct = 0x0000000000000010, + Class = 0x0000000000000020, + ByteProperty = 0x0000000000000040, + IntProperty = 0x0000000000000080, + FloatProperty = 0x0000000000000100, + UInt64Property = 0x0000000000000200, + ClassProperty = 0x0000000000000400, + UInt32Property = 0x0000000000000800, + InterfaceProperty = 0x0000000000001000, + NameProperty = 0x0000000000002000, + StrProperty = 0x0000000000004000, + Property = 0x0000000000008000, + ObjectProperty = 0x0000000000010000, + BoolProperty = 0x0000000000020000, + UInt16Property = 0x0000000000040000, + Function = 0x0000000000080000, + StructProperty = 0x0000000000100000, + ArrayProperty = 0x0000000000200000, + Int64Property = 0x0000000000400000, + DelegateProperty = 0x0000000000800000, + NumericProperty = 0x0000000001000000, + MulticastDelegateProperty = 0x0000000002000000, + ObjectPropertyBase = 0x0000000004000000, + WeakObjectProperty = 0x0000000008000000, + LazyObjectProperty = 0x0000000010000000, + SoftObjectProperty = 0x0000000020000000, + TextProperty = 0x0000000040000000, + Int16Property = 0x0000000080000000, + DoubleProperty = 0x0000000100000000, + SoftClassProperty = 0x0000000200000000, + Package = 0x0000000400000000, + Level = 0x0000000800000000, + Actor = 0x0000001000000000, + PlayerController = 0x0000002000000000, + Pawn = 0x0000004000000000, + SceneComponent = 0x0000008000000000, + PrimitiveComponent = 0x0000010000000000, + SkinnedMeshComponent = 0x0000020000000000, + SkeletalMeshComponent = 0x0000040000000000, + Blueprint = 0x0000080000000000, + DelegateFunction = 0x0000100000000000, + StaticMeshComponent = 0x0000200000000000, + MapProperty = 0x0000400000000000, + SetProperty = 0x0000800000000000, + EnumProperty = 0x0001000000000000, + USparseDelegateFunction = 0x0002000000000000, + FMulticastInlineDelegateProperty = 0x0004000000000000, + FMulticastSparseDelegateProperty = 0x0008000000000000, + FFieldPathProperty = 0x0010000000000000, + FLargeWorldCoordinatesRealProperty = 0x0080000000000000, + FOptionalProperty = 0x0100000000000000, + FVValueProperty = 0x0200000000000000, + UVerseVMClass = 0x0400000000000000, + FVRestValueProperty = 0x0800000000000000, + }; + + enum class EPropertyFlags : uint64 + { + None = 0x0000000000000000, + + Edit = 0x0000000000000001, + ConstParm = 0x0000000000000002, + BlueprintVisible = 0x0000000000000004, + ExportObject = 0x0000000000000008, + BlueprintReadOnly = 0x0000000000000010, + Net = 0x0000000000000020, + EditFixedSize = 0x0000000000000040, + Parm = 0x0000000000000080, + OutParm = 0x0000000000000100, + ZeroConstructor = 0x0000000000000200, + ReturnParm = 0x0000000000000400, + DisableEditOnTemplate = 0x0000000000000800, + + Transient = 0x0000000000002000, + Config = 0x0000000000004000, + + DisableEditOnInstance = 0x0000000000010000, + EditConst = 0x0000000000020000, + GlobalConfig = 0x0000000000040000, + InstancedReference = 0x0000000000080000, + + DuplicateTransient = 0x0000000000200000, + SubobjectReference = 0x0000000000400000, + + SaveGame = 0x0000000001000000, + NoClear = 0x0000000002000000, + + ReferenceParm = 0x0000000008000000, + BlueprintAssignable = 0x0000000010000000, + Deprecated = 0x0000000020000000, + IsPlainOldData = 0x0000000040000000, + RepSkip = 0x0000000080000000, + RepNotify = 0x0000000100000000, + Interp = 0x0000000200000000, + NonTransactional = 0x0000000400000000, + EditorOnly = 0x0000000800000000, + NoDestructor = 0x0000001000000000, + + AutoWeak = 0x0000004000000000, + ContainsInstancedReference = 0x0000008000000000, + AssetRegistrySearchable = 0x0000010000000000, + SimpleDisplay = 0x0000020000000000, + AdvancedDisplay = 0x0000040000000000, + Protected = 0x0000080000000000, + BlueprintCallable = 0x0000100000000000, + BlueprintAuthorityOnly = 0x0000200000000000, + TextExportTransient = 0x0000400000000000, + NonPIEDuplicateTransient = 0x0000800000000000, + ExposeOnSpawn = 0x0001000000000000, + PersistentInstance = 0x0002000000000000, + UObjectWrapper = 0x0004000000000000, + HasGetValueTypeHash = 0x0008000000000000, + NativeAccessSpecifierPublic = 0x0010000000000000, + NativeAccessSpecifierProtected = 0x0020000000000000, + NativeAccessSpecifierPrivate = 0x0040000000000000, + SkipSerialization = 0x0080000000000000, + }; + + UE_ENUM_OPERATORS(EObjectFlags); + UE_ENUM_OPERATORS(EFunctionFlags); + UE_ENUM_OPERATORS(EClassFlags); + UE_ENUM_OPERATORS(EClassCastFlags); + UE_ENUM_OPERATORS(EPropertyFlags); + + namespace CyclicDependencyFixupImpl + { + template + struct alignas(Align) TCylicStructFixup + { + private: + uint8 Pad[Size]; + + public: + UnderlayingStructType& GetTyped() { return reinterpret_cast(*this); } + const UnderlayingStructType& GetTyped() const { return reinterpret_cast(*this); } + }; + template + struct alignas(Align) TCyclicClassFixup : public BaseClassType + { + private: + uint8 Pad[Size]; + + public: + UnderlayingClassType* GetTyped() { return reinterpret_cast(this); } + const UnderlayingClassType* GetTyped() const { return reinterpret_cast(this); } + }; + } +} \ No newline at end of file diff --git a/F4Menu/framework.h b/F4Menu/framework.h index 54b83e94f..9f4a88b37 100644 --- a/F4Menu/framework.h +++ b/F4Menu/framework.h @@ -3,3 +3,6 @@ #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers // Windows Header Files #include +#include +#include +#include