mirror of
https://github.com/mod-playerbots/mod-playerbots.git
synced 2026-01-19 03:35:43 +00:00
[FIX] Finalized structure! (do not start fixing PR merge structure conflict till this is merged) (#2025)
Finalized
This commit is contained in:
20
src/Bot/Engine/Action/Action.cpp
Normal file
20
src/Bot/Engine/Action/Action.cpp
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "Action.h"
|
||||
|
||||
#include "Playerbots.h"
|
||||
#include "Timer.h"
|
||||
|
||||
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_t msecs) { return getMSTime() - created >= msecs; }
|
||||
147
src/Bot/Engine/Action/Action.h
Normal file
147
src/Bot/Engine/Action/Action.h
Normal file
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#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 std::vector<NextAction> merge(std::vector<NextAction> const& what, std::vector<NextAction> const& with)
|
||||
{
|
||||
std::vector<NextAction> result = {};
|
||||
|
||||
for (NextAction const& action : what)
|
||||
{
|
||||
result.push_back(action);
|
||||
}
|
||||
|
||||
for (NextAction const& action : with)
|
||||
{
|
||||
result.push_back(action);
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
private:
|
||||
float relevance;
|
||||
std::string 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 std::vector<NextAction> getPrerequisites() { return {}; }
|
||||
virtual std::vector<NextAction> getAlternatives() { return {}; }
|
||||
virtual std::vector<NextAction> getContinuers() { return {}; }
|
||||
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 name,
|
||||
std::vector<NextAction> prerequisites = {},
|
||||
std::vector<NextAction> alternatives = {},
|
||||
std::vector<NextAction> continuers = {}
|
||||
) :
|
||||
name(std::move(name)),
|
||||
action(nullptr),
|
||||
continuers(continuers),
|
||||
alternatives(alternatives),
|
||||
prerequisites(prerequisites)
|
||||
{}
|
||||
|
||||
virtual ~ActionNode() = default;
|
||||
|
||||
Action* getAction() { return action; }
|
||||
void setAction(Action* action) { this->action = action; }
|
||||
const std::string getName() { return name; }
|
||||
|
||||
std::vector<NextAction> getContinuers()
|
||||
{
|
||||
return NextAction::merge(this->continuers, action->getContinuers());
|
||||
}
|
||||
std::vector<NextAction> getAlternatives()
|
||||
{
|
||||
return NextAction::merge(this->alternatives, action->getAlternatives());
|
||||
}
|
||||
std::vector<NextAction> getPrerequisites()
|
||||
{
|
||||
return NextAction::merge(this->prerequisites, action->getPrerequisites());
|
||||
}
|
||||
|
||||
private:
|
||||
const std::string name;
|
||||
Action* action;
|
||||
std::vector<NextAction> continuers;
|
||||
std::vector<NextAction> alternatives;
|
||||
std::vector<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_t msecs);
|
||||
|
||||
private:
|
||||
ActionNode* action;
|
||||
float relevance;
|
||||
bool skipPrerequisites;
|
||||
Event event;
|
||||
uint32_t created;
|
||||
};
|
||||
15
src/Bot/Engine/AiObject.cpp
Normal file
15
src/Bot/Engine/AiObject.cpp
Normal file
@@ -0,0 +1,15 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "AiObject.h"
|
||||
|
||||
#include "Playerbots.h"
|
||||
|
||||
AiObject::AiObject(PlayerbotAI* botAI)
|
||||
: PlayerbotAIAware(botAI), bot(botAI->GetBot()), context(botAI->GetAiObjectContext()), chat(botAI->GetChatHelper())
|
||||
{
|
||||
}
|
||||
|
||||
Player* AiObject::GetMaster() { return botAI->GetMaster(); }
|
||||
444
src/Bot/Engine/AiObject.h
Normal file
444
src/Bot/Engine/AiObject.h
Normal file
@@ -0,0 +1,444 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#ifndef _PLAYERBOT_AIOBJECT_H
|
||||
#define _PLAYERBOT_AIOBJECT_H
|
||||
|
||||
#include "Common.h"
|
||||
#include "PlayerbotAIAware.h"
|
||||
|
||||
class AiObjectContext;
|
||||
class ChatHelper;
|
||||
class Player;
|
||||
class PlayerbotAI;
|
||||
|
||||
class AiObject : public PlayerbotAIAware
|
||||
{
|
||||
public:
|
||||
AiObject(PlayerbotAI* botAI);
|
||||
|
||||
protected:
|
||||
Player* bot;
|
||||
Player* GetMaster();
|
||||
AiObjectContext* context;
|
||||
ChatHelper* chat;
|
||||
};
|
||||
|
||||
class AiNamedObject : public AiObject
|
||||
{
|
||||
public:
|
||||
AiNamedObject(PlayerbotAI* botAI, std::string const name) : AiObject(botAI), name(name) {}
|
||||
|
||||
public:
|
||||
virtual std::string const getName() { return name; }
|
||||
|
||||
protected:
|
||||
std::string const name;
|
||||
};
|
||||
|
||||
//
|
||||
// TRIGGERS
|
||||
//
|
||||
|
||||
#define BEGIN_TRIGGER(clazz, super) \
|
||||
class clazz : public super \
|
||||
{ \
|
||||
public: \
|
||||
clazz(PlayerbotAI* botAI) : super(botAI) {} \
|
||||
bool IsActive() override;
|
||||
|
||||
#define END_TRIGGER() \
|
||||
} \
|
||||
;
|
||||
|
||||
#define BUFF_TRIGGER(clazz, spell) \
|
||||
class clazz : public BuffTrigger \
|
||||
{ \
|
||||
public: \
|
||||
clazz(PlayerbotAI* botAI) : BuffTrigger(botAI, spell) {} \
|
||||
}
|
||||
|
||||
#define BUFF_TRIGGER_A(clazz, spell) \
|
||||
class clazz : public BuffTrigger \
|
||||
{ \
|
||||
public: \
|
||||
clazz(PlayerbotAI* botAI) : BuffTrigger(botAI, spell) {} \
|
||||
bool IsActive() override; \
|
||||
}
|
||||
|
||||
#define BUFF_PARTY_TRIGGER(clazz, spell) \
|
||||
class clazz : public BuffOnPartyTrigger \
|
||||
{ \
|
||||
public: \
|
||||
clazz(PlayerbotAI* botAI) : BuffOnPartyTrigger(botAI, spell) {} \
|
||||
}
|
||||
|
||||
#define DEBUFF_TRIGGER(clazz, spell) \
|
||||
class clazz : public DebuffTrigger \
|
||||
{ \
|
||||
public: \
|
||||
clazz(PlayerbotAI* botAI) : DebuffTrigger(botAI, spell) {} \
|
||||
}
|
||||
|
||||
#define DEBUFF_CHECKISOWNER_TRIGGER(clazz, spell) \
|
||||
class clazz : public DebuffTrigger \
|
||||
{ \
|
||||
public: \
|
||||
clazz(PlayerbotAI* botAI) : DebuffTrigger(botAI, spell, 1, true) {} \
|
||||
}
|
||||
|
||||
#define DEBUFF_TRIGGER_A(clazz, spell) \
|
||||
class clazz : public DebuffTrigger \
|
||||
{ \
|
||||
public: \
|
||||
clazz(PlayerbotAI* botAI) : DebuffTrigger(botAI, spell) {} \
|
||||
bool IsActive() override; \
|
||||
}
|
||||
|
||||
#define DEBUFF_ENEMY_TRIGGER(clazz, spell) \
|
||||
class clazz : public DebuffOnAttackerTrigger \
|
||||
{ \
|
||||
public: \
|
||||
clazz(PlayerbotAI* botAI) : DebuffOnAttackerTrigger(botAI, spell) {} \
|
||||
}
|
||||
|
||||
#define DEBUFF_ENEMY_TRIGGER_A(clazz, spell) \
|
||||
class clazz : public DebuffOnAttackerTrigger \
|
||||
{ \
|
||||
public: \
|
||||
clazz(PlayerbotAI* botAI) : DebuffOnAttackerTrigger(botAI, spell) {} \
|
||||
bool IsActive() override; \
|
||||
}
|
||||
|
||||
#define CURE_TRIGGER(clazz, spell, dispel) \
|
||||
class clazz : public NeedCureTrigger \
|
||||
{ \
|
||||
public: \
|
||||
clazz(PlayerbotAI* botAI) : NeedCureTrigger(botAI, spell, dispel) {} \
|
||||
}
|
||||
|
||||
#define CURE_PARTY_TRIGGER(clazz, spell, dispel) \
|
||||
class clazz : public PartyMemberNeedCureTrigger \
|
||||
{ \
|
||||
public: \
|
||||
clazz(PlayerbotAI* botAI) : PartyMemberNeedCureTrigger(botAI, spell, dispel) {} \
|
||||
}
|
||||
|
||||
#define CAN_CAST_TRIGGER(clazz, spell) \
|
||||
class clazz : public SpellCanBeCastTrigger \
|
||||
{ \
|
||||
public: \
|
||||
clazz(PlayerbotAI* botAI) : SpellCanBeCastTrigger(botAI, spell) {} \
|
||||
}
|
||||
|
||||
#define CAN_CAST_TRIGGER_A(clazz, spell) \
|
||||
class clazz : public SpellCanBeCastTrigger \
|
||||
{ \
|
||||
public: \
|
||||
clazz(PlayerbotAI* botAI) : SpellCanBeCastTrigger(botAI, spell) {} \
|
||||
bool IsActive() override; \
|
||||
}
|
||||
|
||||
#define CD_TRIGGER(clazz, spell) \
|
||||
class clazz : public SpellNoCooldownTrigger \
|
||||
{ \
|
||||
public: \
|
||||
clazz(PlayerbotAI* botAI) : SpellNoCooldownTrigger(botAI, spell) {} \
|
||||
}
|
||||
|
||||
#define INTERRUPT_TRIGGER(clazz, spell) \
|
||||
class clazz : public InterruptSpellTrigger \
|
||||
{ \
|
||||
public: \
|
||||
clazz(PlayerbotAI* botAI) : InterruptSpellTrigger(botAI, spell) {} \
|
||||
}
|
||||
|
||||
#define INTERRUPT_TRIGGER_A(clazz, spell) \
|
||||
class clazz : public InterruptSpellTrigger \
|
||||
{ \
|
||||
public: \
|
||||
clazz(PlayerbotAI* botAI) : InterruptSpellTrigger(botAI, spell) {} \
|
||||
bool IsActive() override; \
|
||||
}
|
||||
|
||||
#define HAS_AURA_TRIGGER(clazz, spell) \
|
||||
class clazz : public HasAuraTrigger \
|
||||
{ \
|
||||
public: \
|
||||
clazz(PlayerbotAI* botAI) : HasAuraTrigger(botAI, spell) {} \
|
||||
}
|
||||
|
||||
#define HAS_AURA_TRIGGER_A(clazz, spell) \
|
||||
class clazz : public HasAuraTrigger \
|
||||
{ \
|
||||
public: \
|
||||
clazz(PlayerbotAI* botAI) : HasAuraTrigger(botAI, spell) {} \
|
||||
bool IsActive() override; \
|
||||
}
|
||||
|
||||
#define SNARE_TRIGGER(clazz, spell) \
|
||||
class clazz : public SnareTargetTrigger \
|
||||
{ \
|
||||
public: \
|
||||
clazz(PlayerbotAI* botAI) : SnareTargetTrigger(botAI, spell) {} \
|
||||
}
|
||||
|
||||
#define SNARE_TRIGGER_A(clazz, spell) \
|
||||
class clazz : public SnareTargetTrigger \
|
||||
{ \
|
||||
public: \
|
||||
clazz(PlayerbotAI* botAI) : SnareTargetTrigger(botAI, spell) {} \
|
||||
bool IsActive() override; \
|
||||
}
|
||||
|
||||
#define PROTECT_TRIGGER(clazz, spell) \
|
||||
class clazz : public ProtectPartyMemberTrigger \
|
||||
{ \
|
||||
public: \
|
||||
clazz(PlayerbotAI* botAI) : ProtectPartyMemberTrigger(botAI) {} \
|
||||
}
|
||||
|
||||
#define DEFLECT_TRIGGER(clazz, spell) \
|
||||
class clazz : public DeflectSpellTrigger \
|
||||
{ \
|
||||
public: \
|
||||
clazz(PlayerbotAI* botAI) : DeflectSpellTrigger(botAI, spell) {} \
|
||||
}
|
||||
|
||||
#define BOOST_TRIGGER(clazz, spell) \
|
||||
class clazz : public BoostTrigger \
|
||||
{ \
|
||||
public: \
|
||||
clazz(PlayerbotAI* botAI) : BoostTrigger(botAI, spell) {} \
|
||||
}
|
||||
|
||||
#define BOOST_TRIGGER_A(clazz, spell) \
|
||||
class clazz : public BoostTrigger \
|
||||
{ \
|
||||
public: \
|
||||
clazz(PlayerbotAI* botAI) : BoostTrigger(botAI, spell) {} \
|
||||
bool IsActive() override; \
|
||||
}
|
||||
|
||||
#define INTERRUPT_HEALER_TRIGGER(clazz, spell) \
|
||||
class clazz : public InterruptEnemyHealerTrigger \
|
||||
{ \
|
||||
public: \
|
||||
clazz(PlayerbotAI* botAI) : InterruptEnemyHealerTrigger(botAI, spell) {} \
|
||||
}
|
||||
|
||||
#define INTERRUPT_HEALER_TRIGGER_A(clazz, spell) \
|
||||
class clazz : public InterruptEnemyHealerTrigger \
|
||||
{ \
|
||||
public: \
|
||||
clazz(PlayerbotAI* botAI) : InterruptEnemyHealerTrigger(botAI, spell) {} \
|
||||
bool IsActive() override; \
|
||||
}
|
||||
|
||||
#define CC_TRIGGER(clazz, spell) \
|
||||
class clazz : public HasCcTargetTrigger \
|
||||
{ \
|
||||
public: \
|
||||
clazz(PlayerbotAI* botAI) : HasCcTargetTrigger(botAI, spell) {} \
|
||||
}
|
||||
|
||||
//
|
||||
// ACTIONS
|
||||
//
|
||||
|
||||
#define MELEE_ACTION(clazz, spell) \
|
||||
class clazz : public CastMeleeSpellAction \
|
||||
{ \
|
||||
public: \
|
||||
clazz(PlayerbotAI* botAI) : CastMeleeSpellAction(botAI, spell) {} \
|
||||
}
|
||||
|
||||
#define MELEE_ACTION_U(clazz, spell, useful) \
|
||||
class clazz : public CastMeleeSpellAction \
|
||||
{ \
|
||||
public: \
|
||||
clazz(PlayerbotAI* botAI) : CastMeleeSpellAction(botAI, spell) {} \
|
||||
bool isUseful() override { return useful; } \
|
||||
}
|
||||
|
||||
#define SPELL_ACTION(clazz, spell) \
|
||||
class clazz : public CastSpellAction \
|
||||
{ \
|
||||
public: \
|
||||
clazz(PlayerbotAI* botAI) : CastSpellAction(botAI, spell) {} \
|
||||
}
|
||||
|
||||
#define SPELL_ACTION_U(clazz, spell, useful) \
|
||||
class clazz : public CastSpellAction \
|
||||
{ \
|
||||
public: \
|
||||
clazz(PlayerbotAI* botAI) : CastSpellAction(botAI, spell) {} \
|
||||
bool isUseful() override { return useful; } \
|
||||
}
|
||||
|
||||
#define HEAL_ACTION(clazz, spell) \
|
||||
class clazz : public CastHealingSpellAction \
|
||||
{ \
|
||||
public: \
|
||||
clazz(PlayerbotAI* botAI) : CastHealingSpellAction(botAI, spell) {} \
|
||||
}
|
||||
|
||||
#define HEAL_PARTY_ACTION(clazz, spell, estAmount, manaEfficiency) \
|
||||
class clazz : public HealPartyMemberAction \
|
||||
{ \
|
||||
public: \
|
||||
clazz(PlayerbotAI* botAI) : HealPartyMemberAction(botAI, spell, estAmount, manaEfficiency) {} \
|
||||
}
|
||||
|
||||
#define AOE_HEAL_ACTION(clazz, spell, estAmount, manaEfficiency) \
|
||||
class clazz : public CastAoeHealSpellAction \
|
||||
{ \
|
||||
public: \
|
||||
clazz(PlayerbotAI* botAI) : CastAoeHealSpellAction(botAI, spell) {} \
|
||||
}
|
||||
|
||||
#define BUFF_ACTION(clazz, spell) \
|
||||
class clazz : public CastBuffSpellAction \
|
||||
{ \
|
||||
public: \
|
||||
clazz(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, spell) {} \
|
||||
}
|
||||
|
||||
#define BUFF_ACTION_U(clazz, spell, useful) \
|
||||
class clazz : public CastBuffSpellAction \
|
||||
{ \
|
||||
public: \
|
||||
clazz(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, spell) {} \
|
||||
bool isUseful() override { return useful; } \
|
||||
}
|
||||
|
||||
#define BUFF_PARTY_ACTION(clazz, spell) \
|
||||
class clazz : public BuffOnPartyAction \
|
||||
{ \
|
||||
public: \
|
||||
clazz(PlayerbotAI* botAI) : BuffOnPartyAction(botAI, spell) {} \
|
||||
}
|
||||
|
||||
#define CURE_ACTION(clazz, spell) \
|
||||
class clazz : public CastCureSpellAction \
|
||||
{ \
|
||||
public: \
|
||||
clazz(PlayerbotAI* botAI) : CastCureSpellAction(botAI, spell) {} \
|
||||
}
|
||||
|
||||
#define CURE_PARTY_ACTION(clazz, spell, dispel) \
|
||||
class clazz : public CurePartyMemberAction \
|
||||
{ \
|
||||
public: \
|
||||
clazz(PlayerbotAI* botAI) : CurePartyMemberAction(botAI, spell, dispel) {} \
|
||||
}
|
||||
|
||||
#define RESS_ACTION(clazz, spell) \
|
||||
class clazz : public ResurrectPartyMemberAction \
|
||||
{ \
|
||||
public: \
|
||||
clazz(PlayerbotAI* botAI) : ResurrectPartyMemberAction(botAI, spell) {} \
|
||||
}
|
||||
|
||||
#define DEBUFF_ACTION(clazz, spell) \
|
||||
class clazz : public CastDebuffSpellAction \
|
||||
{ \
|
||||
public: \
|
||||
clazz(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, spell) {} \
|
||||
}
|
||||
|
||||
#define DEBUFF_CHECKISOWNER_ACTION(clazz, spell) \
|
||||
class clazz : public CastDebuffSpellAction \
|
||||
{ \
|
||||
public: \
|
||||
clazz(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, spell, true) {} \
|
||||
}
|
||||
|
||||
#define DEBUFF_ACTION_U(clazz, spell, useful) \
|
||||
class clazz : public CastDebuffSpellAction \
|
||||
{ \
|
||||
public: \
|
||||
clazz(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, spell) {} \
|
||||
bool isUseful() override { return useful; } \
|
||||
}
|
||||
|
||||
#define DEBUFF_ACTION_R(clazz, spell, distance) \
|
||||
class clazz : public CastDebuffSpellAction \
|
||||
{ \
|
||||
public: \
|
||||
clazz(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, spell) { range = distance; } \
|
||||
}
|
||||
|
||||
#define DEBUFF_ENEMY_ACTION(clazz, spell) \
|
||||
class clazz : public CastDebuffSpellOnAttackerAction \
|
||||
{ \
|
||||
public: \
|
||||
clazz(PlayerbotAI* botAI) : CastDebuffSpellOnAttackerAction(botAI, spell) {} \
|
||||
}
|
||||
|
||||
#define REACH_ACTION(clazz, spell, range) \
|
||||
class clazz : public CastReachTargetSpellAction \
|
||||
{ \
|
||||
public: \
|
||||
clazz(PlayerbotAI* botAI) : CastReachTargetSpellAction(botAI, spell, range) {} \
|
||||
}
|
||||
|
||||
#define ENEMY_HEALER_ACTION(clazz, spell) \
|
||||
class clazz : public CastSpellOnEnemyHealerAction \
|
||||
{ \
|
||||
public: \
|
||||
clazz(PlayerbotAI* botAI) : CastSpellOnEnemyHealerAction(botAI, spell) {} \
|
||||
}
|
||||
|
||||
#define SNARE_ACTION(clazz, spell) \
|
||||
class clazz : public CastSnareSpellAction \
|
||||
{ \
|
||||
public: \
|
||||
clazz(PlayerbotAI* botAI) : CastSnareSpellAction(botAI, spell) {} \
|
||||
}
|
||||
|
||||
#define CC_ACTION(clazz, spell) \
|
||||
class clazz : public CastCrowdControlSpellAction \
|
||||
{ \
|
||||
public: \
|
||||
clazz(PlayerbotAI* botAI) : CastCrowdControlSpellAction(botAI, spell) {} \
|
||||
}
|
||||
|
||||
#define PROTECT_ACTION(clazz, spell) \
|
||||
class clazz : public CastProtectSpellAction \
|
||||
{ \
|
||||
public: \
|
||||
clazz(PlayerbotAI* botAI) : CastProtectSpellAction(botAI, spell) {} \
|
||||
}
|
||||
|
||||
#define BEGIN_SPELL_ACTION(clazz, name) \
|
||||
class clazz : public CastSpellAction \
|
||||
{ \
|
||||
public: \
|
||||
clazz(PlayerbotAI* botAI) : CastSpellAction(botAI, name) {}
|
||||
|
||||
#define END_SPELL_ACTION() \
|
||||
} \
|
||||
;
|
||||
|
||||
#define BEGIN_DEBUFF_ACTION(clazz, name) \
|
||||
class clazz : public CastDebuffSpellAction \
|
||||
{ \
|
||||
public: \
|
||||
clazz(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, name) {}
|
||||
|
||||
#define BEGIN_RANGED_SPELL_ACTION(clazz, name) \
|
||||
class clazz : public CastSpellAction \
|
||||
{ \
|
||||
public: \
|
||||
clazz(PlayerbotAI* botAI) : CastSpellAction(botAI, name) {}
|
||||
|
||||
#define BEGIN_MELEE_SPELL_ACTION(clazz, name) \
|
||||
class clazz : public CastMeleeSpellAction \
|
||||
{ \
|
||||
public: \
|
||||
clazz(PlayerbotAI* botAI) : CastMeleeSpellAction(botAI, name) {}
|
||||
|
||||
#endif
|
||||
269
src/Bot/Engine/AiObjectContext.cpp
Normal file
269
src/Bot/Engine/AiObjectContext.cpp
Normal file
@@ -0,0 +1,269 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "AiObjectContext.h"
|
||||
|
||||
#include "ActionContext.h"
|
||||
#include "ChatActionContext.h"
|
||||
#include "ChatTriggerContext.h"
|
||||
#include "DKAiObjectContext.h"
|
||||
#include "DruidAiObjectContext.h"
|
||||
#include "HunterAiObjectContext.h"
|
||||
#include "MageAiObjectContext.h"
|
||||
#include "PaladinAiObjectContext.h"
|
||||
#include "Playerbots.h"
|
||||
#include "PriestAiObjectContext.h"
|
||||
#include "RaidUlduarActionContext.h"
|
||||
#include "RaidUlduarTriggerContext.h"
|
||||
#include "RogueAiObjectContext.h"
|
||||
#include "ShamanAiObjectContext.h"
|
||||
#include "SharedValueContext.h"
|
||||
#include "StrategyContext.h"
|
||||
#include "TriggerContext.h"
|
||||
#include "ValueContext.h"
|
||||
#include "WarlockAiObjectContext.h"
|
||||
#include "WarriorAiObjectContext.h"
|
||||
#include "WorldPacketActionContext.h"
|
||||
#include "WorldPacketTriggerContext.h"
|
||||
#include "Scenario/DungeonAi/DungeonStrategyContext.h"
|
||||
#include "Scenario/DungeonAi/Wotlk/WotlkDungeonActionContext.h"
|
||||
#include "Scenario/DungeonAi/Wotlk/WotlkDungeonTriggerContext.h"
|
||||
#include "Scenario/RaidAi/RaidStrategyContext.h"
|
||||
#include "Scenario/RaidAi/Aq20/RaidAq20ActionContext.h"
|
||||
#include "Scenario/RaidAi/Aq20/RaidAq20TriggerContext.h"
|
||||
#include "Scenario/RaidAi/MoltenCore/RaidMcActionContext.h"
|
||||
#include "Scenario/RaidAi/MoltenCore/RaidMcTriggerContext.h"
|
||||
#include "Scenario/RaidAi/BlackwingLair/RaidBwlActionContext.h"
|
||||
#include "Scenario/RaidAi/BlackwingLair/RaidBwlTriggerContext.h"
|
||||
#include "Scenario/RaidAi/Karazhan/RaidKarazhanActionContext.h"
|
||||
#include "Scenario/RaidAi/Karazhan/RaidKarazhanTriggerContext.h"
|
||||
#include "Scenario/RaidAi/Magtheridon/RaidMagtheridonActionContext.h"
|
||||
#include "Scenario/RaidAi/Magtheridon/RaidMagtheridonTriggerContext.h"
|
||||
#include "Scenario/RaidAi/GruulsLair/RaidGruulsLairActionContext.h"
|
||||
#include "Scenario/RaidAi/GruulsLair/RaidGruulsLairTriggerContext.h"
|
||||
#include "Scenario/RaidAi/EyeOfEternity/RaidEoEActionContext.h"
|
||||
#include "Scenario/RaidAi/EyeOfEternity/RaidEoETriggerContext.h"
|
||||
#include "Scenario/RaidAi/VaultOfArchavon/RaidVoAActionContext.h"
|
||||
#include "Scenario/RaidAi/VaultOfArchavon/RaidVoATriggerContext.h"
|
||||
#include "Scenario/RaidAi/ObsidianSanctum/RaidOsActionContext.h"
|
||||
#include "Scenario/RaidAi/ObsidianSanctum/RaidOsTriggerContext.h"
|
||||
#include "Scenario/RaidAi/Onyxia/RaidOnyxiaActionContext.h"
|
||||
#include "Scenario/RaidAi/Onyxia/RaidOnyxiaTriggerContext.h"
|
||||
#include "Scenario/RaidAi/Icecrown/RaidIccActionContext.h"
|
||||
#include "Scenario/RaidAi/Icecrown/RaidIccTriggerContext.h"
|
||||
|
||||
SharedNamedObjectContextList<Strategy> AiObjectContext::sharedStrategyContexts;
|
||||
SharedNamedObjectContextList<Action> AiObjectContext::sharedActionContexts;
|
||||
SharedNamedObjectContextList<Trigger> AiObjectContext::sharedTriggerContexts;
|
||||
SharedNamedObjectContextList<UntypedValue> AiObjectContext::sharedValueContexts;
|
||||
|
||||
AiObjectContext::AiObjectContext(PlayerbotAI* botAI, SharedNamedObjectContextList<Strategy>& sharedStrategyContext,
|
||||
SharedNamedObjectContextList<Action>& sharedActionContext,
|
||||
SharedNamedObjectContextList<Trigger>& sharedTriggerContext,
|
||||
SharedNamedObjectContextList<UntypedValue>& sharedValueContext)
|
||||
: PlayerbotAIAware(botAI),
|
||||
strategyContexts(sharedStrategyContext),
|
||||
actionContexts(sharedActionContext),
|
||||
triggerContexts(sharedTriggerContext),
|
||||
valueContexts(sharedValueContext)
|
||||
{
|
||||
}
|
||||
|
||||
void AiObjectContext::BuildAllSharedContexts()
|
||||
{
|
||||
AiObjectContext::BuildSharedContexts();
|
||||
PriestAiObjectContext::BuildSharedContexts();
|
||||
MageAiObjectContext::BuildSharedContexts();
|
||||
WarlockAiObjectContext::BuildSharedContexts();
|
||||
WarriorAiObjectContext::BuildSharedContexts();
|
||||
ShamanAiObjectContext::BuildSharedContexts();
|
||||
PaladinAiObjectContext::BuildSharedContexts();
|
||||
DruidAiObjectContext::BuildSharedContexts();
|
||||
HunterAiObjectContext::BuildSharedContexts();
|
||||
RogueAiObjectContext::BuildSharedContexts();
|
||||
DKAiObjectContext::BuildSharedContexts();
|
||||
}
|
||||
|
||||
void AiObjectContext::BuildSharedContexts()
|
||||
{
|
||||
BuildSharedStrategyContexts(sharedStrategyContexts);
|
||||
BuildSharedActionContexts(sharedActionContexts);
|
||||
BuildSharedTriggerContexts(sharedTriggerContexts);
|
||||
BuildSharedValueContexts(sharedValueContexts);
|
||||
}
|
||||
|
||||
void AiObjectContext::BuildSharedStrategyContexts(SharedNamedObjectContextList<Strategy>& strategyContexts)
|
||||
{
|
||||
strategyContexts.Add(new StrategyContext());
|
||||
strategyContexts.Add(new MovementStrategyContext());
|
||||
strategyContexts.Add(new AssistStrategyContext());
|
||||
strategyContexts.Add(new QuestStrategyContext());
|
||||
strategyContexts.Add(new DungeonStrategyContext());
|
||||
strategyContexts.Add(new RaidStrategyContext());
|
||||
}
|
||||
|
||||
void AiObjectContext::BuildSharedActionContexts(SharedNamedObjectContextList<Action>& actionContexts)
|
||||
{
|
||||
actionContexts.Add(new ActionContext());
|
||||
actionContexts.Add(new ChatActionContext());
|
||||
actionContexts.Add(new WorldPacketActionContext());
|
||||
actionContexts.Add(new RaidAq20ActionContext());
|
||||
actionContexts.Add(new RaidMcActionContext());
|
||||
actionContexts.Add(new RaidBwlActionContext());
|
||||
actionContexts.Add(new RaidKarazhanActionContext());
|
||||
actionContexts.Add(new RaidMagtheridonActionContext());
|
||||
actionContexts.Add(new RaidGruulsLairActionContext());
|
||||
actionContexts.Add(new RaidOsActionContext());
|
||||
actionContexts.Add(new RaidEoEActionContext());
|
||||
actionContexts.Add(new RaidVoAActionContext());
|
||||
actionContexts.Add(new RaidUlduarActionContext());
|
||||
actionContexts.Add(new RaidOnyxiaActionContext());
|
||||
actionContexts.Add(new RaidIccActionContext());
|
||||
actionContexts.Add(new WotlkDungeonUKActionContext());
|
||||
actionContexts.Add(new WotlkDungeonNexActionContext());
|
||||
actionContexts.Add(new WotlkDungeonANActionContext());
|
||||
actionContexts.Add(new WotlkDungeonOKActionContext());
|
||||
actionContexts.Add(new WotlkDungeonDTKActionContext());
|
||||
actionContexts.Add(new WotlkDungeonVHActionContext());
|
||||
actionContexts.Add(new WotlkDungeonGDActionContext());
|
||||
actionContexts.Add(new WotlkDungeonHoSActionContext());
|
||||
actionContexts.Add(new WotlkDungeonHoLActionContext());
|
||||
actionContexts.Add(new WotlkDungeonOccActionContext());
|
||||
actionContexts.Add(new WotlkDungeonUPActionContext());
|
||||
actionContexts.Add(new WotlkDungeonCoSActionContext());
|
||||
actionContexts.Add(new WotlkDungeonFoSActionContext());
|
||||
actionContexts.Add(new WotlkDungeonPoSActionContext());
|
||||
actionContexts.Add(new WotlkDungeonToCActionContext());
|
||||
}
|
||||
|
||||
void AiObjectContext::BuildSharedTriggerContexts(SharedNamedObjectContextList<Trigger>& triggerContexts)
|
||||
{
|
||||
triggerContexts.Add(new TriggerContext());
|
||||
triggerContexts.Add(new ChatTriggerContext());
|
||||
triggerContexts.Add(new WorldPacketTriggerContext());
|
||||
triggerContexts.Add(new RaidAq20TriggerContext());
|
||||
triggerContexts.Add(new RaidMcTriggerContext());
|
||||
triggerContexts.Add(new RaidBwlTriggerContext());
|
||||
triggerContexts.Add(new RaidKarazhanTriggerContext());
|
||||
triggerContexts.Add(new RaidMagtheridonTriggerContext());
|
||||
triggerContexts.Add(new RaidGruulsLairTriggerContext());
|
||||
triggerContexts.Add(new RaidOsTriggerContext());
|
||||
triggerContexts.Add(new RaidEoETriggerContext());
|
||||
triggerContexts.Add(new RaidVoATriggerContext());
|
||||
triggerContexts.Add(new RaidUlduarTriggerContext());
|
||||
triggerContexts.Add(new RaidOnyxiaTriggerContext());
|
||||
triggerContexts.Add(new RaidIccTriggerContext());
|
||||
triggerContexts.Add(new WotlkDungeonUKTriggerContext());
|
||||
triggerContexts.Add(new WotlkDungeonNexTriggerContext());
|
||||
triggerContexts.Add(new WotlkDungeonANTriggerContext());
|
||||
triggerContexts.Add(new WotlkDungeonOKTriggerContext());
|
||||
triggerContexts.Add(new WotlkDungeonDTKTriggerContext());
|
||||
triggerContexts.Add(new WotlkDungeonVHTriggerContext());
|
||||
triggerContexts.Add(new WotlkDungeonGDTriggerContext());
|
||||
triggerContexts.Add(new WotlkDungeonHoSTriggerContext());
|
||||
triggerContexts.Add(new WotlkDungeonHoLTriggerContext());
|
||||
triggerContexts.Add(new WotlkDungeonOccTriggerContext());
|
||||
triggerContexts.Add(new WotlkDungeonUPTriggerContext());
|
||||
triggerContexts.Add(new WotlkDungeonCoSTriggerContext());
|
||||
triggerContexts.Add(new WotlkDungeonFoSTriggerContext());
|
||||
triggerContexts.Add(new WotlkDungeonPoSTriggerContext());
|
||||
triggerContexts.Add(new WotlkDungeonToCTriggerContext());
|
||||
}
|
||||
|
||||
void AiObjectContext::BuildSharedValueContexts(SharedNamedObjectContextList<UntypedValue>& valueContexts)
|
||||
{
|
||||
valueContexts.Add(new ValueContext());
|
||||
}
|
||||
|
||||
std::vector<std::string> AiObjectContext::Save()
|
||||
{
|
||||
std::vector<std::string> result;
|
||||
|
||||
std::set<std::string> names = valueContexts.GetCreated();
|
||||
for (std::set<std::string>::iterator i = names.begin(); i != names.end(); ++i)
|
||||
{
|
||||
UntypedValue* value = GetUntypedValue(*i);
|
||||
if (!value)
|
||||
continue;
|
||||
|
||||
std::string const data = value->Save();
|
||||
if (data == "?")
|
||||
continue;
|
||||
|
||||
std::string const name = *i;
|
||||
std::ostringstream out;
|
||||
out << name;
|
||||
|
||||
out << ">" << data;
|
||||
result.push_back(out.str());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void AiObjectContext::Load(std::vector<std::string> data)
|
||||
{
|
||||
for (std::vector<std::string>::iterator i = data.begin(); i != data.end(); ++i)
|
||||
{
|
||||
std::string const row = *i;
|
||||
std::vector<std::string> parts = split(row, '>');
|
||||
if (parts.size() != 2)
|
||||
continue;
|
||||
|
||||
std::string const name = parts[0];
|
||||
std::string const text = parts[1];
|
||||
|
||||
UntypedValue* value = GetUntypedValue(name);
|
||||
if (!value)
|
||||
continue;
|
||||
|
||||
value->Load(text);
|
||||
}
|
||||
}
|
||||
|
||||
Strategy* AiObjectContext::GetStrategy(std::string const name)
|
||||
{
|
||||
return strategyContexts.GetContextObject(name, botAI);
|
||||
}
|
||||
|
||||
std::set<std::string> AiObjectContext::GetSiblingStrategy(std::string const name)
|
||||
{
|
||||
return strategyContexts.GetSiblings(name);
|
||||
}
|
||||
|
||||
Trigger* AiObjectContext::GetTrigger(std::string const name) { return triggerContexts.GetContextObject(name, botAI); }
|
||||
|
||||
Action* AiObjectContext::GetAction(std::string const name) { return actionContexts.GetContextObject(name, botAI); }
|
||||
|
||||
UntypedValue* AiObjectContext::GetUntypedValue(std::string const name)
|
||||
{
|
||||
return valueContexts.GetContextObject(name, botAI);
|
||||
}
|
||||
|
||||
std::set<std::string> AiObjectContext::GetValues() { return valueContexts.GetCreated(); }
|
||||
|
||||
std::set<std::string> AiObjectContext::GetSupportedStrategies() { return strategyContexts.supports(); }
|
||||
|
||||
std::set<std::string> AiObjectContext::GetSupportedActions() { return actionContexts.supports(); }
|
||||
|
||||
std::string const AiObjectContext::FormatValues()
|
||||
{
|
||||
std::ostringstream out;
|
||||
std::set<std::string> names = valueContexts.GetCreated();
|
||||
for (std::set<std::string>::iterator i = names.begin(); i != names.end(); ++i, out << "|")
|
||||
{
|
||||
UntypedValue* value = GetUntypedValue(*i);
|
||||
if (!value)
|
||||
continue;
|
||||
|
||||
std::string const text = value->Format();
|
||||
if (text == "?")
|
||||
continue;
|
||||
|
||||
out << "{" << *i << "=" << text << "}";
|
||||
}
|
||||
|
||||
return out.str();
|
||||
}
|
||||
95
src/Bot/Engine/AiObjectContext.h
Normal file
95
src/Bot/Engine/AiObjectContext.h
Normal file
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#ifndef _PLAYERBOT_AIOBJECTCONTEXT_H
|
||||
#define _PLAYERBOT_AIOBJECTCONTEXT_H
|
||||
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
#include "Common.h"
|
||||
#include "DynamicObject.h"
|
||||
#include "NamedObjectContext.h"
|
||||
#include "PlayerbotAIAware.h"
|
||||
#include "Strategy.h"
|
||||
#include "Trigger.h"
|
||||
#include "Value.h"
|
||||
|
||||
class PlayerbotAI;
|
||||
|
||||
typedef Strategy* (*StrategyCreator)(PlayerbotAI* botAI);
|
||||
typedef Action* (*ActionCreator)(PlayerbotAI* botAI);
|
||||
typedef Trigger* (*TriggerCreator)(PlayerbotAI* botAI);
|
||||
typedef UntypedValue* (*ValueCreator)(PlayerbotAI* botAI);
|
||||
|
||||
class AiObjectContext : public PlayerbotAIAware
|
||||
{
|
||||
public:
|
||||
static BoolCalculatedValue* custom_glyphs(PlayerbotAI* ai); // Added for cutom glyphs
|
||||
AiObjectContext(PlayerbotAI* botAI,
|
||||
SharedNamedObjectContextList<Strategy>& sharedStrategyContext = sharedStrategyContexts,
|
||||
SharedNamedObjectContextList<Action>& sharedActionContext = sharedActionContexts,
|
||||
SharedNamedObjectContextList<Trigger>& sharedTriggerContext = sharedTriggerContexts,
|
||||
SharedNamedObjectContextList<UntypedValue>& sharedValueContext = sharedValueContexts);
|
||||
virtual ~AiObjectContext() {}
|
||||
|
||||
virtual Strategy* GetStrategy(std::string const name);
|
||||
virtual std::set<std::string> GetSiblingStrategy(std::string const name);
|
||||
virtual Trigger* GetTrigger(std::string const name);
|
||||
virtual Action* GetAction(std::string const name);
|
||||
virtual UntypedValue* GetUntypedValue(std::string const name);
|
||||
|
||||
template <class T>
|
||||
Value<T>* GetValue(std::string const name)
|
||||
{
|
||||
return dynamic_cast<Value<T>*>(GetUntypedValue(name));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
Value<T>* GetValue(std::string const name, std::string const param)
|
||||
{
|
||||
return GetValue<T>((std::string(name) + "::" + param));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
Value<T>* GetValue(std::string const name, int32 param)
|
||||
{
|
||||
std::ostringstream out;
|
||||
out << param;
|
||||
return GetValue<T>(name, out.str());
|
||||
}
|
||||
|
||||
std::set<std::string> GetValues();
|
||||
std::set<std::string> GetSupportedStrategies();
|
||||
std::set<std::string> GetSupportedActions();
|
||||
std::string const FormatValues();
|
||||
|
||||
std::vector<std::string> Save();
|
||||
void Load(std::vector<std::string> data);
|
||||
|
||||
std::vector<std::string> performanceStack;
|
||||
|
||||
static void BuildAllSharedContexts();
|
||||
|
||||
static void BuildSharedContexts();
|
||||
static void BuildSharedStrategyContexts(SharedNamedObjectContextList<Strategy>& strategyContexts);
|
||||
static void BuildSharedActionContexts(SharedNamedObjectContextList<Action>& actionContexts);
|
||||
static void BuildSharedTriggerContexts(SharedNamedObjectContextList<Trigger>& triggerContexts);
|
||||
static void BuildSharedValueContexts(SharedNamedObjectContextList<UntypedValue>& valueContexts);
|
||||
|
||||
protected:
|
||||
NamedObjectContextList<Strategy> strategyContexts;
|
||||
NamedObjectContextList<Action> actionContexts;
|
||||
NamedObjectContextList<Trigger> triggerContexts;
|
||||
NamedObjectContextList<UntypedValue> valueContexts;
|
||||
|
||||
private:
|
||||
static SharedNamedObjectContextList<Strategy> sharedStrategyContexts;
|
||||
static SharedNamedObjectContextList<Action> sharedActionContexts;
|
||||
static SharedNamedObjectContextList<Trigger> sharedTriggerContexts;
|
||||
static SharedNamedObjectContextList<UntypedValue> sharedValueContexts;
|
||||
};
|
||||
|
||||
#endif
|
||||
669
src/Bot/Engine/Engine.cpp
Normal file
669
src/Bot/Engine/Engine.cpp
Normal file
@@ -0,0 +1,669 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "Engine.h"
|
||||
|
||||
#include "Action.h"
|
||||
#include "Event.h"
|
||||
#include "PerfMonitor.h"
|
||||
#include "Playerbots.h"
|
||||
#include "Queue.h"
|
||||
#include "Strategy.h"
|
||||
#include "Timer.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();
|
||||
|
||||
actionNodeFactories.creators.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);
|
||||
for (auto &iter : strategy->actionNodeFactories.creators)
|
||||
{
|
||||
actionNodeFactories.creators[iter.first] = iter.second;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
PerfMonitorOperation* pmo = sPerfMonitor->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)
|
||||
{
|
||||
ActionNode* node = actionNodeFactories.GetContextObject(name, botAI);
|
||||
if (node)
|
||||
return node;
|
||||
|
||||
return new ActionNode(name,
|
||||
/*P*/ {},
|
||||
/*A*/ {},
|
||||
/*C*/ {});
|
||||
}
|
||||
|
||||
bool Engine::MultiplyAndPush(
|
||||
std::vector<NextAction> actions,
|
||||
float forceRelevance,
|
||||
bool skipPrerequisites,
|
||||
Event event,
|
||||
char const* pushType
|
||||
)
|
||||
{
|
||||
bool pushed = false;
|
||||
|
||||
for (NextAction nextAction : actions)
|
||||
{
|
||||
ActionNode* action = this->CreateActionNode(nextAction.getName());
|
||||
|
||||
this->InitializeAction(action);
|
||||
|
||||
float k = nextAction.getRelevance();
|
||||
|
||||
if (forceRelevance > 0.0f)
|
||||
{
|
||||
k = forceRelevance;
|
||||
}
|
||||
|
||||
if (k > 0)
|
||||
{
|
||||
this->LogAction("PUSH:%s - %f (%s)", action->getName().c_str(), k, pushType);
|
||||
queue.Push(new ActionBasket(action, k, skipPrerequisites, event));
|
||||
pushed = true;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
delete action;
|
||||
|
||||
}
|
||||
|
||||
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;
|
||||
uint32 now = getMSTime();
|
||||
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(now))
|
||||
{
|
||||
if (minimal && node->getFirstRelevance() < 100)
|
||||
continue;
|
||||
|
||||
PerfMonitorOperation* pmo =
|
||||
sPerfMonitor->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)
|
||||
{
|
||||
std::vector<NextAction> nextAction = { NextAction(actionNode->getName(), relevance) };
|
||||
|
||||
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 (action == nullptr)
|
||||
{
|
||||
LOG_ERROR("playerbots", "Action is nullptr");
|
||||
|
||||
return actionExecuted;
|
||||
}
|
||||
|
||||
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);
|
||||
vsnprintf(buf, sizeof(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());
|
||||
}
|
||||
120
src/Bot/Engine/Engine.h
Normal file
120
src/Bot/Engine/Engine.h
Normal file
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 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(std::vector<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;
|
||||
NamedObjectFactoryList<ActionNode> actionNodeFactories;
|
||||
};
|
||||
|
||||
#endif
|
||||
67
src/Bot/Engine/ExternalEventHelper.cpp
Normal file
67
src/Bot/Engine/ExternalEventHelper.cpp
Normal file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 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;
|
||||
}
|
||||
30
src/Bot/Engine/ExternalEventHelper.h
Normal file
30
src/Bot/Engine/ExternalEventHelper.h
Normal file
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 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
|
||||
23
src/Bot/Engine/Multiplier.h
Normal file
23
src/Bot/Engine/Multiplier.h
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 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
|
||||
52
src/Bot/Engine/NamedObjectContext.cpp
Normal file
52
src/Bot/Engine/NamedObjectContext.cpp
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 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(const 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(const std::string& qualifier1)
|
||||
{
|
||||
std::istringstream iss(qualifier1);
|
||||
return {std::istream_iterator<std::string>{iss}, std::istream_iterator<std::string>{}};
|
||||
}
|
||||
|
||||
int32 Qualified::getMultiQualifier(const std::string& qualifier1, uint32 pos)
|
||||
{
|
||||
return std::stoi(getMultiQualifiers(qualifier1)[pos]);
|
||||
}
|
||||
310
src/Bot/Engine/NamedObjectContext.h
Normal file
310
src/Bot/Engine/NamedObjectContext.h
Normal file
@@ -0,0 +1,310 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 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 <functional>
|
||||
|
||||
#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(const std::vector<std::string>& qualifiers, const std::string& separator,
|
||||
const std::string_view brackets = "{}");
|
||||
static std::vector<std::string> getMultiQualifiers(const std::string& qualifier1);
|
||||
static int32 getMultiQualifier(const std::string& qualifier1, uint32 pos);
|
||||
|
||||
protected:
|
||||
std::string qualifier;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class NamedObjectFactory
|
||||
{
|
||||
public:
|
||||
using ObjectCreator = std::function<T*(PlayerbotAI* ai)>;
|
||||
std::unordered_map<std::string, ObjectCreator> creators;
|
||||
|
||||
public:
|
||||
virtual ~NamedObjectFactory() = default;
|
||||
|
||||
virtual 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;
|
||||
|
||||
ObjectCreator& creator = creators[name];
|
||||
|
||||
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, ObjectCreator>::const_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(); }
|
||||
|
||||
virtual T* create(std::string name, PlayerbotAI* botAI) override
|
||||
{
|
||||
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*>::const_iterator i = created.begin(); i != created.end(); i++)
|
||||
{
|
||||
if (i->second)
|
||||
delete i->second;
|
||||
}
|
||||
|
||||
created.clear();
|
||||
}
|
||||
|
||||
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 SharedNamedObjectContextList
|
||||
{
|
||||
public:
|
||||
using ObjectCreator = std::function<T*(PlayerbotAI* ai)>;
|
||||
std::unordered_map<std::string, ObjectCreator> creators;
|
||||
std::vector<NamedObjectContext<T>*> contexts;
|
||||
|
||||
~SharedNamedObjectContextList()
|
||||
{
|
||||
for (typename std::vector<NamedObjectContext<T>*>::const_iterator i = contexts.begin(); i != contexts.end(); i++)
|
||||
delete *i;
|
||||
}
|
||||
|
||||
void Add(NamedObjectContext<T>* context)
|
||||
{
|
||||
contexts.push_back(context);
|
||||
for (auto const& iter : context->creators)
|
||||
creators[iter.first] = iter.second;
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class NamedObjectContextList
|
||||
{
|
||||
public:
|
||||
using ObjectCreator = std::function<T*(PlayerbotAI* ai)>;
|
||||
const std::unordered_map<std::string, ObjectCreator>& creators;
|
||||
const std::vector<NamedObjectContext<T>*>& contexts;
|
||||
std::unordered_map<std::string, T*> created;
|
||||
|
||||
NamedObjectContextList(const SharedNamedObjectContextList<T>& shared)
|
||||
: creators(shared.creators), contexts(shared.contexts)
|
||||
{
|
||||
}
|
||||
|
||||
~NamedObjectContextList()
|
||||
{
|
||||
for (typename std::unordered_map<std::string, T*>::const_iterator i = created.begin(); i != created.end(); i++)
|
||||
{
|
||||
if (i->second)
|
||||
delete i->second;
|
||||
}
|
||||
|
||||
created.clear();
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
const ObjectCreator& creator = creators.at(name);
|
||||
|
||||
T* object = creator(botAI);
|
||||
Qualified* q = dynamic_cast<Qualified*>(object);
|
||||
if (q && found != std::string::npos)
|
||||
q->Qualify(qualifier);
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
T* GetContextObject(const std::string& name, PlayerbotAI* botAI)
|
||||
{
|
||||
if (created.find(name) == created.end())
|
||||
{
|
||||
if (T* object = create(name, botAI))
|
||||
return created[name] = object;
|
||||
}
|
||||
|
||||
return created[name];
|
||||
}
|
||||
|
||||
std::set<std::string> GetSiblings(const std::string& name)
|
||||
{
|
||||
for (auto 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 (auto i = contexts.begin(); i != contexts.end(); i++)
|
||||
{
|
||||
std::set<std::string> supported = (*i)->supports();
|
||||
for (std::set<std::string>::const_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::unordered_map<std::string, T*>::const_iterator i = created.begin(); i != created.end(); i++)
|
||||
result.insert(i->first);
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class NamedObjectFactoryList
|
||||
{
|
||||
public:
|
||||
using ObjectCreator = std::function<T*(PlayerbotAI* ai)>;
|
||||
std::vector<NamedObjectFactory<T>*> factories;
|
||||
std::unordered_map<std::string, ObjectCreator> creators;
|
||||
|
||||
virtual ~NamedObjectFactoryList()
|
||||
{
|
||||
for (typename std::vector<NamedObjectFactory<T>*>::const_iterator i = factories.begin(); i != factories.end(); i++)
|
||||
delete *i;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
const ObjectCreator& creator = creators[name];
|
||||
|
||||
T* object = creator(botAI);
|
||||
Qualified* q = dynamic_cast<Qualified*>(object);
|
||||
if (q && found != std::string::npos)
|
||||
q->Qualify(qualifier);
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
void Add(NamedObjectFactory<T>* context)
|
||||
{
|
||||
factories.push_back(context);
|
||||
for (auto const& iter : context->creators)
|
||||
creators[iter.first] = iter.second;
|
||||
}
|
||||
|
||||
T* GetContextObject(const std::string& name, PlayerbotAI* botAI)
|
||||
{
|
||||
if (T* object = create(name, botAI))
|
||||
return object;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
54
src/Bot/Engine/PassiveMultiplier.cpp
Normal file
54
src/Bot/Engine/PassiveMultiplier.cpp
Normal file
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "PassiveMultiplier.h"
|
||||
|
||||
#include "Action.h"
|
||||
#include "AiObjectContext.h"
|
||||
|
||||
std::vector<std::string> PassiveMultiplier::allowedActions;
|
||||
std::vector<std::string> PassiveMultiplier::allowedParts;
|
||||
|
||||
PassiveMultiplier::PassiveMultiplier(PlayerbotAI* botAI) : Multiplier(botAI, "passive")
|
||||
{
|
||||
if (allowedActions.empty())
|
||||
{
|
||||
allowedActions.push_back("co");
|
||||
allowedActions.push_back("nc");
|
||||
allowedActions.push_back("reset botAI");
|
||||
allowedActions.push_back("check mount state");
|
||||
allowedActions.push_back("lfg");
|
||||
}
|
||||
|
||||
if (allowedParts.empty())
|
||||
{
|
||||
allowedParts.push_back("follow");
|
||||
allowedParts.push_back("move from group");
|
||||
allowedParts.push_back("stay");
|
||||
allowedParts.push_back("chat shortcut");
|
||||
}
|
||||
}
|
||||
|
||||
float PassiveMultiplier::GetValue(Action* action)
|
||||
{
|
||||
if (!action)
|
||||
return 1.0f;
|
||||
|
||||
std::string const name = action->getName();
|
||||
|
||||
for (std::vector<std::string>::iterator i = allowedActions.begin(); i != allowedActions.end(); i++)
|
||||
{
|
||||
if (name == *i)
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
for (std::vector<std::string>::iterator i = allowedParts.begin(); i != allowedParts.end(); i++)
|
||||
{
|
||||
if (name.find(*i) != std::string::npos)
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
28
src/Bot/Engine/PassiveMultiplier.h
Normal file
28
src/Bot/Engine/PassiveMultiplier.h
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#ifndef _PLAYERBOT_PASSIVEMULTIPLIER_H
|
||||
#define _PLAYERBOT_PASSIVEMULTIPLIER_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "Multiplier.h"
|
||||
|
||||
class Action;
|
||||
class PlayerbotAI;
|
||||
|
||||
class PassiveMultiplier : public Multiplier
|
||||
{
|
||||
public:
|
||||
PassiveMultiplier(PlayerbotAI* botAI);
|
||||
|
||||
float GetValue(Action* action) override;
|
||||
|
||||
private:
|
||||
static std::vector<std::string> allowedActions;
|
||||
static std::vector<std::string> allowedParts;
|
||||
};
|
||||
|
||||
#endif
|
||||
20
src/Bot/Engine/PlayerbotAIAware.h
Normal file
20
src/Bot/Engine/PlayerbotAIAware.h
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#ifndef _PLAYERBOT_PLAYERbotAIAWARE_H
|
||||
#define _PLAYERBOT_PLAYERbotAIAWARE_H
|
||||
|
||||
class PlayerbotAI;
|
||||
|
||||
class PlayerbotAIAware
|
||||
{
|
||||
public:
|
||||
PlayerbotAIAware(PlayerbotAI* botAI) : botAI(botAI) {}
|
||||
|
||||
protected:
|
||||
PlayerbotAI* botAI;
|
||||
};
|
||||
|
||||
#endif
|
||||
60
src/Bot/Engine/PlayerbotAIBase.cpp
Normal file
60
src/Bot/Engine/PlayerbotAIBase.cpp
Normal file
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "PlayerbotAIBase.h"
|
||||
|
||||
#include "Playerbots.h"
|
||||
|
||||
PlayerbotAIBase::PlayerbotAIBase(bool isBotAI) : nextAICheckDelay(0), _isBotAI(isBotAI) {}
|
||||
|
||||
void PlayerbotAIBase::UpdateAI(uint32 elapsed, bool minimal)
|
||||
{
|
||||
if (totalPmo)
|
||||
totalPmo->finish();
|
||||
|
||||
totalPmo = sPerfMonitor->start(PERF_MON_TOTAL, "PlayerbotAIBase::FullTick");
|
||||
|
||||
if (nextAICheckDelay > elapsed)
|
||||
nextAICheckDelay -= elapsed;
|
||||
else
|
||||
nextAICheckDelay = 0;
|
||||
|
||||
if (!CanUpdateAI())
|
||||
return;
|
||||
|
||||
UpdateAIInternal(elapsed, minimal);
|
||||
YieldThread();
|
||||
}
|
||||
|
||||
void PlayerbotAIBase::SetNextCheckDelay(uint32 const delay)
|
||||
{
|
||||
// if (nextAICheckDelay < delay)
|
||||
// LOG_DEBUG("playerbots", "Setting lesser delay {} -> {}", nextAICheckDelay, delay);
|
||||
|
||||
nextAICheckDelay = delay;
|
||||
|
||||
// if (nextAICheckDelay > sPlayerbotAIConfig->globalCoolDown)
|
||||
// LOG_DEBUG("playerbots", "std::set next check delay: {}", nextAICheckDelay);
|
||||
}
|
||||
|
||||
void PlayerbotAIBase::IncreaseNextCheckDelay(uint32 delay)
|
||||
{
|
||||
nextAICheckDelay += delay;
|
||||
|
||||
// if (nextAICheckDelay > sPlayerbotAIConfig->globalCoolDown)
|
||||
// LOG_DEBUG("playerbots", "increase next check delay: {}", nextAICheckDelay);
|
||||
}
|
||||
|
||||
bool PlayerbotAIBase::CanUpdateAI() { return nextAICheckDelay == 0; }
|
||||
|
||||
void PlayerbotAIBase::YieldThread(uint32 delay)
|
||||
{
|
||||
if (nextAICheckDelay < delay)
|
||||
nextAICheckDelay = delay;
|
||||
}
|
||||
|
||||
bool PlayerbotAIBase::IsActive() { return nextAICheckDelay < sPlayerbotAIConfig->maxWaitForMove; }
|
||||
|
||||
bool PlayerbotAIBase::IsBotAI() const { return _isBotAI; }
|
||||
34
src/Bot/Engine/PlayerbotAIBase.h
Normal file
34
src/Bot/Engine/PlayerbotAIBase.h
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#ifndef _PLAYERBOT_PLAYERBOTAIBASE_H
|
||||
#define _PLAYERBOT_PLAYERBOTAIBASE_H
|
||||
|
||||
#include "Define.h"
|
||||
#include "PlayerbotAIConfig.h"
|
||||
|
||||
class PlayerbotAIBase
|
||||
{
|
||||
public:
|
||||
PlayerbotAIBase(bool isBotAI);
|
||||
|
||||
bool CanUpdateAI();
|
||||
void SetNextCheckDelay(uint32 const delay);
|
||||
void IncreaseNextCheckDelay(uint32 delay);
|
||||
void YieldThread(uint32 delay = sPlayerbotAIConfig->reactDelay);
|
||||
virtual void UpdateAI(uint32 elapsed, bool minimal = false);
|
||||
virtual void UpdateAIInternal(uint32 elapsed, bool minimal = false) = 0;
|
||||
bool IsActive();
|
||||
bool IsBotAI() const;
|
||||
|
||||
protected:
|
||||
uint32 nextAICheckDelay;
|
||||
class PerfMonitorOperation* totalPmo = nullptr;
|
||||
|
||||
private:
|
||||
bool _isBotAI;
|
||||
};
|
||||
|
||||
#endif
|
||||
116
src/Bot/Engine/Strategy/CustomStrategy.cpp
Normal file
116
src/Bot/Engine/Strategy/CustomStrategy.cpp
Normal file
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "CustomStrategy.h"
|
||||
|
||||
#include <regex>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "Playerbots.h"
|
||||
|
||||
std::map<std::string, std::string> CustomStrategy::actionLinesCache;
|
||||
|
||||
NextAction toNextAction(std::string const action)
|
||||
{
|
||||
std::vector<std::string> tokens = split(action, '!');
|
||||
|
||||
if (tokens[0].empty())
|
||||
throw std::invalid_argument("Invalid action");
|
||||
|
||||
if (tokens.size() == 2)
|
||||
return NextAction(tokens[0], atof(tokens[1].c_str()));
|
||||
|
||||
if (tokens.size() == 1)
|
||||
return NextAction(tokens[0], ACTION_NORMAL);
|
||||
|
||||
LOG_ERROR("playerbots", "Invalid action {}", action.c_str());
|
||||
|
||||
throw std::invalid_argument("Invalid action");
|
||||
}
|
||||
|
||||
std::vector<NextAction> toNextActionArray(const std::string actions)
|
||||
{
|
||||
const std::vector<std::string> tokens = split(actions, ',');
|
||||
std::vector<NextAction> res = {};
|
||||
|
||||
for (const std::string token : tokens)
|
||||
{
|
||||
res.push_back(toNextAction(token));
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
TriggerNode* toTriggerNode(std::string const actionLine)
|
||||
{
|
||||
std::vector<std::string> tokens = split(actionLine, '>');
|
||||
if (tokens.size() == 2)
|
||||
return new TriggerNode(tokens[0], toNextActionArray(tokens[1]));
|
||||
|
||||
LOG_ERROR("playerbots", "Invalid action line {}", actionLine.c_str());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CustomStrategy::CustomStrategy(PlayerbotAI* botAI) : Strategy(botAI), Qualified() {}
|
||||
|
||||
void CustomStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
if (actionLines.empty())
|
||||
{
|
||||
if (actionLinesCache[qualifier].empty())
|
||||
{
|
||||
LoadActionLines((uint32)botAI->GetBot()->GetGUID().GetCounter());
|
||||
if (actionLines.empty())
|
||||
LoadActionLines(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::vector<std::string> tokens = split(actionLinesCache[qualifier], '\n');
|
||||
std::regex tpl("\\(nullptr,\\s*'.+',\\s*'(.+)'\\)(,|;)");
|
||||
for (std::vector<std::string>::iterator i = tokens.begin(); i != tokens.end(); ++i)
|
||||
{
|
||||
std::string const line = *i;
|
||||
for (std::sregex_iterator j = std::sregex_iterator(line.begin(), line.end(), tpl);
|
||||
j != std::sregex_iterator(); ++j)
|
||||
{
|
||||
std::smatch match = *j;
|
||||
std::string const actionLine = match[1].str();
|
||||
if (!actionLine.empty())
|
||||
actionLines.push_back(actionLine);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (std::vector<std::string>::iterator i = actionLines.begin(); i != actionLines.end(); ++i)
|
||||
{
|
||||
if (TriggerNode* tn = toTriggerNode(*i))
|
||||
triggers.push_back(tn);
|
||||
}
|
||||
}
|
||||
|
||||
void CustomStrategy::LoadActionLines(uint32 owner)
|
||||
{
|
||||
PlayerbotsDatabasePreparedStatement* stmt =
|
||||
PlayerbotsDatabase.GetPreparedStatement(PLAYERBOTS_SEL_CUSTOM_STRATEGY_BY_OWNER_AND_NAME);
|
||||
stmt->SetData(0, owner);
|
||||
stmt->SetData(1, qualifier);
|
||||
PreparedQueryResult result = PlayerbotsDatabase.Query(stmt);
|
||||
if (result)
|
||||
{
|
||||
do
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
std::string const action = fields[1].Get<std::string>();
|
||||
actionLines.push_back(action);
|
||||
} while (result->NextRow());
|
||||
}
|
||||
}
|
||||
|
||||
void CustomStrategy::Reset()
|
||||
{
|
||||
actionLines.clear();
|
||||
actionLinesCache[qualifier].clear();
|
||||
}
|
||||
31
src/Bot/Engine/Strategy/CustomStrategy.h
Normal file
31
src/Bot/Engine/Strategy/CustomStrategy.h
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#ifndef _PLAYERBOT_CUSTOMSTRATEGY_H
|
||||
#define _PLAYERBOT_CUSTOMSTRATEGY_H
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "Strategy.h"
|
||||
|
||||
class PlayerbotAI;
|
||||
|
||||
class CustomStrategy : public Strategy, public Qualified
|
||||
{
|
||||
public:
|
||||
CustomStrategy(PlayerbotAI* botAI);
|
||||
|
||||
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
|
||||
std::string const getName() override { return std::string("custom::" + qualifier); }
|
||||
void Reset();
|
||||
|
||||
static std::map<std::string, std::string> actionLinesCache;
|
||||
|
||||
private:
|
||||
std::vector<std::string> actionLines;
|
||||
void LoadActionLines(uint32 owner);
|
||||
};
|
||||
|
||||
#endif
|
||||
145
src/Bot/Engine/Strategy/Strategy.cpp
Normal file
145
src/Bot/Engine/Strategy/Strategy.cpp
Normal file
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 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*/ {},
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* healthstone([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"healthstone",
|
||||
/*P*/ {},
|
||||
/*A*/ { NextAction("healing potion") },
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* follow_master_random([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"be near",
|
||||
/*P*/ {},
|
||||
/*A*/ { NextAction("follow") },
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* attack_anything([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"attack anything",
|
||||
/*P*/ {},
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* move_random([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"move random",
|
||||
/*P*/ {},
|
||||
/*A*/ { NextAction("stay line") },
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* move_to_loot([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"move to loot",
|
||||
/*P*/ {},
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* food([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"food",
|
||||
/*P*/ {},
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* drink([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"drink",
|
||||
/*P*/ {},
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* mana_potion([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"mana potion",
|
||||
/*P*/ {},
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* healing_potion([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"healing potion",
|
||||
/*P*/ {},
|
||||
/*A*/ { NextAction("food") },
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
|
||||
static ActionNode* flee([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode(
|
||||
"flee",
|
||||
/*P*/ {},
|
||||
/*A*/ {},
|
||||
/*C*/ {}
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
Strategy::Strategy(PlayerbotAI* botAI) : PlayerbotAIAware(botAI)
|
||||
{
|
||||
actionNodeFactories.Add(new ActionNodeFactoryInternal());
|
||||
}
|
||||
|
||||
ActionNode* Strategy::GetAction(std::string const name) { return actionNodeFactories.GetContextObject(name, botAI); }
|
||||
76
src/Bot/Engine/Strategy/Strategy.h
Normal file
76
src/Bot/Engine/Strategy/Strategy.h
Normal file
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 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_BG = 1.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 std::vector<NextAction> getDefaultActions() { return {}; }
|
||||
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() {}
|
||||
|
||||
public:
|
||||
NamedObjectFactoryList<ActionNode> actionNodeFactories;
|
||||
};
|
||||
|
||||
#endif
|
||||
47
src/Bot/Engine/Trigger/Trigger.cpp
Normal file
47
src/Bot/Engine/Trigger/Trigger.cpp
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 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(uint32 now)
|
||||
{
|
||||
if (checkInterval < 2)
|
||||
return true;
|
||||
|
||||
if (!lastCheckTime || now - lastCheckTime >= checkInterval)
|
||||
{
|
||||
lastCheckTime = now;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
84
src/Bot/Engine/Trigger/Trigger.h
Normal file
84
src/Bot/Engine/Trigger/Trigger.h
Normal file
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Action.h"
|
||||
#include "Common.h"
|
||||
|
||||
class PlayerbotAI;
|
||||
class Unit;
|
||||
|
||||
class Trigger : public AiNamedObject
|
||||
{
|
||||
public:
|
||||
Trigger(
|
||||
PlayerbotAI* botAI,
|
||||
const std::string name = "trigger",
|
||||
int32_t 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 std::vector<NextAction> getHandlers() { return {}; }
|
||||
void Update() {}
|
||||
virtual void Reset() {}
|
||||
virtual Unit* GetTarget();
|
||||
virtual Value<Unit*>* GetTargetValue();
|
||||
virtual std::string const GetTargetName() { return "self target"; }
|
||||
|
||||
bool needCheck(uint32 now);
|
||||
|
||||
protected:
|
||||
int32_t checkInterval;
|
||||
uint32_t lastCheckTime;
|
||||
};
|
||||
|
||||
class TriggerNode
|
||||
{
|
||||
public:
|
||||
TriggerNode(
|
||||
const std::string& name,
|
||||
std::vector<NextAction> handlers = {}
|
||||
) :
|
||||
trigger(nullptr),
|
||||
handlers(std::move(handlers)),
|
||||
name(name)
|
||||
{}
|
||||
|
||||
Trigger* getTrigger() { return trigger; }
|
||||
void setTrigger(Trigger* trigger) { this->trigger = trigger; }
|
||||
const std::string getName() { return name; }
|
||||
|
||||
std::vector<NextAction> getHandlers()
|
||||
{
|
||||
std::vector<NextAction> result = this->handlers;
|
||||
|
||||
if (trigger != nullptr)
|
||||
{
|
||||
std::vector<NextAction> extra = trigger->getHandlers();
|
||||
result.insert(result.end(), extra.begin(), extra.end());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
float getFirstRelevance()
|
||||
{
|
||||
if (this->handlers.size() > 0)
|
||||
return this->handlers[0].getRelevance();
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
private:
|
||||
Trigger* trigger;
|
||||
std::vector<NextAction> handlers;
|
||||
const std::string name;
|
||||
};
|
||||
157
src/Bot/Engine/Value/Value.cpp
Normal file
157
src/Bot/Engine/Value/Value.cpp
Normal file
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "Value.h"
|
||||
|
||||
#include "PerfMonitor.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)
|
||||
{
|
||||
PerfMonitorOperation* pmo = sPerfMonitor->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;
|
||||
PerfMonitorOperation* pmo = sPerfMonitor->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;
|
||||
}
|
||||
419
src/Bot/Engine/Value/Value.h
Normal file
419
src/Bot/Engine/Value/Value.h
Normal file
@@ -0,0 +1,419 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 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 "PerfMonitor.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)
|
||||
{
|
||||
// PerfMonitorOperation* pmo = sPerfMonitor->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;
|
||||
// PerfMonitorOperation* pmo = sPerfMonitor->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)
|
||||
{
|
||||
// PerfMonitorOperation* pmo = sPerfMonitor->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;
|
||||
// PerfMonitorOperation* pmo = sPerfMonitor->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;
|
||||
|
||||
PerfMonitorOperation* pmo = sPerfMonitor->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
|
||||
27
src/Bot/Engine/WorldPacket/Event.cpp
Normal file
27
src/Bot/Engine/WorldPacket/Event.cpp
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 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;
|
||||
}
|
||||
45
src/Bot/Engine/WorldPacket/Event.h
Normal file
45
src/Bot/Engine/WorldPacket/Event.h
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 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
|
||||
Reference in New Issue
Block a user