From d8332f9e4081de3b638cc61dea11fe24c01627a3 Mon Sep 17 00:00:00 2001 From: Deukhoofd Date: Sun, 10 Nov 2019 17:08:42 +0100 Subject: [PATCH] Another rework for scripthooks, for better performance. This new version caches pointers to the pointers to scripts, so that we can build the data once and then simply iterate over it whenever we want to run a hook. --- src/Battling/Flow/ChoiceQueue.hpp | 6 ++-- src/Battling/Flow/TurnOrdering.cpp | 8 ++--- src/Battling/Flow/TurnOrdering.hpp | 2 +- src/Battling/Models/Battle.cpp | 8 ++--- src/Battling/Models/Battle.hpp | 2 +- src/Battling/Models/BattleSide.cpp | 10 +++--- src/Battling/Models/BattleSide.hpp | 8 ++--- src/Battling/Models/Creature.cpp | 13 ++++---- src/Battling/Models/Creature.hpp | 6 ++-- src/Battling/Models/ExecutingAttack.hpp | 6 ++-- .../ScriptHandling/ScriptAggregator.hpp | 33 +++++++++---------- src/Battling/ScriptHandling/ScriptMacros.cpp | 3 +- src/Battling/ScriptHandling/ScriptSource.hpp | 12 ++++++- src/Battling/ScriptHandling/ScriptWrapper.cpp | 3 ++ src/Battling/ScriptHandling/ScriptWrapper.hpp | 33 +++++++++++++++++++ src/Battling/TurnChoices/AttackTurnChoice.hpp | 8 +++-- src/Battling/TurnChoices/BaseTurnChoice.hpp | 4 --- src/Battling/TurnChoices/PassTurnChoice.hpp | 5 +-- tests/BattleTests/TurnOrderTests.cpp | 20 +++++------ 19 files changed, 118 insertions(+), 72 deletions(-) create mode 100644 src/Battling/ScriptHandling/ScriptWrapper.cpp create mode 100644 src/Battling/ScriptHandling/ScriptWrapper.hpp diff --git a/src/Battling/Flow/ChoiceQueue.hpp b/src/Battling/Flow/ChoiceQueue.hpp index 1735eff..5d6975c 100644 --- a/src/Battling/Flow/ChoiceQueue.hpp +++ b/src/Battling/Flow/ChoiceQueue.hpp @@ -7,12 +7,12 @@ namespace CreatureLib::Battling{ class ChoiceQueue { - std::vector _queue; + std::vector _queue; size_t _current = 0; public: bool HasCompletedQueue = false; - explicit ChoiceQueue(std::vector queue) + explicit ChoiceQueue(std::vector queue) :_queue(std::move(queue)){} const BaseTurnChoice* Dequeue(){ @@ -25,7 +25,7 @@ namespace CreatureLib::Battling{ return _current < _queue.size(); } - std::vector& GetInnerQueue(){ + std::vector& GetInnerQueue(){ return _queue; } }; diff --git a/src/Battling/Flow/TurnOrdering.cpp b/src/Battling/Flow/TurnOrdering.cpp index ac0eb0f..75cc559 100644 --- a/src/Battling/Flow/TurnOrdering.cpp +++ b/src/Battling/Flow/TurnOrdering.cpp @@ -1,8 +1,6 @@ #include "TurnOrdering.hpp" #include "../TurnChoices/AttackTurnChoice.hpp" -#include "../Models/Creature.hpp" #include "../Models/Battle.hpp" -#include "../../Core/Exceptions/NotImplementedException.hpp" #include @@ -15,8 +13,8 @@ bool ___ChoiceOrderFunc(const BaseTurnChoice* a, const BaseTurnChoice* b, Core:: if (aKind != bKind) return aKind > bKind; if (aKind == TurnChoiceKind::Attack){ - auto aPriority = static_cast(a)->GetPriority(); - auto bPriority = static_cast(b)->GetPriority(); + auto aPriority = dynamic_cast(a)->GetPriority(); + auto bPriority = dynamic_cast(b)->GetPriority(); if (aPriority != bPriority) return aPriority > bPriority; } @@ -29,7 +27,7 @@ bool ___ChoiceOrderFunc(const BaseTurnChoice* a, const BaseTurnChoice* b, Core:: return randomValue == 0; } -void TurnOrdering::OrderChoices(std::vector &vec, Core::Random& rand) { +void TurnOrdering::OrderChoices(std::vector &vec, Core::Random& rand) { auto comp = [&](const BaseTurnChoice * a,const BaseTurnChoice * b)-> bool { return ___ChoiceOrderFunc(a,b,rand); }; diff --git a/src/Battling/Flow/TurnOrdering.hpp b/src/Battling/Flow/TurnOrdering.hpp index e760f92..b84c452 100644 --- a/src/Battling/Flow/TurnOrdering.hpp +++ b/src/Battling/Flow/TurnOrdering.hpp @@ -8,7 +8,7 @@ namespace CreatureLib::Battling { class TurnOrdering { public: - static void OrderChoices(std::vector& vec, CreatureLib::Core::Random& rand); + static void OrderChoices(std::vector& vec, CreatureLib::Core::Random& rand); }; } diff --git a/src/Battling/Models/Battle.cpp b/src/Battling/Models/Battle.cpp index 338d933..e657045 100644 --- a/src/Battling/Models/Battle.cpp +++ b/src/Battling/Models/Battle.cpp @@ -33,10 +33,10 @@ void Battle::CheckChoicesSetAndRun() { return; } } - auto choices = std::vector(_numberOfSides * _creaturesPerSide); + auto choices = std::vector(_numberOfSides * _creaturesPerSide); auto i = 0; for (auto side: _sides){ - for (const BaseTurnChoice* choice: side->GetChoices()){ + for (BaseTurnChoice* choice: side->GetChoices()){ if (choice->GetKind() == TurnChoiceKind::Attack){ auto attack = dynamic_cast(choice)->GetAttack(); uint8_t uses = 1; @@ -93,6 +93,6 @@ void Battle::FillRecall(uint8_t side, uint8_t, Creature *c) { } } -void Battle::GetActiveScripts(ScriptAggregator &aggr) const { - aggr.Add(&_volatile); +void Battle::GetActiveScripts(std::vector &scripts) { + scripts.emplace_back(&_volatile); } diff --git a/src/Battling/Models/Battle.hpp b/src/Battling/Models/Battle.hpp index cdcef0c..d49d129 100644 --- a/src/Battling/Models/Battle.hpp +++ b/src/Battling/Models/Battle.hpp @@ -42,7 +42,7 @@ namespace CreatureLib::Battling { void FillRecall(uint8_t side, uint8_t, Creature* c); - void GetActiveScripts(ScriptAggregator &aggr) const override; + void GetActiveScripts(std::vector &scripts) override; }; } diff --git a/src/Battling/Models/BattleSide.cpp b/src/Battling/Models/BattleSide.cpp index 6331ca1..10379c7 100644 --- a/src/Battling/Models/BattleSide.cpp +++ b/src/Battling/Models/BattleSide.cpp @@ -16,11 +16,11 @@ void BattleSide::ResetChoices() { } } -const std::vector& BattleSide::GetChoices() const{ +const std::vector& BattleSide::GetChoices() const{ return _choices; } -void BattleSide::SetChoice(const BaseTurnChoice *choice) { +void BattleSide::SetChoice(BaseTurnChoice *choice) { auto find = std::find(_creatures.begin(), _creatures.end(), choice->GetUser()); if (find ==_creatures.end()) throw CreatureException("User not found"); @@ -41,7 +41,7 @@ Creature *BattleSide::GetCreature(uint8_t index) const { return _creatures[index]; } -void BattleSide::GetActiveScripts(ScriptAggregator &aggr) const { - aggr.Add(&_volatile); - _battle->GetActiveScripts(aggr); +void BattleSide::GetActiveScripts(std::vector &scripts) { + scripts.emplace_back(&_volatile); + _battle->GetActiveScripts(scripts); } diff --git a/src/Battling/Models/BattleSide.hpp b/src/Battling/Models/BattleSide.hpp index c4a95bf..1c10d31 100644 --- a/src/Battling/Models/BattleSide.hpp +++ b/src/Battling/Models/BattleSide.hpp @@ -9,7 +9,7 @@ namespace CreatureLib::Battling{ class BattleSide : public ScriptSource{ uint8_t _creaturesPerSide; std::vector _creatures; - std::vector _choices; + std::vector _choices; uint8_t _choicesSet = 0; ScriptSet _volatile; Battle* _battle; @@ -21,9 +21,9 @@ namespace CreatureLib::Battling{ } [[nodiscard]] bool AllChoicesSet() const; - [[nodiscard]] const std::vector& GetChoices() const; + [[nodiscard]] const std::vector& GetChoices() const; - void SetChoice(const BaseTurnChoice* choice); + void SetChoice(BaseTurnChoice* choice); void ResetChoices(); void SetCreature(Creature* creature, uint8_t index); @@ -31,7 +31,7 @@ namespace CreatureLib::Battling{ Creature* GetCreature(uint8_t index) const; bool CreatureOnSide(const Creature* creature) const; - void GetActiveScripts(ScriptAggregator &aggr) const override; + void GetActiveScripts(std::vector &scripts) override; }; } diff --git a/src/Battling/Models/Creature.cpp b/src/Battling/Models/Creature.cpp index a263447..8fa1c93 100644 --- a/src/Battling/Models/Creature.cpp +++ b/src/Battling/Models/Creature.cpp @@ -1,4 +1,5 @@ #include +#include #include "Creature.hpp" #include "../Models/Battle.hpp" @@ -20,9 +21,9 @@ Battling::Creature::Creature(const Library::CreatureSpecies* species, const Libr __Gender(gender), __Coloring(coloring), __HeldItem(heldItem), - _nickname(nickname), + _nickname(std::move(nickname)), _talentIndex(talent), - _attacks(attacks) + _attacks(std::move(attacks)) {} @@ -140,8 +141,8 @@ bool Battling::Creature::HasType(uint8_t type) const { return std::find(t.begin(), t.end(), type) != t.end(); } -void Battling::Creature::GetActiveScripts(Battling::ScriptAggregator &aggr) const { - aggr.Add(_status); - aggr.Add(&_volatile); - _side->GetActiveScripts(aggr); +void Battling::Creature::GetActiveScripts(std::vector &scripts) { + scripts.emplace_back(&_status); + scripts.emplace_back(&_volatile); + _side->GetActiveScripts(scripts); } diff --git a/src/Battling/Models/Creature.hpp b/src/Battling/Models/Creature.hpp index 9b4b18a..b8f7885 100644 --- a/src/Battling/Models/Creature.hpp +++ b/src/Battling/Models/Creature.hpp @@ -18,7 +18,8 @@ namespace CreatureLib::Battling{ class Creature : public ScriptSource{ GetProperty(const Library::CreatureSpecies*, Species); - GetProperty(const Library::SpeciesVariant*, Variant); + GetProperty(const Library::SpeciesVariant*, Variant) + GetProperty(uint8_t, Level); GetProperty(uint32_t, Experience); GetProperty(Core::StatisticSet, StatExperience); @@ -67,7 +68,7 @@ namespace CreatureLib::Battling{ [[nodiscard]] const std::vector& GetTypes() const; [[nodiscard]] bool HasType(uint8_t type) const; - void GetActiveScripts(ScriptAggregator& aggr) const override; + void GetActiveScripts(std::vector &scripts) override; //region Stat APIs @@ -85,6 +86,7 @@ namespace CreatureLib::Battling{ void RecalculateBoostedStats(); void RecalculateFlatStat(Core::Statistic); void RecalculateBoostedStat(Core::Statistic); + //endregion diff --git a/src/Battling/Models/ExecutingAttack.hpp b/src/Battling/Models/ExecutingAttack.hpp index 0f5870d..e61ee09 100644 --- a/src/Battling/Models/ExecutingAttack.hpp +++ b/src/Battling/Models/ExecutingAttack.hpp @@ -89,8 +89,10 @@ namespace CreatureLib::Battling { return _attack; } - void GetActiveScripts(ScriptAggregator &aggr) const override { - aggr.Add(_script); + protected: + void GetActiveScripts(std::vector &scripts) override { + scripts.emplace_back(&_script); + GetUser()->GetActiveScripts(scripts); } }; } diff --git a/src/Battling/ScriptHandling/ScriptAggregator.hpp b/src/Battling/ScriptHandling/ScriptAggregator.hpp index 1d7b09f..0e0654f 100644 --- a/src/Battling/ScriptHandling/ScriptAggregator.hpp +++ b/src/Battling/ScriptHandling/ScriptAggregator.hpp @@ -6,26 +6,23 @@ #include "Script.hpp" #include "ScriptSet.hpp" #include "../../Core/Exceptions/NotReachableException.hpp" +#include "ScriptWrapper.hpp" namespace CreatureLib::Battling{ class ScriptAggregator{ - std::queue _queue; + __gnu_cxx::__normal_iterator> _selfIterator; + __gnu_cxx::__normal_iterator> _selfEnd; bool _isSetSet = false; std::__detail::_Node_const_iterator, false, true> _setIterator; std::__detail::_Node_const_iterator, false, true> _setEnd; public: - ScriptAggregator() = default; - - void Add(Script* script){ - _queue.push(script); - } - - void Add(const ScriptSet* scriptSet){ - _queue.push(scriptSet); - } + ScriptAggregator(std::vector scripts){ + _selfIterator = scripts.begin(); + _selfEnd = scripts.end(); + }; bool HasNext(){ - return !_queue.empty() || _isSetSet; + return _selfIterator != _selfEnd || _isSetSet; } Script* GetNext(){ @@ -42,15 +39,17 @@ namespace CreatureLib::Battling{ } return s; } - if (_queue.empty()) + if (_selfIterator == _selfEnd) return nullptr; - auto next = _queue.front(); - _queue.pop(); - if (next.type() == typeid(Script*)){ - return std::any_cast(next); + auto next = *_selfIterator; + if (!next.IsSet()){ + auto scriptPtr = next.GetScript(); + if (scriptPtr == nullptr) + return GetNext(); + return *scriptPtr; } else{ - auto set = std::any_cast(next); + auto set = next.GetScriptSet(); if (set->Count() == 0) return GetNext(); auto it = set->GetIterator(); diff --git a/src/Battling/ScriptHandling/ScriptMacros.cpp b/src/Battling/ScriptHandling/ScriptMacros.cpp index d4d89f4..ca5b288 100644 --- a/src/Battling/ScriptHandling/ScriptMacros.cpp +++ b/src/Battling/ScriptHandling/ScriptMacros.cpp @@ -1,7 +1,6 @@ #define HOOK(hookName, source, ... ) \ { \ -auto aggregator = CreatureLib::Battling::ScriptAggregator(); \ -source -> GetActiveScripts(aggregator); \ +auto aggregator = source -> GetScriptIterator(); \ while (aggregator.HasNext()){ \ auto next = aggregator.GetNext(); \ if (next == nullptr) continue; \ diff --git a/src/Battling/ScriptHandling/ScriptSource.hpp b/src/Battling/ScriptHandling/ScriptSource.hpp index 9a8d3de..0e964a9 100644 --- a/src/Battling/ScriptHandling/ScriptSource.hpp +++ b/src/Battling/ScriptHandling/ScriptSource.hpp @@ -7,8 +7,18 @@ namespace CreatureLib::Battling{ class ScriptSource { + bool _areScriptsInitialized = false; + std::vector _scripts; + protected: + virtual void GetActiveScripts(std::vector& scripts) = 0; public: - virtual void GetActiveScripts(ScriptAggregator& aggr) const = 0; + ScriptAggregator GetScriptIterator(){ + if (!_areScriptsInitialized){ + GetActiveScripts(_scripts); + _areScriptsInitialized = true; + } + return ScriptAggregator(_scripts); + } }; } diff --git a/src/Battling/ScriptHandling/ScriptWrapper.cpp b/src/Battling/ScriptHandling/ScriptWrapper.cpp new file mode 100644 index 0000000..aaef513 --- /dev/null +++ b/src/Battling/ScriptHandling/ScriptWrapper.cpp @@ -0,0 +1,3 @@ + + +#include "ScriptWrapper.hpp" diff --git a/src/Battling/ScriptHandling/ScriptWrapper.hpp b/src/Battling/ScriptHandling/ScriptWrapper.hpp new file mode 100644 index 0000000..412211a --- /dev/null +++ b/src/Battling/ScriptHandling/ScriptWrapper.hpp @@ -0,0 +1,33 @@ + + +#ifndef CREATURELIB_SCRIPTWRAPPER_HPP +#define CREATURELIB_SCRIPTWRAPPER_HPP + +#include +#include "Script.hpp" +#include "ScriptSet.hpp" + +namespace CreatureLib::Battling{ + class ScriptWrapper { + std::variant _value; + bool _isSet; + public: + ScriptWrapper(Script** s) : _value(s), _isSet(false){} + ScriptWrapper(ScriptSet* s) : _value(s), _isSet(true){} + + bool IsSet() const{ + return _isSet; + } + + Script** GetScript() const{ + return std::get(_value); + } + + ScriptSet* GetScriptSet() const{ + return std::get(_value); + } + }; +} + + +#endif //CREATURELIB_SCRIPTWRAPPER_HPP diff --git a/src/Battling/TurnChoices/AttackTurnChoice.hpp b/src/Battling/TurnChoices/AttackTurnChoice.hpp index 3c1fe8b..b5dacfa 100644 --- a/src/Battling/TurnChoices/AttackTurnChoice.hpp +++ b/src/Battling/TurnChoices/AttackTurnChoice.hpp @@ -31,10 +31,12 @@ namespace CreatureLib::Battling{ return _target; } - void GetActiveScripts(ScriptAggregator &aggr) const override { - aggr.Add(_attackScript); - GetUser()->GetActiveScripts(aggr); + protected: + void GetActiveScripts(std::vector &scripts) override { + scripts.emplace_back(&_attackScript); + GetUser()->GetActiveScripts(scripts); } + }; } diff --git a/src/Battling/TurnChoices/BaseTurnChoice.hpp b/src/Battling/TurnChoices/BaseTurnChoice.hpp index bdd0db9..5058b84 100644 --- a/src/Battling/TurnChoices/BaseTurnChoice.hpp +++ b/src/Battling/TurnChoices/BaseTurnChoice.hpp @@ -17,10 +17,6 @@ namespace CreatureLib::Battling{ [[nodiscard]] inline Creature* GetUser() const{ return _user; } - - void GetActiveScripts(ScriptAggregator &aggr) const override { - - } }; } diff --git a/src/Battling/TurnChoices/PassTurnChoice.hpp b/src/Battling/TurnChoices/PassTurnChoice.hpp index 60b3118..2342334 100644 --- a/src/Battling/TurnChoices/PassTurnChoice.hpp +++ b/src/Battling/TurnChoices/PassTurnChoice.hpp @@ -12,8 +12,9 @@ namespace CreatureLib::Battling { return TurnChoiceKind ::Pass; } - void GetActiveScripts(ScriptAggregator &aggr) const override { - GetUser()->GetActiveScripts(aggr); + protected: + void GetActiveScripts(std::vector &scripts) override { + GetUser()->GetActiveScripts(scripts); } }; } diff --git a/tests/BattleTests/TurnOrderTests.cpp b/tests/BattleTests/TurnOrderTests.cpp index d888084..0f3f7f2 100644 --- a/tests/BattleTests/TurnOrderTests.cpp +++ b/tests/BattleTests/TurnOrderTests.cpp @@ -11,12 +11,12 @@ using namespace CreatureLib::Battling; TEST_CASE( "Turn ordering: Attack before pass", "[Battling]" ) { auto choice1 = new PassTurnChoice(nullptr); auto choice2 = new AttackTurnChoice(nullptr, nullptr, Target(0,0)); - auto vec = std::vector{choice1, choice2}; + auto vec = std::vector{choice1, choice2}; auto rand = Core::Random(); TurnOrdering::OrderChoices(vec,rand); CHECK(vec[0] == choice2); CHECK(vec[1] == choice1); - vec = std::vector{choice2, choice1}; + vec = std::vector{choice2, choice1}; TurnOrdering::OrderChoices(vec,rand); CHECK(vec[0] == choice2); CHECK(vec[1] == choice1); @@ -31,12 +31,12 @@ TEST_CASE( "Turn ordering: High priority goes before no priority", "[Battling]" auto a2 = new LearnedAttack(l->GetAttack("highPriority"), AttackLearnMethod::Unknown); auto choice1 = new AttackTurnChoice(nullptr, a1, Target(0,0)); auto choice2 = new AttackTurnChoice(nullptr, a2, Target(0,0)); - auto vec = std::vector{choice1, choice2}; + auto vec = std::vector{choice1, choice2}; auto rand = Core::Random(); TurnOrdering::OrderChoices(vec,rand); CHECK(vec[0] == choice2); CHECK(vec[1] == choice1); - vec = std::vector{choice2, choice1}; + vec = std::vector{choice2, choice1}; TurnOrdering::OrderChoices(vec,rand); CHECK(vec[0] == choice2); CHECK(vec[1] == choice1); @@ -53,12 +53,12 @@ TEST_CASE( "Turn ordering: Higher priority goes before high priority", "[Battlin auto a2 = new LearnedAttack(l->GetAttack("higherPriority"), AttackLearnMethod::Unknown); auto choice1 = new AttackTurnChoice(nullptr, a1, Target(0,0)); auto choice2 = new AttackTurnChoice(nullptr, a2, Target(0,0)); - auto vec = std::vector{choice1, choice2}; + auto vec = std::vector{choice1, choice2}; auto rand = Core::Random(); TurnOrdering::OrderChoices(vec,rand); CHECK(vec[0] == choice2); CHECK(vec[1] == choice1); - vec = std::vector{choice2, choice1}; + vec = std::vector{choice2, choice1}; TurnOrdering::OrderChoices(vec,rand); CHECK(vec[0] == choice2); CHECK(vec[1] == choice1); @@ -75,12 +75,12 @@ TEST_CASE( "Turn ordering: High priority goes before low priority", "[Battling]" auto a2 = new LearnedAttack(l->GetAttack("higherPriority"), AttackLearnMethod::Unknown); auto choice1 = new AttackTurnChoice(nullptr, a1, Target(0,0)); auto choice2 = new AttackTurnChoice(nullptr, a2, Target(0,0)); - auto vec = std::vector{choice1, choice2}; + auto vec = std::vector{choice1, choice2}; auto rand = Core::Random(); TurnOrdering::OrderChoices(vec,rand); CHECK(vec[0] == choice2); CHECK(vec[1] == choice1); - vec = std::vector{choice2, choice1}; + vec = std::vector{choice2, choice1}; TurnOrdering::OrderChoices(vec,rand); CHECK(vec[0] == choice2); CHECK(vec[1] == choice1); @@ -97,12 +97,12 @@ TEST_CASE( "Turn ordering: No priority goes before low priority", "[Battling]" ) auto a2 = new LearnedAttack(l->GetAttack("standard"), AttackLearnMethod::Unknown); auto choice1 = new AttackTurnChoice(nullptr, a1, Target(0,0)); auto choice2 = new AttackTurnChoice(nullptr, a2, Target(0,0)); - auto vec = std::vector{choice1, choice2}; + auto vec = std::vector{choice1, choice2}; auto rand = Core::Random(); TurnOrdering::OrderChoices(vec,rand); CHECK(vec[0] == choice2); CHECK(vec[1] == choice1); - vec = std::vector{choice2, choice1}; + vec = std::vector{choice2, choice1}; TurnOrdering::OrderChoices(vec,rand); CHECK(vec[0] == choice2); CHECK(vec[1] == choice1);