From 0c2f14d97fb01619055cf9fb91357e5c1a31e1dc Mon Sep 17 00:00:00 2001 From: blinkysc <37940565+blinkysc@users.noreply.github.com> Date: Fri, 24 Jan 2025 12:09:12 -0600 Subject: [PATCH] Refactor Bot engine Queue (#895) * Update Queue.cpp * Update Queue.h --- src/strategy/Queue.cpp | 144 +++++++++++++++++++++++++---------------- src/strategy/Queue.h | 76 ++++++++++++++++++++-- 2 files changed, 158 insertions(+), 62 deletions(-) diff --git a/src/strategy/Queue.cpp b/src/strategy/Queue.cpp index 7ffc3ae1..b2c6e88d 100644 --- a/src/strategy/Queue.cpp +++ b/src/strategy/Queue.cpp @@ -4,72 +4,93 @@ */ #include "Queue.h" - #include "AiObjectContext.h" #include "Log.h" #include "PlayerbotAIConfig.h" void Queue::Push(ActionBasket* action) { - if (action) + if (!action) { - for (std::list::iterator iter = actions.begin(); iter != actions.end(); iter++) - { - ActionBasket* basket = *iter; - if (action->getAction()->getName() == basket->getAction()->getName()) - { - if (basket->getRelevance() < action->getRelevance()) - basket->setRelevance(action->getRelevance()); - - if (ActionNode* actionNode = action->getAction()) - delete actionNode; - - delete action; - - return; - } - } - - actions.push_back(action); + return; } + + for (ActionBasket* basket : actions) + { + if (action->getAction()->getName() == basket->getAction()->getName()) + { + updateExistingBasket(basket, action); + return; + } + } + + actions.push_back(action); } ActionNode* Queue::Pop() { - float max = -1; - ActionBasket* selection = nullptr; - - for (std::list::iterator iter = actions.begin(); iter != actions.end(); iter++) + ActionBasket* highestRelevanceBasket = findHighestRelevanceBasket(); + if (!highestRelevanceBasket) { - ActionBasket* basket = *iter; - if (basket->getRelevance() > max) - { - max = basket->getRelevance(); - selection = basket; - } + return nullptr; } - if (selection != nullptr) - { - ActionNode* action = selection->getAction(); - actions.remove(selection); - delete selection; - return action; - } - - return nullptr; + return extractAndDeleteBasket(highestRelevanceBasket); } ActionBasket* Queue::Peek() { - float max = -1; - ActionBasket* selection = nullptr; - for (std::list::iterator iter = actions.begin(); iter != actions.end(); iter++) + return findHighestRelevanceBasket(); +} + +uint32 Queue::Size() +{ + return actions.size(); +} + +void Queue::RemoveExpired() +{ + if (!sPlayerbotAIConfig->expireActionTime) { - ActionBasket* basket = *iter; - if (basket->getRelevance() > max) + return; + } + + std::list expiredBaskets; + collectExpiredBaskets(expiredBaskets); + removeAndDeleteBaskets(expiredBaskets); +} + +// Private helper methods +void Queue::updateExistingBasket(ActionBasket* existing, ActionBasket* newBasket) +{ + if (existing->getRelevance() < newBasket->getRelevance()) + { + existing->setRelevance(newBasket->getRelevance()); + } + + if (ActionNode* actionNode = newBasket->getAction()) + { + delete actionNode; + } + + delete newBasket; +} + +ActionBasket* Queue::findHighestRelevanceBasket() const +{ + if (actions.empty()) + { + return nullptr; + } + + float maxRelevance = -1.0f; + ActionBasket* selection = nullptr; + + for (ActionBasket* basket : actions) + { + if (basket->getRelevance() > maxRelevance) { - max = basket->getRelevance(); + maxRelevance = basket->getRelevance(); selection = basket; } } @@ -77,21 +98,30 @@ ActionBasket* Queue::Peek() return selection; } -uint32 Queue::Size() { return actions.size(); } - -void Queue::RemoveExpired() +ActionNode* Queue::extractAndDeleteBasket(ActionBasket* basket) { - std::list expired; - for (std::list::iterator iter = actions.begin(); iter != actions.end(); iter++) - { - ActionBasket* basket = *iter; - if (sPlayerbotAIConfig->expireActionTime && basket->isExpired(sPlayerbotAIConfig->expireActionTime)) - expired.push_back(basket); - } + ActionNode* action = basket->getAction(); + actions.remove(basket); + delete basket; + return action; +} - for (std::list::iterator iter = expired.begin(); iter != expired.end(); iter++) +void Queue::collectExpiredBaskets(std::list& expiredBaskets) +{ + uint32 expiryTime = sPlayerbotAIConfig->expireActionTime; + for (ActionBasket* basket : actions) + { + if (basket->isExpired(expiryTime)) + { + expiredBaskets.push_back(basket); + } + } +} + +void Queue::removeAndDeleteBaskets(std::list& basketsToRemove) +{ + for (ActionBasket* basket : basketsToRemove) { - ActionBasket* basket = *iter; actions.remove(basket); if (ActionNode* action = basket->getAction()) diff --git a/src/strategy/Queue.h b/src/strategy/Queue.h index 5378d5e4..23776655 100644 --- a/src/strategy/Queue.h +++ b/src/strategy/Queue.h @@ -3,26 +3,92 @@ * and/or modify it under version 2 of the License, or (at your option), any later version. */ -#ifndef _PLAYERBOT_QUEUE_H -#define _PLAYERBOT_QUEUE_H +#ifndef PLAYERBOT_QUEUE_H +#define PLAYERBOT_QUEUE_H #include "Action.h" #include "Common.h" +/** + * @class Queue + * @brief Manages a priority queue of actions for the playerbot system + * + * This queue maintains a list of ActionBasket objects, each containing an action + * and its relevance score. Actions with higher relevance scores are prioritized. + */ class Queue { public: - Queue(void) {} - ~Queue(void) {} + Queue() = default; + ~Queue() = default; + /** + * @brief Adds an action to the queue or updates existing action's relevance + * @param action Pointer to the ActionBasket to be added + * + * If an action with the same name exists, updates its relevance if the new + * relevance is higher, then deletes the new action. Otherwise, adds the new + * action to the queue. + */ void Push(ActionBasket* action); + + /** + * @brief Removes and returns the action with highest relevance + * @return Pointer to the highest relevance ActionNode, or nullptr if queue is empty + * + * Ownership of the returned ActionNode is transferred to the caller. + * The associated ActionBasket is deleted. + */ ActionNode* Pop(); + + /** + * @brief Returns the action with highest relevance without removing it + * @return Pointer to the ActionBasket with highest relevance, or nullptr if queue is empty + */ ActionBasket* Peek(); + + /** + * @brief Returns the current size of the queue + * @return Number of actions in the queue + */ uint32 Size(); + + /** + * @brief Removes and deletes expired actions from the queue + * + * Uses sPlayerbotAIConfig->expireActionTime to determine if actions have expired. + * Both the ActionNode and ActionBasket are deleted for expired actions. + */ void RemoveExpired(); private: - std::list actions; + /** + * @brief Updates existing basket with new relevance and cleans up new basket + */ + void updateExistingBasket(ActionBasket* existing, ActionBasket* newBasket); + + /** + * @brief Finds the basket with the highest relevance score + * @return Pointer to the highest relevance basket, or nullptr if queue is empty + */ + ActionBasket* findHighestRelevanceBasket() const; + + /** + * @brief Extracts action from basket and handles basket cleanup + */ + ActionNode* extractAndDeleteBasket(ActionBasket* basket); + + /** + * @brief Collects all expired baskets into the provided list + */ + void collectExpiredBaskets(std::list& expiredBaskets); + + /** + * @brief Removes and deletes all baskets in the provided list + */ + void removeAndDeleteBaskets(std::list& basketsToRemove); + + std::list actions; /**< Container for action baskets */ }; #endif