#include "objectviewer.h" void ObjectViewer::DumpContentsToFile(UObject* Object, const std::string& FileName, bool bExcludeUnhandled) { 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 (!FileName.empty() && !Stream.is_open()) { LOG_ERROR(LogObjectViewer, "Failed to open file {}!", FileName); return; } auto log = [&](const std::string& str) { if (FileName.empty()) { LOG_INFO(LogObjectViewer, "{}", str); } else { Stream << str; } }; for (auto CurrentClass = Object->ClassPrivate; CurrentClass; CurrentClass = (UClass*)CurrentClass->GetSuperStruct()) { void* Property = *(void**)(__int64(CurrentClass) + Offsets::Children); while (Property) { std::string PropertyName = GetFNameOfProp(Property)->ToString(); int Offset = *(int*)(__int64(Property) + Offsets::Offset_Internal); // log(std::format("Handling prop {}\n", PropertyName)); if (Offsets::PropertyClass) { if (IsPropertyA(Property, ObjectPropertyClass)) { auto PropertyClass = *(UClass**)(__int64(Property) + Offsets::PropertyClass); if (PropertyClass->IsValidLowLevel()) log(std::format("{} Object: {}\n", PropertyName, PropertyClass->GetFullName())); } /* 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); log(std::format("{} SoftObjectPtr (type: {}): {}\n", PropertyName, PropertyClass->GetName(), SoftObjectPtrObject ? SoftObjectPtrObject->GetPathName() : "BadRead")); } } */ } if (IsPropertyA(Property, BytePropertyClass)) { log(std::format("uint8 {} = {}\n", PropertyName, *(uint8*)(__int64(Object) + Offset))); } else if (IsPropertyA(Property, DoublePropertyClass)) { log(std::format("double {} = {}\n", PropertyName, *(double*)(__int64(Object) + Offset))); } else if (IsPropertyA(Property, UInt16PropertyClass)) { log(std::format("uint16 {} = {}\n", PropertyName, *(uint16*)(__int64(Object) + Offset))); } else if (IsPropertyA(Property, Int8PropertyClass)) { log(std::format("int8 {} = {}\n", PropertyName, *(int8*)(__int64(Object) + Offset))); } else if (IsPropertyA(Property, NamePropertyClass)) { log(std::format("FName {} = {}\n", PropertyName, (*(FName*)(__int64(Object) + Offset)).ToString())); } else if (IsPropertyA(Property, StrPropertyClass)) { auto string = (FString*)(__int64(Object) + Offset); log(std::format("FString {} = {}\n", PropertyName, string->Data.Data ? string->ToString() : "")); } else if (IsPropertyA(Property, FloatPropertyClass)) { log(std::format("float {} = {}\n", PropertyName, *(float*)(__int64(Object) + Offset))); } else if (IsPropertyA(Property, BoolPropertyClass)) { auto FieldMask = GetFieldMask(Property); log(std::format("bool {} = {}\n", PropertyName, ReadBitfield((PlaceholderBitfield*)(__int64(Object) + Offset), FieldMask))); } else if (IsPropertyA(Property, IntPropertyClass)) { log(std::format("int32 {} = {}\n", PropertyName, *(int*)(__int64(Object) + Offset))); } else if (IsPropertyA(Property, UInt32PropertyClass)) { log(std::format("uint32 {} = {}\n", PropertyName, *(uint32*)(__int64(Object) + Offset))); } else if (IsPropertyA(Property, UInt64PropertyClass)) { log(std::format("uint64 {} = {}\n", PropertyName, *(uint64*)(__int64(Object) + Offset))); } else if (IsPropertyA(Property, Int64PropertyClass)) { log(std::format("int64 {} = {}\n", PropertyName, *(int64*)(__int64(Object) + Offset))); } else if (IsPropertyA(Property, ArrayPropertyClass)) { log(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); // log(std::format("{} Enum: {}\n", PropertyName, (int)EnumValueIg)); log(std::format("{} Enum\n", PropertyName)); } */ else if (IsPropertyA(Property, FunctionClass)) { } else if (!bExcludeUnhandled) { // log(std::format("{}: {}\n", PropertyName, "UNHANDLED"); log(std::format("{}: {} {}\n", PropertyName, "UNHANDLED", ""/*, ((UObject*)Property)->GetName()*/)); } Property = GetNext(Property); } } return; }