Another rework for scripthooks, for better performance.
continuous-integration/drone/push Build is passing
Details
continuous-integration/drone/push Build is passing
Details
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.
This commit is contained in:
parent
e1a8d80863
commit
d8332f9e40
|
@ -7,12 +7,12 @@
|
|||
|
||||
namespace CreatureLib::Battling{
|
||||
class ChoiceQueue {
|
||||
std::vector<const BaseTurnChoice*> _queue;
|
||||
std::vector<BaseTurnChoice*> _queue;
|
||||
size_t _current = 0;
|
||||
public:
|
||||
bool HasCompletedQueue = false;
|
||||
|
||||
explicit ChoiceQueue(std::vector<const BaseTurnChoice*> queue)
|
||||
explicit ChoiceQueue(std::vector<BaseTurnChoice*> queue)
|
||||
:_queue(std::move(queue)){}
|
||||
|
||||
const BaseTurnChoice* Dequeue(){
|
||||
|
@ -25,7 +25,7 @@ namespace CreatureLib::Battling{
|
|||
return _current < _queue.size();
|
||||
}
|
||||
|
||||
std::vector<const BaseTurnChoice*>& GetInnerQueue(){
|
||||
std::vector<BaseTurnChoice*>& GetInnerQueue(){
|
||||
return _queue;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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 <algorithm>
|
||||
|
||||
|
@ -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<const AttackTurnChoice*>(a)->GetPriority();
|
||||
auto bPriority = static_cast<const AttackTurnChoice*>(b)->GetPriority();
|
||||
auto aPriority = dynamic_cast<const AttackTurnChoice*>(a)->GetPriority();
|
||||
auto bPriority = dynamic_cast<const AttackTurnChoice*>(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<const BaseTurnChoice *> &vec, Core::Random& rand) {
|
||||
void TurnOrdering::OrderChoices(std::vector<BaseTurnChoice *> &vec, Core::Random& rand) {
|
||||
auto comp = [&](const BaseTurnChoice * a,const BaseTurnChoice * b)-> bool {
|
||||
return ___ChoiceOrderFunc(a,b,rand);
|
||||
};
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
namespace CreatureLib::Battling {
|
||||
class TurnOrdering {
|
||||
public:
|
||||
static void OrderChoices(std::vector<const BaseTurnChoice*>& vec, CreatureLib::Core::Random& rand);
|
||||
static void OrderChoices(std::vector<BaseTurnChoice*>& vec, CreatureLib::Core::Random& rand);
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -33,10 +33,10 @@ void Battle::CheckChoicesSetAndRun() {
|
|||
return;
|
||||
}
|
||||
}
|
||||
auto choices = std::vector<const BaseTurnChoice*>(_numberOfSides * _creaturesPerSide);
|
||||
auto choices = std::vector<BaseTurnChoice*>(_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<const AttackTurnChoice*>(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<ScriptWrapper> &scripts) {
|
||||
scripts.emplace_back(&_volatile);
|
||||
}
|
||||
|
|
|
@ -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<ScriptWrapper> &scripts) override;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -16,11 +16,11 @@ void BattleSide::ResetChoices() {
|
|||
}
|
||||
}
|
||||
|
||||
const std::vector<const BaseTurnChoice *>& BattleSide::GetChoices() const{
|
||||
const std::vector<BaseTurnChoice *>& 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<ScriptWrapper> &scripts) {
|
||||
scripts.emplace_back(&_volatile);
|
||||
_battle->GetActiveScripts(scripts);
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ namespace CreatureLib::Battling{
|
|||
class BattleSide : public ScriptSource{
|
||||
uint8_t _creaturesPerSide;
|
||||
std::vector<Creature*> _creatures;
|
||||
std::vector<const BaseTurnChoice*> _choices;
|
||||
std::vector<BaseTurnChoice*> _choices;
|
||||
uint8_t _choicesSet = 0;
|
||||
ScriptSet _volatile;
|
||||
Battle* _battle;
|
||||
|
@ -21,9 +21,9 @@ namespace CreatureLib::Battling{
|
|||
}
|
||||
|
||||
[[nodiscard]] bool AllChoicesSet() const;
|
||||
[[nodiscard]] const std::vector<const BaseTurnChoice*>& GetChoices() const;
|
||||
[[nodiscard]] const std::vector<BaseTurnChoice*>& 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<ScriptWrapper> &scripts) override;
|
||||
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include <algorithm>
|
||||
#include <utility>
|
||||
#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<ScriptWrapper> &scripts) {
|
||||
scripts.emplace_back(&_status);
|
||||
scripts.emplace_back(&_volatile);
|
||||
_side->GetActiveScripts(scripts);
|
||||
}
|
||||
|
|
|
@ -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<uint8_t >, StatExperience);
|
||||
|
@ -67,7 +68,7 @@ namespace CreatureLib::Battling{
|
|||
[[nodiscard]] const std::vector<uint8_t>& GetTypes() const;
|
||||
[[nodiscard]] bool HasType(uint8_t type) const;
|
||||
|
||||
void GetActiveScripts(ScriptAggregator& aggr) const override;
|
||||
void GetActiveScripts(std::vector<ScriptWrapper> &scripts) override;
|
||||
|
||||
//region Stat APIs
|
||||
|
||||
|
@ -85,6 +86,7 @@ namespace CreatureLib::Battling{
|
|||
void RecalculateBoostedStats();
|
||||
void RecalculateFlatStat(Core::Statistic);
|
||||
void RecalculateBoostedStat(Core::Statistic);
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
|
|
@ -89,8 +89,10 @@ namespace CreatureLib::Battling {
|
|||
return _attack;
|
||||
}
|
||||
|
||||
void GetActiveScripts(ScriptAggregator &aggr) const override {
|
||||
aggr.Add(_script);
|
||||
protected:
|
||||
void GetActiveScripts(std::vector<ScriptWrapper> &scripts) override {
|
||||
scripts.emplace_back(&_script);
|
||||
GetUser()->GetActiveScripts(scripts);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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<std::any> _queue;
|
||||
__gnu_cxx::__normal_iterator<ScriptWrapper *, std::vector<ScriptWrapper>> _selfIterator;
|
||||
__gnu_cxx::__normal_iterator<ScriptWrapper *, std::vector<ScriptWrapper>> _selfEnd;
|
||||
bool _isSetSet = false;
|
||||
std::__detail::_Node_const_iterator<std::pair<const std::string, Script *>, false, true> _setIterator;
|
||||
std::__detail::_Node_const_iterator<std::pair<const std::string, Script *>, false, true> _setEnd;
|
||||
public:
|
||||
ScriptAggregator() = default;
|
||||
|
||||
void Add(Script* script){
|
||||
_queue.push(script);
|
||||
}
|
||||
|
||||
void Add(const ScriptSet* scriptSet){
|
||||
_queue.push(scriptSet);
|
||||
}
|
||||
ScriptAggregator(std::vector<ScriptWrapper> 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<Script*>(next);
|
||||
auto next = *_selfIterator;
|
||||
if (!next.IsSet()){
|
||||
auto scriptPtr = next.GetScript();
|
||||
if (scriptPtr == nullptr)
|
||||
return GetNext();
|
||||
return *scriptPtr;
|
||||
}
|
||||
else{
|
||||
auto set = std::any_cast<const ScriptSet*>(next);
|
||||
auto set = next.GetScriptSet();
|
||||
if (set->Count() == 0)
|
||||
return GetNext();
|
||||
auto it = set->GetIterator();
|
||||
|
|
|
@ -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; \
|
||||
|
|
|
@ -7,8 +7,18 @@
|
|||
|
||||
namespace CreatureLib::Battling{
|
||||
class ScriptSource {
|
||||
bool _areScriptsInitialized = false;
|
||||
std::vector<ScriptWrapper> _scripts;
|
||||
protected:
|
||||
virtual void GetActiveScripts(std::vector<ScriptWrapper>& scripts) = 0;
|
||||
public:
|
||||
virtual void GetActiveScripts(ScriptAggregator& aggr) const = 0;
|
||||
ScriptAggregator GetScriptIterator(){
|
||||
if (!_areScriptsInitialized){
|
||||
GetActiveScripts(_scripts);
|
||||
_areScriptsInitialized = true;
|
||||
}
|
||||
return ScriptAggregator(_scripts);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
|
||||
#include "ScriptWrapper.hpp"
|
|
@ -0,0 +1,33 @@
|
|||
|
||||
|
||||
#ifndef CREATURELIB_SCRIPTWRAPPER_HPP
|
||||
#define CREATURELIB_SCRIPTWRAPPER_HPP
|
||||
|
||||
#include <variant>
|
||||
#include "Script.hpp"
|
||||
#include "ScriptSet.hpp"
|
||||
|
||||
namespace CreatureLib::Battling{
|
||||
class ScriptWrapper {
|
||||
std::variant<Script**, ScriptSet*> _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<Script**>(_value);
|
||||
}
|
||||
|
||||
ScriptSet* GetScriptSet() const{
|
||||
return std::get<ScriptSet*>(_value);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#endif //CREATURELIB_SCRIPTWRAPPER_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<ScriptWrapper> &scripts) override {
|
||||
scripts.emplace_back(&_attackScript);
|
||||
GetUser()->GetActiveScripts(scripts);
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -17,10 +17,6 @@ namespace CreatureLib::Battling{
|
|||
[[nodiscard]] inline Creature* GetUser() const{
|
||||
return _user;
|
||||
}
|
||||
|
||||
void GetActiveScripts(ScriptAggregator &aggr) const override {
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -12,8 +12,9 @@ namespace CreatureLib::Battling {
|
|||
return TurnChoiceKind ::Pass;
|
||||
}
|
||||
|
||||
void GetActiveScripts(ScriptAggregator &aggr) const override {
|
||||
GetUser()->GetActiveScripts(aggr);
|
||||
protected:
|
||||
void GetActiveScripts(std::vector<ScriptWrapper> &scripts) override {
|
||||
GetUser()->GetActiveScripts(scripts);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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<const BaseTurnChoice*>{choice1, choice2};
|
||||
auto vec = std::vector<BaseTurnChoice*>{choice1, choice2};
|
||||
auto rand = Core::Random();
|
||||
TurnOrdering::OrderChoices(vec,rand);
|
||||
CHECK(vec[0] == choice2);
|
||||
CHECK(vec[1] == choice1);
|
||||
vec = std::vector<const BaseTurnChoice*>{choice2, choice1};
|
||||
vec = std::vector<BaseTurnChoice*>{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<const BaseTurnChoice*>{choice1, choice2};
|
||||
auto vec = std::vector<BaseTurnChoice*>{choice1, choice2};
|
||||
auto rand = Core::Random();
|
||||
TurnOrdering::OrderChoices(vec,rand);
|
||||
CHECK(vec[0] == choice2);
|
||||
CHECK(vec[1] == choice1);
|
||||
vec = std::vector<const BaseTurnChoice*>{choice2, choice1};
|
||||
vec = std::vector<BaseTurnChoice*>{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<const BaseTurnChoice*>{choice1, choice2};
|
||||
auto vec = std::vector<BaseTurnChoice*>{choice1, choice2};
|
||||
auto rand = Core::Random();
|
||||
TurnOrdering::OrderChoices(vec,rand);
|
||||
CHECK(vec[0] == choice2);
|
||||
CHECK(vec[1] == choice1);
|
||||
vec = std::vector<const BaseTurnChoice*>{choice2, choice1};
|
||||
vec = std::vector<BaseTurnChoice*>{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<const BaseTurnChoice*>{choice1, choice2};
|
||||
auto vec = std::vector<BaseTurnChoice*>{choice1, choice2};
|
||||
auto rand = Core::Random();
|
||||
TurnOrdering::OrderChoices(vec,rand);
|
||||
CHECK(vec[0] == choice2);
|
||||
CHECK(vec[1] == choice1);
|
||||
vec = std::vector<const BaseTurnChoice*>{choice2, choice1};
|
||||
vec = std::vector<BaseTurnChoice*>{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<const BaseTurnChoice*>{choice1, choice2};
|
||||
auto vec = std::vector<BaseTurnChoice*>{choice1, choice2};
|
||||
auto rand = Core::Random();
|
||||
TurnOrdering::OrderChoices(vec,rand);
|
||||
CHECK(vec[0] == choice2);
|
||||
CHECK(vec[1] == choice1);
|
||||
vec = std::vector<const BaseTurnChoice*>{choice2, choice1};
|
||||
vec = std::vector<BaseTurnChoice*>{choice2, choice1};
|
||||
TurnOrdering::OrderChoices(vec,rand);
|
||||
CHECK(vec[0] == choice2);
|
||||
CHECK(vec[1] == choice1);
|
||||
|
|
Loading…
Reference in New Issue