Directory reorganization

This commit is contained in:
Yunfan Li
2025-05-07 00:06:31 +08:00
parent 0d170f5370
commit 6003dbc1b5
948 changed files with 28 additions and 28 deletions

View File

@@ -1,104 +0,0 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it
* and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#include "Action.h"
#include "Playerbots.h"
#include "Timer.h"
uint32 NextAction::size(NextAction** actions)
{
if (!actions)
return 0;
uint32 size = 0;
for (size = 0; actions[size];)
++size;
return size;
}
NextAction** NextAction::clone(NextAction** actions)
{
if (!actions)
return nullptr;
uint32 size = NextAction::size(actions);
NextAction** res = new NextAction*[size + 1];
for (uint32 i = 0; i < size; i++)
res[i] = new NextAction(*actions[i]);
res[size] = nullptr;
return res;
}
NextAction** NextAction::merge(NextAction** left, NextAction** right)
{
uint32 leftSize = NextAction::size(left);
uint32 rightSize = NextAction::size(right);
NextAction** res = new NextAction*[leftSize + rightSize + 1];
for (uint32 i = 0; i < leftSize; i++)
res[i] = new NextAction(*left[i]);
for (uint32 i = 0; i < rightSize; i++)
res[leftSize + i] = new NextAction(*right[i]);
res[leftSize + rightSize] = nullptr;
NextAction::destroy(left);
NextAction::destroy(right);
return res;
}
NextAction** NextAction::array(uint32 nil, ...)
{
va_list vl;
va_start(vl, nil);
uint32 size = 0;
NextAction* cur = nullptr;
do
{
cur = va_arg(vl, NextAction*);
++size;
} while (cur);
va_end(vl);
NextAction** res = new NextAction*[size];
va_start(vl, nil);
for (uint32 i = 0; i < size; i++)
res[i] = va_arg(vl, NextAction*);
va_end(vl);
return res;
}
void NextAction::destroy(NextAction** actions)
{
if (!actions)
return;
for (uint32 i = 0; actions[i]; i++)
delete actions[i];
delete[] actions;
}
Value<Unit*>* Action::GetTargetValue() { return context->GetValue<Unit*>(GetTargetName()); }
Unit* Action::GetTarget() { return GetTargetValue()->Get(); }
ActionBasket::ActionBasket(ActionNode* action, float relevance, bool skipPrerequisites, Event event)
: action(action), relevance(relevance), skipPrerequisites(skipPrerequisites), event(event), created(getMSTime())
{
}
bool ActionBasket::isExpired(uint32 msecs) { return getMSTime() - created >= msecs; }

View File

@@ -1,134 +0,0 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it
* and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#ifndef _PLAYERBOT_ACTION_H
#define _PLAYERBOT_ACTION_H
#include "AiObject.h"
#include "Common.h"
#include "Event.h"
#include "Value.h"
class PlayerbotAI;
class Unit;
class NextAction
{
public:
NextAction(std::string const name, float relevance = 0.0f)
: relevance(relevance), name(name) {} // name after relevance - whipowill
NextAction(NextAction const& o) : relevance(o.relevance), name(o.name) {} // name after relevance - whipowill
std::string const getName() { return name; }
float getRelevance() { return relevance; }
static uint32 size(NextAction** actions);
static NextAction** clone(NextAction** actions);
static NextAction** merge(NextAction** what, NextAction** with);
static NextAction** array(uint32 nil, ...);
static void destroy(NextAction** actions);
private:
float relevance;
std::string const name;
};
class Action : public AiNamedObject
{
public:
enum class ActionThreatType
{
None = 0,
Single = 1,
Aoe = 2
};
Action(PlayerbotAI* botAI, std::string const name = "action")
: AiNamedObject(botAI, name), verbose(false) {} // verbose after ainamedobject - whipowill
virtual ~Action(void) {}
virtual bool Execute([[maybe_unused]] Event event) { return true; }
virtual bool isPossible() { return true; }
virtual bool isUseful() { return true; }
virtual NextAction** getPrerequisites() { return nullptr; }
virtual NextAction** getAlternatives() { return nullptr; }
virtual NextAction** getContinuers() { return nullptr; }
virtual ActionThreatType getThreatType() { return ActionThreatType::None; }
void Update() {}
void Reset() {}
virtual Unit* GetTarget();
virtual Value<Unit*>* GetTargetValue();
virtual std::string const GetTargetName() { return "self target"; }
void MakeVerbose() { verbose = true; }
void setRelevance(uint32 relevance1) { relevance = relevance1; };
virtual float getRelevance() { return relevance; }
protected:
bool verbose;
float relevance = 0;
};
class ActionNode
{
public:
ActionNode(std::string const name, NextAction** prerequisites = nullptr, NextAction** alternatives = nullptr,
NextAction** continuers = nullptr)
: name(name), action(nullptr), continuers(continuers), alternatives(alternatives), prerequisites(prerequisites)
{
} // reorder arguments - whipowill
virtual ~ActionNode()
{
NextAction::destroy(prerequisites);
NextAction::destroy(alternatives);
NextAction::destroy(continuers);
}
Action* getAction() { return action; }
void setAction(Action* action) { this->action = action; }
std::string const getName() { return name; }
NextAction** getContinuers() { return NextAction::merge(NextAction::clone(continuers), action->getContinuers()); }
NextAction** getAlternatives()
{
return NextAction::merge(NextAction::clone(alternatives), action->getAlternatives());
}
NextAction** getPrerequisites()
{
return NextAction::merge(NextAction::clone(prerequisites), action->getPrerequisites());
}
private:
std::string const name;
Action* action;
NextAction** continuers;
NextAction** alternatives;
NextAction** prerequisites;
};
class ActionBasket
{
public:
ActionBasket(ActionNode* action, float relevance, bool skipPrerequisites, Event event);
virtual ~ActionBasket(void) {}
float getRelevance() { return relevance; }
ActionNode* getAction() { return action; }
Event getEvent() { return event; }
bool isSkipPrerequisites() { return skipPrerequisites; }
void AmendRelevance(float k) { relevance *= k; }
void setRelevance(float relevance) { this->relevance = relevance; }
bool isExpired(uint32 msecs);
private:
ActionNode* action;
float relevance;
bool skipPrerequisites;
Event event;
uint32 created;
};
#endif

View File

@@ -17,28 +17,28 @@
#include "ValueContext.h"
#include "WorldPacketActionContext.h"
#include "WorldPacketTriggerContext.h"
#include "raids/RaidStrategyContext.h"
#include "raids/blackwinglair/RaidBwlActionContext.h"
#include "raids/blackwinglair/RaidBwlTriggerContext.h"
#include "raids/naxxramas/RaidNaxxActionContext.h"
#include "raids/naxxramas/RaidNaxxTriggerContext.h"
#include "raids/icecrown/RaidIccActionContext.h"
#include "raids/icecrown/RaidIccTriggerContext.h"
#include "raids/obsidiansanctum/RaidOsActionContext.h"
#include "raids/obsidiansanctum/RaidOsTriggerContext.h"
#include "raids/eyeofeternity/RaidEoEActionContext.h"
#include "raids/vaultofarchavon/RaidVoATriggerContext.h"
#include "raids/onyxia/RaidOnyxiaActionContext.h"
#include "raids/onyxia/RaidOnyxiaTriggerContext.h"
#include "raids/vaultofarchavon/RaidVoAActionContext.h"
#include "raids/eyeofeternity/RaidEoETriggerContext.h"
#include "raids/moltencore/RaidMcActionContext.h"
#include "raids/moltencore/RaidMcTriggerContext.h"
#include "raids/aq20/RaidAq20ActionContext.h"
#include "raids/aq20/RaidAq20TriggerContext.h"
#include "dungeons/DungeonStrategyContext.h"
#include "dungeons/wotlk/WotlkDungeonActionContext.h"
#include "dungeons/wotlk/WotlkDungeonTriggerContext.h"
#include "RaidStrategyContext.h"
#include "RaidBwlActionContext.h"
#include "RaidBwlTriggerContext.h"
#include "RaidNaxxActionContext.h"
#include "RaidNaxxTriggerContext.h"
#include "RaidIccActionContext.h"
#include "RaidIccTriggerContext.h"
#include "RaidOsActionContext.h"
#include "RaidOsTriggerContext.h"
#include "RaidEoEActionContext.h"
#include "RaidVoATriggerContext.h"
#include "RaidOnyxiaActionContext.h"
#include "RaidOnyxiaTriggerContext.h"
#include "RaidVoAActionContext.h"
#include "RaidEoETriggerContext.h"
#include "RaidMcActionContext.h"
#include "RaidMcTriggerContext.h"
#include "RaidAq20ActionContext.h"
#include "RaidAq20TriggerContext.h"
#include "DungeonStrategyContext.h"
#include "WotlkDungeonActionContext.h"
#include "WotlkDungeonTriggerContext.h"
AiObjectContext::AiObjectContext(PlayerbotAI* botAI) : PlayerbotAIAware(botAI)
{

View File

@@ -1,662 +0,0 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it
* and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#include "Engine.h"
#include "Action.h"
#include "Event.h"
#include "PerformanceMonitor.h"
#include "Playerbots.h"
#include "Queue.h"
#include "Strategy.h"
Engine::Engine(PlayerbotAI* botAI, AiObjectContext* factory) : PlayerbotAIAware(botAI), aiObjectContext(factory)
{
lastRelevance = 0.0f;
testMode = false;
}
bool ActionExecutionListeners::Before(Action* action, Event event)
{
bool result = true;
for (std::list<ActionExecutionListener*>::iterator i = listeners.begin(); i != listeners.end(); i++)
{
result &= (*i)->Before(action, event);
}
return result;
}
void ActionExecutionListeners::After(Action* action, bool executed, Event event)
{
for (std::list<ActionExecutionListener*>::iterator i = listeners.begin(); i != listeners.end(); i++)
{
(*i)->After(action, executed, event);
}
}
bool ActionExecutionListeners::OverrideResult(Action* action, bool executed, Event event)
{
bool result = executed;
for (std::list<ActionExecutionListener*>::iterator i = listeners.begin(); i != listeners.end(); i++)
{
result = (*i)->OverrideResult(action, result, event);
}
return result;
}
bool ActionExecutionListeners::AllowExecution(Action* action, Event event)
{
bool result = true;
for (std::list<ActionExecutionListener*>::iterator i = listeners.begin(); i != listeners.end(); i++)
{
result &= (*i)->AllowExecution(action, event);
}
return result;
}
ActionExecutionListeners::~ActionExecutionListeners()
{
for (std::list<ActionExecutionListener*>::iterator i = listeners.begin(); i != listeners.end(); i++)
{
delete *i;
}
listeners.clear();
}
Engine::~Engine(void)
{
Reset();
// for (std::map<std::string, Strategy*>::iterator i = strategies.begin(); i != strategies.end(); i++)
// {
// Strategy* strategy = i->second;
// if (strategy) {
// delete strategy;
// }
// }
strategies.clear();
}
void Engine::Reset()
{
strategyTypeMask = 0;
ActionNode* action = nullptr;
while ((action = queue.Pop()) != nullptr)
{
delete action;
}
for (TriggerNode* trigger : triggers)
{
delete trigger;
}
triggers.clear();
for (Multiplier* multiplier : multipliers)
{
delete multiplier;
}
multipliers.clear();
}
void Engine::Init()
{
Reset();
for (std::map<std::string, Strategy*>::iterator i = strategies.begin(); i != strategies.end(); i++)
{
Strategy* strategy = i->second;
strategyTypeMask |= strategy->GetType();
strategy->InitMultipliers(multipliers);
strategy->InitTriggers(triggers);
Event emptyEvent;
MultiplyAndPush(strategy->getDefaultActions(), 0.0f, false, emptyEvent, "default");
}
if (testMode)
{
FILE* file = fopen("test.log", "w");
fprintf(file, "\n");
fclose(file);
}
}
bool Engine::DoNextAction(Unit* unit, uint32 depth, bool minimal)
{
LogAction("--- AI Tick ---");
if (sPlayerbotAIConfig->logValuesPerTick)
LogValues();
bool actionExecuted = false;
ActionBasket* basket = nullptr;
time_t currentTime = time(nullptr);
// Update triggers and push default actions
ProcessTriggers(minimal);
PushDefaultActions();
uint32 iterations = 0;
uint32 iterationsPerTick = queue.Size() * (minimal ? 2 : sPlayerbotAIConfig->iterationsPerTick);
while (++iterations <= iterationsPerTick)
{
basket = queue.Peek();
if (!basket)
break;
float relevance = basket->getRelevance(); // for reference
bool skipPrerequisites = basket->isSkipPrerequisites();
if (minimal && (relevance < 100))
continue;
Event event = basket->getEvent();
ActionNode* actionNode = queue.Pop(); // NOTE: Pop() deletes basket
Action* action = InitializeAction(actionNode);
if (!action)
{
LogAction("A:%s - UNKNOWN", actionNode->getName().c_str());
}
else if (action->isUseful())
{
// Apply multipliers early to avoid unnecessary iterations
for (Multiplier* multiplier : multipliers)
{
relevance *= multiplier->GetValue(action);
action->setRelevance(relevance);
if (relevance <= 0)
{
LogAction("Multiplier %s made action %s useless", multiplier->getName().c_str(), action->getName().c_str());
break;
}
}
if (action->isPossible() && relevance > 0)
{
if (!skipPrerequisites)
{
LogAction("A:%s - PREREQ", action->getName().c_str());
if (MultiplyAndPush(actionNode->getPrerequisites(), relevance + 0.002f, false, event, "prereq"))
{
PushAgain(actionNode, relevance + 0.001f, event);
continue;
}
}
PerformanceMonitorOperation* pmo = sPerformanceMonitor->start(PERF_MON_ACTION, action->getName(), &aiObjectContext->performanceStack);
actionExecuted = ListenAndExecute(action, event);
if (pmo)
pmo->finish();
if (actionExecuted)
{
LogAction("A:%s - OK", action->getName().c_str());
MultiplyAndPush(actionNode->getContinuers(), relevance, false, event, "cont");
lastRelevance = relevance;
delete actionNode; // Safe memory management
break;
}
else
{
LogAction("A:%s - FAILED", action->getName().c_str());
MultiplyAndPush(actionNode->getAlternatives(), relevance + 0.003f, false, event, "alt");
}
}
else
{
LogAction("A:%s - IMPOSSIBLE", action->getName().c_str());
MultiplyAndPush(actionNode->getAlternatives(), relevance + 0.003f, false, event, "alt");
}
}
else
{
LogAction("A:%s - USELESS", action->getName().c_str());
lastRelevance = relevance;
}
delete actionNode; // Always delete after processing the action node
}
if (time(nullptr) - currentTime > 1)
{
LogAction("Execution time exceeded 1 second");
}
if (!actionExecuted)
LogAction("no actions executed");
queue.RemoveExpired();
return actionExecuted;
}
ActionNode* Engine::CreateActionNode(std::string const name)
{
for (std::map<std::string, Strategy*>::iterator i = strategies.begin(); i != strategies.end(); i++)
{
if (ActionNode* node = i->second->GetAction(name))
return node;
}
return new ActionNode(name,
/*P*/ nullptr,
/*A*/ nullptr,
/*C*/ nullptr);
}
bool Engine::MultiplyAndPush(NextAction** actions, float forceRelevance, bool skipPrerequisites, Event event,
char const* pushType)
{
bool pushed = false;
if (actions)
{
for (uint32 j = 0; actions[j]; j++)
{
if (NextAction* nextAction = actions[j])
{
ActionNode* action = CreateActionNode(nextAction->getName());
InitializeAction(action);
float k = nextAction->getRelevance();
if (forceRelevance > 0.0f)
{
k = forceRelevance;
}
if (k > 0)
{
LogAction("PUSH:%s - %f (%s)", action->getName().c_str(), k, pushType);
queue.Push(new ActionBasket(action, k, skipPrerequisites, event));
pushed = true;
}
else
{
delete action;
}
delete nextAction;
}
else
break;
}
delete[] actions;
}
return pushed;
}
ActionResult Engine::ExecuteAction(std::string const name, Event event, std::string const qualifier)
{
bool result = false;
ActionNode* actionNode = CreateActionNode(name);
if (!actionNode)
return ACTION_RESULT_UNKNOWN;
Action* action = InitializeAction(actionNode);
if (!action)
{
delete actionNode;
return ACTION_RESULT_UNKNOWN;
}
if (!qualifier.empty())
{
if (Qualified* q = dynamic_cast<Qualified*>(action))
q->Qualify(qualifier);
}
if (!action->isPossible())
{
delete actionNode;
return ACTION_RESULT_IMPOSSIBLE;
}
if (!action->isUseful())
{
delete actionNode;
return ACTION_RESULT_USELESS;
}
action->MakeVerbose();
result = ListenAndExecute(action, event);
MultiplyAndPush(action->getContinuers(), 0.0f, false, event, "default");
delete actionNode;
return result ? ACTION_RESULT_OK : ACTION_RESULT_FAILED;
}
void Engine::addStrategy(std::string const name, bool init)
{
removeStrategy(name, init);
if (Strategy* strategy = aiObjectContext->GetStrategy(name))
{
std::set<std::string> siblings = aiObjectContext->GetSiblingStrategy(name);
for (std::set<std::string>::iterator i = siblings.begin(); i != siblings.end(); i++)
removeStrategy(*i, init);
LogAction("S:+%s", strategy->getName().c_str());
strategies[strategy->getName()] = strategy;
}
if (init)
Init();
}
void Engine::addStrategies(std::string first, ...)
{
addStrategy(first, false);
va_list vl;
va_start(vl, first);
const char* cur;
do
{
cur = va_arg(vl, const char*);
if (cur)
addStrategy(cur, false);
} while (cur);
Init();
va_end(vl);
}
void Engine::addStrategiesNoInit(std::string first, ...)
{
addStrategy(first, false);
va_list vl;
va_start(vl, first);
const char* cur;
do
{
cur = va_arg(vl, const char*);
if (cur)
addStrategy(cur, false);
} while (cur);
va_end(vl);
}
bool Engine::removeStrategy(std::string const name, bool init)
{
std::map<std::string, Strategy*>::iterator i = strategies.find(name);
if (i == strategies.end())
return false;
LogAction("S:-%s", name.c_str());
strategies.erase(i);
if (init)
Init();
return true;
}
void Engine::removeAllStrategies()
{
strategies.clear();
Init();
}
void Engine::toggleStrategy(std::string const name)
{
if (!removeStrategy(name))
addStrategy(name);
}
bool Engine::HasStrategy(std::string const name) { return strategies.find(name) != strategies.end(); }
void Engine::ProcessTriggers(bool minimal)
{
std::unordered_map<Trigger*, Event> fires;
for (std::vector<TriggerNode*>::iterator i = triggers.begin(); i != triggers.end(); i++)
{
TriggerNode* node = *i;
if (!node)
continue;
Trigger* trigger = node->getTrigger();
if (!trigger)
{
trigger = aiObjectContext->GetTrigger(node->getName());
node->setTrigger(trigger);
}
if (!trigger)
continue;
if (fires.find(trigger) != fires.end())
continue;
if (testMode || trigger->needCheck())
{
if (minimal && node->getFirstRelevance() < 100)
continue;
PerformanceMonitorOperation* pmo =
sPerformanceMonitor->start(PERF_MON_TRIGGER, trigger->getName(), &aiObjectContext->performanceStack);
Event event = trigger->Check();
if (pmo)
pmo->finish();
if (!event)
continue;
fires[trigger] = event;
LogAction("T:%s", trigger->getName().c_str());
}
}
for (std::vector<TriggerNode*>::iterator i = triggers.begin(); i != triggers.end(); i++)
{
TriggerNode* node = *i;
Trigger* trigger = node->getTrigger();
if (fires.find(trigger) == fires.end())
continue;
Event event = fires[trigger];
MultiplyAndPush(node->getHandlers(), 0.0f, false, event, "trigger");
}
for (std::vector<TriggerNode*>::iterator i = triggers.begin(); i != triggers.end(); i++)
{
if (Trigger* trigger = (*i)->getTrigger())
trigger->Reset();
}
}
void Engine::PushDefaultActions()
{
for (std::map<std::string, Strategy*>::iterator i = strategies.begin(); i != strategies.end(); i++)
{
Strategy* strategy = i->second;
Event emptyEvent;
MultiplyAndPush(strategy->getDefaultActions(), 0.0f, false, emptyEvent, "default");
}
}
std::string const Engine::ListStrategies()
{
std::string s = "Strategies: ";
if (strategies.empty())
return s;
for (std::map<std::string, Strategy*>::iterator i = strategies.begin(); i != strategies.end(); i++)
{
s.append(i->first);
s.append(", ");
}
return s.substr(0, s.length() - 2);
}
std::vector<std::string> Engine::GetStrategies()
{
std::vector<std::string> result;
for (std::map<std::string, Strategy*>::iterator i = strategies.begin(); i != strategies.end(); i++)
{
result.push_back(i->first);
}
return result;
}
void Engine::PushAgain(ActionNode* actionNode, float relevance, Event event)
{
NextAction** nextAction = new NextAction*[2];
nextAction[0] = new NextAction(actionNode->getName(), relevance);
nextAction[1] = nullptr;
MultiplyAndPush(nextAction, relevance, true, event, "again");
delete actionNode;
}
bool Engine::ContainsStrategy(StrategyType type)
{
for (std::map<std::string, Strategy*>::iterator i = strategies.begin(); i != strategies.end(); i++)
{
if (i->second->GetType() & type)
return true;
}
return false;
}
Action* Engine::InitializeAction(ActionNode* actionNode)
{
Action* action = actionNode->getAction();
if (!action)
{
action = aiObjectContext->GetAction(actionNode->getName());
actionNode->setAction(action);
}
return action;
}
bool Engine::ListenAndExecute(Action* action, Event event)
{
bool actionExecuted = false;
if (actionExecutionListeners.Before(action, event))
{
actionExecuted = actionExecutionListeners.AllowExecution(action, event) ? action->Execute(event) : true;
}
if (botAI->HasStrategy("debug", BOT_STATE_NON_COMBAT))
{
std::ostringstream out;
out << "do: ";
out << action->getName();
if (actionExecuted)
out << " 1 (";
else
out << " 0 (";
out << action->getRelevance() << ")";
if (!event.GetSource().empty())
out << " [" << event.GetSource() << "]";
botAI->TellMasterNoFacing(out);
}
actionExecuted = actionExecutionListeners.OverrideResult(action, actionExecuted, event);
actionExecutionListeners.After(action, actionExecuted, event);
return actionExecuted;
}
void Engine::LogAction(char const* format, ...)
{
Player* bot = botAI->GetBot();
if (sPlayerbotAIConfig->logInGroupOnly && (!bot->GetGroup() || !botAI->HasRealPlayerMaster()) && !testMode)
return;
char buf[1024];
va_list ap;
va_start(ap, format);
vsprintf(buf, format, ap);
va_end(ap);
lastAction += "|";
lastAction += buf;
if (lastAction.size() > 512)
{
lastAction = lastAction.substr(512);
size_t pos = lastAction.find("|");
lastAction = (pos == std::string::npos ? "" : lastAction.substr(pos));
}
if (testMode)
{
FILE* file = fopen("test.log", "a");
fprintf(file, "'%s'", buf);
fprintf(file, "\n");
fclose(file);
}
else
{
LOG_DEBUG("playerbots", "{} {}", bot->GetName().c_str(), buf);
}
}
void Engine::ChangeStrategy(std::string const names)
{
std::vector<std::string> splitted = split(names, ',');
for (std::vector<std::string>::iterator i = splitted.begin(); i != splitted.end(); i++)
{
char const* name = i->c_str();
switch (name[0])
{
case '+':
addStrategy(name + 1);
break;
case '-':
removeStrategy(name + 1);
break;
case '~':
toggleStrategy(name + 1);
break;
case '?':
botAI->TellMaster(ListStrategies());
break;
}
}
}
void Engine::LogValues()
{
if (testMode)
return;
Player* bot = botAI->GetBot();
if (sPlayerbotAIConfig->logInGroupOnly && (!bot->GetGroup() || !botAI->HasRealPlayerMaster()))
return;
std::string const text = botAI->GetAiObjectContext()->FormatValues();
LOG_DEBUG("playerbots", "Values for {}: {}", bot->GetName().c_str(), text.c_str());
}

View File

@@ -1,119 +0,0 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it
* and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#ifndef _PLAYERBOT_ENGINE_H
#define _PLAYERBOT_ENGINE_H
#include <map>
#include "Multiplier.h"
#include "PlayerbotAIAware.h"
#include "Queue.h"
#include "Strategy.h"
#include "Trigger.h"
class Action;
class ActionNode;
class AiObjectContext;
class Event;
class NextAction;
class PlayerbotAI;
enum ActionResult
{
ACTION_RESULT_UNKNOWN,
ACTION_RESULT_OK,
ACTION_RESULT_IMPOSSIBLE,
ACTION_RESULT_USELESS,
ACTION_RESULT_FAILED
};
class ActionExecutionListener
{
public:
virtual ~ActionExecutionListener(){};
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;
};
class ActionExecutionListeners : public ActionExecutionListener
{
public:
virtual ~ActionExecutionListeners();
bool Before(Action* action, Event event) override;
bool AllowExecution(Action* action, Event event) override;
void After(Action* action, bool executed, Event event) override;
bool OverrideResult(Action* action, bool executed, Event event) override;
void Add(ActionExecutionListener* listener) { listeners.push_back(listener); }
void Remove(ActionExecutionListener* listener) { listeners.remove(listener); }
private:
std::list<ActionExecutionListener*> listeners;
};
class Engine : public PlayerbotAIAware
{
public:
Engine(PlayerbotAI* botAI, AiObjectContext* factory);
void Init();
void addStrategy(std::string const name, bool init = true);
void addStrategies(std::string first, ...);
void addStrategiesNoInit(std::string first, ...);
bool removeStrategy(std::string const name, bool init = true);
bool HasStrategy(std::string const name);
void removeAllStrategies();
void toggleStrategy(std::string const name);
std::string const ListStrategies();
std::vector<std::string> GetStrategies();
bool ContainsStrategy(StrategyType type);
void ChangeStrategy(std::string const names);
std::string const GetLastAction() { return lastAction; }
virtual bool DoNextAction(Unit*, uint32 depth = 0, bool minimal = false);
ActionResult ExecuteAction(std::string const name, Event event = Event(), std::string const qualifier = "");
void AddActionExecutionListener(ActionExecutionListener* listener) { actionExecutionListeners.Add(listener); }
void removeActionExecutionListener(ActionExecutionListener* listener) { actionExecutionListeners.Remove(listener); }
bool HasStrategyType(StrategyType type) { return strategyTypeMask & type; }
virtual ~Engine(void);
bool testMode;
private:
bool MultiplyAndPush(NextAction** actions, float forceRelevance, bool skipPrerequisites, Event event,
const char* pushType);
void Reset();
void ProcessTriggers(bool minimal);
void PushDefaultActions();
void PushAgain(ActionNode* actionNode, float relevance, Event event);
ActionNode* CreateActionNode(std::string const name);
Action* InitializeAction(ActionNode* actionNode);
bool ListenAndExecute(Action* action, Event event);
void LogAction(char const* format, ...);
void LogValues();
ActionExecutionListeners actionExecutionListeners;
protected:
Queue queue;
std::vector<TriggerNode*> triggers;
std::vector<Multiplier*> multipliers;
AiObjectContext* aiObjectContext;
std::map<std::string, Strategy*> strategies;
float lastRelevance;
std::string lastAction;
uint32 strategyTypeMask;
};
#endif

View File

@@ -1,27 +0,0 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it
* and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#include "Event.h"
#include "Playerbots.h"
Event::Event(std::string const source, ObjectGuid object, Player* owner) : source(source), owner(owner)
{
packet << object;
}
ObjectGuid Event::getObject()
{
if (packet.empty())
return ObjectGuid::Empty;
WorldPacket p(packet);
p.rpos(0);
ObjectGuid guid;
p >> guid;
return guid;
}

View File

@@ -1,45 +0,0 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it
* and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#ifndef _PLAYERBOT_EVENT_H
#define _PLAYERBOT_EVENT_H
#include "WorldPacket.h"
class ObjectGuid;
class Player;
class Event
{
public:
Event(Event const& other) : source(other.source), param(other.param), packet(other.packet), owner(other.owner) {}
Event() {}
Event(std::string const source) : source(source) {}
Event(std::string const source, std::string const param, Player* owner = nullptr)
: source(source), param(param), owner(owner)
{
}
Event(std::string const source, WorldPacket& packet, Player* owner = nullptr)
: source(source), packet(packet), owner(owner)
{
}
Event(std::string const source, ObjectGuid object, Player* owner = nullptr);
virtual ~Event() {}
std::string const GetSource() { return source; }
std::string const getParam() { return param; }
WorldPacket& getPacket() { return packet; }
ObjectGuid getObject();
Player* getOwner() { return owner; }
bool operator!() const { return source.empty(); }
protected:
std::string source;
std::string param;
WorldPacket packet;
Player* owner = nullptr;
};
#endif

View File

@@ -1,67 +0,0 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it
* and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#include "ExternalEventHelper.h"
#include "ChatHelper.h"
#include "Playerbots.h"
#include "Trigger.h"
bool ExternalEventHelper::ParseChatCommand(std::string const command, Player* owner)
{
if (HandleCommand(command, "", owner))
return true;
size_t i = std::string::npos;
while (true)
{
size_t found = command.rfind(" ", i);
if (found == std::string::npos || !found)
break;
std::string const name = command.substr(0, found);
std::string const param = command.substr(found + 1);
i = found - 1;
if (HandleCommand(name, param, owner))
return true;
}
if (!ChatHelper::parseable(command))
return false;
HandleCommand("c", command, owner);
HandleCommand("t", command, owner);
return true;
}
void ExternalEventHelper::HandlePacket(std::map<uint16, std::string>& handlers, WorldPacket const& packet,
Player* owner)
{
uint16 opcode = packet.GetOpcode();
std::string const name = handlers[opcode];
if (name.empty())
return;
Trigger* trigger = aiObjectContext->GetTrigger(name);
if (!trigger)
return;
WorldPacket p(packet);
trigger->ExternalEvent(p, owner);
}
bool ExternalEventHelper::HandleCommand(std::string const name, std::string const param, Player* owner)
{
Trigger* trigger = aiObjectContext->GetTrigger(name);
if (!trigger)
return false;
trigger->ExternalEvent(param, owner);
return true;
}

View File

@@ -1,30 +0,0 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it
* and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#ifndef _PLAYERBOT_EXTERNALEVENTHELPER_H
#define _PLAYERBOT_EXTERNALEVENTHELPER_H
#include <map>
#include "Common.h"
class AiObjectContext;
class Player;
class WorldPacket;
class ExternalEventHelper
{
public:
ExternalEventHelper(AiObjectContext* aiObjectContext) : aiObjectContext(aiObjectContext) {}
bool ParseChatCommand(std::string const command, Player* owner = nullptr);
void HandlePacket(std::map<uint16, std::string>& handlers, WorldPacket const& packet, Player* owner = nullptr);
bool HandleCommand(std::string const name, std::string const param, Player* owner = nullptr);
private:
AiObjectContext* aiObjectContext;
};
#endif

View File

@@ -1,95 +0,0 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it
* and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#include "ItemVisitors.h"
#include "Playerbots.h"
bool FindUsableItemVisitor::Visit(Item* item)
{
if (bot->CanUseItem(item->GetTemplate()) == EQUIP_ERR_OK)
return FindItemVisitor::Visit(item);
return true;
}
bool FindPotionVisitor::Accept(ItemTemplate const* proto)
{
if (proto->Class == ITEM_CLASS_CONSUMABLE &&
(proto->SubClass == ITEM_SUBCLASS_POTION || proto->SubClass == ITEM_SUBCLASS_FLASK))
{
for (uint8 j = 0; j < MAX_ITEM_PROTO_SPELLS; j++)
{
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(proto->Spells[j].SpellId);
if (!spellInfo)
return false;
for (uint8 i = 0; i < 3; i++)
{
if (spellInfo->Effects[i].Effect == effectId)
return true;
}
}
}
return false;
}
bool FindMountVisitor::Accept(ItemTemplate const* proto)
{
for (uint8 j = 0; j < MAX_ITEM_PROTO_SPELLS; j++)
{
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(proto->Spells[j].SpellId);
if (!spellInfo)
return false;
for (uint8 i = 0; i < 3; i++)
{
if (spellInfo->Effects[i].ApplyAuraName == SPELL_AURA_MOUNTED)
return true;
}
}
return false;
}
bool FindPetVisitor::Accept(ItemTemplate const* proto)
{
if (proto->Class == ITEM_CLASS_MISC)
{
for (uint8 j = 0; j < MAX_ITEM_PROTO_SPELLS; j++)
{
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(proto->Spells[j].SpellId);
if (!spellInfo)
return false;
for (uint8 i = 0; i < 3; i++)
{
if (spellInfo->Effects[i].Effect == SPELL_EFFECT_SUMMON_PET)
return true;
}
}
}
return false;
}
FindItemUsageVisitor::FindItemUsageVisitor(Player* bot, ItemUsage usage) : FindUsableItemVisitor(bot), usage(usage)
{
context = GET_PLAYERBOT_AI(bot)->GetAiObjectContext();
};
bool FindItemUsageVisitor::Accept(ItemTemplate const* proto)
{
if (AI_VALUE2(ItemUsage, "item usage", proto->ItemId) == usage)
return true;
return false;
}
bool FindUsableNamedItemVisitor::Accept(ItemTemplate const* proto)
{
return proto && !proto->Name1.empty() && strstri(proto->Name1.c_str(), name.c_str());
}

View File

@@ -1,418 +0,0 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it
* and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#ifndef _PLAYERBOT_ITEMVISITORS_H
#define _PLAYERBOT_ITEMVISITORS_H
#include "ChatHelper.h"
#include "Common.h"
#include "Item.h"
#include "ItemUsageValue.h"
class AiObjectContext;
class Player;
char* strstri(char const* str1, char const* str2);
enum IterateItemsMask : uint32
{
ITERATE_ITEMS_IN_BAGS = 1,
ITERATE_ITEMS_IN_EQUIP = 2,
ITERATE_ITEMS_IN_BANK = 4,
ITERATE_ALL_ITEMS = 255
};
class IterateItemsVisitor
{
public:
IterateItemsVisitor() {}
virtual bool Visit(Item* item) = 0;
};
class FindItemVisitor : public IterateItemsVisitor
{
public:
FindItemVisitor() : IterateItemsVisitor(), result() {}
bool Visit(Item* item) override
{
if (!Accept(item->GetTemplate()))
return true;
result.push_back(item);
return true;
}
std::vector<Item*>& GetResult() { return result; }
protected:
virtual bool Accept(ItemTemplate const* proto) = 0;
private:
std::vector<Item*> result;
};
class FindUsableItemVisitor : public FindItemVisitor
{
public:
FindUsableItemVisitor(Player* bot) : FindItemVisitor(), bot(bot) {}
bool Visit(Item* item) override;
private:
Player* bot;
};
class FindItemsByQualityVisitor : public IterateItemsVisitor
{
public:
FindItemsByQualityVisitor(uint32 quality, uint32 count) : IterateItemsVisitor(), quality(quality), count(count) {}
bool Visit(Item* item) override
{
if (item->GetTemplate()->Quality != quality)
return true;
if (result.size() >= (size_t)count)
return false;
result.push_back(item);
return true;
}
std::vector<Item*>& GetResult() { return result; }
private:
uint32 quality;
uint32 count;
std::vector<Item*> result;
};
class FindItemsToTradeByQualityVisitor : public FindItemsByQualityVisitor
{
public:
FindItemsToTradeByQualityVisitor(uint32 quality, uint32 count) : FindItemsByQualityVisitor(quality, count) {}
bool Visit(Item* item) override
{
if (item->IsSoulBound())
return true;
return FindItemsByQualityVisitor::Visit(item);
}
};
class FindItemsToTradeByClassVisitor : public IterateItemsVisitor
{
public:
FindItemsToTradeByClassVisitor(uint32 itemClass, uint32 itemSubClass, uint32 count)
: IterateItemsVisitor(), itemClass(itemClass), itemSubClass(itemSubClass), count(count)
{
} // reorder args - whipowill
bool Visit(Item* item) override
{
if (item->IsSoulBound())
return true;
if (item->GetTemplate()->Class != itemClass || item->GetTemplate()->SubClass != itemSubClass)
return true;
if (result.size() >= (size_t)count)
return false;
result.push_back(item);
return true;
}
std::vector<Item*>& GetResult() { return result; }
private:
uint32 itemClass;
uint32 itemSubClass;
uint32 count;
std::vector<Item*> result;
};
class QueryItemCountVisitor : public IterateItemsVisitor
{
public:
QueryItemCountVisitor(uint32 itemId) : count(0), itemId(itemId) {}
bool Visit(Item* item) override
{
if (item->GetTemplate()->ItemId == itemId)
count += item->GetCount();
return true;
}
uint32 GetCount() { return count; }
protected:
uint32 count;
uint32 itemId;
};
class QueryNamedItemCountVisitor : public QueryItemCountVisitor
{
public:
QueryNamedItemCountVisitor(std::string const name) : QueryItemCountVisitor(0), name(name) {}
bool Visit(Item* item) override
{
ItemTemplate const* proto = item->GetTemplate();
if (proto && proto->Name1.c_str() && strstri(proto->Name1.c_str(), name.c_str()))
count += item->GetCount();
return true;
}
private:
std::string const name;
};
class FindNamedItemVisitor : public FindItemVisitor
{
public:
FindNamedItemVisitor([[maybe_unused]] Player* bot, std::string const name) : FindItemVisitor(), name(name) {}
bool Accept(ItemTemplate const* proto) override
{
return proto && proto->Name1.c_str() && strstri(proto->Name1.c_str(), name.c_str());
}
private:
std::string const name;
};
class FindItemByIdVisitor : public FindItemVisitor
{
public:
FindItemByIdVisitor(uint32 id) : FindItemVisitor(), id(id) {}
bool Accept(ItemTemplate const* proto) override { return proto->ItemId == id; }
private:
uint32 id;
};
class FindItemByIdsVisitor : public FindItemVisitor
{
public:
FindItemByIdsVisitor(ItemIds ids) : FindItemVisitor(), ids(ids) {}
bool Accept(ItemTemplate const* proto) override { return ids.find(proto->ItemId) != ids.end(); }
private:
ItemIds ids;
};
class ListItemsVisitor : public IterateItemsVisitor
{
public:
ListItemsVisitor() : IterateItemsVisitor() {}
std::map<uint32, uint32> items;
std::map<uint32, bool> soulbound;
bool Visit(Item* item) override
{
uint32 id = item->GetTemplate()->ItemId;
if (items.find(id) == items.end())
items[id] = 0;
items[id] += item->GetCount();
soulbound[id] = item->IsSoulBound();
return true;
}
};
class ItemCountByQuality : public IterateItemsVisitor
{
public:
ItemCountByQuality() : IterateItemsVisitor()
{
for (uint32 i = 0; i < MAX_ITEM_QUALITY; ++i)
count[i] = 0;
}
bool Visit(Item* item) override
{
++count[item->GetTemplate()->Quality];
return true;
}
public:
std::map<uint32, uint32> count;
};
class FindPotionVisitor : public FindUsableItemVisitor
{
public:
FindPotionVisitor(Player* bot, uint32 effectId) : FindUsableItemVisitor(bot), effectId(effectId) {}
bool Accept(ItemTemplate const* proto) override;
private:
uint32 effectId;
};
class FindFoodVisitor : public FindUsableItemVisitor
{
public:
FindFoodVisitor(Player* bot, uint32 spellCategory, bool conjured = false)
: FindUsableItemVisitor(bot), spellCategory(spellCategory), conjured(conjured)
{
}
bool Accept(ItemTemplate const* proto) override
{
return proto->Class == ITEM_CLASS_CONSUMABLE &&
(proto->SubClass == ITEM_SUBCLASS_CONSUMABLE || proto->SubClass == ITEM_SUBCLASS_FOOD) &&
proto->Spells[0].SpellCategory == spellCategory && (!conjured || proto->IsConjuredConsumable());
}
private:
uint32 spellCategory;
bool conjured;
};
class FindMountVisitor : public FindUsableItemVisitor
{
public:
FindMountVisitor(Player* bot) : FindUsableItemVisitor(bot) {}
bool Accept(ItemTemplate const* proto) override;
private:
uint32 effectId;
};
class FindPetVisitor : public FindUsableItemVisitor
{
public:
FindPetVisitor(Player* bot) : FindUsableItemVisitor(bot) {}
bool Accept(ItemTemplate const* proto) override;
};
class FindAmmoVisitor : public FindUsableItemVisitor
{
public:
FindAmmoVisitor(Player* bot, uint32 weaponType) : FindUsableItemVisitor(bot), weaponType(weaponType) {}
bool Accept(ItemTemplate const* proto) override
{
if (proto->Class == ITEM_CLASS_PROJECTILE)
{
uint32 subClass = 0;
switch (weaponType)
{
case ITEM_SUBCLASS_WEAPON_GUN:
subClass = ITEM_SUBCLASS_BULLET;
break;
case ITEM_SUBCLASS_WEAPON_BOW:
case ITEM_SUBCLASS_WEAPON_CROSSBOW:
subClass = ITEM_SUBCLASS_ARROW;
break;
}
if (!subClass)
return false;
if (proto->SubClass == subClass)
return true;
}
return false;
}
private:
uint32 weaponType;
};
class FindQuestItemVisitor : public FindUsableItemVisitor
{
public:
FindQuestItemVisitor(Player* bot) : FindUsableItemVisitor(bot) {}
bool Accept(ItemTemplate const* proto) override
{
if (proto->Class == ITEM_CLASS_QUEST)
{
return true;
}
return false;
}
};
class FindRecipeVisitor : public FindUsableItemVisitor
{
public:
FindRecipeVisitor(Player* bot, SkillType skill = SKILL_NONE) : FindUsableItemVisitor(bot), skill(skill){};
bool Accept(ItemTemplate const* proto) override
{
if (proto->Class == ITEM_CLASS_RECIPE)
{
if (skill == SKILL_NONE)
return true;
switch (proto->SubClass)
{
case ITEM_SUBCLASS_LEATHERWORKING_PATTERN:
return skill == SKILL_LEATHERWORKING;
case ITEM_SUBCLASS_TAILORING_PATTERN:
return skill == SKILL_TAILORING;
case ITEM_SUBCLASS_ENGINEERING_SCHEMATIC:
return skill == SKILL_ENGINEERING;
case ITEM_SUBCLASS_BLACKSMITHING:
return skill == SKILL_BLACKSMITHING;
case ITEM_SUBCLASS_COOKING_RECIPE:
return skill == SKILL_COOKING;
case ITEM_SUBCLASS_ALCHEMY_RECIPE:
return skill == SKILL_ALCHEMY;
case ITEM_SUBCLASS_FIRST_AID_MANUAL:
return skill == SKILL_FIRST_AID;
case ITEM_SUBCLASS_ENCHANTING_FORMULA:
return skill == SKILL_ENCHANTING;
case ITEM_SUBCLASS_FISHING_MANUAL:
return skill == SKILL_FISHING;
}
}
return false;
}
private:
SkillType skill;
};
class FindItemUsageVisitor : public FindUsableItemVisitor
{
public:
FindItemUsageVisitor(Player* bot, ItemUsage usage = ITEM_USAGE_NONE);
bool Accept(ItemTemplate const* proto) override;
private:
AiObjectContext* context;
ItemUsage usage;
};
class FindUsableNamedItemVisitor : public FindUsableItemVisitor
{
public:
FindUsableNamedItemVisitor(Player* bot, std::string name) : FindUsableItemVisitor(bot), name(name) {}
bool Accept(ItemTemplate const* proto) override;
private:
std::string name;
};
#endif

View File

@@ -1,23 +0,0 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it
* and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#ifndef _PLAYERBOT_MULTIPLIER_H
#define _PLAYERBOT_MULTIPLIER_H
#include "AiObject.h"
class Action;
class PlayerbotAI;
class Multiplier : public AiNamedObject
{
public:
Multiplier(PlayerbotAI* botAI, std::string const name) : AiNamedObject(botAI, name) {}
virtual ~Multiplier() {}
virtual float GetValue([[maybe_unused]] Action* action) { return 1.0f; }
};
#endif

View File

@@ -1,52 +0,0 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it
* and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#include "NamedObjectContext.h"
#include "Playerbots.h"
void Qualified::Qualify(int qual)
{
std::ostringstream out;
out << qual;
qualifier = out.str();
}
std::string const Qualified::MultiQualify(std::vector<std::string> qualifiers, const std::string& separator, const std::string_view brackets)
{
std::stringstream out;
for (uint8 i = 0; i < qualifiers.size(); i++)
{
const std::string& qualifier = qualifiers[i];
if (i == qualifiers.size() - 1)
{
out << qualifier;
}
else
{
out << qualifier << separator;
}
}
if (brackets.empty())
{
return out.str();
}
else
{
return brackets[0] + out.str() + brackets[1];
}
}
std::vector<std::string> Qualified::getMultiQualifiers(std::string const qualifier1)
{
std::istringstream iss(qualifier1);
return {std::istream_iterator<std::string>{iss}, std::istream_iterator<std::string>{}};
}
int32 Qualified::getMultiQualifier(std::string const qualifier1, uint32 pos)
{
return std::stoi(getMultiQualifiers(qualifier1)[pos]);
}

View File

@@ -1,272 +0,0 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it
* and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#ifndef _PLAYERBOT_NAMEDOBJECTCONEXT_H
#define _PLAYERBOT_NAMEDOBJECTCONEXT_H
#include <list>
#include <set>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include "Common.h"
class PlayerbotAI;
class Qualified
{
public:
Qualified(){};
Qualified(std::string const qualifier) : qualifier(qualifier) {}
Qualified(int32 qualifier1) { Qualify(qualifier1); }
virtual void Qualify(int qual);
virtual void Qualify(std::string const qual) { qualifier = qual; }
std::string const getQualifier() { return qualifier; }
static std::string const MultiQualify(std::vector<std::string> qualifiers, const std::string& separator, const std::string_view brackets = "{}");
static std::vector<std::string> getMultiQualifiers(std::string const qualifier1);
static int32 getMultiQualifier(std::string const qualifier1, uint32 pos);
protected:
std::string qualifier;
};
template <class T>
class NamedObjectFactory
{
protected:
typedef T* (*ActionCreator)(PlayerbotAI* botAI);
std::unordered_map<std::string, ActionCreator> creators;
public:
T* create(std::string name, PlayerbotAI* botAI)
{
size_t found = name.find("::");
std::string qualifier;
if (found != std::string::npos)
{
qualifier = name.substr(found + 2);
name = name.substr(0, found);
}
if (creators.find(name) == creators.end())
return nullptr;
ActionCreator creator = creators[name];
if (!creator)
return nullptr;
T* object = (*creator)(botAI);
Qualified* q = dynamic_cast<Qualified*>(object);
if (q && found != std::string::npos)
q->Qualify(qualifier);
return object;
}
std::set<std::string> supports()
{
std::set<std::string> keys;
for (typename std::unordered_map<std::string, ActionCreator>::iterator it = creators.begin();
it != creators.end(); it++)
keys.insert(it->first);
return keys;
}
};
template <class T>
class NamedObjectContext : public NamedObjectFactory<T>
{
public:
NamedObjectContext(bool shared = false, bool supportsSiblings = false)
: NamedObjectFactory<T>(), shared(shared), supportsSiblings(supportsSiblings)
{
}
virtual ~NamedObjectContext() { Clear(); }
T* create(std::string const name, PlayerbotAI* botAI)
{
if (created.find(name) == created.end())
return created[name] = NamedObjectFactory<T>::create(name, botAI);
return created[name];
}
void Clear()
{
for (typename std::unordered_map<std::string, T*>::iterator i = created.begin(); i != created.end(); i++)
{
if (i->second)
delete i->second;
}
created.clear();
}
void Update()
{
for (typename std::unordered_map<std::string, T*>::iterator i = created.begin(); i != created.end(); i++)
{
if (i->second)
i->second->Update();
}
}
void Reset()
{
for (typename std::unordered_map<std::string, T*>::iterator i = created.begin(); i != created.end(); i++)
{
if (i->second)
i->second->Reset();
}
}
bool IsShared() { return shared; }
bool IsSupportsSiblings() { return supportsSiblings; }
std::set<std::string> GetCreated()
{
std::set<std::string> keys;
for (typename std::unordered_map<std::string, T*>::iterator it = created.begin(); it != created.end(); it++)
keys.insert(it->first);
return keys;
}
protected:
std::unordered_map<std::string, T*> created;
bool shared;
bool supportsSiblings;
};
template <class T>
class NamedObjectContextList
{
public:
virtual ~NamedObjectContextList()
{
for (typename std::vector<NamedObjectContext<T>*>::iterator i = contexts.begin(); i != contexts.end(); i++)
{
NamedObjectContext<T>* context = *i;
if (!context->IsShared())
delete context;
}
}
void Add(NamedObjectContext<T>* context) { contexts.push_back(context); }
T* GetContextObject(std::string const name, PlayerbotAI* botAI)
{
for (typename std::vector<NamedObjectContext<T>*>::iterator i = contexts.begin(); i != contexts.end(); i++)
{
if (T* object = (*i)->create(name, botAI))
return object;
}
return nullptr;
}
void Update()
{
for (typename std::vector<NamedObjectContext<T>*>::iterator i = contexts.begin(); i != contexts.end(); i++)
{
if (!(*i)->IsShared())
(*i)->Update();
}
}
void Reset()
{
for (typename std::vector<NamedObjectContext<T>*>::iterator i = contexts.begin(); i != contexts.end(); i++)
{
(*i)->Reset();
}
}
std::set<std::string> GetSiblings(std::string const name)
{
for (typename std::vector<NamedObjectContext<T>*>::iterator i = contexts.begin(); i != contexts.end(); i++)
{
if (!(*i)->IsSupportsSiblings())
continue;
std::set<std::string> supported = (*i)->supports();
std::set<std::string>::iterator found = supported.find(name);
if (found == supported.end())
continue;
supported.erase(found);
return supported;
}
return std::set<std::string>();
}
std::set<std::string> supports()
{
std::set<std::string> result;
for (typename std::vector<NamedObjectContext<T>*>::iterator i = contexts.begin(); i != contexts.end(); i++)
{
std::set<std::string> supported = (*i)->supports();
for (std::set<std::string>::iterator j = supported.begin(); j != supported.end(); j++)
result.insert(*j);
}
return result;
}
std::set<std::string> GetCreated()
{
std::set<std::string> result;
for (typename std::vector<NamedObjectContext<T>*>::iterator i = contexts.begin(); i != contexts.end(); i++)
{
std::set<std::string> createdKeys = (*i)->GetCreated();
for (std::set<std::string>::iterator j = createdKeys.begin(); j != createdKeys.end(); j++)
result.insert(*j);
}
return result;
}
private:
std::vector<NamedObjectContext<T>*> contexts;
};
template <class T>
class NamedObjectFactoryList
{
public:
virtual ~NamedObjectFactoryList()
{
for (typename std::list<NamedObjectFactory<T>*>::iterator i = factories.begin(); i != factories.end(); i++)
delete *i;
}
void Add(NamedObjectFactory<T>* context) { factories.push_front(context); }
T* GetContextObject(std::string const& name, PlayerbotAI* botAI)
{
for (typename std::list<NamedObjectFactory<T>*>::iterator i = factories.begin(); i != factories.end(); i++)
{
if (T* object = (*i)->create(name, botAI))
return object;
}
return nullptr;
}
private:
std::list<NamedObjectFactory<T>*> factories;
};
#endif

View File

@@ -1,134 +0,0 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it
* and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#include "Queue.h"
#include "AiObjectContext.h"
#include "Log.h"
#include "PlayerbotAIConfig.h"
void Queue::Push(ActionBasket* action)
{
if (!action)
{
return;
}
for (ActionBasket* basket : actions)
{
if (action->getAction()->getName() == basket->getAction()->getName())
{
updateExistingBasket(basket, action);
return;
}
}
actions.push_back(action);
}
ActionNode* Queue::Pop()
{
ActionBasket* highestRelevanceBasket = findHighestRelevanceBasket();
if (!highestRelevanceBasket)
{
return nullptr;
}
return extractAndDeleteBasket(highestRelevanceBasket);
}
ActionBasket* Queue::Peek()
{
return findHighestRelevanceBasket();
}
uint32 Queue::Size()
{
return actions.size();
}
void Queue::RemoveExpired()
{
if (!sPlayerbotAIConfig->expireActionTime)
{
return;
}
std::list<ActionBasket*> 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)
{
maxRelevance = basket->getRelevance();
selection = basket;
}
}
return selection;
}
ActionNode* Queue::extractAndDeleteBasket(ActionBasket* basket)
{
ActionNode* action = basket->getAction();
actions.remove(basket);
delete basket;
return action;
}
void Queue::collectExpiredBaskets(std::list<ActionBasket*>& expiredBaskets)
{
uint32 expiryTime = sPlayerbotAIConfig->expireActionTime;
for (ActionBasket* basket : actions)
{
if (basket->isExpired(expiryTime))
{
expiredBaskets.push_back(basket);
}
}
}
void Queue::removeAndDeleteBaskets(std::list<ActionBasket*>& basketsToRemove)
{
for (ActionBasket* basket : basketsToRemove)
{
actions.remove(basket);
if (ActionNode* action = basket->getAction())
{
delete action;
}
delete basket;
}
}

View File

@@ -1,94 +0,0 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it
* 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
#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() = 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:
/**
* @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<ActionBasket*>& expiredBaskets);
/**
* @brief Removes and deletes all baskets in the provided list
*/
void removeAndDeleteBaskets(std::list<ActionBasket*>& basketsToRemove);
std::list<ActionBasket*> actions; /**< Container for action baskets */
};
#endif

View File

@@ -1,123 +0,0 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it
* and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#include "Strategy.h"
#include "Playerbots.h"
class ActionNodeFactoryInternal : public NamedObjectFactory<ActionNode>
{
public:
ActionNodeFactoryInternal()
{
creators["melee"] = &melee;
creators["healthstone"] = &healthstone;
creators["be near"] = &follow_master_random;
creators["attack anything"] = &attack_anything;
creators["move random"] = &move_random;
creators["move to loot"] = &move_to_loot;
creators["food"] = &food;
creators["drink"] = &drink;
creators["mana potion"] = &mana_potion;
creators["healing potion"] = &healing_potion;
creators["flee"] = &flee;
}
private:
static ActionNode* melee([[maybe_unused]] PlayerbotAI* botAI)
{
return new ActionNode("melee",
/*P*/ nullptr,
/*A*/ nullptr,
/*C*/ nullptr);
}
static ActionNode* healthstone([[maybe_unused]] PlayerbotAI* botAI)
{
return new ActionNode("healthstone",
/*P*/ nullptr,
/*A*/ NextAction::array(0, new NextAction("healing potion"), nullptr),
/*C*/ nullptr);
}
static ActionNode* follow_master_random([[maybe_unused]] PlayerbotAI* botAI)
{
return new ActionNode("be near",
/*P*/ nullptr,
/*A*/ NextAction::array(0, new NextAction("follow"), nullptr),
/*C*/ nullptr);
}
static ActionNode* attack_anything([[maybe_unused]] PlayerbotAI* botAI)
{
return new ActionNode("attack anything",
/*P*/ nullptr,
/*A*/ nullptr,
/*C*/ nullptr);
}
static ActionNode* move_random([[maybe_unused]] PlayerbotAI* botAI)
{
return new ActionNode("move random",
/*P*/ nullptr,
/*A*/ NextAction::array(0, new NextAction("stay line"), nullptr),
/*C*/ nullptr);
}
static ActionNode* move_to_loot([[maybe_unused]] PlayerbotAI* botAI)
{
return new ActionNode("move to loot",
/*P*/ nullptr,
/*A*/ nullptr,
/*C*/ nullptr);
}
static ActionNode* food([[maybe_unused]] PlayerbotAI* botAI)
{
return new ActionNode("food",
/*P*/ nullptr,
/*A*/ nullptr,
/*C*/ nullptr);
}
static ActionNode* drink([[maybe_unused]] PlayerbotAI* botAI)
{
return new ActionNode("drink",
/*P*/ nullptr,
/*A*/ nullptr,
/*C*/ nullptr);
}
static ActionNode* mana_potion([[maybe_unused]] PlayerbotAI* botAI)
{
return new ActionNode("mana potion",
/*P*/ nullptr,
/*A*/ nullptr,
/*C*/ nullptr);
}
static ActionNode* healing_potion([[maybe_unused]] PlayerbotAI* botAI)
{
return new ActionNode("healing potion",
/*P*/ nullptr,
/*A*/ NextAction::array(0, new NextAction("food"), nullptr),
/*C*/ nullptr);
}
static ActionNode* flee([[maybe_unused]] PlayerbotAI* botAI)
{
return new ActionNode("flee",
/*P*/ nullptr,
/*A*/ nullptr,
/*C*/ nullptr);
}
};
Strategy::Strategy(PlayerbotAI* botAI) : PlayerbotAIAware(botAI)
{
actionNodeFactories.Add(new ActionNodeFactoryInternal());
}
ActionNode* Strategy::GetAction(std::string const name) { return actionNodeFactories.GetContextObject(name, botAI); }

View File

@@ -1,75 +0,0 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it
* and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#ifndef _PLAYERBOT_STRATEGY_H
#define _PLAYERBOT_STRATEGY_H
#include "Action.h"
#include "Multiplier.h"
#include "NamedObjectContext.h"
#include "PlayerbotAIAware.h"
#include "Trigger.h"
enum StrategyType : uint32
{
STRATEGY_TYPE_GENERIC = 0,
STRATEGY_TYPE_COMBAT = 1,
STRATEGY_TYPE_NONCOMBAT = 2,
STRATEGY_TYPE_TANK = 4,
STRATEGY_TYPE_DPS = 8,
STRATEGY_TYPE_HEAL = 16,
STRATEGY_TYPE_RANGED = 32,
STRATEGY_TYPE_MELEE = 64
};
// enum ActionPriority
// {
// ACTION_IDLE = 0,
// ACTION_DEFAULT = 5,
// ACTION_NORMAL = 10,
// ACTION_HIGH = 20,
// ACTION_MOVE = 30,
// ACTION_INTERRUPT = 40,
// ACTION_DISPEL = 50,
// ACTION_RAID = 60,
// ACTION_LIGHT_HEAL = 10,
// ACTION_MEDIUM_HEAL = 20,
// ACTION_CRITICAL_HEAL = 30,
// ACTION_EMERGENCY = 90
// };
static float ACTION_IDLE = 0.0f;
static float ACTION_DEFAULT = 5.0f;
static float ACTION_NORMAL = 10.0f;
static float ACTION_HIGH = 20.0f;
static float ACTION_MOVE = 30.0f;
static float ACTION_INTERRUPT = 40.0f;
static float ACTION_DISPEL = 50.0f;
static float ACTION_RAID = 60.0f;
static float ACTION_LIGHT_HEAL = 10.0f;
static float ACTION_MEDIUM_HEAL = 20.0f;
static float ACTION_CRITICAL_HEAL = 30.0f;
static float ACTION_EMERGENCY = 90.0f;
class Strategy : public PlayerbotAIAware
{
public:
Strategy(PlayerbotAI* botAI);
virtual ~Strategy() {}
virtual NextAction** getDefaultActions() { return nullptr; }
virtual void InitTriggers([[maybe_unused]] std::vector<TriggerNode*>& triggers) {}
virtual void InitMultipliers([[maybe_unused]] std::vector<Multiplier*>& multipliers) {}
virtual std::string const getName() = 0;
virtual uint32 GetType() const { return STRATEGY_TYPE_GENERIC; }
virtual ActionNode* GetAction(std::string const name);
void Update() {}
void Reset() {}
protected:
NamedObjectFactoryList<ActionNode> actionNodeFactories;
};
#endif

View File

@@ -1,48 +0,0 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it
* and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#include "Trigger.h"
#include "Event.h"
#include "Playerbots.h"
#include "Timer.h"
Trigger::Trigger(PlayerbotAI* botAI, std::string const name, int32 checkInterval)
: AiNamedObject(botAI, name),
checkInterval(checkInterval == 1 ? 1 : (checkInterval < 100 ? checkInterval * 1000 : checkInterval)),
lastCheckTime(0)
{
}
Event Trigger::Check()
{
if (IsActive())
{
Event event(getName());
return event;
}
Event event;
return event;
}
Value<Unit*>* Trigger::GetTargetValue() { return context->GetValue<Unit*>(GetTargetName()); }
Unit* Trigger::GetTarget() { return GetTargetValue()->Get(); }
bool Trigger::needCheck()
{
if (checkInterval < 2)
return true;
uint32 now = getMSTime();
if (!lastCheckTime || now - lastCheckTime >= checkInterval)
{
lastCheckTime = now;
return true;
}
return false;
}

View File

@@ -1,64 +0,0 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it
* and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#ifndef _PLAYERBOT_TRIGGER_H
#define _PLAYERBOT_TRIGGER_H
#include "Action.h"
#include "Common.h"
class PlayerbotAI;
class Unit;
class Trigger : public AiNamedObject
{
public:
Trigger(PlayerbotAI* botAI, std::string const name = "trigger", int32 checkInterval = 1);
virtual ~Trigger() {}
virtual Event Check();
virtual void ExternalEvent([[maybe_unused]] std::string const param, [[maybe_unused]] Player* owner = nullptr) {}
virtual void ExternalEvent([[maybe_unused]] WorldPacket& packet, [[maybe_unused]] Player* owner = nullptr) {}
virtual bool IsActive() { return false; }
virtual NextAction** getHandlers() { return nullptr; }
void Update() {}
virtual void Reset() {}
virtual Unit* GetTarget();
virtual Value<Unit*>* GetTargetValue();
virtual std::string const GetTargetName() { return "self target"; }
bool needCheck();
protected:
int32 checkInterval;
uint32 lastCheckTime;
};
class TriggerNode
{
public:
TriggerNode(std::string const name, NextAction** handlers = nullptr)
: trigger(nullptr), handlers(handlers), name(name)
{
} // reorder args - whipowill
virtual ~TriggerNode() { NextAction::destroy(handlers); }
Trigger* getTrigger() { return trigger; }
void setTrigger(Trigger* trigger) { this->trigger = trigger; }
std::string const getName() { return name; }
NextAction** getHandlers() { return NextAction::merge(NextAction::clone(handlers), trigger->getHandlers()); }
float getFirstRelevance() { return handlers[0] ? handlers[0]->getRelevance() : -1; }
private:
Trigger* trigger;
NextAction** handlers;
std::string const name;
};
#endif

View File

@@ -1,157 +0,0 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it
* and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#include "Value.h"
#include "PerformanceMonitor.h"
#include "Playerbots.h"
#include "Timer.h"
UnitCalculatedValue::UnitCalculatedValue(PlayerbotAI* botAI, std::string const name, int32 checkInterval)
: CalculatedValue<Unit*>(botAI, name, checkInterval)
{
}
std::string const UnitCalculatedValue::Format()
{
Unit* unit = Calculate();
return unit ? unit->GetName() : "<none>";
}
std::string const UnitManualSetValue::Format()
{
Unit* unit = Get();
return unit ? unit->GetName() : "<none>";
}
std::string const Uint8CalculatedValue::Format()
{
std::ostringstream out;
out << Calculate();
return out.str();
}
std::string const Uint32CalculatedValue::Format()
{
std::ostringstream out;
out << Calculate();
return out.str();
}
std::string const FloatCalculatedValue::Format()
{
std::ostringstream out;
out << Calculate();
return out.str();
}
CDPairCalculatedValue::CDPairCalculatedValue(PlayerbotAI* botAI, std::string const name, int32 checkInterval)
: CalculatedValue<CreatureData const*>(botAI, name, checkInterval)
{
// lastCheckTime = getMSTime() - checkInterval / 2;
}
std::string const CDPairCalculatedValue::Format()
{
CreatureData const* creatureData = Calculate();
if (creatureData)
{
CreatureTemplate const* bmTemplate = sObjectMgr->GetCreatureTemplate(creatureData->id1);
return bmTemplate ? bmTemplate->Name : "<none>";
}
return "<none>";
}
CDPairListCalculatedValue::CDPairListCalculatedValue(PlayerbotAI* botAI, std::string const name, int32 checkInterval)
: CalculatedValue<std::vector<CreatureData const*>>(botAI, name, checkInterval)
{
// lastCheckTime = time(nullptr) - checkInterval / 2;
}
std::string const CDPairListCalculatedValue::Format()
{
std::ostringstream out;
out << "{";
std::vector<CreatureData const*> cdPairs = Calculate();
for (CreatureData const* cdPair : cdPairs)
{
out << cdPair->id1 << ",";
}
out << "}";
return out.str();
}
ObjectGuidCalculatedValue::ObjectGuidCalculatedValue(PlayerbotAI* botAI, std::string const name, int32 checkInterval)
: CalculatedValue<ObjectGuid>(botAI, name, checkInterval)
{
// lastCheckTime = time(nullptr) - checkInterval / 2;
}
std::string const ObjectGuidCalculatedValue::Format()
{
ObjectGuid guid = Calculate();
return guid ? std::to_string(guid.GetRawValue()) : "<none>";
}
ObjectGuidListCalculatedValue::ObjectGuidListCalculatedValue(PlayerbotAI* botAI, std::string const name,
int32 checkInterval)
: CalculatedValue<GuidVector>(botAI, name, checkInterval)
{
}
std::string const ObjectGuidListCalculatedValue::Format()
{
std::ostringstream out;
out << "{";
GuidVector guids = Calculate();
for (GuidVector::iterator i = guids.begin(); i != guids.end(); ++i)
{
ObjectGuid guid = *i;
out << guid.GetRawValue() << ",";
}
out << "}";
return out.str();
}
Unit* UnitCalculatedValue::Get()
{
if (checkInterval < 2)
{
PerformanceMonitorOperation* pmo = sPerformanceMonitor->start(
PERF_MON_VALUE, this->getName(), this->context ? &this->context->performanceStack : nullptr);
value = Calculate();
if (pmo)
pmo->finish();
}
else
{
time_t now = getMSTime();
if (!lastCheckTime || now - lastCheckTime >= checkInterval)
{
lastCheckTime = now;
PerformanceMonitorOperation* pmo = sPerformanceMonitor->start(
PERF_MON_VALUE, this->getName(), this->context ? &this->context->performanceStack : nullptr);
value = Calculate();
if (pmo)
pmo->finish();
}
}
// Prevent crashing by InWorld check
if (value && value->IsInWorld())
return value;
return nullptr;
}
Unit* UnitManualSetValue::Get()
{
// Prevent crashing by InWorld check
if (value && value->IsInWorld())
return value;
return nullptr;
}

View File

@@ -1,419 +0,0 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it
* and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#ifndef _PLAYERBOT_VALUE_H
#define _PLAYERBOT_VALUE_H
#include <time.h>
#include "AiObject.h"
#include "ObjectGuid.h"
#include "PerformanceMonitor.h"
#include "Timer.h"
#include "Unit.h"
class PlayerbotAI;
class Unit;
class FleeInfo
{
public:
Position fromPos;
float radius;
float angle;
uint32 timestamp;
int GetAngleRangeIndex() { return (angle + 2 * M_PI) / (M_PI / 2); } // [0, 7)
};
struct CreatureData;
class UntypedValue : public AiNamedObject
{
public:
UntypedValue(PlayerbotAI* botAI, std::string const name) : AiNamedObject(botAI, name) {}
virtual ~UntypedValue() {}
virtual void Update() {}
virtual void Reset() {}
virtual std::string const Format() { return "?"; }
virtual std::string const Save() { return "?"; }
virtual bool Load([[maybe_unused]] std::string const value) { return false; }
};
template <class T>
class Value
{
public:
virtual ~Value() {}
virtual T Get() = 0;
virtual T LazyGet() = 0;
virtual T& RefGet() = 0;
virtual void Reset() {}
virtual void Set(T value) = 0;
operator T() { return Get(); }
};
template <class T>
class CalculatedValue : public UntypedValue, public Value<T>
{
public:
CalculatedValue(PlayerbotAI* botAI, std::string const name = "value", uint32 checkInterval = 1)
: UntypedValue(botAI, name),
checkInterval(
checkInterval == 1 ? 1 : (checkInterval < 100 ? checkInterval * 1000 : checkInterval)) /*turn s -> ms?*/,
lastCheckTime(0)
{
}
virtual ~CalculatedValue() {}
T Get() override
{
if (checkInterval < 2)
{
// PerformanceMonitorOperation* pmo = sPerformanceMonitor->start(PERF_MON_VALUE, this->getName(),
// this->context ? &this->context->performanceStack : nullptr);
value = Calculate();
// if (pmo)
// pmo->finish();
}
else
{
time_t now = getMSTime();
if (!lastCheckTime || now - lastCheckTime >= checkInterval)
{
lastCheckTime = now;
// PerformanceMonitorOperation* pmo = sPerformanceMonitor->start(PERF_MON_VALUE, this->getName(),
// this->context ? &this->context->performanceStack : nullptr);
value = Calculate();
// if (pmo)
// pmo->finish();
}
}
return value;
}
T LazyGet() override
{
if (!lastCheckTime)
return Get();
return value;
}
T& RefGet() override
{
if (checkInterval < 2)
{
// PerformanceMonitorOperation* pmo = sPerformanceMonitor->start(PERF_MON_VALUE, this->getName(),
// this->context ? &this->context->performanceStack : nullptr);
value = Calculate();
// if (pmo)
// pmo->finish();
}
else
{
time_t now = getMSTime();
if (!lastCheckTime || now - lastCheckTime >= checkInterval)
{
lastCheckTime = now;
// PerformanceMonitorOperation* pmo = sPerformanceMonitor->start(PERF_MON_VALUE, this->getName(),
// this->context ? &this->context->performanceStack : nullptr);
value = Calculate();
// if (pmo)
// pmo->finish();
}
}
return value;
}
void Set(T val) override { value = val; }
void Update() override {}
void Reset() override { lastCheckTime = 0; }
protected:
virtual T Calculate() = 0;
uint32 checkInterval;
uint32 lastCheckTime;
T value;
};
template <class T>
class SingleCalculatedValue : public CalculatedValue<T>
{
public:
SingleCalculatedValue(PlayerbotAI* botAI, std::string const name = "value") : CalculatedValue<T>(botAI, name)
{
this->Reset();
}
T Get() override
{
time_t now = time(0);
if (!this->lastCheckTime)
{
this->lastCheckTime = now;
PerformanceMonitorOperation* pmo = sPerformanceMonitor->start(
PERF_MON_VALUE, this->getName(), this->context ? &this->context->performanceStack : nullptr);
this->value = this->Calculate();
if (pmo)
pmo->finish();
}
return this->value;
}
};
template <class T>
class MemoryCalculatedValue : public CalculatedValue<T>
{
public:
MemoryCalculatedValue(PlayerbotAI* botAI, std::string const name = "value", int32 checkInterval = 1)
: CalculatedValue<T>(botAI, name, checkInterval)
{
lastChangeTime = time(0);
}
virtual bool EqualToLast(T value) = 0;
virtual bool CanCheckChange() { return time(0) - lastChangeTime < minChangeInterval || EqualToLast(this->value); }
virtual bool UpdateChange()
{
if (CanCheckChange())
return false;
lastChangeTime = time(0);
lastValue = this->value;
return true;
}
void Set([[maybe_unused]] T value) override
{
CalculatedValue<T>::Set(this->value);
UpdateChange();
}
T Get() override
{
this->value = CalculatedValue<T>::Get();
UpdateChange();
return this->value;
}
T LazyGet() override { return this->value; }
time_t LastChangeOn()
{
Get();
UpdateChange();
return lastChangeTime;
}
uint32 LastChangeDelay() { return time(0) - LastChangeOn(); }
void Reset() override
{
CalculatedValue<T>::Reset();
lastChangeTime = time(0);
}
protected:
T lastValue;
uint32 minChangeInterval = 0;
time_t lastChangeTime;
};
template <class T>
class LogCalculatedValue : public MemoryCalculatedValue<T>
{
public:
LogCalculatedValue(PlayerbotAI* botAI, std::string const name = "value", int32 checkInterval = 1)
: MemoryCalculatedValue<T>(botAI, name, checkInterval)
{
}
bool UpdateChange() override
{
if (MemoryCalculatedValue<T>::UpdateChange())
return false;
valueLog.push_back(std::make_pair(this->value, time(0)));
if (valueLog.size() > logLength)
valueLog.pop_front();
return true;
}
std::list<std::pair<T, time_t>> ValueLog() { return valueLog; }
void Reset() override
{
MemoryCalculatedValue<T>::Reset();
valueLog.clear();
}
protected:
std::list<std::pair<T, time_t>> valueLog;
uint8 logLength = 10;
};
class Uint8CalculatedValue : public CalculatedValue<uint8>
{
public:
Uint8CalculatedValue(PlayerbotAI* botAI, std::string const name = "value", uint32 checkInterval = 1)
: CalculatedValue<uint8>(botAI, name, checkInterval)
{
}
std::string const Format() override;
};
class Uint32CalculatedValue : public CalculatedValue<uint32>
{
public:
Uint32CalculatedValue(PlayerbotAI* botAI, std::string const name = "value", int checkInterval = 1)
: CalculatedValue<uint32>(botAI, name, checkInterval)
{
}
std::string const Format() override;
};
class FloatCalculatedValue : public CalculatedValue<float>
{
public:
FloatCalculatedValue(PlayerbotAI* botAI, std::string const name = "value", int checkInterval = 1)
: CalculatedValue<float>(botAI, name, checkInterval)
{
}
std::string const Format() override;
};
class BoolCalculatedValue : public CalculatedValue<bool>
{
public:
BoolCalculatedValue(PlayerbotAI* botAI, std::string const name = "value", int checkInterval = 1)
: CalculatedValue<bool>(botAI, name, checkInterval)
{
}
std::string const Format() override { return Calculate() ? "true" : "false"; }
};
class UnitCalculatedValue : public CalculatedValue<Unit*>
{
public:
UnitCalculatedValue(PlayerbotAI* botAI, std::string const name = "value", int32 checkInterval = 1);
std::string const Format() override;
Unit* Get() override;
};
class CDPairCalculatedValue : public CalculatedValue<CreatureData const*>
{
public:
CDPairCalculatedValue(PlayerbotAI* botAI, std::string const name = "value", int32 checkInterval = 1);
std::string const Format() override;
};
class CDPairListCalculatedValue : public CalculatedValue<std::vector<CreatureData const*>>
{
public:
CDPairListCalculatedValue(PlayerbotAI* botAI, std::string const name = "value", int32 checkInterval = 1);
std::string const Format() override;
};
class ObjectGuidCalculatedValue : public CalculatedValue<ObjectGuid>
{
public:
ObjectGuidCalculatedValue(PlayerbotAI* botAI, std::string const name = "value", int32 checkInterval = 1);
std::string const Format() override;
};
class ObjectGuidListCalculatedValue : public CalculatedValue<GuidVector>
{
public:
ObjectGuidListCalculatedValue(PlayerbotAI* botAI, std::string const name = "value", int32 checkInterval = 1);
std::string const Format() override;
};
template <class T>
class ManualSetValue : public UntypedValue, public Value<T>
{
public:
ManualSetValue(PlayerbotAI* botAI, T defaultValue, std::string const name = "value")
: UntypedValue(botAI, name), value(defaultValue), defaultValue(defaultValue)
{
}
virtual ~ManualSetValue() {}
T Get() override { return value; }
T LazyGet() override { return value; }
T& RefGet() override { return value; }
void Set(T val) override { value = val; }
void Update() override {}
void Reset() override { value = defaultValue; }
protected:
T value;
T defaultValue;
};
class UnitManualSetValue : public ManualSetValue<Unit*>
{
public:
UnitManualSetValue(PlayerbotAI* botAI, Unit* defaultValue, std::string const name = "value")
: ManualSetValue<Unit*>(botAI, defaultValue, name)
{
}
std::string const Format() override;
Unit* Get() override;
};
class DisperseDistanceValue : public ManualSetValue<float>
{
public:
DisperseDistanceValue(PlayerbotAI* botAI, float defaultValue = -1.0f, std::string const name = "disperse distance")
: ManualSetValue<float>(botAI, defaultValue, name)
{
}
};
class LastFleeAngleValue : public ManualSetValue<float>
{
public:
LastFleeAngleValue(PlayerbotAI* botAI, float defaultValue = 0.0f, std::string const name = "last flee angle")
: ManualSetValue<float>(botAI, defaultValue, name)
{
}
};
class LastFleeTimestampValue : public ManualSetValue<uint32>
{
public:
LastFleeTimestampValue(PlayerbotAI* botAI, uint32 defaultValue = 0, std::string const name = "last flee timestamp")
: ManualSetValue<uint32>(botAI, defaultValue, name)
{
}
};
class RecentlyFleeInfo : public ManualSetValue<std::list<FleeInfo>&>
{
public:
RecentlyFleeInfo(PlayerbotAI* botAI, std::string const name = "recently flee info")
: ManualSetValue<std::list<FleeInfo>&>(botAI, data, name)
{
}
private:
std::list<FleeInfo> data = {};
};
#endif

Some files were not shown because too many files have changed in this diff Show More