mirror of
https://github.com/mod-playerbots/mod-playerbots
synced 2025-11-29 15:58:20 +08:00
@@ -412,7 +412,7 @@ AiPlayerbot.MinRandomBotReviveTime = 60
|
||||
AiPlayerbot.MaxRandomBotReviveTime = 300
|
||||
AiPlayerbot.MinRandomBotTeleportInterval = 3600
|
||||
AiPlayerbot.MaxRandomBotTeleportInterval = 18000
|
||||
AiPlayerbot.RandomBotInWorldWithRotaionDisabled = 31104000
|
||||
AiPlayerbot.RandomBotInWorldWithRotationDisabled = 31104000
|
||||
|
||||
# How far random bots are teleported after death
|
||||
AiPlayerbot.RandomBotTeleportDistance = 100
|
||||
@@ -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 #
|
||||
|
||||
@@ -130,7 +130,7 @@ bool PlayerbotAIConfig::Initialize()
|
||||
maxRandomBotReviveTime = sConfigMgr->GetOption<int32>("AiPlayerbot.MaxRandomBotReviveTime", 5 * MINUTE);
|
||||
minRandomBotTeleportInterval = sConfigMgr->GetOption<int32>("AiPlayerbot.MinRandomBotTeleportInterval", 1 * 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);
|
||||
randomBotsPerInterval = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotsPerInterval", MINUTE);
|
||||
minRandomBotsPriceChangeInterval = sConfigMgr->GetOption<int32>("AiPlayerbot.MinRandomBotsPriceChangeInterval", 2 * HOUR);
|
||||
@@ -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);
|
||||
|
||||
@@ -88,7 +88,7 @@ class PlayerbotAIConfig
|
||||
uint32 minRandomBotChangeStrategyTime, maxRandomBotChangeStrategyTime;
|
||||
uint32 minRandomBotReviveTime, maxRandomBotReviveTime;
|
||||
uint32 minRandomBotTeleportInterval, maxRandomBotTeleportInterval;
|
||||
uint32 randomBotInWorldWithRotaionDisabled;
|
||||
uint32 randomBotInWorldWithRotationDisabled;
|
||||
uint32 minRandomBotPvpTime, maxRandomBotPvpTime;
|
||||
uint32 randomBotsPerInterval;
|
||||
uint32 minRandomBotsPriceChangeInterval, maxRandomBotsPriceChangeInterval;
|
||||
@@ -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");
|
||||
@@ -375,7 +501,7 @@ uint32 RandomPlayerbotMgr::AddRandomBots()
|
||||
for (uint32 &guid : guids) {
|
||||
uint32 add_time = sPlayerbotAIConfig->enableRotation ?
|
||||
urand(sPlayerbotAIConfig->minRandomBotInWorldTime, sPlayerbotAIConfig->maxRandomBotInWorldTime) :
|
||||
sPlayerbotAIConfig->randomBotInWorldWithRotaionDisabled;
|
||||
sPlayerbotAIConfig->randomBotInWorldWithRotationDisabled;
|
||||
|
||||
SetEventValue(guid, "add", 1, add_time);
|
||||
SetEventValue(guid, "logout", 0, 0);
|
||||
|
||||
@@ -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