From ec8b3616c3ae2c4d2690271827381c551e735bfb Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Tue, 1 Sep 2026 14:58:15 -0500 Subject: [PATCH] use deep comparisons on `struct_identity` This uses a deep compare (when necessary) when testing if two `struct_identity`s are the same in the case when their pointers do not match. this test is not perfect but should work correctly on all existing instances --- library/DataDefs.cpp | 33 +++++++++++++++++++++++++++++++++ library/LuaWrapper.cpp | 6 +++++- library/include/CoordTemplate.h | 2 +- library/include/DataDefs.h | 9 ++++++++- 4 files changed, 47 insertions(+), 3 deletions(-) diff --git a/library/DataDefs.cpp b/library/DataDefs.cpp index 880a8b93a5..97dc331406 100644 --- a/library/DataDefs.cpp +++ b/library/DataDefs.cpp @@ -134,6 +134,18 @@ const std::string compound_identity::getFullName() const return getName(); } +bool compound_identity::is_equivalent(const compound_identity* other) const +{ + if (this->byte_size() != other->byte_size() || strcmp(this->getName(), other->getName()) != 0) + return false; + + if (this->scope_parent != other->scope_parent && + !(this->scope_parent && other->scope_parent && this->scope_parent->is_equivalent(other->scope_parent))) + return false; + + return true; +} + static std::mutex *known_mutex = NULL; void compound_identity::Init(Core *core) @@ -239,6 +251,27 @@ bool struct_identity::is_subclass(const struct_identity *actual) const return false; } +bool struct_identity::is_equivalent(const struct_identity* other) const +{ + if (!static_cast(this)->is_equivalent(static_cast(other))) + return false; + + if (this->parent != other->parent && + !(this->parent && other->parent && this->parent->is_equivalent(other->parent))) + return false; + + const struct_field_info* f0 = this->fields; + const struct_field_info* f1 = other->fields; + + for (; f0->mode != struct_field_info::Mode::END && f1->mode != struct_field_info::Mode::END; f0++, f1++) + { + if (f0->mode != f1->mode || f0->offset != f1->offset || f0->count != f1->count || strcmp(f0->name, f1->name) != 0) + return false; + } + + return true; +} + const std::string pointer_identity::getFullName() const { return (target ? target->getFullName() : std::string("void")) + "*"; diff --git a/library/LuaWrapper.cpp b/library/LuaWrapper.cpp index 9f0ecab738..1a0c5c3bfe 100644 --- a/library/LuaWrapper.cpp +++ b/library/LuaWrapper.cpp @@ -314,6 +314,8 @@ bool LuaWrapper::is_type_compatible(lua_State *state, const type_identity *type1 auto b1 = (struct_identity*)type1; auto b2 = (struct_identity*)type2; + if (b1->is_equivalent(b2)) return true; + return (!exact_equal && b1->is_subclass(b2)); } @@ -373,7 +375,9 @@ void *LuaWrapper::get_object_internal(lua_State *state, const type_identity *typ if (!LookupTypeInfo(state, in_method)) // metatable -> type? return NULL; - if (type && lua_touserdata(state, -1) != type) + type_identity* othertype = static_cast(lua_touserdata(state, -1)); + + if (type && othertype != type) { /* * If valid but different type, do an intelligent comparison. diff --git a/library/include/CoordTemplate.h b/library/include/CoordTemplate.h index 3a472343a6..a3260ef886 100644 --- a/library/include/CoordTemplate.h +++ b/library/include/CoordTemplate.h @@ -89,7 +89,7 @@ namespace DFHack }; template , typename U = DFHack::Coord2d> - static inline const struct_identity coord2d_identity{sizeof(U), &df::allocator_fn, nullptr, "coord", nullptr, coord2d_fields}; + static inline const struct_identity coord2d_identity{sizeof(U), &df::allocator_fn, nullptr, "coord2d", nullptr, coord2d_fields}; template > struct Coord3d diff --git a/library/include/DataDefs.h b/library/include/DataDefs.h index 5e03e9ab63..c802b7ab09 100644 --- a/library/include/DataDefs.h +++ b/library/include/DataDefs.h @@ -143,11 +143,12 @@ namespace DFHack static std::vector* top_scope; const char *dfhack_name; - const compound_identity *const scope_parent; static void ensure_compound_identity_init(); protected: + const compound_identity *const scope_parent; + compound_identity(size_t size, TAllocateFn alloc, const compound_identity *scope_parent, const char *dfhack_name); @@ -163,6 +164,9 @@ namespace DFHack static const std::vector &getTopScope() { return *top_scope; } static void Init(Core *core); + + bool is_equivalent(const compound_identity* other) const; + }; // Bitfields @@ -297,6 +301,7 @@ namespace DFHack const struct_field_info *fields; static void ensure_struct_identity_init(); + struct_identity* parent; protected: virtual void doInit(Core *core) const override; @@ -317,6 +322,8 @@ namespace DFHack bool is_subclass(const struct_identity *subtype) const; virtual void build_metatable(lua_State *state) const; + + bool is_equivalent(const struct_identity* other) const; }; class DFHACK_EXPORT global_identity : public struct_identity {