Merge pull request #243 from brian8544/master

Add performance tuning
This commit is contained in:
Yunfan Li
2024-05-28 18:22:26 +08:00
committed by GitHub
6 changed files with 204 additions and 7 deletions

View File

@@ -412,7 +412,7 @@ AiPlayerbot.MinRandomBotReviveTime = 60
AiPlayerbot.MaxRandomBotReviveTime = 300 AiPlayerbot.MaxRandomBotReviveTime = 300
AiPlayerbot.MinRandomBotTeleportInterval = 3600 AiPlayerbot.MinRandomBotTeleportInterval = 3600
AiPlayerbot.MaxRandomBotTeleportInterval = 18000 AiPlayerbot.MaxRandomBotTeleportInterval = 18000
AiPlayerbot.RandomBotInWorldWithRotaionDisabled = 31104000 AiPlayerbot.RandomBotInWorldWithRotationDisabled = 31104000
# How far random bots are teleported after death # How far random bots are teleported after death
AiPlayerbot.RandomBotTeleportDistance = 100 AiPlayerbot.RandomBotTeleportDistance = 100
@@ -449,6 +449,11 @@ AiPlayerbot.BotCheats = "taxi"
# Enables/Disables password to bot account # Enables/Disables password to bot account
AiPlayerbot.RandomBotRandomPassword = 0 AiPlayerbot.RandomBotRandomPassword = 0
# Diff with/without player in server. The server will tune bot activity to reach the desired server tick speed (in ms).
# AiPlayerbot.EnablePrototypePerformanceDiff = 0
# AiPlayerbot.DiffWithPlayer = 100
# AiPlayerbot.DiffEmpty = 200
################################################################################## ##################################################################################
# # # #
# Database Stuff # # Database Stuff #

View File

@@ -130,7 +130,7 @@ bool PlayerbotAIConfig::Initialize()
maxRandomBotReviveTime = sConfigMgr->GetOption<int32>("AiPlayerbot.MaxRandomBotReviveTime", 5 * MINUTE); maxRandomBotReviveTime = sConfigMgr->GetOption<int32>("AiPlayerbot.MaxRandomBotReviveTime", 5 * MINUTE);
minRandomBotTeleportInterval = sConfigMgr->GetOption<int32>("AiPlayerbot.MinRandomBotTeleportInterval", 1 * HOUR); minRandomBotTeleportInterval = sConfigMgr->GetOption<int32>("AiPlayerbot.MinRandomBotTeleportInterval", 1 * HOUR);
maxRandomBotTeleportInterval = sConfigMgr->GetOption<int32>("AiPlayerbot.MaxRandomBotTeleportInterval", 5 * HOUR); maxRandomBotTeleportInterval = sConfigMgr->GetOption<int32>("AiPlayerbot.MaxRandomBotTeleportInterval", 5 * HOUR);
randomBotInWorldWithRotaionDisabled = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotInWorldWithRotaionDisabled", 1 * YEAR); randomBotInWorldWithRotationDisabled = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotInWorldWithRotationDisabled", 1 * YEAR);
randomBotTeleportDistance = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotTeleportDistance", 100); randomBotTeleportDistance = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotTeleportDistance", 100);
randomBotsPerInterval = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotsPerInterval", MINUTE); randomBotsPerInterval = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotsPerInterval", MINUTE);
minRandomBotsPriceChangeInterval = sConfigMgr->GetOption<int32>("AiPlayerbot.MinRandomBotsPriceChangeInterval", 2 * HOUR); minRandomBotsPriceChangeInterval = sConfigMgr->GetOption<int32>("AiPlayerbot.MinRandomBotsPriceChangeInterval", 2 * HOUR);
@@ -282,6 +282,11 @@ bool PlayerbotAIConfig::Initialize()
playerbotsXPrate = sConfigMgr->GetOption<int32>("AiPlayerbot.KillXPRate", 1); playerbotsXPrate = sConfigMgr->GetOption<int32>("AiPlayerbot.KillXPRate", 1);
botActiveAlone = sConfigMgr->GetOption<int32>("AiPlayerbot.BotActiveAlone", 10); botActiveAlone = sConfigMgr->GetOption<int32>("AiPlayerbot.BotActiveAlone", 10);
enablePrototypePerformanceDiff = sConfigMgr->GetOption<bool>("AiPlayerbot.EnablePrototypePerformanceDiff", false);
diffWithPlayer = sConfigMgr->GetOption("AiPlayerbot.DiffWithPlayer", 100);
diffEmpty = sConfigMgr->GetIntDefault("AiPlayerbot.DiffEmpty", 200);
randombotsWalkingRPG = sConfigMgr->GetOption<bool>("AiPlayerbot.RandombotsWalkingRPG", false); randombotsWalkingRPG = sConfigMgr->GetOption<bool>("AiPlayerbot.RandombotsWalkingRPG", false);
randombotsWalkingRPGInDoors = sConfigMgr->GetOption<bool>("AiPlayerbot.RandombotsWalkingRPG.InDoors", false); randombotsWalkingRPGInDoors = sConfigMgr->GetOption<bool>("AiPlayerbot.RandombotsWalkingRPG.InDoors", false);
minEnchantingBotLevel = sConfigMgr->GetOption<int32>("AiPlayerbot.MinEnchantingBotLevel", 60); minEnchantingBotLevel = sConfigMgr->GetOption<int32>("AiPlayerbot.MinEnchantingBotLevel", 60);

View File

@@ -88,7 +88,7 @@ class PlayerbotAIConfig
uint32 minRandomBotChangeStrategyTime, maxRandomBotChangeStrategyTime; uint32 minRandomBotChangeStrategyTime, maxRandomBotChangeStrategyTime;
uint32 minRandomBotReviveTime, maxRandomBotReviveTime; uint32 minRandomBotReviveTime, maxRandomBotReviveTime;
uint32 minRandomBotTeleportInterval, maxRandomBotTeleportInterval; uint32 minRandomBotTeleportInterval, maxRandomBotTeleportInterval;
uint32 randomBotInWorldWithRotaionDisabled; uint32 randomBotInWorldWithRotationDisabled;
uint32 minRandomBotPvpTime, maxRandomBotPvpTime; uint32 minRandomBotPvpTime, maxRandomBotPvpTime;
uint32 randomBotsPerInterval; uint32 randomBotsPerInterval;
uint32 minRandomBotsPriceChangeInterval, maxRandomBotsPriceChangeInterval; uint32 minRandomBotsPriceChangeInterval, maxRandomBotsPriceChangeInterval;
@@ -178,6 +178,10 @@ class PlayerbotAIConfig
uint32 playerbotsXPrate; uint32 playerbotsXPrate;
uint32 botActiveAlone; uint32 botActiveAlone;
uint32 enablePrototypePerformanceDiff;
uint32 diffWithPlayer;
uint32 diffEmpty;
bool freeMethodLoot; bool freeMethodLoot;
int32 lootRollLevel; int32 lootRollLevel;
std::string autoPickReward; std::string autoPickReward;

View File

@@ -28,6 +28,7 @@
#include "ChannelMgr.h" #include "ChannelMgr.h"
#include "Unit.h" #include "Unit.h"
#include "World.h" #include "World.h"
#include "UpdateTime.h"
#include <algorithm> #include <algorithm>
#include <cstdlib> #include <cstdlib>
@@ -79,6 +80,106 @@ void activateCheckPlayersThread()
t.detach(); t.detach();
} }
class botPIDImpl
{
public:
botPIDImpl(double dt, double max, double min, double Kp, double Ki, double Kd);
~botPIDImpl();
double calculate(double setpoint, double pv);
void adjust(double Kp, double Ki, double Kd) { _Kp = Kp; _Ki = Ki; _Kd = Kd; }
void reset() { _integral = 0; }
private:
double _dt;
double _max;
double _min;
double _Kp;
double _Ki;
double _Kd;
double _pre_error;
double _integral;
};
botPID::botPID(double dt, double max, double min, double Kp, double Ki, double Kd)
{
pimpl = new botPIDImpl(dt, max, min, Kp, Ki, Kd);
}
void botPID::adjust(double Kp, double Ki, double Kd)
{
pimpl->adjust(Kp, Ki, Kd);
}
void botPID::reset()
{
pimpl->reset();
}
double botPID::calculate(double setpoint, double pv)
{
return pimpl->calculate(setpoint, pv);
}
botPID::~botPID()
{
delete pimpl;
}
/**
* Implementation
*/
botPIDImpl::botPIDImpl(double dt, double max, double min, double Kp, double Ki, double Kd) :
_dt(dt),
_max(max),
_min(min),
_Kp(Kp),
_Ki(Ki),
_Kd(Kd),
_pre_error(0),
_integral(0)
{
}
double botPIDImpl::calculate(double setpoint, double pv)
{
// Calculate error
double error = setpoint - pv;
// Proportional term
double Pout = _Kp * error;
// Integral term
_integral += error * _dt;
double Iout = _Ki * _integral;
// Derivative term
double derivative = (error - _pre_error) / _dt;
double Dout = _Kd * derivative;
// Calculate total output
double output = Pout + Iout + Dout;
// Restrict to max/min
if (output > _max)
{
output = _max;
_integral -= error * _dt; //Stop integral buildup at max
}
else if (output < _min)
{
output = _min;
_integral -= error * _dt; //Stop integral buildup at min
}
// Save error to previous error
_pre_error = error;
return output;
}
botPIDImpl::~botPIDImpl()
{
}
RandomPlayerbotMgr::RandomPlayerbotMgr() : PlayerbotHolder(), processTicks(0), totalPmo(nullptr) RandomPlayerbotMgr::RandomPlayerbotMgr() : PlayerbotHolder(), processTicks(0), totalPmo(nullptr)
{ {
playersLevel = sPlayerbotAIConfig->randombotStartingLevel; playersLevel = sPlayerbotAIConfig->randombotStartingLevel;
@@ -236,6 +337,14 @@ void RandomPlayerbotMgr::UpdateAIInternal(uint32 elapsed, bool /*minimal*/)
if (!sPlayerbotAIConfig->randomBotAutologin || !sPlayerbotAIConfig->enabled) if (!sPlayerbotAIConfig->randomBotAutologin || !sPlayerbotAIConfig->enabled)
return; return;
if (sPlayerbotAIConfig->enablePrototypePerformanceDiff)
{
LOG_INFO("playerbots", "---------------------------------------");
LOG_INFO("playerbots", "PROTOTYPE: Playerbot performance enhancements are active. Issues and instability may occur.");
LOG_INFO("playerbots", "---------------------------------------");
ScaleBotActivity();
}
uint32 maxAllowedBotCount = GetEventValue(0, "bot_count"); uint32 maxAllowedBotCount = GetEventValue(0, "bot_count");
if (!maxAllowedBotCount || (maxAllowedBotCount < sPlayerbotAIConfig->minRandomBots || maxAllowedBotCount > sPlayerbotAIConfig->maxRandomBots)) if (!maxAllowedBotCount || (maxAllowedBotCount < sPlayerbotAIConfig->minRandomBots || maxAllowedBotCount > sPlayerbotAIConfig->maxRandomBots))
{ {
@@ -327,6 +436,23 @@ void RandomPlayerbotMgr::UpdateAIInternal(uint32 elapsed, bool /*minimal*/)
} }
} }
void RandomPlayerbotMgr::ScaleBotActivity()
{
float activityPercentage = getActivityPercentage();
//if (activityPercentage >= 100.0f || activityPercentage <= 0.0f) pid.reset(); //Stop integer buildup during max/min activity
// % increase/decrease wanted diff , avg diff
float activityPercentageMod = pid.calculate(sRandomPlayerbotMgr->GetPlayers().empty() ? sPlayerbotAIConfig->diffEmpty : sPlayerbotAIConfig->diffWithPlayer, sWorldUpdateTime.GetAverageUpdateTime());
activityPercentage = activityPercentageMod + 50;
//Cap the percentage between 0 and 100.
activityPercentage = std::max(0.0f, std::min(100.0f, activityPercentage));
setActivityPercentage(activityPercentage);
}
uint32 RandomPlayerbotMgr::AddRandomBots() uint32 RandomPlayerbotMgr::AddRandomBots()
{ {
uint32 maxAllowedBotCount = GetEventValue(0, "bot_count"); uint32 maxAllowedBotCount = GetEventValue(0, "bot_count");
@@ -375,7 +501,7 @@ uint32 RandomPlayerbotMgr::AddRandomBots()
for (uint32 &guid : guids) { for (uint32 &guid : guids) {
uint32 add_time = sPlayerbotAIConfig->enableRotation ? uint32 add_time = sPlayerbotAIConfig->enableRotation ?
urand(sPlayerbotAIConfig->minRandomBotInWorldTime, sPlayerbotAIConfig->maxRandomBotInWorldTime) : urand(sPlayerbotAIConfig->minRandomBotInWorldTime, sPlayerbotAIConfig->maxRandomBotInWorldTime) :
sPlayerbotAIConfig->randomBotInWorldWithRotaionDisabled; sPlayerbotAIConfig->randomBotInWorldWithRotationDisabled;
SetEventValue(guid, "add", 1, add_time); SetEventValue(guid, "add", 1, add_time);
SetEventValue(guid, "logout", 0, 0); SetEventValue(guid, "logout", 0, 0);

View File

@@ -27,6 +27,29 @@ class CachedEvent
std::string data; std::string data;
}; };
//https://gist.github.com/bradley219/5373998
class botPIDImpl;
class botPID
{
public:
// Kp - proportional gain
// Ki - Integral gain
// Kd - derivative gain
// dt - loop interval time
// max - maximum value of manipulated variable
// min - minimum value of manipulated variable
botPID(double dt, double max, double min, double Kp, double Ki, double Kd);
void adjust(double Kp, double Ki, double Kd);
void reset();
double calculate(double setpoint, double pv);
~botPID();
private:
botPIDImpl* pimpl;
};
class RandomPlayerbotMgr : public PlayerbotHolder class RandomPlayerbotMgr : public PlayerbotHolder
{ {
public: public:
@@ -41,6 +64,9 @@ class RandomPlayerbotMgr : public PlayerbotHolder
void LogPlayerLocation(); void LogPlayerLocation();
void UpdateAIInternal(uint32 elapsed, bool minimal = false) override; void UpdateAIInternal(uint32 elapsed, bool minimal = false) override;
private:
void ScaleBotActivity();
public: public:
uint32 activeBots = 0; uint32 activeBots = 0;
static bool HandlePlayerbotConsoleCommand(ChatHandler* handler, char const* args); static bool HandlePlayerbotConsoleCommand(ChatHandler* handler, char const* args);
@@ -99,10 +125,17 @@ class RandomPlayerbotMgr : public PlayerbotHolder
std::map<TeamId, std::map<BattlegroundTypeId, std::vector<uint32>>> getBattleMastersCache() { return BattleMastersCache; } std::map<TeamId, std::map<BattlegroundTypeId, std::vector<uint32>>> getBattleMastersCache() { return BattleMastersCache; }
float getActivityMod() { return activityMod; }
float getActivityPercentage() { return activityMod * 100.0f; }
void setActivityPercentage(float percentage) { activityMod = percentage / 100.0f; }
protected: protected:
void OnBotLoginInternal(Player* const bot) override; void OnBotLoginInternal(Player* const bot) override;
private: private:
//pid values are set in constructor
botPID pid = botPID(1, 50, -50, 0, 0, 0);
float activityMod = 0.25;
uint32 GetEventValue(uint32 bot, std::string const event); uint32 GetEventValue(uint32 bot, std::string const event);
std::string const GetEventData(uint32 bot, std::string const event); std::string const GetEventData(uint32 bot, std::string const event);
uint32 SetEventValue(uint32 bot, std::string const event, uint32 value, uint32 validIn, std::string const data = ""); uint32 SetEventValue(uint32 bot, std::string const event, uint32 value, uint32 validIn, std::string const data = "");
@@ -137,4 +170,4 @@ class RandomPlayerbotMgr : public PlayerbotHolder
#define sRandomPlayerbotMgr RandomPlayerbotMgr::instance() #define sRandomPlayerbotMgr RandomPlayerbotMgr::instance()
#endif #endif

View File

@@ -11,6 +11,7 @@
#include "PlayerbotAI.h" #include "PlayerbotAI.h"
#include "Playerbots.h" #include "Playerbots.h"
#include "PositionValue.h" #include "PositionValue.h"
#include "UpdateTime.h"
bool BGJoinAction::Execute(Event event) bool BGJoinAction::Execute(Event event)
{ {
@@ -239,6 +240,7 @@ bool BGJoinAction::shouldJoinBg(BattlegroundQueueTypeId queueTypeId, Battlegroun
bool isArena = false; bool isArena = false;
bool isRated = false; bool isRated = false;
bool noLag = sWorldUpdateTime.GetAverageUpdateTime() < (sRandomPlayerbotMgr->GetPlayers().empty() ? sPlayerbotAIConfig->diffEmpty : sPlayerbotAIConfig->diffWithPlayer) * 1.1;
ArenaType type = ArenaType(BattlegroundMgr::BGArenaType(queueTypeId)); ArenaType type = ArenaType(BattlegroundMgr::BGArenaType(queueTypeId));
if (type != ARENA_TYPE_NONE) if (type != ARENA_TYPE_NONE)
@@ -246,12 +248,33 @@ bool BGJoinAction::shouldJoinBg(BattlegroundQueueTypeId queueTypeId, Battlegroun
bool hasPlayers = (sRandomPlayerbotMgr->BgPlayers[queueTypeId][bracketId][TEAM_ALLIANCE] + sRandomPlayerbotMgr->BgPlayers[queueTypeId][bracketId][TEAM_HORDE]) > 0; bool hasPlayers = (sRandomPlayerbotMgr->BgPlayers[queueTypeId][bracketId][TEAM_ALLIANCE] + sRandomPlayerbotMgr->BgPlayers[queueTypeId][bracketId][TEAM_HORDE]) > 0;
bool hasBots = (sRandomPlayerbotMgr->BgBots[queueTypeId][bracketId][TEAM_ALLIANCE] + sRandomPlayerbotMgr->BgBots[queueTypeId][bracketId][TEAM_HORDE]) >= bg->GetMinPlayersPerTeam(); bool hasBots = (sRandomPlayerbotMgr->BgBots[queueTypeId][bracketId][TEAM_ALLIANCE] + sRandomPlayerbotMgr->BgBots[queueTypeId][bracketId][TEAM_HORDE]) >= bg->GetMinPlayersPerTeam();
if (!sPlayerbotAIConfig->randomBotAutoJoinBG && !hasPlayers) if (!sPlayerbotAIConfig->randomBotAutoJoinBG && !hasPlayers)
{
return false; return false;
if (!(hasPlayers || hasBots)) if (sPlayerbotAIConfig->enablePrototypePerformanceDiff)
{
if (!noLag)
{
return false;
}
}
}
if (!hasPlayers && !(isArena))
{
return false; return false;
if (sPlayerbotAIConfig->enablePrototypePerformanceDiff)
{
if (!noLag)
{
return false;
}
}
}
uint32 BracketSize = bg->GetMaxPlayersPerTeam() * 2; uint32 BracketSize = bg->GetMaxPlayersPerTeam() * 2;
uint32 TeamSize = bg->GetMaxPlayersPerTeam(); uint32 TeamSize = bg->GetMaxPlayersPerTeam();
@@ -584,6 +607,7 @@ bool FreeBGJoinAction::shouldJoinBg(BattlegroundQueueTypeId queueTypeId, Battleg
bool isArena = false; bool isArena = false;
bool isRated = false; bool isRated = false;
bool noLag = sWorldUpdateTime.GetAverageUpdateTime() < (sRandomPlayerbotMgr->GetPlayers().empty() ? sPlayerbotAIConfig->diffEmpty : sPlayerbotAIConfig->diffWithPlayer) * 1.1;
ArenaType type = ArenaType(BattlegroundMgr::BGArenaType(queueTypeId)); ArenaType type = ArenaType(BattlegroundMgr::BGArenaType(queueTypeId));
if (type != ARENA_TYPE_NONE) if (type != ARENA_TYPE_NONE)
@@ -1117,4 +1141,4 @@ bool BGStrategyCheckAction::Execute(Event event)
return false; return false;
} }
return false; return false;
} }