From 16e43e92232e8e39d78483735de9a36f9a6fee46 Mon Sep 17 00:00:00 2001 From: SkylineR390 Date: Thu, 11 Apr 2024 17:41:10 -0400 Subject: [PATCH 1/3] Fixes stack overflow caused by recursing over ill-formed perk tree. --- skse64/GameFormComponents.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/skse64/GameFormComponents.h b/skse64/GameFormComponents.h index 15e8533..5b2983c 100644 --- a/skse64/GameFormComponents.h +++ b/skse64/GameFormComponents.h @@ -1332,7 +1332,7 @@ class BGSSkillPerkTreeNode virtual bool Accept(BGSPerk * node) = 0; }; - bool VisitPerks(PerkVisitor & visitor) + bool VisitPerks(PerkVisitor & visitor, const int depth = 0) { if(visitor.Accept(perk)) return true; @@ -1342,7 +1342,7 @@ class BGSSkillPerkTreeNode BGSSkillPerkTreeNode* connector = NULL; connections.GetNthItem(i, connector); - if(connector->VisitPerks(visitor)) + if(depth < 32 && connector->VisitPerks(visitor, depth + 1)) return true; } From 0acceac1fd8c518275daf91e91d68a5f411eda55 Mon Sep 17 00:00:00 2001 From: SkylineR390 Date: Thu, 11 Apr 2024 17:56:49 -0400 Subject: [PATCH 2/3] Prevents duplicate perks in the resulting VMArray --- skse64/PapyrusActorValueInfo.cpp | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/skse64/PapyrusActorValueInfo.cpp b/skse64/PapyrusActorValueInfo.cpp index 752f035..f79e97d 100644 --- a/skse64/PapyrusActorValueInfo.cpp +++ b/skse64/PapyrusActorValueInfo.cpp @@ -15,7 +15,7 @@ class MatchSkillPerks : public BGSSkillPerkTreeNode::PerkVisitor virtual bool Accept(BGSPerk * perk) { - if(perk) + if(perk && !GetPerkAdded(perk)) { bool addPerk = true; if(m_actor) { @@ -52,6 +52,7 @@ class MatchSkillPerks : public BGSSkillPerkTreeNode::PerkVisitor return false; } virtual void AddPerk(BGSPerk * perk) = 0; + virtual bool GetPerkAdded(BGSPerk *perk) = 0; }; class PerkFormListVisitor : public MatchSkillPerks @@ -67,6 +68,13 @@ class PerkFormListVisitor : public MatchSkillPerks { CALL_MEMBER_FN(m_formList, AddFormToList)(perk); } + + virtual bool GetPerkAdded(BGSPerk *perk) + { + TESForm *base = perk; + + return ((*m_formList).forms.GetItemIndex(base) > -1); + } }; class PerkArrayVisitor : public MatchSkillPerks @@ -81,6 +89,17 @@ class PerkArrayVisitor : public MatchSkillPerks { m_perks->push_back(perk); } + virtual bool GetPerkAdded(BGSPerk *perk) + { + std::vector::const_iterator offbounds = (*m_perks).cend(); + + for (std::vector::const_iterator i = (*m_perks).cbegin(); i != offbounds; ++i) + { if (*i != perk) + continue ; + return (true); + } + return (false); + } }; namespace papyrusActorValueInfo From 4888873390f9c571ffc7b441f1dbddd5582bd428 Mon Sep 17 00:00:00 2001 From: SkylineR390 Date: Thu, 11 Apr 2024 18:12:30 -0400 Subject: [PATCH 3/3] Simplifies the logic of the perk traversal code. --- skse64/PapyrusActorValueInfo.cpp | 35 +++++--------------------------- 1 file changed, 5 insertions(+), 30 deletions(-) diff --git a/skse64/PapyrusActorValueInfo.cpp b/skse64/PapyrusActorValueInfo.cpp index f79e97d..b94ca01 100644 --- a/skse64/PapyrusActorValueInfo.cpp +++ b/skse64/PapyrusActorValueInfo.cpp @@ -17,36 +17,11 @@ class MatchSkillPerks : public BGSSkillPerkTreeNode::PerkVisitor { if(perk && !GetPerkAdded(perk)) { - bool addPerk = true; - if(m_actor) { - if(!CALL_MEMBER_FN(m_actor, HasPerk)(perk)) - addPerk = m_unowned; - else - addPerk = !m_unowned; - } - - if(addPerk) { - AddPerk(perk); - } - - if(m_allRanks) { - BGSPerk * nextPerk = perk->nextPerk; - while(nextPerk) { - addPerk = true; - if(m_actor) { - if(!CALL_MEMBER_FN(m_actor, HasPerk)(nextPerk)) - addPerk = m_unowned; - else - addPerk = !m_unowned; - } - - if(addPerk) { - AddPerk(nextPerk); - } - - nextPerk = nextPerk->nextPerk; - } - } + do + { if (!m_actor || (!CALL_MEMBER_FN(m_actor, HasPerk)(perk) ? m_unowned : !m_unowned) ) + AddPerk(perk); + perk = m_allRanks ? perk->nextPerk : nullptr; + } while (perk); } return false;