Skip to content

Commit

Permalink
Travel: Action refactor to improve performance and simply the system
Browse files Browse the repository at this point in the history
  • Loading branch information
mostlikely4r committed Jan 29, 2025
1 parent 769a47a commit 1b16f38
Show file tree
Hide file tree
Showing 13 changed files with 303 additions and 643 deletions.
1 change: 1 addition & 0 deletions playerbot/TravelMgr.h
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ namespace ai
virtual GameObjectInfo const* GetGoInfo() const { return goInfo; }
virtual CreatureInfo const* GetCreatureInfo() const { return creatureInfo; }
TravelDestinationPurpose GetPurpose() const { return purpose; }
bool HasNpcFlag(uint32 flag) { if(GetCreatureInfo() && (GetCreatureInfo()->NpcFlags & flag)) return true; return false; }
private:
CreatureInfo const* creatureInfo = nullptr;
GameObjectInfo const* goInfo = nullptr;
Expand Down
12 changes: 6 additions & 6 deletions playerbot/strategy/actions/ActionContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,13 +82,14 @@ namespace ai
creators["choose rpg target"] = &ActionContext::choose_rpg_target;
creators["move to rpg target"] = &ActionContext::move_to_rpg_target;
creators["travel"] = &ActionContext::travel;
creators["choose travel target"] = &ActionContext::choose_travel_target;
creators["move to travel target"] = &ActionContext::move_to_travel_target;
creators["choose travel target"] = [](PlayerbotAI* ai) { return new ChooseTravelTargetAction(ai); };
creators["choose group travel target"] = [](PlayerbotAI* ai) { return new ChooseGroupTravelTargetAction(ai); };
creators["refresh travel target"] = [](PlayerbotAI* ai) { return new RefreshTravelTargetAction(ai); };
creators["choose async travel target"] = [](PlayerbotAI* ai) { return new ChooseAsyncTravelTargetAction(ai); };
creators["choose async named travel target"] = [](PlayerbotAI* ai) { return new ChooseAsyncNamedTravelTargetAction(ai); };
creators["choose async quest travel target"] = [](PlayerbotAI* ai) { return new ChooseAsyncQuestTravelTargetAction(ai); };
creators["request travel target"] = [](PlayerbotAI* ai) { return new RequestTravelTargetAction(ai); };
creators["request named travel target"] = [](PlayerbotAI* ai) { return new RequestNamedTravelTargetAction(ai); };
creators["request quest travel target"] = [](PlayerbotAI* ai) { return new RequestQuestTravelTargetAction(ai); };
creators["reset travel target"] = [](PlayerbotAI* ai) { return new ResetTargetAction(ai); };
creators["move to travel target"] = &ActionContext::move_to_travel_target;
creators["move out of collision"] = &ActionContext::move_out_of_collision;
creators["move random"] = &ActionContext::move_random;
creators["attack"] = &ActionContext::melee;
Expand Down Expand Up @@ -352,7 +353,6 @@ namespace ai
static Action* choose_rpg_target(PlayerbotAI* ai) { return new ChooseRpgTargetAction(ai); }
static Action* move_to_rpg_target(PlayerbotAI* ai) { return new MoveToRpgTargetAction(ai); }
static Action* travel(PlayerbotAI* ai) { return new TravelAction(ai); }
static Action* choose_travel_target(PlayerbotAI* ai) { return new ChooseTravelTargetAction(ai); }
static Action* move_to_travel_target(PlayerbotAI* ai) { return new MoveToTravelTargetAction(ai); }
static Action* move_out_of_collision(PlayerbotAI* ai) { return new MoveOutOfCollisionAction(ai); }
static Action* move_random(PlayerbotAI* ai) { return new MoveRandomAction(ai); }
Expand Down
631 changes: 175 additions & 456 deletions playerbot/strategy/actions/ChooseTravelTargetAction.cpp

Large diffs are not rendered by default.

67 changes: 28 additions & 39 deletions playerbot/strategy/actions/ChooseTravelTargetAction.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,28 +7,23 @@

namespace ai
{
class ChooseTravelTargetAction : public MovementAction {
class ChooseTravelTargetAction : public Action {
public:
ChooseTravelTargetAction(PlayerbotAI* ai, std::string name = "choose travel target") : MovementAction(ai, name) {}

virtual bool Execute(Event& event);
virtual bool isUseful();

void getNewTarget(Player* requester, TravelTarget* newTarget, TravelTarget* oldTarget);
ChooseTravelTargetAction(PlayerbotAI* ai, std::string name = "choose travel target") : Action(ai, name) {}

virtual bool Execute(Event& event) override;
virtual bool isUseful() override;
protected:
void setNewTarget(Player* requester, TravelTarget* newTarget, TravelTarget* oldTarget);
void ReportTravelTarget(Player* requester, TravelTarget* newTarget, TravelTarget* oldTarget);

bool SetBestTarget(Player* requester, TravelTarget* target, PartitionedTravelList& travelPartitions, bool onlyActive = true);

bool SetNpcFlagTarget(Player* requester, TravelTarget* target, std::vector<NPCFlags> flags, std::string name = "", std::vector<uint32> items = {}, bool force = false);
//bool SetNpcFlagTarget(Player* requester, TravelTarget* target, std::vector<NPCFlags> flags, std::string name = "", std::vector<uint32> items = {}, bool force = false);

bool SetNullTarget(TravelTarget* target);
public:
static DestinationList FindDestination(PlayerTravelInfo info, std::string name, bool zones = true, bool npcs = true, bool quests = true, bool mobs = true, bool bosses = true);
protected:
const std::vector<uint32> travelPartitions = { 100, 250, 500, 1000, 2000, 3000, 4000, 5000, 6000, 10000, 50000, 100000, 500000 };
private:
#ifdef GenerateBotHelp
virtual std::string GetHelpName() { return "choose travel target"; } //Must equal iternal name
Expand All @@ -48,57 +43,51 @@ namespace ai
public:
ChooseGroupTravelTargetAction(PlayerbotAI* ai, std::string name = "choose group travel target") : ChooseTravelTargetAction(ai, name) {}

virtual bool Execute(Event& event);
virtual bool isUseful() { return ChooseTravelTargetAction::isUseful() && bot->GetGroup(); }
virtual bool Execute(Event& event) override;
virtual bool isUseful() override;
};

class RefreshTravelTargetAction : public ChooseTravelTargetAction {
public:
RefreshTravelTargetAction(PlayerbotAI* ai, std::string name = "refresh travel target") : ChooseTravelTargetAction(ai, name) {}

virtual bool Execute(Event& event);
virtual bool isUseful() { return ChooseTravelTargetAction::isUseful() && AI_VALUE(TravelTarget*, "travel target")->GetDestination()->IsActive(bot, PlayerTravelInfo(bot)) && (!WorldPosition(bot).isOverworld() || urand(1, 100) > 10); }
virtual bool Execute(Event& event) override;
virtual bool isUseful() override;
};

using FutureDestinations = std::future<PartitionedTravelList>;

class ChooseAsyncTravelTargetAction : public ChooseTravelTargetAction, public Qualified {
class ResetTargetAction : public ChooseTravelTargetAction {
public:
ChooseAsyncTravelTargetAction(PlayerbotAI* ai, std::string name = "choose async travel target") : ChooseTravelTargetAction(ai, name), Qualified() {}
protected:
TravelDestinationPurpose actionPurpose = TravelDestinationPurpose::None;
ResetTargetAction(PlayerbotAI* ai, std::string name = "reset travel target") : ChooseTravelTargetAction(ai, name) {}

virtual bool RequestNewDestinations(Event& event);
virtual bool isAllowed() const; //We need this skip on the request instead of isUsefull to only skip the request sometimes but not the Wait and Set that could follow a nonskip.
virtual bool Execute(Event& event) override;
virtual bool isUseful() override;
};

bool hasDestinations = false;
PartitionedTravelList destinationList = {};
FutureDestinations futureDestinations;
class RequestTravelTargetAction : public Action, public Qualified {
public:
RequestTravelTargetAction(PlayerbotAI* ai, std::string name = "request travel target") : Action(ai, name), Qualified() {}
protected:
const std::vector<uint32> travelPartitions = { 100, 250, 500, 1000, 2000, 3000, 4000, 5000, 6000, 10000, 50000, 100000, 500000 };
private:
virtual bool Execute(Event& event) override;

virtual bool isUseful() override;
bool WaitForDestinations();
bool SetBestDestination(Event& event);
virtual bool isAllowed() const;
};

class ChooseAsyncNamedTravelTargetAction : public ChooseAsyncTravelTargetAction {
class RequestNamedTravelTargetAction : public RequestTravelTargetAction {
public:
ChooseAsyncNamedTravelTargetAction(PlayerbotAI* ai, std::string name = "choose async named travel target") : ChooseAsyncTravelTargetAction(ai, name) {}
protected:
RequestNamedTravelTargetAction(PlayerbotAI* ai, std::string name = "request named travel target") : RequestTravelTargetAction(ai, name) {}
private:
virtual bool Execute(Event& event) override;
virtual bool isAllowed() const override;
virtual bool RequestNewDestinations(Event& event) override;
virtual bool isUseful() override { return !AI_VALUE(TravelTarget*, "travel target")->IsPreparing() &&
ChooseTravelTargetAction::isUseful(); };
};

class ChooseAsyncQuestTravelTargetAction : public ChooseAsyncTravelTargetAction {
class RequestQuestTravelTargetAction : public RequestTravelTargetAction {
public:
ChooseAsyncQuestTravelTargetAction(PlayerbotAI* ai, std::string name = "choose async quest travel target") : ChooseAsyncTravelTargetAction(ai, name) {}
protected:
RequestQuestTravelTargetAction(PlayerbotAI* ai, std::string name = "choose async quest travel target") : RequestTravelTargetAction(ai, name) {}
private:
virtual bool Execute(Event& event) override;
virtual bool isAllowed() const override;
virtual bool RequestNewDestinations(Event& event) override;
virtual bool isUseful() override { return !AI_VALUE(TravelTarget*, "travel target")->IsPreparing() && ChooseTravelTargetAction::isUseful(); };
};

class FocusTravelTargetAction : public ChatCommandAction {
Expand Down
52 changes: 2 additions & 50 deletions playerbot/strategy/actions/GoAction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -166,56 +166,8 @@ bool GoAction::TellWhereToGo(std::string& param, Player* requester) const
if (param.size() > 6)
text = param.substr(6);

ChooseTravelTargetAction* travelAction = new ChooseTravelTargetAction(ai);

TravelTarget* target = context->GetValue<TravelTarget*>("travel target")->Get();

target->SetStatus(TravelStatus::TRAVEL_STATUS_EXPIRED);

travelAction->getNewTarget(requester, target, target);

if (!target->GetDestination() || target->GetDestination()->GetTitle().empty())
{
ai->TellPlayerNoFacing(requester, "I have no place I want to go to.");
return false;
}

std::string title = target->GetDestination()->GetTitle();

if (title.find('[') != std::string::npos)
title = title.substr(title.find("[") + 1, title.find("]") - title.find("[") - 1);


DestinationList dests;
TravelDestination* dest = nullptr;

dests = ChooseTravelTargetAction::FindDestination(bot, title);

if (dests.empty())
{
ai->TellPlayerNoFacing(requester, "I don't know how to travel to " + title);
return false;
}

WorldPosition botPos(bot);

dest = *std::min_element(dests.begin(), dests.end(), [botPos](TravelDestination* i, TravelDestination* j) {return i->DistanceTo(botPos) < j->DistanceTo(botPos); });

if (!dest)
dest = target->GetDestination();

if (!dest)
{
ai->TellPlayerNoFacing(requester, "I don't know how to travel to " + title);
return false;
}

std::string link = ChatHelper::formatValue("command", "go to " + title, title, "FF00FFFF");

ai->TellPlayerNoFacing(requester, "I would like to travel to " + link + "(" + target->GetDestination()->GetTitle() + ")");

delete travelAction;
return true;
ai->TellPlayerNoFacing(requester, "I have no place I want to go to.");
return false;
}

bool GoAction::LeaderAlreadyTraveling(TravelDestination* dest) const
Expand Down
43 changes: 24 additions & 19 deletions playerbot/strategy/actions/GuildCreateActions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -270,23 +270,29 @@ bool PetitionTurnInAction::Execute(Event& event)
return true;
}

TravelTarget* oldTarget = context->GetValue<TravelTarget*>("travel target")->Get();

//Select a new target to travel to.
TravelTarget newTarget = TravelTarget(ai);

ai->TellDebug(requester, "Handing in guild petition", "debug travel");

bool foundTarget = SetNpcFlagTarget(requester, &newTarget, { UNIT_NPC_FLAG_PETITIONER });
TravelTarget* oldTarget = AI_VALUE(TravelTarget*, "travel target");

if (!foundTarget || !newTarget.IsActive())
if (oldTarget->IsPreparing())
return false;

newTarget.SetRadius(INTERACTION_DISTANCE);
if (oldTarget->GetDestination())
{
TravelDestination* dest = oldTarget->GetDestination();

setNewTarget(requester, &newTarget, oldTarget);
EntryTravelDestination* eDest = dynamic_cast<EntryTravelDestination*>(dest);

return true;
if (eDest && eDest->HasNpcFlag(UNIT_NPC_FLAG_PETITIONER))
return false;
}

oldTarget->SetStatus(TravelStatus::TRAVEL_STATUS_EXPIRED);

return ai->DoSpecificAction("request named travel target::petition", Event("buy tabard"), true);
};

bool PetitionTurnInAction::isUseful()
Expand Down Expand Up @@ -322,23 +328,22 @@ bool BuyTabardAction::Execute(Event& event)
if (canBuy && AI_VALUE2(uint32, "item count", chat->formatQItem(5976)))
return true;

TravelTarget* oldTarget = context->GetValue<TravelTarget*>("travel target")->Get();
TravelTarget* oldTarget = AI_VALUE(TravelTarget*, "travel target");

//Select a new target to travel to.
TravelTarget newTarget = TravelTarget(ai);

ai->TellDebug(requester, "Buying a tabard", "debug travel");

bool foundTarget = SetNpcFlagTarget(requester, &newTarget, { UNIT_NPC_FLAG_TABARDDESIGNER }, "Tabard Vendor", { 5976 });

if (!foundTarget || !newTarget.IsActive())
if (oldTarget->IsPreparing())
return false;

newTarget.SetRadius(INTERACTION_DISTANCE);
if (oldTarget->GetDestination())
{
TravelDestination* dest = oldTarget->GetDestination();

EntryTravelDestination* eDest = dynamic_cast<EntryTravelDestination*>(dest);

setNewTarget(requester, &newTarget, oldTarget);
if (eDest && eDest->HasNpcFlag(UNIT_NPC_FLAG_TABARDDESIGNER))
return false;
}

return true;
return ai->DoSpecificAction("request named travel target::tabard", Event("buy tabard"), true);
};

bool BuyTabardAction::isUseful()
Expand Down
Loading

0 comments on commit 1b16f38

Please sign in to comment.