From 73e6120eb83b8719ebbd30e30ad4e0b2dfe03cad Mon Sep 17 00:00:00 2001 From: Zzyxzz Date: Wed, 15 Apr 2026 18:36:45 +0200 Subject: [PATCH 1/2] Updated Members and added functions: addKeyword and removeKeyword --- include/RE/B/BGSTypedKeywordValueArray.h | 94 ++++++++++++++++++++++-- 1 file changed, 87 insertions(+), 7 deletions(-) diff --git a/include/RE/B/BGSTypedKeywordValueArray.h b/include/RE/B/BGSTypedKeywordValueArray.h index ed24923e..2aa76fc6 100644 --- a/include/RE/B/BGSTypedKeywordValueArray.h +++ b/include/RE/B/BGSTypedKeywordValueArray.h @@ -33,9 +33,11 @@ namespace RE class BGSTypedKeywordValue { public: - // members std::uint16_t keywordIndex; // 0 + std::uint16_t pad02; // 2 + std::uint32_t pad04; // 4 }; + static_assert(sizeof(BGSTypedKeywordValue) == 0x8); namespace detail { @@ -48,8 +50,12 @@ namespace RE public: [[nodiscard]] bool HasKeyword(BGSKeyword* a_keyword) { - for (std::uint32_t i = 0; i < size; ++i) { - const auto kywd = detail::BGSKeywordGetTypedKeywordByIndex(TYPE, array[i].keywordIndex); + if (!a_keyword) { + return false; + } + + for (auto it = begin; it != end; ++it) { + const auto kywd = detail::BGSKeywordGetTypedKeywordByIndex(TYPE, it->keywordIndex); if (kywd == a_keyword) { return true; } @@ -57,10 +63,84 @@ namespace RE return false; } - // members - BGSTypedKeywordValue* array; // 00 - std::uint32_t size; // 08 - std::uint64_t unk10; // 10 + [[nodiscard]] bool AddKeyword(BGSKeyword* a_keyword) + { + if (!a_keyword) { + REX::WARN("AddKeyword: a_keyword is null"); + return false; + } + + auto first = reinterpret_cast(begin); + auto last = reinterpret_cast(end); + + for (auto it = first; it != last; ++it) { + if (*it && (*it)->formID == a_keyword->formID) { + REX::DEBUG("AddKeyword: keyword already exists {:08X}", a_keyword->formID); + return false; + } + } + + const auto oldSize = static_cast(last - first); + const auto newSize = oldSize + 1; + + auto* newData = static_cast( + RE::MemoryManager::GetSingleton()->Allocate(sizeof(BGSKeyword*) * newSize, 0, false)); + + if (!newData) { + REX::WARN("AddKeyword: allocation failed for keyword {:08X}", a_keyword->formID); + return false; + } + + for (std::size_t i = 0; i < oldSize; ++i) { + newData[i] = first[i]; + } + + newData[oldSize] = a_keyword; + + auto oldFirst = first; + auto oldLast = last; + auto oldCap = reinterpret_cast(capacityEnd); + + begin = reinterpret_cast*>(newData); + end = reinterpret_cast*>(newData + newSize); + capacityEnd = reinterpret_cast*>(newData + newSize); + + REX::DEBUG( + "AddKeyword: reallocated array for keyword {:08X}, oldBegin={} oldEnd={} oldCap={}, newBegin={} newEnd={}", + a_keyword->formID, + static_cast(oldFirst), + static_cast(oldLast), + static_cast(oldCap), + static_cast(begin), + static_cast(end)); + + return true; + } + + [[nodiscard]] bool RemoveKeyword(BGSKeyword* a_keyword) + { + if (!a_keyword) { + return false; + } + auto first = reinterpret_cast(begin); + auto last = reinterpret_cast(end); + for (auto it = first; it != last; ++it) { + if (*it && (*it)->formID == a_keyword->formID) { + for (auto jt = it; jt + 1 != last; ++jt) { + *jt = *(jt + 1); + } + --last; + *last = nullptr; + end = reinterpret_cast*>(last); + return true; + } + } + return false; + } + + BGSTypedKeywordValue* begin; // 00 + BGSTypedKeywordValue* end; // 08 + BGSTypedKeywordValue* capacityEnd; // 10 }; static_assert(sizeof(BGSTypedKeywordValueArray) == 0x18); } From 83bc6a6a85961c1498680855b8abc7228759fed2 Mon Sep 17 00:00:00 2001 From: Zzyxzz Date: Thu, 16 Apr 2026 11:15:35 +0200 Subject: [PATCH 2/2] Removed Logging --- include/RE/B/BGSTypedKeywordValueArray.h | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/include/RE/B/BGSTypedKeywordValueArray.h b/include/RE/B/BGSTypedKeywordValueArray.h index 2aa76fc6..1ef0fb88 100644 --- a/include/RE/B/BGSTypedKeywordValueArray.h +++ b/include/RE/B/BGSTypedKeywordValueArray.h @@ -66,7 +66,6 @@ namespace RE [[nodiscard]] bool AddKeyword(BGSKeyword* a_keyword) { if (!a_keyword) { - REX::WARN("AddKeyword: a_keyword is null"); return false; } @@ -75,7 +74,6 @@ namespace RE for (auto it = first; it != last; ++it) { if (*it && (*it)->formID == a_keyword->formID) { - REX::DEBUG("AddKeyword: keyword already exists {:08X}", a_keyword->formID); return false; } } @@ -87,7 +85,6 @@ namespace RE RE::MemoryManager::GetSingleton()->Allocate(sizeof(BGSKeyword*) * newSize, 0, false)); if (!newData) { - REX::WARN("AddKeyword: allocation failed for keyword {:08X}", a_keyword->formID); return false; } @@ -96,7 +93,6 @@ namespace RE } newData[oldSize] = a_keyword; - auto oldFirst = first; auto oldLast = last; auto oldCap = reinterpret_cast(capacityEnd); @@ -104,16 +100,6 @@ namespace RE begin = reinterpret_cast*>(newData); end = reinterpret_cast*>(newData + newSize); capacityEnd = reinterpret_cast*>(newData + newSize); - - REX::DEBUG( - "AddKeyword: reallocated array for keyword {:08X}, oldBegin={} oldEnd={} oldCap={}, newBegin={} newEnd={}", - a_keyword->formID, - static_cast(oldFirst), - static_cast(oldLast), - static_cast(oldCap), - static_cast(begin), - static_cast(end)); - return true; }