mirror of
https://github.com/mod-playerbots/mod-playerbots.git
synced 2026-02-16 00:26:10 +00:00
# Pull Request This change replaces the non‑standard WorldPosition::getX/getY/getZ/getO/getMapId wrappers with the core getters (GetPositionX/Y/Z, GetOrientation, GetMapId) and removes the redundant wrappers. Goal: align the module with AzerothCore conventions, reduce local adapters, and improve long‑term maintainability. --- ## Design Philosophy This is a structural cleanup only (coordinate access) and does not alter any AI behavior or decision logic. It follows the stability/performance-first philosophy and does not add branches or extra runtime work. Before submitting: yes, this change aligns with the principles of stability, performance, and predictability. Principles: - **Stability before intelligence** A stable system is always preferred over a smarter one. - **Performance is a shared resource** Any increase in bot cost affects all players and all bots. - **Simple logic scales better than smart logic** Predictable behavior under load is more valuable than perfect decisions. - **Complexity must justify itself** If a feature cannot clearly explain its cost, it should not exist. - **Defaults must be cheap** Expensive behavior must always be optional and clearly communicated. - **Bots should look reasonable, not perfect** The goal is believable behavior, not human simulation. Before submitting, confirm that this change aligns with those principles. --- ## Feature Evaluation Please answer the following: - Minimum logic required: use core getters (GetPositionX/Y/Z, GetMapId, GetOrientation) wherever coordinates are needed. - Cheapest implementation: direct call replacement and removal of redundant wrappers. - Runtime cost: negligible (same data access, no additional logic). --- ## How to Test the Changes - No functional testing required (behavior‑neutral refactor). - Recommended: compile the module and run a normal server startup as validation. ## Complexity & Impact Does this change add new decision branches? - - [x] No - - [x] Yes (**explain below**) Does this change increase per-bot or per-tick processing? - - [x] No - - [ ] Yes (**describe and justify impact**) Could this logic scale poorly under load? - - [x] No - - [ ] Yes (**explain why**) --- ## Defaults & Configuration Does this change modify default bot behavior? - - [x] No - - [ ] Yes (**explain why**) If this introduces more advanced or AI-heavy logic: - - [x] Lightweight mode remains the default - - [x] More complex behavior is optional and thereby configurable --- ## AI Assistance Was AI assistance (e.g. ChatGPT or similar tools) used while working on this change? - - [ ] No - - [x] Yes (**explain below**) If yes, please specify: - AI tool or model used: Copilot - Purpose of usage: Translate this PR text from french to English --- ## Final Checklist - - [x] Stability is not compromised - - [x] Performance impact is understood, tested, and acceptable - - [x] Added logic complexity is justified and explained - - [x] Documentation updated if needed --- ## Notes for Reviewers This is a core-friendly cleanup only, with no behavioral change. No additional logic or CPU cost is introduced.
200 lines
5.8 KiB
C++
200 lines
5.8 KiB
C++
/*
|
|
* 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 "StuckTriggers.h"
|
|
|
|
#include "CellImpl.h"
|
|
#include "PathGenerator.h"
|
|
#include "Playerbots.h"
|
|
#include "MMapFactory.h"
|
|
|
|
bool MoveStuckTrigger::IsActive()
|
|
{
|
|
if (botAI->HasActivePlayerMaster())
|
|
return false;
|
|
|
|
if (!botAI->AllowActivity(ALL_ACTIVITY))
|
|
return false;
|
|
|
|
WorldPosition botPos(bot);
|
|
|
|
LogCalculatedValue<WorldPosition>* posVal =
|
|
dynamic_cast<LogCalculatedValue<WorldPosition>*>(context->GetUntypedValue("current position"));
|
|
|
|
if (posVal->LastChangeDelay() > 5 * MINUTE)
|
|
{
|
|
// LOG_INFO("playerbots", "Bot {} {}:{} <{}> was in the same position for {} seconds",
|
|
// bot->GetGUID().ToString().c_str(), bot->GetTeamId() == TEAM_ALLIANCE ? "A" : "H", bot->GetLevel(),
|
|
// bot->GetName(), posVal->LastChangeDelay());
|
|
|
|
return true;
|
|
}
|
|
|
|
bool longLog = false;
|
|
|
|
for (auto tPos : posVal->ValueLog())
|
|
{
|
|
uint32 timePassed = time(0) - tPos.second;
|
|
|
|
if (timePassed > 10 * MINUTE)
|
|
{
|
|
if (botPos.fDist(tPos.first) > 50.0f)
|
|
return false;
|
|
|
|
longLog = true;
|
|
}
|
|
}
|
|
|
|
if (longLog)
|
|
{
|
|
// LOG_INFO("playerbots", "Bot {} {}:{} <{}> was in the same position for 10mins",
|
|
// bot->GetGUID().ToString().c_str(), bot->GetTeamId() == TEAM_ALLIANCE ? "A" : "H", bot->GetLevel(),
|
|
// bot->GetName(), posVal->LastChangeDelay());
|
|
}
|
|
|
|
return longLog;
|
|
}
|
|
|
|
bool MoveLongStuckTrigger::IsActive()
|
|
{
|
|
if (botAI->HasActivePlayerMaster())
|
|
return false;
|
|
|
|
if (!botAI->AllowActivity(ALL_ACTIVITY))
|
|
return false;
|
|
|
|
WorldPosition botPos(bot);
|
|
|
|
Cell cell(bot->GetPositionX(), bot->GetPositionY());
|
|
|
|
GridCoord grid = botPos.getGridCoord();
|
|
|
|
if (grid.x_coord < 0 || grid.x_coord >= MAX_NUMBER_OF_GRIDS)
|
|
{
|
|
// LOG_INFO("playerbots", "Bot {} {}:{} <{}> was in grid {},{} on map {}",
|
|
// bot->GetGUID().ToString().c_str(), bot->GetTeamId() == TEAM_ALLIANCE ? "A" : "H", bot->GetLevel(),
|
|
// bot->GetName(), grid.x_coord, grid.y_coord, botPos.getMapId());
|
|
|
|
return true;
|
|
}
|
|
|
|
if (grid.y_coord < 0 || grid.y_coord >= MAX_NUMBER_OF_GRIDS)
|
|
{
|
|
// LOG_INFO("playerbots", "Bot {} {}:{} <{}> was in grid {},{} on map {}",
|
|
// bot->GetGUID().ToString().c_str(), bot->GetTeamId() == TEAM_ALLIANCE ? "A" : "H", bot->GetLevel(),
|
|
// bot->GetName(), grid.x_coord, grid.y_coord, botPos.getMapId());
|
|
|
|
return true;
|
|
}
|
|
|
|
if (cell.GridX() > 0 && cell.GridY() > 0 &&
|
|
!MMAP::MMapFactory::createOrGetMMapMgr()->loadMap(botPos.GetMapId(), cell.GridX(), cell.GridY()))
|
|
{
|
|
// LOG_INFO("playerbots", "Bot {} {}:{} <{}> was in unloaded grid {},{} on map {}",
|
|
// bot->GetGUID().ToString().c_str(), bot->GetTeamId() == TEAM_ALLIANCE ? "A" : "H", bot->GetLevel(),
|
|
// bot->GetName(), grid.x_coord, grid.y_coord, botPos.getMapId());
|
|
|
|
return true;
|
|
}
|
|
|
|
LogCalculatedValue<WorldPosition>* posVal =
|
|
dynamic_cast<LogCalculatedValue<WorldPosition>*>(context->GetUntypedValue("current position"));
|
|
|
|
if (posVal->LastChangeDelay() > 10 * MINUTE)
|
|
{
|
|
// LOG_INFO("playerbots", "Bot {} {}:{} <{}> was in the same position for {} seconds",
|
|
// bot->GetGUID().ToString().c_str(), bot->GetTeamId() == TEAM_ALLIANCE ? "A" : "H", bot->GetLevel(),
|
|
// bot->GetName(), posVal->LastChangeDelay());
|
|
|
|
return true;
|
|
}
|
|
|
|
MemoryCalculatedValue<uint32>* expVal =
|
|
dynamic_cast<MemoryCalculatedValue<uint32>*>(context->GetUntypedValue("experience"));
|
|
|
|
if (expVal->LastChangeDelay() < 15 * MINUTE)
|
|
return false;
|
|
|
|
bool longLog = false;
|
|
|
|
for (auto tPos : posVal->ValueLog())
|
|
{
|
|
uint32 timePassed = time(0) - tPos.second;
|
|
|
|
if (timePassed > 15 * MINUTE)
|
|
{
|
|
if (botPos.fDist(tPos.first) > 50.0f)
|
|
return false;
|
|
|
|
longLog = true;
|
|
}
|
|
}
|
|
|
|
if (longLog)
|
|
{
|
|
// LOG_INFO("playerbots", "Bot {} {}:{} <{}> was in the same position for 15mins",
|
|
// bot->GetGUID().ToString().c_str(), bot->GetTeamId() == TEAM_ALLIANCE ? "A" : "H", bot->GetLevel(),
|
|
// bot->GetName(), posVal->LastChangeDelay());
|
|
}
|
|
|
|
return longLog;
|
|
}
|
|
|
|
bool CombatStuckTrigger::IsActive()
|
|
{
|
|
if (!bot->IsInCombat())
|
|
return false;
|
|
|
|
if (botAI->HasActivePlayerMaster())
|
|
return false;
|
|
|
|
if (!botAI->AllowActivity(ALL_ACTIVITY))
|
|
return false;
|
|
|
|
WorldPosition botPos(bot);
|
|
|
|
MemoryCalculatedValue<bool>* combatVal =
|
|
dynamic_cast<MemoryCalculatedValue<bool>*>(context->GetUntypedValue("combat::self target"));
|
|
|
|
if (combatVal->LastChangeDelay() > 5 * MINUTE)
|
|
{
|
|
// LOG_INFO("playerbots", "Bot {} {}:{} <{}> was in combat for {} seconds",
|
|
// bot->GetGUID().ToString().c_str(), bot->GetTeamId() == TEAM_ALLIANCE ? "A" : "H", bot->GetLevel(),
|
|
// bot->GetName(), posVal->LastChangeDelay());
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool CombatLongStuckTrigger::IsActive()
|
|
{
|
|
if (!bot->IsInCombat())
|
|
return false;
|
|
|
|
if (botAI->HasActivePlayerMaster())
|
|
return false;
|
|
|
|
if (!botAI->AllowActivity(ALL_ACTIVITY))
|
|
return false;
|
|
|
|
WorldPosition botPos(bot);
|
|
|
|
MemoryCalculatedValue<bool>* combatVal =
|
|
dynamic_cast<MemoryCalculatedValue<bool>*>(context->GetUntypedValue("combat::self target"));
|
|
|
|
if (combatVal->LastChangeDelay() > 15 * MINUTE)
|
|
{
|
|
// LOG_INFO("playerbots", "Bot {} {}:{} <{}> was in combat for {} seconds",
|
|
// bot->GetGUID().ToString().c_str(), bot->GetTeamId() == TEAM_ALLIANCE ? "A" : "H", bot->GetLevel(),
|
|
// bot->GetName(), posVal->LastChangeDelay());
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|