/** * UniversalSlashingSimulator - UObject Wrapper Implementation */ #include "UObjectWrapper.h" #include "../../Core/Memory/Memory.h" #include "../../Core/Versioning/VersionResolver.h" #include "../CoreTypes/OffsetResolver.h" #include namespace USS { // Static name pool instance (lazy initialized) static std::unique_ptr g_pNamePool; static INamePool* GetNamePoolInstance() { if (!g_pNamePool) { g_pNamePool = CreateNamePool(); // Note: Initialization happens separately via EngineCore } return g_pNamePool.get(); } //========================================================================= // FNameWrapper Implementation //========================================================================= std::string FNameWrapper::GetName() const { if (m_ComparisonIndex <= 0) return "None"; INamePool* Pool = GetNamePoolInstance(); if (!Pool || !Pool->IsInitialized()) return ""; return Pool->GetNameString(m_ComparisonIndex); } std::string FNameWrapper::GetFullName() const { std::string Name = GetName(); if (m_Number > 0) { Name += "_"; Name += std::to_string(m_Number); } return Name; } //========================================================================= // UObjectWrapper Implementation //========================================================================= bool UObjectWrapper::IsValid() const { return m_pObject != nullptr && Memory::IsValidAddress(reinterpret_cast(m_pObject)); } int32 UObjectWrapper::GetObjectFlags() const { if (!IsValid()) return 0; const auto& Offsets = GetOffsetResolver().GetOffsets(); int32 Flags = 0; Memory::Read( reinterpret_cast(m_pObject) + Offsets.UObject.ObjectFlags, Flags ); return Flags; } int32 UObjectWrapper::GetInternalIndex() const { if (!IsValid()) return -1; const auto& Offsets = GetOffsetResolver().GetOffsets(); int32 Index = -1; Memory::Read( reinterpret_cast(m_pObject) + Offsets.UObject.InternalIndex, Index ); return Index; } UClassWrapper UObjectWrapper::GetClass() const { if (!IsValid()) return UClassWrapper(); const auto& Offsets = GetOffsetResolver().GetOffsets(); void* ClassPtr = nullptr; Memory::Read( reinterpret_cast(m_pObject) + Offsets.UObject.Class, ClassPtr ); return UClassWrapper(ClassPtr); } FNameWrapper UObjectWrapper::GetFName() const { if (!IsValid()) return FNameWrapper(); const auto& Offsets = GetOffsetResolver().GetOffsets(); uintptr NameAddr = reinterpret_cast(m_pObject) + Offsets.UObject.Name; int32 ComparisonIndex = 0; int32 Number = 0; Memory::Read(NameAddr + 0, ComparisonIndex); Memory::Read(NameAddr + 4, Number); return FNameWrapper(ComparisonIndex, Number); } UObjectWrapper UObjectWrapper::GetOuter() const { if (!IsValid()) return UObjectWrapper(); const auto& Offsets = GetOffsetResolver().GetOffsets(); void* OuterPtr = nullptr; Memory::Read( reinterpret_cast(m_pObject) + Offsets.UObject.Outer, OuterPtr ); return UObjectWrapper(OuterPtr); } std::string UObjectWrapper::GetName() const { return GetFName().GetFullName(); } std::string UObjectWrapper::GetFullName() const { if (!IsValid()) return ""; UClassWrapper Class = GetClass(); std::string ClassName = Class.IsValid() ? Class.GetName() : "Unknown"; return ClassName + " " + GetPathName(); } std::string UObjectWrapper::GetPathName() const { if (!IsValid()) return ""; std::string Path; UObjectWrapper Current = GetOuter(); // Build path from outermost to innermost std::vector Parts; Parts.push_back(GetName()); while (Current.IsValid()) { Parts.push_back(Current.GetName()); Current = Current.GetOuter(); } // Reverse and join for (auto It = Parts.rbegin(); It != Parts.rend(); ++It) { if (!Path.empty()) Path += "."; Path += *It; } return Path; } std::string UObjectWrapper::GetObjectClassName() const { if (!IsValid()) return ""; UClassWrapper Class = GetClass(); if (!Class.IsValid()) return ""; return Class.GetName(); } bool UObjectWrapper::IsA(const UClassWrapper& Class) const { if (!IsValid() || !Class.IsValid()) return false; UClassWrapper MyClass = GetClass(); return MyClass.IsChildOf(Class); } bool UObjectWrapper::IsA(const char* ClassName) const { if (!IsValid() || !ClassName) return false; UClassWrapper MyClass = GetClass(); while (MyClass.IsValid()) { if (MyClass.GetName() == ClassName) return true; MyClass = MyClass.GetSuperClass(); } return false; } //========================================================================= // UClassWrapper Implementation //========================================================================= UClassWrapper UClassWrapper::GetSuperClass() const { if (!IsValid()) return UClassWrapper(); const auto& Offsets = GetOffsetResolver().GetOffsets(); void* SuperPtr = nullptr; Memory::Read( reinterpret_cast(m_pObject) + Offsets.UStruct.SuperStruct, SuperPtr ); return UClassWrapper(SuperPtr); } UObjectWrapper UClassWrapper::GetDefaultObject() const { if (!IsValid()) return UObjectWrapper(); const auto& Offsets = GetOffsetResolver().GetOffsets(); void* CDOPtr = nullptr; Memory::Read( reinterpret_cast(m_pObject) + Offsets.UClass.ClassDefaultObject, CDOPtr ); return UObjectWrapper(CDOPtr); } bool UClassWrapper::IsChildOf(const UClassWrapper& Parent) const { if (!IsValid() || !Parent.IsValid()) return false; if (m_pObject == Parent.m_pObject) return true; UClassWrapper Super = GetSuperClass(); while (Super.IsValid()) { if (Super.m_pObject == Parent.m_pObject) return true; Super = Super.GetSuperClass(); } return false; } //========================================================================= // UStructWrapper Implementation //========================================================================= UStructWrapper UStructWrapper::GetSuperStruct() const { if (!IsValid()) return UStructWrapper(); const auto& Offsets = GetOffsetResolver().GetOffsets(); void* SuperPtr = nullptr; Memory::Read( reinterpret_cast(m_pObject) + Offsets.UStruct.SuperStruct, SuperPtr ); return UStructWrapper(SuperPtr); } int32 UStructWrapper::GetPropertiesSize() const { if (!IsValid()) return 0; const auto& Offsets = GetOffsetResolver().GetOffsets(); int32 Size = 0; Memory::Read( reinterpret_cast(m_pObject) + Offsets.UStruct.PropertiesSize, Size ); return Size; } int32 UStructWrapper::GetMinAlignment() const { if (!IsValid()) return 1; const auto& Offsets = GetOffsetResolver().GetOffsets(); int32 Alignment = 1; Memory::Read( reinterpret_cast(m_pObject) + Offsets.UStruct.MinAlignment, Alignment ); return Alignment; } UStructWrapper::PropertyIterator UStructWrapper::GetProperties() const { if (!IsValid()) return PropertyIterator(nullptr, false); const auto& Version = GetVersionResolver().GetVersionInfo(); const auto& Offsets = GetOffsetResolver().GetOffsets(); void* FirstProperty = nullptr; bool bIsFField = Version.bUseFField; if (bIsFField && Offsets.UStruct.ChildProperties != 0) { // UE 4.25+: Use ChildProperties (FField*) Memory::Read( reinterpret_cast(m_pObject) + Offsets.UStruct.ChildProperties, FirstProperty ); } else { // Pre-4.25: Use Children (UField*), filter to properties Memory::Read( reinterpret_cast(m_pObject) + Offsets.UStruct.Children, FirstProperty ); } return PropertyIterator(FirstProperty, bIsFField); } //========================================================================= // PropertyIterator Implementation //========================================================================= UStructWrapper::PropertyIterator::PropertyIterator(void* First, bool bIsFField) : m_pCurrent(First) , m_bIsFField(bIsFField) { } void UStructWrapper::PropertyIterator::Next() { if (!m_pCurrent) return; const auto& Offsets = GetOffsetResolver().GetOffsets(); void* NextPtr = nullptr; if (m_bIsFField) { Memory::Read( reinterpret_cast(m_pCurrent) + Offsets.FField.Next, NextPtr ); } else { Memory::Read( reinterpret_cast(m_pCurrent) + Offsets.UField.Next, NextPtr ); } m_pCurrent = NextPtr; } std::string UStructWrapper::PropertyIterator::GetName() const { if (!m_pCurrent) return ""; const auto& Offsets = GetOffsetResolver().GetOffsets(); int32 ComparisonIndex = 0; int32 Number = 0; if (m_bIsFField) { uintptr NameAddr = reinterpret_cast(m_pCurrent) + Offsets.FField.NamePrivate; Memory::Read(NameAddr + 0, ComparisonIndex); Memory::Read(NameAddr + 4, Number); } else { // UProperty is a UObject, name at standard offset uintptr NameAddr = reinterpret_cast(m_pCurrent) + Offsets.UObject.Name; Memory::Read(NameAddr + 0, ComparisonIndex); Memory::Read(NameAddr + 4, Number); } return FNameWrapper(ComparisonIndex, Number).GetFullName(); } int32 UStructWrapper::PropertyIterator::GetOffset() const { if (!m_pCurrent) return -1; const auto& Offsets = GetOffsetResolver().GetOffsets(); int32 Offset = 0; if (m_bIsFField) { Memory::Read( reinterpret_cast(m_pCurrent) + Offsets.FProperty.Offset, Offset ); } else { Memory::Read( reinterpret_cast(m_pCurrent) + Offsets.UProperty.Offset, Offset ); } return Offset; } int32 UStructWrapper::PropertyIterator::GetElementSize() const { if (!m_pCurrent) return 0; const auto& Offsets = GetOffsetResolver().GetOffsets(); int32 Size = 0; if (m_bIsFField) { Memory::Read( reinterpret_cast(m_pCurrent) + Offsets.FProperty.ElementSize, Size ); } else { Memory::Read( reinterpret_cast(m_pCurrent) + Offsets.UProperty.ElementSize, Size ); } return Size; } //========================================================================= // UFunctionWrapper Implementation //========================================================================= uint32 UFunctionWrapper::GetFunctionFlags() const { if (!IsValid()) return 0; const auto& Offsets = GetOffsetResolver().GetOffsets(); uint32 Flags = 0; Memory::Read( reinterpret_cast(m_pObject) + Offsets.UFunction.FunctionFlags, Flags ); return Flags; } uint8 UFunctionWrapper::GetNumParms() const { if (!IsValid()) return 0; const auto& Offsets = GetOffsetResolver().GetOffsets(); uint8 NumParms = 0; Memory::Read( reinterpret_cast(m_pObject) + Offsets.UFunction.NumParms, NumParms ); return NumParms; } uint16 UFunctionWrapper::GetParmsSize() const { if (!IsValid()) return 0; const auto& Offsets = GetOffsetResolver().GetOffsets(); uint16 Size = 0; Memory::Read( reinterpret_cast(m_pObject) + Offsets.UFunction.ParmsSize, Size ); return Size; } void* UFunctionWrapper::GetNativeFunc() const { if (!IsValid()) return nullptr; const auto& Offsets = GetOffsetResolver().GetOffsets(); void* Func = nullptr; Memory::Read( reinterpret_cast(m_pObject) + Offsets.UFunction.Func, Func ); return Func; } }