diff --git a/src/modules/Bots/playerbot/strategy/Action.h b/src/modules/Bots/playerbot/strategy/Action.h index e4e5ded4d..5ba79227d 100644 --- a/src/modules/Bots/playerbot/strategy/Action.h +++ b/src/modules/Bots/playerbot/strategy/Action.h @@ -112,13 +112,13 @@ namespace ai class ActionBasket { public: - ActionBasket(ActionNode* action, float relevance, bool skipPrerequisites, Event event) : + ActionBasket(ActionNode* action, float relevance, bool skipPrerequisites, const Event& event) : action(action), relevance(relevance), skipPrerequisites(skipPrerequisites), event(event) {} virtual ~ActionBasket(void) {} public: float getRelevance() {return relevance;} ActionNode* getAction() {return action;} - Event getEvent() { return event; } + const Event& getEvent() { return event; } bool isSkipPrerequisites() { return skipPrerequisites; } void AmendRelevance(float k) {relevance *= k; } void setRelevance(float relevance) { this->relevance = relevance; } diff --git a/src/modules/Bots/playerbot/strategy/Engine.cpp b/src/modules/Bots/playerbot/strategy/Engine.cpp index 992732b60..7b7559bbd 100755 --- a/src/modules/Bots/playerbot/strategy/Engine.cpp +++ b/src/modules/Bots/playerbot/strategy/Engine.cpp @@ -12,10 +12,11 @@ Engine::Engine(PlayerbotAI* ai, AiObjectContext *factory) : PlayerbotAIAware(ai) { lastRelevance = 0.0f; testMode = false; + strategiesDirty = false; } // Executes actions before the main action -bool ActionExecutionListeners::Before(Action* action, Event event) +bool ActionExecutionListeners::Before(Action* action, const Event& event) { bool result = true; for (list::iterator i = listeners.begin(); i!=listeners.end(); i++) @@ -26,7 +27,7 @@ bool ActionExecutionListeners::Before(Action* action, Event event) } // Executes actions after the main action -void ActionExecutionListeners::After(Action* action, bool executed, Event event) +void ActionExecutionListeners::After(Action* action, bool executed, const Event& event) { for (list::iterator i = listeners.begin(); i!=listeners.end(); i++) { @@ -35,7 +36,7 @@ void ActionExecutionListeners::After(Action* action, bool executed, Event event) } // Overrides the result of the action execution -bool ActionExecutionListeners::OverrideResult(Action* action, bool executed, Event event) +bool ActionExecutionListeners::OverrideResult(Action* action, bool executed, const Event& event) { bool result = executed; for (list::iterator i = listeners.begin(); i!=listeners.end(); i++) @@ -46,7 +47,7 @@ bool ActionExecutionListeners::OverrideResult(Action* action, bool executed, Eve } // Checks if the action execution is allowed -bool ActionExecutionListeners::AllowExecution(Action* action, Event event) +bool ActionExecutionListeners::AllowExecution(Action* action, const Event& event) { bool result = true; for (list::iterator i = listeners.begin(); i!=listeners.end(); i++) @@ -71,6 +72,16 @@ Engine::~Engine(void) { Reset(); strategies.clear(); + ClearActionNodeCache(); +} + +void Engine::ClearActionNodeCache() +{ + for (unordered_map::iterator i = actionNodeCache.begin(); i != actionNodeCache.end(); i++) + { + delete i->second; + } + actionNodeCache.clear(); } // Resets the engine by clearing the action queue, triggers, and multipliers @@ -79,8 +90,7 @@ void Engine::Reset() ActionNode* action = NULL; do { - action = queue.Pop(); - delete action; + action = queue.Pop(); // popped from queue, remain in cache } while (action != NULL); for (list::iterator i = triggers.begin(); i != triggers.end(); i++) @@ -98,10 +108,18 @@ void Engine::Reset() multipliers.clear(); } -// Initializes the engine by resetting it and initializing strategies +// Marks the engine for reinitialization at the next DoNextAction entry void Engine::Init() +{ + strategiesDirty = true; +} + +// Initializes strategies, triggers, multipliers, and default actions +void Engine::InitStrategies() { Reset(); + ClearActionNodeCache(); + strategiesDirty = false; for (map::iterator i = strategies.begin(); i != strategies.end(); i++) { @@ -132,6 +150,11 @@ bool Engine::DoNextAction(Unit* unit, int depth) bool actionExecuted = false; ActionBasket* basket = NULL; + if (strategiesDirty) + { + InitStrategies(); + } + time_t currentTime = time(0); aiObjectContext->Update(); ProcessTriggers(); @@ -188,7 +211,6 @@ bool Engine::DoNextAction(Unit* unit, int depth) LogAction("A:%s - OK", action->getName().c_str()); MultiplyAndPush(actionNode->getContinuers(), 0, false, event); lastRelevance = relevance; - delete actionNode; break; } else @@ -208,7 +230,6 @@ bool Engine::DoNextAction(Unit* unit, int depth) lastRelevance = relevance; LogAction("A:%s - USELESS", action->getName().c_str()); } - delete actionNode; } } while (basket); @@ -240,23 +261,30 @@ bool Engine::DoNextAction(Unit* unit, int depth) // Creates an action node based on the action name ActionNode* Engine::CreateActionNode(string name) { + unordered_map::iterator cached = actionNodeCache.find(name); + if (cached != actionNodeCache.end()) + { + return cached->second; + } + + ActionNode* node = NULL; for (map::iterator i = strategies.begin(); i != strategies.end(); i++) { - Strategy* strategy = i->second; - ActionNode* node = strategy->GetAction(name); + node = i->second->GetAction(name); if (node) - { - return node; - } + break; + } + if (!node) + { + node = new ActionNode(name, /*P*/ NULL, /*A*/ NULL, /*C*/ NULL); } - return new ActionNode (name, - /*P*/ NULL, - /*A*/ NULL, - /*C*/ NULL); + + actionNodeCache[name] = node; + return node; } // Multiplies the relevance of actions and pushes them to the queue -bool Engine::MultiplyAndPush(NextAction** actions, float forceRelevance, bool skipPrerequisites, Event event) +bool Engine::MultiplyAndPush(NextAction** actions, float forceRelevance, bool skipPrerequisites, const Event& event) { bool pushed = false; if (actions) @@ -281,11 +309,6 @@ bool Engine::MultiplyAndPush(NextAction** actions, float forceRelevance, bool sk queue.Push(new ActionBasket(action, k, skipPrerequisites, event)); pushed = true; } - else - { - delete action; - } - delete nextAction; } else @@ -317,13 +340,11 @@ ActionResult Engine::ExecuteAction(string &name) if (!action->isPossible()) { - delete actionNode; return ACTION_RESULT_IMPOSSIBLE; } if (!action->isUseful()) { - delete actionNode; return ACTION_RESULT_USELESS; } @@ -331,7 +352,6 @@ ActionResult Engine::ExecuteAction(string &name) Event emptyEvent; result = ListenAndExecute(action, emptyEvent); MultiplyAndPush(action->getContinuers(), 0.0f, false, emptyEvent); - delete actionNode; return result ? ACTION_RESULT_OK : ACTION_RESULT_FAILED; } @@ -487,13 +507,12 @@ string Engine::ListStrategies() } // Pushes an action node to the queue again -void Engine::PushAgain(ActionNode* actionNode, float relevance, Event event) +void Engine::PushAgain(ActionNode* actionNode, float relevance, const Event& event) { NextAction** nextAction = new NextAction*[2]; nextAction[0] = new NextAction(actionNode->getName(), relevance); nextAction[1] = NULL; MultiplyAndPush(nextAction, relevance, true, event); - delete actionNode; } // Checks if the engine contains a specific strategy type @@ -523,7 +542,7 @@ Action* Engine::InitializeAction(ActionNode* actionNode) } // Listens and executes an action -bool Engine::ListenAndExecute(Action* action, Event event) +bool Engine::ListenAndExecute(Action* action, const Event& event) { bool actionExecuted = false; diff --git a/src/modules/Bots/playerbot/strategy/Engine.h b/src/modules/Bots/playerbot/strategy/Engine.h index 48014132e..5677b7375 100644 --- a/src/modules/Bots/playerbot/strategy/Engine.h +++ b/src/modules/Bots/playerbot/strategy/Engine.h @@ -1,5 +1,6 @@ #pragma once +#include #include "Action.h" #include "Queue.h" #include "Trigger.h" @@ -16,10 +17,10 @@ namespace ai { public: virtual ~ActionExecutionListener() = default; // Add a virtual destructor - virtual bool Before(Action* action, Event event) = 0; - virtual bool AllowExecution(Action* action, Event event) = 0; - virtual void After(Action* action, bool executed, Event event) = 0; - virtual bool OverrideResult(Action* action, bool executed, Event event) = 0; + virtual bool Before(Action* action, const Event& event) = 0; + virtual bool AllowExecution(Action* action, const Event& event) = 0; + virtual void After(Action* action, bool executed, const Event& event) = 0; + virtual bool OverrideResult(Action* action, bool executed, const Event& event) = 0; }; // ----------------------------------------------------------------------------------------------------------------------- @@ -34,10 +35,10 @@ namespace ai // ActionExecutionListener public: - virtual bool Before(Action* action, Event event); - virtual bool AllowExecution(Action* action, Event event); - virtual void After(Action* action, bool executed, Event event); - virtual bool OverrideResult(Action* action, bool executed, Event event); + virtual bool Before(Action* action, const Event& event); + virtual bool AllowExecution(Action* action, const Event& event); + virtual void After(Action* action, bool executed, const Event& event); + virtual bool OverrideResult(Action* action, bool executed, const Event& event); public: /** @@ -127,14 +128,16 @@ namespace ai virtual ~Engine(void); private: - bool MultiplyAndPush(NextAction** actions, float forceRelevance, bool skipPrerequisites, Event event); + bool MultiplyAndPush(NextAction** actions, float forceRelevance, bool skipPrerequisites, const Event& event); void Reset(); void ProcessTriggers(); void PushDefaultActions(); - void PushAgain(ActionNode* actionNode, float relevance, Event event); + void PushAgain(ActionNode* actionNode, float relevance, const Event& event); ActionNode* CreateActionNode(string name); Action* InitializeAction(ActionNode* actionNode); - bool ListenAndExecute(Action* action, Event event); + bool ListenAndExecute(Action* action, const Event& event); + void ClearActionNodeCache(); + void InitStrategies(); private: void LogAction(const char* format, ...); @@ -146,8 +149,10 @@ namespace ai std::list multipliers; /**< List of multipliers */ AiObjectContext* aiObjectContext; /**< AI object context */ std::map strategies; /**< Map of strategies */ + std::unordered_map actionNodeCache; /**< Cache of action nodes by name */ float lastRelevance; /**< Last relevance value */ std::string lastAction; /**< Last executed action */ + bool strategiesDirty; /**< True when strategies changed and ActualInit() is pending */ public: bool testMode; /**< Flag for test mode */ diff --git a/src/modules/Bots/playerbot/strategy/Event.h b/src/modules/Bots/playerbot/strategy/Event.h index 0757c6dc0..dca4d503a 100644 --- a/src/modules/Bots/playerbot/strategy/Event.h +++ b/src/modules/Bots/playerbot/strategy/Event.h @@ -62,14 +62,14 @@ namespace ai * * @return string The source of the event */ - string getSource() { return source; } + const string& getSource() { return source; } /** * @brief Get the parameter of the event * * @return string The parameter of the event */ - string getParam() { return param; } + const string& getParam() { return param; } /** * @brief Get the packet associated with the event diff --git a/src/modules/Bots/playerbot/strategy/NamedObjectContext.h b/src/modules/Bots/playerbot/strategy/NamedObjectContext.h index 77bf1beb8..8aa5b7529 100644 --- a/src/modules/Bots/playerbot/strategy/NamedObjectContext.h +++ b/src/modules/Bots/playerbot/strategy/NamedObjectContext.h @@ -1,5 +1,8 @@ #pragma once +#include +#include + namespace ai { using namespace std; @@ -20,7 +23,7 @@ namespace ai { protected: typedef T* (*ActionCreator) (PlayerbotAI* ai); - map creators; + unordered_map creators; public: T* create(string name, PlayerbotAI* ai) @@ -57,7 +60,7 @@ namespace ai set supports() { set keys; - for (typename map::iterator it = creators.begin(); it != creators.end(); it++) + for (typename unordered_map::iterator it = creators.begin(); it != creators.end(); it++) { keys.insert(it->first); } @@ -76,7 +79,11 @@ namespace ai { if (created.find(name) == created.end()) { - return created[name] = NamedObjectFactory::create(name, ai); + T* obj = NamedObjectFactory::create(name, ai); + created[name] = obj; + if (obj) + createdList.push_back(obj); + return obj; } return created[name]; @@ -89,36 +96,28 @@ namespace ai void Clear() { - for (typename map::iterator i = created.begin(); i != created.end(); i++) + for (typename vector::iterator i = createdList.begin(); i != createdList.end(); i++) { - if (i->second) - { - delete i->second; - } + delete *i; } + createdList.clear(); created.clear(); } void Update() { - for (typename map::iterator i = created.begin(); i != created.end(); i++) + for (typename vector::iterator i = createdList.begin(); i != createdList.end(); i++) { - if (i->second) - { - i->second->Update(); - } + (*i)->Update(); } } void Reset() { - for (typename map::iterator i = created.begin(); i != created.end(); i++) + for (typename vector::iterator i = createdList.begin(); i != createdList.end(); i++) { - if (i->second) - { - i->second->Reset(); - } + (*i)->Reset(); } } @@ -128,7 +127,7 @@ namespace ai set GetCreated() { set keys; - for (typename map::iterator it = created.begin(); it != created.end(); it++) + for (typename unordered_map::iterator it = created.begin(); it != created.end(); it++) { keys.insert(it->first); } @@ -136,7 +135,8 @@ namespace ai } protected: - map created; + unordered_map created; + vector createdList; bool shared; bool supportsSiblings; }; diff --git a/src/modules/Bots/playerbot/strategy/Queue.cpp b/src/modules/Bots/playerbot/strategy/Queue.cpp index 3834efe59..b65f9c663 100644 --- a/src/modules/Bots/playerbot/strategy/Queue.cpp +++ b/src/modules/Bots/playerbot/strategy/Queue.cpp @@ -19,7 +19,6 @@ void Queue::Push(ActionBasket *action) { basket->setRelevance(action->getRelevance()); } - delete action->getAction(); delete action; return; }