Skip to content

Commit

Permalink
Travel: Improved loading and destination finding
Browse files Browse the repository at this point in the history
  • Loading branch information
mostlikely4r committed Jan 14, 2025
1 parent ffb84a9 commit 64bd702
Show file tree
Hide file tree
Showing 15 changed files with 365 additions and 279 deletions.
2 changes: 1 addition & 1 deletion playerbot/GuidPosition.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ namespace ai
public:
GuidPosition() : ObjectGuid(), WorldPosition() {}
GuidPosition(ObjectGuid guid, WorldPosition pos) : ObjectGuid(guid), WorldPosition(pos) {};
GuidPosition(ObjectGuid guid, const uint32 mapId, const uint32 instanceId) : ObjectGuid(guid) { WorldPosition::set(guid, mapId, instanceId); }
GuidPosition(ObjectGuid guid, const uint32 mapId, const uint32 instanceId) : ObjectGuid(guid) {WorldPosition::set(guid, mapId, instanceId); if (getX() == 0 && getY() == 0 && getZ() == 0) Set(0);}
GuidPosition(ObjectGuid guid, const WorldObject* wo) : ObjectGuid(guid), WorldPosition(wo) {}
GuidPosition(uint64 const& guid, WorldPosition const& pos) : ObjectGuid(guid), WorldPosition(pos) {};
//template<class T>
Expand Down
208 changes: 123 additions & 85 deletions playerbot/TravelMgr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,13 +67,18 @@ bool QuestRelationTravelDestination::IsPossible(const PlayerTravelInfo& info) co
if (forceThisQuest && !info.IsFocusQuest(GetQuestId()))
return false;

const Quest* quest = GetQuestTemplate();

if (GetRelation() == 0)
{
if (!forceThisQuest && (int32)GetQuestTemplate()->GetQuestLevel() >= (int32)info.GetLevel() + (int32)5)
if (!forceThisQuest && (int32)quest->GetQuestLevel() >= (int32)info.GetLevel() + (int32)5)
return false;

if ((int32)info.GetLevel() < quest->GetMinLevel() || (int32)info.GetLevel() > quest->GetMaxLevel())
return false;

if (GetPoints().front()->getMapId() != info.GetPosition().getMapId()) //CanTakeQuest will check required conditions which will fail on a different map.
if (GetQuestTemplate()->GetRequiredCondition()) //So we skip this quest for now.
if (quest->GetRequiredCondition()) //So we skip this quest for now.
return false;

if (!info.HasFocusQuest())
Expand All @@ -90,14 +95,14 @@ bool QuestRelationTravelDestination::IsPossible(const PlayerTravelInfo& info) co
}

//Do not try to pick up dungeon/elite quests in instances without a group.
if ((GetQuestTemplate()->GetType() == QUEST_TYPE_ELITE || GetQuestTemplate()->GetType() == QUEST_TYPE_DUNGEON) && !info.GetBoolValue("can fight boss"))
if ((quest->GetType() == QUEST_TYPE_ELITE || quest->GetType() == QUEST_TYPE_DUNGEON) && !info.GetBoolValue("can fight boss"))
return false;
}
}
else
{
//Do not try to hand-in dungeon/elite quests in instances without a group.
if ((GetQuestTemplate()->GetType() == QUEST_TYPE_ELITE || GetQuestTemplate()->GetType() == QUEST_TYPE_DUNGEON) && !info.GetBoolValue("can fight boss"))
if ((quest->GetType() == QUEST_TYPE_ELITE || quest->GetType() == QUEST_TYPE_DUNGEON) && !info.GetBoolValue("can fight boss"))
{
if (!this->NearestPoint(info.GetPosition())->isOverworld())
return false;
Expand Down Expand Up @@ -317,6 +322,24 @@ std::string QuestObjectiveTravelDestination::GetTitle() const {
return out.str();
}

uint8 QuestObjectiveTravelDestination::GetObjective() const
{
switch (GetPurpose())
{
case TravelDestinationPurpose::QuestObjective1:
return 0;
case TravelDestinationPurpose::QuestObjective2:
return 1;
case TravelDestinationPurpose::QuestObjective3:
return 2;
case TravelDestinationPurpose::QuestObjective4:
return 3;
default:
return 0;
}
return 0;
}

bool RpgTravelDestination::IsPossible(const PlayerTravelInfo& info) const
{
bool isUsefull = false;
Expand Down Expand Up @@ -689,6 +712,7 @@ std::string GatherTravelDestination::GetTitle() const {
TravelTarget::TravelTarget(PlayerbotAI* ai) : AiObject(ai)
{
sTravelMgr.SetNullTravelTarget(this);
SetStatus(TravelStatus::TRAVEL_STATUS_EXPIRED);
}

void TravelTarget::SetTarget(TravelDestination* tDestination1, WorldPosition* wPosition1, bool groupCopy1) {
Expand Down Expand Up @@ -880,9 +904,10 @@ void TravelMgr::Clear()
TravelMgr::SetNullTravelTarget(itr->second);
#endif
#endif
for (auto& [type, dests] : destinationMap)
for (auto& dest : dests)
delete dest;
for (auto& [purpose, entries] : destinationMap)
for (auto& [id, dests] : entries)
for (auto& dest : dests)
delete dest;
destinationMap.clear();
pointsMap.clear();
}
Expand Down Expand Up @@ -993,7 +1018,7 @@ void TravelMgr::LoadAreaLevels()
std::string query = "SELECT id, level FROM ai_playerbot_zone_level";

{
auto result = WorldDatabase.PQuery(query.c_str());
auto result = WorldDatabase.PQuery("%s", query.c_str());

std::vector<uint32> loadedAreas;

Expand Down Expand Up @@ -1120,10 +1145,12 @@ void TravelMgr::LoadQuestTravelTable()

EntryGuidps guidpMap = GAI_VALUE(EntryGuidps, "entry guidps");

sLog.outString("Creating travel destinations.");
sLog.outString("Finding possible travel destinations.");

EntryQuestRelationMap eMap = GAI_VALUE(EntryQuestRelationMap, "entry quest relation");

sLog.outString("Creating travel destinations.");

BarGoLink bar(eMap.size());

for (auto& [entry, relation] : eMap)
Expand All @@ -1140,75 +1167,85 @@ void TravelMgr::LoadQuestTravelTable()
QuestTravelDestination* loc;
std::vector<QuestTravelDestination*> locs;

if (flag & (uint32)QuestRelationFlag::questGiver)
for (uint32 purposeFlagNr = 0; purposeFlagNr < 6; purposeFlagNr++)
{
loc = AddQuestDestination<QuestRelationTravelDestination>(questId, entry, 0);
locs.push_back(loc);
}
if (flag & (uint32)QuestRelationFlag::questTaker)
{
loc = AddQuestDestination<QuestRelationTravelDestination>(questId, entry, 1);
locs.push_back(loc);
}
if (flag & ((uint32)QuestRelationFlag::objective1 | (uint32)QuestRelationFlag::objective2 | (uint32)QuestRelationFlag::objective3 | (uint32)QuestRelationFlag::objective4))
{
uint32 objective;
if (flag & (uint32)QuestRelationFlag::objective1)
objective = 0;
else if (flag & (uint32)QuestRelationFlag::objective2)
objective = 1;
else if (flag & (uint32)QuestRelationFlag::objective3)
objective = 2;
else if (flag & (uint32)QuestRelationFlag::objective4)
objective = 3;

loc = AddQuestDestination<QuestObjectiveTravelDestination>(questId, entry, objective);
locs.push_back(loc);
}
TravelDestinationPurpose purposeFlag = (TravelDestinationPurpose)(1 << purposeFlagNr);
if (flag & (uint32)purposeFlag)
{
if (purposeFlag == TravelDestinationPurpose::QuestGiver || purposeFlag == TravelDestinationPurpose::QuestTaker)
loc = AddDestination<QuestRelationTravelDestination>(entry, purposeFlag, questId);
else
loc = AddDestination<QuestObjectiveTravelDestination>(entry, purposeFlag, questId);

for (auto& guidP : guidpMap.at(entry))
{
pointsMap.insert(std::make_pair(guidP.GetRawValue(), guidP));
locs.push_back(loc);
}

for (auto tLoc : locs)
for (auto& guidP : guidpMap.at(entry))
{
tLoc->AddPoint(&pointsMap.at(guidP.GetRawValue()));
pointsMap.insert(std::make_pair(guidP.GetRawValue(), guidP));

for (auto tLoc : locs)
{
tLoc->AddPoint(&pointsMap.at(guidP.GetRawValue()));
}
}
}
}
}
}

sLog.outString("Loading Rpg, Grind and Boss locations.");
sLog.outString("Loading all travel locations.");

for (auto& [entry, purpose] : GAI_VALUE(EntryTravelPurposeMap, "entry travel purpose"))
{
if (guidpMap.find(entry) == guidpMap.end())
{
sLog.outDebug("Entry %d for purpose %d has no valid location.", entry, purpose);
continue;
}

std::vector<TravelDestination*> dests;
if (purpose & (uint32)TravelDestinationPurposeFlag::RPG)
dests.push_back(AddDestination<RpgTravelDestination>(entry));

if (purpose & (uint32)TravelDestinationPurposeFlag::GRIND)
dests.push_back(AddDestination<GrindTravelDestination>(entry));
if (guidpMap.find(entry) == guidpMap.end())
continue;

if (purpose & (uint32)TravelDestinationPurposeFlag::BOSS)
dests.push_back(AddDestination<BossTravelDestination>(entry));
for (uint32 purposeFlagNr = 6; purposeFlagNr < 18; purposeFlagNr++)
{
TravelDestinationPurpose purposeFlag = (TravelDestinationPurpose)(1 << purposeFlagNr);
if (purpose & (uint32)purposeFlag)
{
switch (purposeFlag) {
case TravelDestinationPurpose::GenericRpg:
case TravelDestinationPurpose::Trainer:
case TravelDestinationPurpose::Repair:
case TravelDestinationPurpose::Vendor:
case TravelDestinationPurpose::AH:
case TravelDestinationPurpose::MailBox:
dests.push_back(AddDestination<RpgTravelDestination>(entry, purposeFlag));
break;
case TravelDestinationPurpose::GatherSkinning:
case TravelDestinationPurpose::GatherMining:
case TravelDestinationPurpose::GatherHerbalism:
case TravelDestinationPurpose::GatherFishing:
dests.push_back(AddDestination<GatherTravelDestination>(entry, purposeFlag));
break;
case TravelDestinationPurpose::Grind:
dests.push_back(AddDestination<GrindTravelDestination>(entry, purposeFlag));
break;
case TravelDestinationPurpose::Boss:
dests.push_back(AddDestination<BossTravelDestination>(entry, purposeFlag));
break;
default:
break;
};
}
}

if (purpose & (uint32)TravelDestinationPurposeFlag::GATHER)
dests.push_back(AddDestination<GatherTravelDestination>(entry));
if (dests.empty())
continue;

for (auto& point : guidpMap.at(entry))
for (auto& guidP : guidpMap.at(entry))
{
pointsMap.insert_or_assign(point.GetRawValue(), point);
for (auto& dest : dests)
pointsMap.insert(std::make_pair(guidP.GetRawValue(), guidP));

for (auto tLoc : dests)
{
dest->AddPoint(&pointsMap.at(point.GetRawValue()));
tLoc->AddPoint(&pointsMap.at(guidP.GetRawValue()));
}
}
}
}

sLog.outString("Loading Explore locations.");
Expand All @@ -1233,7 +1270,7 @@ void TravelMgr::LoadQuestTravelTable()

pointsMap.insert_or_assign(point.GetRawValue(), point);

loc = AddDestination<ExploreTravelDestination>(area->ID);
loc = AddDestination<ExploreTravelDestination>(area->ID, TravelDestinationPurpose::Explore);
loc->AddPoint(&pointsMap.at(point.GetRawValue()));
}

Expand Down Expand Up @@ -2007,41 +2044,42 @@ void TravelMgr::LoadQuestTravelTable()
#endif
}

std::vector<TravelDestination*> TravelMgr::GetDestinations(const PlayerTravelInfo& info, std::type_index type, int32 entry, int32 subEntry1, int32 subEntry2, bool onlyPossible, float maxDistance) const
std::vector<TravelDestination*> TravelMgr::GetDestinations(const PlayerTravelInfo& info, TravelDestinationPurpose purposeFlag, int32 entry, bool onlyPossible, float maxDistance) const
{
WorldPosition center = info.GetPosition();
std::vector<TravelDestination*> retTravelLocations;

std::mutex resultMutex;

std::for_each(
std::execution::par,
destinationMap.at(type).begin(),
destinationMap.at(type).end(),
[&](TravelDestination* dest) {
if (type == typeid(QuestTravelDestination))
{
if (entry && ((QuestTravelDestination*)dest)->GetQuestId() != entry)
return;
}
else
{
if (entry && dest->GetEntry() != entry)
for (auto& [purpose, entryDests] : destinationMap)
{

if (purposeFlag != TravelDestinationPurpose::None && !((uint32)purpose & (uint32)purposeFlag))
continue;

std::for_each(
std::execution::par,
entryDests.begin(),
entryDests.end(),
[&](auto& entryDests) {
if (entry && entryDests.first != entry)
return;
}

if (subEntry1 && dest->GetSubEntry() != subEntry1 && dest->GetSubEntry() != subEntry2)
return;
std::vector<TravelDestination*> dests = entryDests.second;

if (onlyPossible && !dest->IsPossible(info))
return;
for (auto& dest : dests)
{
if (onlyPossible && !dest->IsPossible(info))
return;

if (maxDistance > 0 && dest->DistanceTo(center) > maxDistance)
return;
if (maxDistance > 0 && dest->DistanceTo(center) > maxDistance)
return;

std::lock_guard<std::mutex> guard(resultMutex);
retTravelLocations.push_back(dest);
});
std::lock_guard<std::mutex> guard(resultMutex);
retTravelLocations.push_back(dest);
}
});
}

return retTravelLocations;
}
Expand Down
Loading

0 comments on commit 64bd702

Please sign in to comment.