#pragma once #include "reboot.h" #include static inline FName* GetNamePrivateOfProperty(void* Property) { FName* NamePrivate = nullptr; if (Engine_Version >= 425) NamePrivate = (FName*)(__int64(Property) + 0x28); else NamePrivate = &((UField*)Property)->NamePrivate; return NamePrivate; }; static inline bool IsPropertyA(void* Property, UClass* Class) { if (Engine_Version < 425) { if (((UField*)Property)->IsA(Class)) return true; } else { // TODO } return false; } namespace ObjectViewer { static inline void DumpContentsToFile(UObject* Object, const std::string& FileName, bool bExcludeUnhandled = false) { if (!Object/*->IsValidLowLevel()*/) { LOG_ERROR(LogObjectViewer, "Invalid object passed into DumpContentsToFile!"); return; } static auto ClassClass = FindObject(L"/Script/CoreUObject.Class"); if (Object->IsA(ClassClass)) { LOG_ERROR(LogObjectViewer, "Object passed into DumpContentsToFile was a class!"); return; } static auto BytePropertyClass = FindObject(L"/Script/CoreUObject.ByteProperty"); static auto ObjectPropertyClass = FindObject(L"/Script/CoreUObject.ObjectProperty"); static auto ClassPropertyClass = FindObject(L"/Script/CoreUObject.ClassProperty"); static auto DoublePropertyClass = FindObject(L"/Script/CoreUObject.DoubleProperty"); static auto FloatPropertyClass = FindObject(L"/Script/CoreUObject.FloatProperty"); static auto Int8PropertyClass = FindObject(L"/Script/CoreUObject.Int8Property"); static auto EnumPropertyClass = FindObject(L"/Script/CoreUObject.EnumProperty"); static auto ArrayPropertyClass = FindObject(L"/Script/CoreUObject.ArrayProperty"); static auto Int64PropertyClass = FindObject(L"/Script/CoreUObject.Int64Property"); static auto UInt16PropertyClass = FindObject(L"/Script/CoreUObject.UInt16Property"); static auto BoolPropertyClass = FindObject(L"/Script/CoreUObject.BoolProperty"); static auto NamePropertyClass = FindObject(L"/Script/CoreUObject.NameProperty"); static auto UInt32PropertyClass = FindObject(L"/Script/CoreUObject.UInt32Property"); static auto FunctionClass = FindObject(L"/Script/CoreUObject.Function"); static auto IntPropertyClass = FindObject(L"/Script/CoreUObject.IntProperty"); static auto UInt64PropertyClass = FindObject(L"/Script/CoreUObject.UInt64Property"); static auto StrPropertyClass = FindObject(L"/Script/CoreUObject.StrProperty"); static auto SoftObjectPropertyClass = FindObject(L"/Script/CoreUObject.SoftObjectProperty"); std::ofstream Stream(FileName); if (!Stream.is_open()) { LOG_ERROR(LogObjectViewer, "Failed to open file {}!", FileName); return; } for (auto CurrentClass = Object->ClassPrivate; CurrentClass; CurrentClass = CurrentClass->GetSuperStruct()) { void* Property = *(void**)(__int64(CurrentClass) + Offsets::Children); while (Property) { std::string PropertyName = GetNamePrivateOfProperty(Property)->ToString(); int Offset = *(int*)(__int64(Property) + Offsets::Offset_Internal); if (Offsets::PropertyClass) { if (IsPropertyA(Property, ObjectPropertyClass)) { auto PropertyClass = *(UClass**)(__int64(Property) + Offsets::PropertyClass); if (PropertyClass->IsValidLowLevel()) Stream << std::format("{} Object: {}\n", PropertyName, PropertyClass->GetPathName()); } /* else if (IsPropertyA(Property, SoftObjectPropertyClass)) { auto PropertyClass = *(UClass**)(__int64(Property) + Offsets::PropertyClass); if (PropertyClass->IsValidLowLevel()) { auto SoftObjectPtr = *(TSoftObjectPtr*)(__int64(Object) + Offset); auto SoftObjectPtrObject = SoftObjectPtr.Get(PropertyClass); Stream << std::format("{} SoftObjectPtr (type: {}): {}\n", PropertyName, PropertyClass->GetName(), SoftObjectPtrObject ? SoftObjectPtrObject->GetPathName() : "BadRead"); } } */ } if (IsPropertyA(Property, BytePropertyClass)) { Stream << std::format("{} Byte: {}\n", PropertyName, *(uint8*)(__int64(Object) + Offset)); } else if (IsPropertyA(Property, DoublePropertyClass)) { Stream << std::format("{} Double: {}\n", PropertyName, *(double*)(__int64(Object) + Offset)); } else if (IsPropertyA(Property, UInt16PropertyClass)) { Stream << std::format("{} UInt16: {}\n", PropertyName, *(uint16*)(__int64(Object) + Offset)); } else if (IsPropertyA(Property, Int8PropertyClass)) { Stream << std::format("{} Int8: {}\n", PropertyName, *(int8*)(__int64(Object) + Offset)); } else if (IsPropertyA(Property, NamePropertyClass)) { Stream << std::format("{} Name: {}\n", PropertyName, (*(FName*)(__int64(Object) + Offset)).ToString()); } else if (IsPropertyA(Property, StrPropertyClass)) { Stream << std::format("{} String: {}\n", PropertyName, (*(FString*)(__int64(Object) + Offset)).ToString()); } else if (IsPropertyA(Property, FloatPropertyClass)) { Stream << std::format("{} Float: {}\n", PropertyName, *(float*)(__int64(Object) + Offset)); } else if (IsPropertyA(Property, BoolPropertyClass)) { auto FieldMask = GetFieldMask(Property); Stream << std::format("{} Bool: {}\n", PropertyName, ReadBitfield((PlaceholderBitfield*)(__int64(Object) + Offset), FieldMask)); } else if (IsPropertyA(Property, IntPropertyClass)) { Stream << std::format("{} Int32: {}\n", PropertyName, *(int*)(__int64(Object) + Offset)); } else if (IsPropertyA(Property, UInt32PropertyClass)) { Stream << std::format("{} UInt32: {}\n", PropertyName, *(uint32*)(__int64(Object) + Offset)); } else if (IsPropertyA(Property, UInt64PropertyClass)) { Stream << std::format("{} UInt64: {}\n", PropertyName, *(uint64*)(__int64(Object) + Offset)); } else if (IsPropertyA(Property, Int64PropertyClass)) { Stream << std::format("{} Int64: {}\n", PropertyName, *(int64*)(__int64(Object) + Offset)); } else if (IsPropertyA(Property, ArrayPropertyClass)) { Stream << std::format("{} Array\n", PropertyName); } else if (IsPropertyA(Property, EnumPropertyClass)) { using UNumericProperty = UObject; auto EnumValueIg = *(uint8*)(__int64(Property) + Offset); auto UnderlyingType = *(UNumericProperty**)(__int64(Property) + Offsets::UnderlyingType); // Stream << std::format("{} Enum: {}\n", PropertyName, (int)EnumValueIg); Stream << std::format("{} Enum\n", PropertyName); } else if (IsPropertyA(Property, FunctionClass)) { } else if (!bExcludeUnhandled) { // Stream << std::format("{}: {}\n", PropertyName, "UNHANDLED"); Stream << std::format("{}: {} {}\n", PropertyName, "UNHANDLED", ""/*, ((UObject*)Property)->GetName()*/); } Property = Engine_Version >= 425 ? *(void**)(__int64(Property) + 0x20) : ((UField*)Property)->Next; } } return; } static inline void DumpContentsToFile(const std::string& ObjectName, const std::string& FileName, bool bExcludeUnhandled = false) { return DumpContentsToFile(FindObject(ObjectName), FileName, bExcludeUnhandled); } }