mirror of
https://github.com/mod-playerbots/mod-playerbots
synced 2025-11-29 15:58:20 +08:00
Add performance tuning
Add a diff with and without player in server. The server will tune bot activity to reach the desired server tick speed (in ms), as what CMaNGOS' playerbots are using.
ce4bd79d2d is used as a reference.
This commit is contained in:
@@ -449,6 +449,11 @@ AiPlayerbot.BotCheats = "taxi"
|
||||
# Enables/Disables password to bot account
|
||||
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 #
|
||||
|
||||
@@ -282,6 +282,11 @@ bool PlayerbotAIConfig::Initialize()
|
||||
|
||||
playerbotsXPrate = sConfigMgr->GetOption<int32>("AiPlayerbot.KillXPRate", 1);
|
||||
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);
|
||||
randombotsWalkingRPGInDoors = sConfigMgr->GetOption<bool>("AiPlayerbot.RandombotsWalkingRPG.InDoors", false);
|
||||
minEnchantingBotLevel = sConfigMgr->GetOption<int32>("AiPlayerbot.MinEnchantingBotLevel", 60);
|
||||
|
||||
@@ -178,6 +178,10 @@ class PlayerbotAIConfig
|
||||
uint32 playerbotsXPrate;
|
||||
uint32 botActiveAlone;
|
||||
|
||||
uint32 enablePrototypePerformanceDiff;
|
||||
uint32 diffWithPlayer;
|
||||
uint32 diffEmpty;
|
||||
|
||||
bool freeMethodLoot;
|
||||
int32 lootRollLevel;
|
||||
std::string autoPickReward;
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "ChannelMgr.h"
|
||||
#include "Unit.h"
|
||||
#include "World.h"
|
||||
#include "UpdateTime.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdlib>
|
||||
@@ -79,6 +80,106 @@ void activateCheckPlayersThread()
|
||||
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)
|
||||
{
|
||||
playersLevel = sPlayerbotAIConfig->randombotStartingLevel;
|
||||
@@ -236,6 +337,14 @@ void RandomPlayerbotMgr::UpdateAIInternal(uint32 elapsed, bool /*minimal*/)
|
||||
if (!sPlayerbotAIConfig->randomBotAutologin || !sPlayerbotAIConfig->enabled)
|
||||
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");
|
||||
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 maxAllowedBotCount = GetEventValue(0, "bot_count");
|
||||
|
||||
@@ -27,6 +27,29 @@ class CachedEvent
|
||||
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
|
||||
{
|
||||
public:
|
||||
@@ -41,6 +64,9 @@ class RandomPlayerbotMgr : public PlayerbotHolder
|
||||
void LogPlayerLocation();
|
||||
void UpdateAIInternal(uint32 elapsed, bool minimal = false) override;
|
||||
|
||||
private:
|
||||
void ScaleBotActivity();
|
||||
|
||||
public:
|
||||
uint32 activeBots = 0;
|
||||
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; }
|
||||
|
||||
float getActivityMod() { return activityMod; }
|
||||
float getActivityPercentage() { return activityMod * 100.0f; }
|
||||
void setActivityPercentage(float percentage) { activityMod = percentage / 100.0f; }
|
||||
|
||||
protected:
|
||||
void OnBotLoginInternal(Player* const bot) override;
|
||||
|
||||
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);
|
||||
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 = "");
|
||||
@@ -137,4 +170,4 @@ class RandomPlayerbotMgr : public PlayerbotHolder
|
||||
|
||||
#define sRandomPlayerbotMgr RandomPlayerbotMgr::instance()
|
||||
|
||||
#endif
|
||||
#endif
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "PlayerbotAI.h"
|
||||
#include "Playerbots.h"
|
||||
#include "PositionValue.h"
|
||||
#include "UpdateTime.h"
|
||||
|
||||
bool BGJoinAction::Execute(Event event)
|
||||
{
|
||||
@@ -239,6 +240,7 @@ bool BGJoinAction::shouldJoinBg(BattlegroundQueueTypeId queueTypeId, Battlegroun
|
||||
|
||||
bool isArena = false;
|
||||
bool isRated = false;
|
||||
bool noLag = sWorldUpdateTime.GetAverageUpdateTime() < (sRandomPlayerbotMgr->GetPlayers().empty() ? sPlayerbotAIConfig->diffEmpty : sPlayerbotAIConfig->diffWithPlayer) * 1.1;
|
||||
|
||||
ArenaType type = ArenaType(BattlegroundMgr::BGArenaType(queueTypeId));
|
||||
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 hasBots = (sRandomPlayerbotMgr->BgBots[queueTypeId][bracketId][TEAM_ALLIANCE] + sRandomPlayerbotMgr->BgBots[queueTypeId][bracketId][TEAM_HORDE]) >= bg->GetMinPlayersPerTeam();
|
||||
|
||||
if (!sPlayerbotAIConfig->randomBotAutoJoinBG && !hasPlayers)
|
||||
{
|
||||
return false;
|
||||
|
||||
if (!(hasPlayers || hasBots))
|
||||
if (sPlayerbotAIConfig->enablePrototypePerformanceDiff)
|
||||
{
|
||||
if (!noLag)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasPlayers && !(isArena))
|
||||
{
|
||||
return false;
|
||||
|
||||
if (sPlayerbotAIConfig->enablePrototypePerformanceDiff)
|
||||
{
|
||||
if (!noLag)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32 BracketSize = bg->GetMaxPlayersPerTeam() * 2;
|
||||
uint32 TeamSize = bg->GetMaxPlayersPerTeam();
|
||||
|
||||
@@ -584,6 +607,7 @@ bool FreeBGJoinAction::shouldJoinBg(BattlegroundQueueTypeId queueTypeId, Battleg
|
||||
|
||||
bool isArena = false;
|
||||
bool isRated = false;
|
||||
bool noLag = sWorldUpdateTime.GetAverageUpdateTime() < (sRandomPlayerbotMgr->GetPlayers().empty() ? sPlayerbotAIConfig->diffEmpty : sPlayerbotAIConfig->diffWithPlayer) * 1.1;
|
||||
|
||||
ArenaType type = ArenaType(BattlegroundMgr::BGArenaType(queueTypeId));
|
||||
if (type != ARENA_TYPE_NONE)
|
||||
@@ -1117,4 +1141,4 @@ bool BGStrategyCheckAction::Execute(Event event)
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user