mirror of
https://github.com/mod-playerbots/mod-playerbots.git
synced 2026-01-13 09:07:19 +00:00
These contains various fixes, fixes that have history worked one in past more then once as person as group, aswell @Wishmaster117. But due various reasons we had to drop them due priority or simply timewise. These fixes have recollected again by @Regrad based on his crash logs. Most crash logs we have, i am talking 30+ of them, to many to post here. @Regrad running a larger server 100+ real players with bots, which means he will walk into issues that most of us wont or are extremely difficult to reproduce. @Regrad used LLM to solve them based on crash log and mentioned his server crashes almost disappeared, instead of redoing every single PR and pull them apart. I tried to keep his bunch of changes together as whole, reviewed them, some redone, verified again etc etc. This is not how would normally do this. But since i want @Regrad being able to confirm, we need this in a package as a whole. Pulling them apart in the current situation is simply to much, to complicated in the verification process. So this PR is open and in my opinion has priority above others, but @Regrad is only person who can give the green light for the mod-playerbot changes for now. I, we spend huge amount of time into these issues over last couple of months. I will put other PR's on hold for abit. --------- Signed-off-by: Engardium <regradius@gmail.com> Co-authored-by: Engardium <regradius@gmail.com>
291 lines
9.4 KiB
C++
291 lines
9.4 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 "PlayerbotSecurity.h"
|
|
|
|
#include "LFGMgr.h"
|
|
#include "PlayerbotAIConfig.h"
|
|
#include "Playerbots.h"
|
|
|
|
PlayerbotSecurity::PlayerbotSecurity(Player* const bot) : bot(bot)
|
|
{
|
|
if (bot)
|
|
account = sCharacterCache->GetCharacterAccountIdByGuid(bot->GetGUID());
|
|
}
|
|
|
|
PlayerbotSecurityLevel PlayerbotSecurity::LevelFor(Player* from, DenyReason* reason, bool ignoreGroup)
|
|
{
|
|
// Basic pointer validity checks
|
|
if (!bot || !from || !from->GetSession())
|
|
{
|
|
if (reason)
|
|
*reason = PLAYERBOT_DENY_NONE;
|
|
|
|
return PLAYERBOT_SECURITY_DENY_ALL;
|
|
}
|
|
|
|
// GMs always have full access
|
|
if (from->GetSession()->GetSecurity() >= SEC_GAMEMASTER)
|
|
return PLAYERBOT_SECURITY_ALLOW_ALL;
|
|
|
|
PlayerbotAI* botAI = GET_PLAYERBOT_AI(bot);
|
|
if (!botAI)
|
|
{
|
|
if (reason)
|
|
*reason = PLAYERBOT_DENY_NONE;
|
|
|
|
return PLAYERBOT_SECURITY_DENY_ALL;
|
|
}
|
|
|
|
if (botAI->IsOpposing(from))
|
|
{
|
|
if (reason)
|
|
*reason = PLAYERBOT_DENY_OPPOSING;
|
|
|
|
return PLAYERBOT_SECURITY_DENY_ALL;
|
|
}
|
|
|
|
if (sPlayerbotAIConfig->IsInRandomAccountList(account))
|
|
{
|
|
// (duplicate check in case of faction change)
|
|
if (botAI->IsOpposing(from))
|
|
{
|
|
if (reason)
|
|
*reason = PLAYERBOT_DENY_OPPOSING;
|
|
|
|
return PLAYERBOT_SECURITY_DENY_ALL;
|
|
}
|
|
|
|
Group* fromGroup = from->GetGroup();
|
|
Group* botGroup = bot->GetGroup();
|
|
|
|
if (fromGroup && botGroup && fromGroup == botGroup && !ignoreGroup)
|
|
{
|
|
if (botAI->GetMaster() == from)
|
|
return PLAYERBOT_SECURITY_ALLOW_ALL;
|
|
|
|
if (reason)
|
|
*reason = PLAYERBOT_DENY_NOT_YOURS;
|
|
|
|
return PLAYERBOT_SECURITY_TALK;
|
|
}
|
|
|
|
if (sPlayerbotAIConfig->groupInvitationPermission <= 0)
|
|
{
|
|
if (reason)
|
|
*reason = PLAYERBOT_DENY_NONE;
|
|
|
|
return PLAYERBOT_SECURITY_TALK;
|
|
}
|
|
|
|
if (sPlayerbotAIConfig->groupInvitationPermission <= 1)
|
|
{
|
|
int32 levelDiff = int32(bot->GetLevel()) - int32(from->GetLevel());
|
|
if (levelDiff > 5)
|
|
{
|
|
if (!bot->GetGuildId() || bot->GetGuildId() != from->GetGuildId())
|
|
{
|
|
if (reason)
|
|
*reason = PLAYERBOT_DENY_LOW_LEVEL;
|
|
|
|
return PLAYERBOT_SECURITY_TALK;
|
|
}
|
|
}
|
|
}
|
|
|
|
int32 botGS = static_cast<int32>(botAI->GetEquipGearScore(bot));
|
|
int32 fromGS = static_cast<int32>(botAI->GetEquipGearScore(from));
|
|
|
|
if (sPlayerbotAIConfig->gearscorecheck && botGS && bot->GetLevel() > 15 && botGS > fromGS)
|
|
{
|
|
uint32 diffPct = uint32(100 * (botGS - fromGS) / botGS);
|
|
uint32 reqPct = uint32(12 * sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL) / from->GetLevel());
|
|
|
|
if (diffPct >= reqPct)
|
|
{
|
|
if (reason)
|
|
*reason = PLAYERBOT_DENY_GEARSCORE;
|
|
|
|
return PLAYERBOT_SECURITY_TALK;
|
|
}
|
|
}
|
|
|
|
if (bot->InBattlegroundQueue())
|
|
{
|
|
if (!bot->GetGuildId() || bot->GetGuildId() != from->GetGuildId())
|
|
{
|
|
if (reason)
|
|
*reason = PLAYERBOT_DENY_BG;
|
|
|
|
return PLAYERBOT_SECURITY_TALK;
|
|
}
|
|
}
|
|
|
|
// If the bot is not in the group, we offer an invite
|
|
botGroup = bot->GetGroup();
|
|
if (!botGroup)
|
|
{
|
|
if (reason)
|
|
*reason = PLAYERBOT_DENY_INVITE;
|
|
|
|
return PLAYERBOT_SECURITY_INVITE;
|
|
}
|
|
|
|
if (!ignoreGroup && botGroup->IsFull())
|
|
{
|
|
if (reason)
|
|
*reason = PLAYERBOT_DENY_FULL_GROUP;
|
|
|
|
return PLAYERBOT_SECURITY_TALK;
|
|
}
|
|
|
|
if (!ignoreGroup && botGroup->GetLeaderGUID() != bot->GetGUID())
|
|
{
|
|
if (reason)
|
|
*reason = PLAYERBOT_DENY_NOT_LEADER;
|
|
|
|
return PLAYERBOT_SECURITY_TALK;
|
|
}
|
|
|
|
// The bot is the group leader, you can invite the initiator
|
|
if (reason)
|
|
*reason = PLAYERBOT_DENY_IS_LEADER;
|
|
|
|
return PLAYERBOT_SECURITY_INVITE;
|
|
}
|
|
|
|
// Non-random bots: only their master has full access
|
|
if (botAI->GetMaster() == from)
|
|
return PLAYERBOT_SECURITY_ALLOW_ALL;
|
|
|
|
if (reason)
|
|
*reason = PLAYERBOT_DENY_NOT_YOURS;
|
|
|
|
return PLAYERBOT_SECURITY_INVITE;
|
|
}
|
|
|
|
bool PlayerbotSecurity::CheckLevelFor(PlayerbotSecurityLevel level, bool silent, Player* from, bool ignoreGroup)
|
|
{
|
|
// If something is wrong with the pointers, we silently refuse
|
|
if (!bot || !from || !from->GetSession())
|
|
return false;
|
|
|
|
DenyReason reason = PLAYERBOT_DENY_NONE;
|
|
PlayerbotSecurityLevel realLevel = LevelFor(from, &reason, ignoreGroup);
|
|
|
|
if (realLevel >= level || from == bot)
|
|
return true;
|
|
|
|
PlayerbotAI* fromBotAI = GET_PLAYERBOT_AI(from);
|
|
if (silent || (fromBotAI && !fromBotAI->IsRealPlayer()))
|
|
return false;
|
|
|
|
PlayerbotAI* botAI = GET_PLAYERBOT_AI(bot);
|
|
if (!botAI)
|
|
return false;
|
|
|
|
Player* master = botAI->GetMaster();
|
|
if (master && botAI->IsOpposing(master))
|
|
if (WorldSession* session = master->GetSession())
|
|
if (session->GetSecurity() < SEC_GAMEMASTER)
|
|
return false;
|
|
|
|
std::ostringstream out;
|
|
|
|
switch (realLevel)
|
|
{
|
|
case PLAYERBOT_SECURITY_DENY_ALL:
|
|
out << "I'm kind of busy now";
|
|
break;
|
|
case PLAYERBOT_SECURITY_TALK:
|
|
switch (reason)
|
|
{
|
|
case PLAYERBOT_DENY_NONE:
|
|
out << "I'll do it later";
|
|
break;
|
|
case PLAYERBOT_DENY_LOW_LEVEL:
|
|
out << "You are too low level: |cffff0000" << uint32(from->GetLevel()) << "|cffffffff/|cff00ff00"
|
|
<< uint32(bot->GetLevel());
|
|
break;
|
|
case PLAYERBOT_DENY_GEARSCORE:
|
|
{
|
|
int botGS = int(botAI->GetEquipGearScore(bot));
|
|
int fromGS = int(botAI->GetEquipGearScore(from));
|
|
int diff = (100 * (botGS - fromGS) / botGS);
|
|
int req = 12 * sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL) / from->GetLevel();
|
|
|
|
out << "Your gearscore is too low: |cffff0000" << fromGS << "|cffffffff/|cff00ff00" << botGS
|
|
<< " |cffff0000" << diff << "%|cffffffff/|cff00ff00" << req << "%";
|
|
break;
|
|
}
|
|
case PLAYERBOT_DENY_NOT_YOURS:
|
|
out << "I have a master already";
|
|
break;
|
|
case PLAYERBOT_DENY_IS_BOT:
|
|
out << "You are a bot";
|
|
break;
|
|
case PLAYERBOT_DENY_OPPOSING:
|
|
out << "You are the enemy";
|
|
break;
|
|
case PLAYERBOT_DENY_DEAD:
|
|
out << "I'm dead. Will do it later";
|
|
break;
|
|
case PLAYERBOT_DENY_INVITE:
|
|
out << "Invite me to your group first";
|
|
break;
|
|
case PLAYERBOT_DENY_FAR:
|
|
{
|
|
out << "You must be closer to invite me to your group. I am in ";
|
|
if (AreaTableEntry const* entry = sAreaTableStore.LookupEntry(bot->GetAreaId()))
|
|
out << " |cffffffff(|cffff0000" << entry->area_name[0] << "|cffffffff)";
|
|
break;
|
|
}
|
|
case PLAYERBOT_DENY_FULL_GROUP:
|
|
out << "I am in a full group. Will do it later";
|
|
break;
|
|
case PLAYERBOT_DENY_IS_LEADER:
|
|
out << "I am currently leading a group. I can invite you if you want.";
|
|
break;
|
|
case PLAYERBOT_DENY_NOT_LEADER:
|
|
if (Player* leader = botAI->GetGroupLeader())
|
|
out << "I am in a group with " << leader->GetName() << ". You can ask him for invite.";
|
|
else
|
|
out << "I am in a group with someone else. You can ask him for invite.";
|
|
break;
|
|
case PLAYERBOT_DENY_BG:
|
|
out << "I am in a queue for BG. Will do it later";
|
|
break;
|
|
case PLAYERBOT_DENY_LFG:
|
|
out << "I am in a queue for dungeon. Will do it later";
|
|
break;
|
|
default:
|
|
out << "I can't do that";
|
|
break;
|
|
}
|
|
break;
|
|
case PLAYERBOT_SECURITY_INVITE:
|
|
out << "Invite me to your group first";
|
|
break;
|
|
default:
|
|
out << "I can't do that";
|
|
break;
|
|
}
|
|
|
|
std::string const text = out.str();
|
|
ObjectGuid guid = from->GetGUID();
|
|
time_t lastSaid = whispers[guid][text];
|
|
|
|
if (!lastSaid || (time(nullptr) - lastSaid) >= sPlayerbotAIConfig->repeatDelay / 1000)
|
|
{
|
|
whispers[guid][text] = time(nullptr);
|
|
|
|
// Additional protection against crashes during logout
|
|
if (bot->IsInWorld() && from->IsInWorld())
|
|
bot->Whisper(text, LANG_UNIVERSAL, from);
|
|
}
|
|
|
|
return false;
|
|
}
|