From 9037ca885bd3e56e8c075b0de9c4acd3061e6ec6 Mon Sep 17 00:00:00 2001 From: RunnerScrab Date: Fri, 31 Oct 2025 03:52:12 -0500 Subject: [PATCH 1/2] Adds BSScript::Object destructor reimplementation Remove forgotten REX::INFO call Correct handling of BSScript::Object's ObjectTypeInfo member release --- include/RE/IDs.h | 5 +++-- include/RE/O/Object.h | 11 ++--------- src/RE/O/Object.cpp | 28 ++++++++++++++++++++++++++++ 3 files changed, 33 insertions(+), 11 deletions(-) diff --git a/include/RE/IDs.h b/include/RE/IDs.h index 19e5701..32963ac 100644 --- a/include/RE/IDs.h +++ b/include/RE/IDs.h @@ -276,6 +276,7 @@ namespace RE::ID { inline constexpr REL::ID ctor{ 137778 }; // 196025 inline constexpr REL::ID dtor{ 0 }; // 196032 - inlined + inline constexpr REL::ID dtorUnkSub{ 137823 }; inline constexpr REL::ID GetHandle{ 0 }; // 196069 - inlined inline constexpr REL::ID SetHandle{ 0 }; // 196079 inline constexpr REL::ID IncRef{ 0 }; // 37879 @@ -289,8 +290,8 @@ namespace RE::ID namespace ObjectTypeInfo { - inline constexpr REL::ID ctor{ 0 }; // 197047 - inline constexpr REL::ID dtor{ 0 }; // 196202 + inline constexpr REL::ID ctor{ 138400 }; // 197047 + inline constexpr REL::ID dtor{ 137885 }; // 196202 inline constexpr REL::ID Clear{ 0 }; // 196218 inline constexpr REL::ID CopyFromLinkedData{ 0 }; // 196219 inline constexpr REL::ID GetProperty{ 0 }; // 196241 diff --git a/include/RE/O/Object.h b/include/RE/O/Object.h index c55b58d..0416cde 100644 --- a/include/RE/O/Object.h +++ b/include/RE/O/Object.h @@ -14,17 +14,10 @@ namespace RE::BSScript class Object { public: - void dtor() - { - using func_t = decltype(&Object::dtor); - static REL::Relocation func{ ID::BSScript::Object::dtor }; - return func(this); - } + void dtor(); ~Object() { - // TODO: The destructor was inlined in version Starfield 1.15 and still needs to be - // pieced together or reimplemented dtor(); } @@ -66,7 +59,7 @@ namespace RE::BSScript std::uint32_t unk1C; // 1C BSTSmartPointer type; // 20 BSFixedString currentState; // 28 - void* lockStructure; // 30 + volatile void* lockStructure; // 30 IObjectHandlePolicy* handlePolicy; // 38 std::size_t handle; // 40 volatile std::uint32_t refCountAndHandleLock; // 48 diff --git a/src/RE/O/Object.cpp b/src/RE/O/Object.cpp index d9affb7..44d2ae5 100644 --- a/src/RE/O/Object.cpp +++ b/src/RE/O/Object.cpp @@ -2,6 +2,34 @@ namespace RE::BSScript { + void Object::dtor() + { + static REL::Relocation UnkObjectDtorSubroutine{ ID::BSScript::Object::dtorUnkSub }; + typedef ObjectTypeInfo* (*ObjectTypeInfoDeallocator)(ObjectTypeInfo*, std::uint32_t); + static REL::Relocation ObjectTypeInfoDealloc{ ID::BSScript::ObjectTypeInfo::dtor }; + + this->lockStructure = + reinterpret_cast(reinterpret_cast(this->lockStructure) & 0xfffffffffffffffe); + + if (this->lockStructure != 0) { + _InterlockedExchangeAdd(reinterpret_cast(this->lockStructure), -1); + } + + ObjectTypeInfo* pType = this->type.get(); + + //BSTSmartPointer will decrement type's refcount automatically at end of scope + if (pType->QRefCount() == 1) + { + //This stops the smart pointer from dereferencing a dangling ObjectTypeInfo pointer after + //ObjectTypeInfoDealloc frees Object::type (and also does unknown global/TLS variable plumbing) + this->type->IncRef(); + this->type.reset(); + ObjectTypeInfoDealloc(pType, 1); + } + + UnkObjectDtorSubroutine(this); + } + [[nodiscard]] std::uint32_t Object::DecRef() { std::int32_t iVar1; From 0e9f0ebca2af332516ff3318c7f6421129a08834 Mon Sep 17 00:00:00 2001 From: RunnerScrab <45054749+RunnerScrab@users.noreply.github.com> Date: Fri, 31 Oct 2025 22:02:05 +0000 Subject: [PATCH 2/2] maintenance --- src/RE/O/Object.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/RE/O/Object.cpp b/src/RE/O/Object.cpp index 44d2ae5..995c0e4 100644 --- a/src/RE/O/Object.cpp +++ b/src/RE/O/Object.cpp @@ -18,9 +18,8 @@ namespace RE::BSScript ObjectTypeInfo* pType = this->type.get(); //BSTSmartPointer will decrement type's refcount automatically at end of scope - if (pType->QRefCount() == 1) - { - //This stops the smart pointer from dereferencing a dangling ObjectTypeInfo pointer after + if (pType->QRefCount() == 1) { + //This stops the smart pointer from dereferencing a dangling ObjectTypeInfo pointer after //ObjectTypeInfoDealloc frees Object::type (and also does unknown global/TLS variable plumbing) this->type->IncRef(); this->type.reset();