mirror of
https://github.com/liyunfan1223/mod-playerbots.git
synced 2026-06-21 16:09:26 +02:00
Compare commits
5 Commits
ca9f23a8e3
...
1a3468368d
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1a3468368d | ||
|
|
55708f397a | ||
|
|
660a5c0543 | ||
|
|
14c77b1e7b | ||
|
|
788c7b025b |
@ -1,124 +1,103 @@
|
|||||||
# Pull Request
|
<!--
|
||||||
|
Thank you for contributing to mod-playerbots, please make sure that you...
|
||||||
|
1. Submit your PR to the test-staging branch, not master.
|
||||||
|
2. Read the guidelines below before submitting.
|
||||||
|
3. Don't delete parts of this template.
|
||||||
|
|
||||||
Describe what this change does and why it is needed...
|
DESIGN PHILOSOPHY: We prioritize STABILITY, PERFORMANCE, AND PREDICTABILITY over behavioral realism.
|
||||||
|
|
||||||
---
|
Every action and decision executes PER BOT AND PER TRIGGER. Small increases in logic complexity scale
|
||||||
|
poorly across thousands of bots and negatively affect all. We prioritize a stable system over a smarter
|
||||||
|
one. Bots don't need to behave perfectly; believable behavior is the goal, not human simulation.
|
||||||
|
Default behavior must be cheap in processing; expensive behavior must be opt-in.
|
||||||
|
|
||||||
## Design Philosophy
|
Before submitting, make sure your changes aligns with these principles.
|
||||||
|
-->
|
||||||
|
|
||||||
We prioritize **stability, performance, and predictability** over behavioral realism.
|
## Pull Request Description
|
||||||
Complex player-mimicking logic is intentionally limited due to its negative impact on scalability, maintainability, and
|
<!-- Describe what this change does and why it is needed -->
|
||||||
long-term robustness.
|
|
||||||
|
|
||||||
Excessive processing overhead can lead to server hiccups, increased CPU usage, and degraded performance for all
|
|
||||||
participants. Because every action and
|
|
||||||
decision tree is executed **per bot and per trigger**, even small increases in logic complexity can scale poorly and
|
|
||||||
negatively affect both players and
|
|
||||||
world (random) bots. Bots are not expected to behave perfectly, and perfect simulation of human decision-making is not a
|
|
||||||
project goal. Increased behavioral
|
|
||||||
realism often introduces disproportionate cost, reduced predictability, and significantly higher maintenance overhead.
|
|
||||||
|
|
||||||
Every additional branch of logic increases long-term responsibility. All decision paths must be tested, validated, and
|
|
||||||
maintained continuously as the system evolves.
|
|
||||||
If advanced or AI-intensive behavior is introduced, the **default configuration must remain the lightweight decision
|
|
||||||
model**. More complex behavior should only be
|
|
||||||
available as an **explicit opt-in option**, clearly documented as having a measurable performance cost.
|
|
||||||
|
|
||||||
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
|
## Feature Evaluation
|
||||||
|
<!--
|
||||||
|
If your PR is very minimal (comment typo, wrong ID reference, etc), and it is very obvious it will not have
|
||||||
|
any impact on performance, you may skip these question. If necessary, a maintainer may ask you for them later.
|
||||||
|
-->
|
||||||
|
|
||||||
Please answer the following:
|
<!-- Please answer the following: -->
|
||||||
|
- Describe the **minimum logic** required to achieve the intended behavior.
|
||||||
|
- Describe the **processing cost** when this logic executes across many bots.
|
||||||
|
|
||||||
- Describe the **minimum logic** required to achieve the intended behavior?
|
|
||||||
- Describe the **cheapest implementation** that produces an acceptable result?
|
|
||||||
- Describe the **runtime cost** when this logic executes across many bots?
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## How to Test the Changes
|
## How to Test the Changes
|
||||||
|
<!--
|
||||||
|
- Step-by-step instructions to test the change.
|
||||||
|
- Any required setup (e.g. multiple players, number of bots, specific configuration).
|
||||||
|
- Expected behavior and how to verify it.
|
||||||
|
-->
|
||||||
|
|
||||||
- Step-by-step instructions to test the change
|
|
||||||
- Any required setup (e.g. multiple players, bots, specific configuration)
|
|
||||||
- Expected behavior and how to verify it
|
|
||||||
|
|
||||||
## Complexity & Impact
|
|
||||||
|
|
||||||
Does this change add new decision branches?
|
## Impact Assessment
|
||||||
- - [ ] No
|
<!-- As a generic test, before and after measure of pmon (playerbot pmon tick) can help you here. -->
|
||||||
- - [ ] Yes (**explain below**)
|
- Does this change increase per-bot/per-tick processing or risk scaling poorly with thousands of bots?
|
||||||
|
- [ ] No, not at all
|
||||||
|
- [ ] Minimal impact (**explain below**)
|
||||||
|
- [ ] Moderate impact (**explain below**)
|
||||||
|
|
||||||
Does this change increase per-bot or per-tick processing?
|
|
||||||
- - [ ] No
|
|
||||||
- - [ ] Yes (**describe and justify impact**)
|
|
||||||
|
|
||||||
Could this logic scale poorly under load?
|
|
||||||
- - [ ] No
|
|
||||||
- - [ ] Yes (**explain why**)
|
|
||||||
---
|
|
||||||
|
|
||||||
## Defaults & Configuration
|
- Does this change modify default bot behavior?
|
||||||
|
- [ ] No
|
||||||
|
- [ ] Yes (**explain why**)
|
||||||
|
|
||||||
Does this change modify default bot behavior?
|
|
||||||
- - [ ] No
|
|
||||||
- - [ ] Yes (**explain why**)
|
|
||||||
|
|
||||||
If this introduces more advanced or AI-heavy logic:
|
|
||||||
- - [ ] Lightweight mode remains the default
|
- Does this change add new decision branches or increase maintenance complexity?
|
||||||
- - [ ] More complex behavior is optional and thereby configurable
|
- [ ] No
|
||||||
---
|
- [ ] Yes (**explain below**)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Messages to Translate
|
||||||
|
<!--
|
||||||
|
Bot messages have to be translatable, but you don't need to do the translations here. You only need to make sure
|
||||||
|
the message is in a translatable format, and list in the table the message_key and the default English message.
|
||||||
|
Search for GetBotTextOrDefault in the codebase for examples.
|
||||||
|
-->
|
||||||
|
Does this change add bot messages to translate?
|
||||||
|
- [ ] No
|
||||||
|
- [ ] Yes (**list messages in the table**)
|
||||||
|
|
||||||
|
| Message key | Default message |
|
||||||
|
| --------------- | ------------------ |
|
||||||
|
| | |
|
||||||
|
| | |
|
||||||
|
|
||||||
## AI Assistance
|
## AI Assistance
|
||||||
|
<!--
|
||||||
Was AI assistance (e.g. ChatGPT or similar tools) used while working on this change?
|
|
||||||
- - [ ] No
|
|
||||||
- - [ ] Yes (**explain below**)
|
|
||||||
|
|
||||||
If yes, please specify:
|
|
||||||
|
|
||||||
- AI tool or model used (e.g. ChatGPT, GPT-4, Claude, etc.)
|
|
||||||
- Purpose of usage (e.g. brainstorming, refactoring, documentation, code generation)
|
|
||||||
- Which parts of the change were influenced or generated
|
|
||||||
- Whether the result was manually reviewed and adapted
|
|
||||||
|
|
||||||
AI assistance is allowed, but all submitted code must be fully understood, reviewed, and owned by the contributor.
|
AI assistance is allowed, but all submitted code must be fully understood, reviewed, and owned by the contributor.
|
||||||
Any AI-influenced changes must be verified against existing CORE and PB logic. We expect contributors to be honest
|
We expect contributors to be honest about what they do and do not understand.
|
||||||
about what they do and do not understand.
|
-->
|
||||||
|
Was AI assistance used while working on this change?
|
||||||
|
- [ ] No
|
||||||
|
- [ ] Yes (**explain below**)
|
||||||
|
<!--
|
||||||
|
If yes, please specify:
|
||||||
|
- Purpose of usage (e.g. brainstorming, refactoring, documentation, code generation).
|
||||||
|
- Which parts of the change were influenced or generated, and whether it was thoroughly reviewed.
|
||||||
|
-->
|
||||||
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Final Checklist
|
## Final Checklist
|
||||||
|
|
||||||
- - [ ] Stability is not compromised
|
- [ ] Stability is not compromised.
|
||||||
- - [ ] Performance impact is understood, tested, and acceptable
|
- [ ] Performance impact is understood, tested, and acceptable.
|
||||||
- - [ ] Added logic complexity is justified and explained
|
- [ ] Added logic complexity is justified and explained.
|
||||||
- - [ ] Documentation updated if needed
|
- [ ] Documentation updated if needed (Conf comments, WiKi commands).
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Notes for Reviewers
|
## Notes for Reviewers
|
||||||
|
<!-- Anything else that's helpful to review or test your pull request. -->
|
||||||
Anything that significantly improves realism at the cost of stability or performance should be carefully discussed
|
|
||||||
before merging.
|
|
||||||
|
|||||||
@ -0,0 +1 @@
|
|||||||
|
UPDATE `ai_playerbot_texts` SET `text_loc3`='%s, du hörst den triefenden Sarkasmus in meinem text nicht' WHERE `id`=1353;
|
||||||
@ -598,9 +598,9 @@ uint32 ChatHelper::parseSlot(std::string const text)
|
|||||||
return EQUIPMENT_SLOT_END;
|
return EQUIPMENT_SLOT_END;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ChatHelper::parseable(std::string const text)
|
bool ChatHelper::parseableItem(std::string const text)
|
||||||
{
|
{
|
||||||
return text.find("|H") != std::string::npos || text == "questitem" || text == "ammo" ||
|
return text.find("|Hitem:") != std::string::npos || text == "questitem" || text == "ammo" ||
|
||||||
substrContainsInMap<uint32>(text, consumableSubClasses) ||
|
substrContainsInMap<uint32>(text, consumableSubClasses) ||
|
||||||
substrContainsInMap<uint32>(text, tradeSubClasses) || substrContainsInMap<uint32>(text, itemQualities) ||
|
substrContainsInMap<uint32>(text, tradeSubClasses) || substrContainsInMap<uint32>(text, itemQualities) ||
|
||||||
substrContainsInMap<uint32>(text, slots) || substrContainsInMap<ChatMsg>(text, chats) ||
|
substrContainsInMap<uint32>(text, slots) || substrContainsInMap<ChatMsg>(text, chats) ||
|
||||||
|
|||||||
@ -66,7 +66,7 @@ public:
|
|||||||
static uint32 parseSlot(std::string const text);
|
static uint32 parseSlot(std::string const text);
|
||||||
uint32 parseSkill(std::string const text);
|
uint32 parseSkill(std::string const text);
|
||||||
|
|
||||||
static bool parseable(std::string const text);
|
static bool parseableItem(std::string const text);
|
||||||
|
|
||||||
void eraseAllSubStr(std::string& mainStr, std::string const toErase);
|
void eraseAllSubStr(std::string& mainStr, std::string const toErase);
|
||||||
|
|
||||||
|
|||||||
@ -30,7 +30,7 @@ bool ExternalEventHelper::ParseChatCommand(std::string const command, Player* ow
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ChatHelper::parseable(command))
|
if (!ChatHelper::parseableItem(command))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
HandleCommand("c", command, owner);
|
HandleCommand("c", command, owner);
|
||||||
|
|||||||
@ -9,6 +9,7 @@
|
|||||||
#include "ArenaTeamMgr.h"
|
#include "ArenaTeamMgr.h"
|
||||||
#include "DatabaseEnv.h"
|
#include "DatabaseEnv.h"
|
||||||
#include "PlayerbotAI.h"
|
#include "PlayerbotAI.h"
|
||||||
|
#include "RaceMgr.h"
|
||||||
#include "ScriptMgr.h"
|
#include "ScriptMgr.h"
|
||||||
#include "SharedDefines.h"
|
#include "SharedDefines.h"
|
||||||
#include "SocialMgr.h"
|
#include "SocialMgr.h"
|
||||||
@ -60,7 +61,7 @@ Player* RandomPlayerbotFactory::CreateRandomBot(WorldSession* session, uint8 cls
|
|||||||
const bool alliance = static_cast<bool>(urand(0, 1));
|
const bool alliance = static_cast<bool>(urand(0, 1));
|
||||||
|
|
||||||
std::vector<uint8> raceOptions;
|
std::vector<uint8> raceOptions;
|
||||||
for (uint8 race = RACE_HUMAN; race < MAX_RACES; ++race)
|
for (uint8 race = RACE_HUMAN; race < sRaceMgr->GetMaxRaces(); ++race)
|
||||||
{
|
{
|
||||||
// skip disabled with config races
|
// skip disabled with config races
|
||||||
if ((1 << (race - 1)) & sWorld->getIntConfig(CONFIG_CHARACTER_CREATING_DISABLED_RACEMASK))
|
if ((1 << (race - 1)) & sWorld->getIntConfig(CONFIG_CHARACTER_CREATING_DISABLED_RACEMASK))
|
||||||
|
|||||||
@ -1532,6 +1532,21 @@ std::vector<std::string> PlayerbotAI::GetStrategies(BotState type)
|
|||||||
|
|
||||||
void PlayerbotAI::ApplyInstanceStrategies(uint32 mapId, bool tellMaster)
|
void PlayerbotAI::ApplyInstanceStrategies(uint32 mapId, bool tellMaster)
|
||||||
{
|
{
|
||||||
|
static const std::vector<std::string> allInstanceStrategies =
|
||||||
|
{
|
||||||
|
"aq20", "bwl", "karazhan", "gruulslair", "icc", "magtheridon", "moltencore",
|
||||||
|
"naxx", "onyxia", "ssc", "tempestkeep", "ulduar", "voa", "wotlk-an", "wotlk-cos",
|
||||||
|
"wotlk-dtk", "wotlk-eoe", "wotlk-fos", "wotlk-gd", "wotlk-hol", "wotlk-hor",
|
||||||
|
"wotlk-hos", "wotlk-nex", "wotlk-occ", "wotlk-ok", "wotlk-os", "wotlk-pos",
|
||||||
|
"wotlk-toc", "wotlk-uk", "wotlk-up", "wotlk-vh"
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const std::string& strat : allInstanceStrategies)
|
||||||
|
{
|
||||||
|
engines[BOT_STATE_COMBAT]->removeStrategy(strat);
|
||||||
|
engines[BOT_STATE_NON_COMBAT]->removeStrategy(strat);
|
||||||
|
}
|
||||||
|
|
||||||
std::string strategyName;
|
std::string strategyName;
|
||||||
switch (mapId)
|
switch (mapId)
|
||||||
{
|
{
|
||||||
@ -1631,10 +1646,13 @@ void PlayerbotAI::ApplyInstanceStrategies(uint32 mapId, bool tellMaster)
|
|||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strategyName.empty())
|
if (strategyName.empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
engines[BOT_STATE_COMBAT]->addStrategy(strategyName);
|
engines[BOT_STATE_COMBAT]->addStrategy(strategyName);
|
||||||
engines[BOT_STATE_NON_COMBAT]->addStrategy(strategyName);
|
engines[BOT_STATE_NON_COMBAT]->addStrategy(strategyName);
|
||||||
|
|
||||||
if (tellMaster && !strategyName.empty())
|
if (tellMaster && !strategyName.empty())
|
||||||
{
|
{
|
||||||
std::ostringstream out;
|
std::ostringstream out;
|
||||||
|
|||||||
@ -37,6 +37,7 @@
|
|||||||
#include "PlayerbotFactory.h"
|
#include "PlayerbotFactory.h"
|
||||||
#include "Playerbots.h"
|
#include "Playerbots.h"
|
||||||
#include "Position.h"
|
#include "Position.h"
|
||||||
|
#include "RaceMgr.h"
|
||||||
#include "Random.h"
|
#include "Random.h"
|
||||||
#include "RandomPlayerbotFactory.h"
|
#include "RandomPlayerbotFactory.h"
|
||||||
#include "ServerFacade.h"
|
#include "ServerFacade.h"
|
||||||
@ -1995,7 +1996,7 @@ void RandomPlayerbotMgr::PrepareTeleportCache()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// add all initial position
|
// add all initial position
|
||||||
for (uint32 i = 1; i < MAX_RACES; i++)
|
for (uint32 i = 1; i < sRaceMgr->GetMaxRaces(); i++)
|
||||||
{
|
{
|
||||||
for (uint32 j = 1; j < MAX_CLASSES; j++)
|
for (uint32 j = 1; j < MAX_CLASSES; j++)
|
||||||
{
|
{
|
||||||
@ -2008,7 +2009,7 @@ void RandomPlayerbotMgr::PrepareTeleportCache()
|
|||||||
|
|
||||||
for (int32 l = 1; l <= 5; l++)
|
for (int32 l = 1; l <= 5; l++)
|
||||||
{
|
{
|
||||||
if ((1 << (i - 1)) & RACEMASK_ALLIANCE)
|
if ((1 << (i - 1)) & sRaceMgr->GetAllianceRaceMask())
|
||||||
allianceStarterPerLevelCache[(uint8)l].push_back(pos);
|
allianceStarterPerLevelCache[(uint8)l].push_back(pos);
|
||||||
else
|
else
|
||||||
hordeStarterPerLevelCache[(uint8)l].push_back(pos);
|
hordeStarterPerLevelCache[(uint8)l].push_back(pos);
|
||||||
@ -3126,7 +3127,7 @@ void RandomPlayerbotMgr::PrintStats()
|
|||||||
|
|
||||||
std::map<uint8, uint32> lvlPerRace;
|
std::map<uint8, uint32> lvlPerRace;
|
||||||
std::map<uint8, uint32> lvlPerClass;
|
std::map<uint8, uint32> lvlPerClass;
|
||||||
for (uint8 race = RACE_HUMAN; race < MAX_RACES; ++race)
|
for (uint8 race = RACE_HUMAN; race < sRaceMgr->GetMaxRaces(); ++race)
|
||||||
{
|
{
|
||||||
perRace[race] = 0;
|
perRace[race] = 0;
|
||||||
lvlPerRace[race] = 0;
|
lvlPerRace[race] = 0;
|
||||||
@ -3273,7 +3274,7 @@ void RandomPlayerbotMgr::PrintStats()
|
|||||||
}
|
}
|
||||||
|
|
||||||
LOG_INFO("playerbots", "Bots race:");
|
LOG_INFO("playerbots", "Bots race:");
|
||||||
for (uint8 race = RACE_HUMAN; race < MAX_RACES; ++race)
|
for (uint8 race = RACE_HUMAN; race < sRaceMgr->GetMaxRaces(); ++race)
|
||||||
{
|
{
|
||||||
if (perRace[race])
|
if (perRace[race])
|
||||||
{
|
{
|
||||||
|
|||||||
@ -14,6 +14,7 @@
|
|||||||
#include "MapMgr.h"
|
#include "MapMgr.h"
|
||||||
#include "PathGenerator.h"
|
#include "PathGenerator.h"
|
||||||
#include "Playerbots.h"
|
#include "Playerbots.h"
|
||||||
|
#include "RaceMgr.h"
|
||||||
#include "TransportMgr.h"
|
#include "TransportMgr.h"
|
||||||
#include "VMapFactory.h"
|
#include "VMapFactory.h"
|
||||||
#include "VMapMgr2.h"
|
#include "VMapMgr2.h"
|
||||||
@ -3335,7 +3336,7 @@ void TravelMgr::LoadQuestTravelTable()
|
|||||||
|
|
||||||
std::ostringstream out;
|
std::ostringstream out;
|
||||||
|
|
||||||
for (uint8 race = RACE_HUMAN; race < MAX_RACES; race++)
|
for (uint8 race = RACE_HUMAN; race < sRaceMgr->GetMaxRaces(); race++)
|
||||||
{
|
{
|
||||||
for (uint8 cls = CLASS_WARRIOR; cls < MAX_CLASSES; ++cls)
|
for (uint8 cls = CLASS_WARRIOR; cls < MAX_CLASSES; ++cls)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -11,6 +11,7 @@
|
|||||||
#include "BudgetValues.h"
|
#include "BudgetValues.h"
|
||||||
#include "PathGenerator.h"
|
#include "PathGenerator.h"
|
||||||
#include "Playerbots.h"
|
#include "Playerbots.h"
|
||||||
|
#include "RaceMgr.h"
|
||||||
#include "ServerFacade.h"
|
#include "ServerFacade.h"
|
||||||
#include "TransportMgr.h"
|
#include "TransportMgr.h"
|
||||||
|
|
||||||
@ -1660,7 +1661,7 @@ void TravelNodeMap::generateStartNodes()
|
|||||||
startNames[RACE_GNOME] = "Dwarf and Gnome";
|
startNames[RACE_GNOME] = "Dwarf and Gnome";
|
||||||
startNames[RACE_TROLL] = "Orc and Troll";
|
startNames[RACE_TROLL] = "Orc and Troll";
|
||||||
|
|
||||||
for (uint32 i = 0; i < MAX_RACES; i++)
|
for (uint32 i = 0; i < sRaceMgr->GetMaxRaces(); i++)
|
||||||
{
|
{
|
||||||
for (uint32 j = 0; j < MAX_CLASSES; j++)
|
for (uint32 j = 0; j < MAX_CLASSES; j++)
|
||||||
{
|
{
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user