mirror of
https://github.com/mod-playerbots/mod-playerbots
synced 2025-11-29 15:58:20 +08:00
feature - (#1100) Linking of "trusted" accounts to allow altbot-control apart from own account or guild (#1267)
* Add table to store the security keys for accounts. * Add table to store relationships between accounts. * Add a new configuration option to enable or disable trusted account bots. * add checks for linked accounts * Handle account linking and chat commands * fix uppercase typo * change query & fix chatcommandtable * add missing functions to header * move account linking to updates dir * moved table creation to correct updates folder * use playerbots db instead of character db * fix db * fix install? * remove duplicated logic and add hashing to stored securityKey * add object before call * change chat variable * rename SQL file for correct execution order * add header include for ubuntu compatibility * remove old sql
This commit is contained in:
@@ -41,7 +41,7 @@
|
|||||||
# MAGE
|
# MAGE
|
||||||
# WARLOCK
|
# WARLOCK
|
||||||
# DRUID
|
# DRUID
|
||||||
# RANDOM BOT DEFAULT TALENT SPEC
|
# RANDOM BOT DEFAULT TALENT SPEC
|
||||||
# WARRIOR
|
# WARRIOR
|
||||||
# PALADIN
|
# PALADIN
|
||||||
# HUNTER
|
# HUNTER
|
||||||
@@ -54,7 +54,7 @@
|
|||||||
# DRUID
|
# DRUID
|
||||||
# PLAYERBOT SYSTEM SETTINGS
|
# PLAYERBOT SYSTEM SETTINGS
|
||||||
# DATABASE & CONNECTIONS
|
# DATABASE & CONNECTIONS
|
||||||
# DEBUG
|
# DEBUG
|
||||||
# CHAT SETTINGS
|
# CHAT SETTINGS
|
||||||
# LOGS
|
# LOGS
|
||||||
# DEPRECIATED (TEMPORARY)
|
# DEPRECIATED (TEMPORARY)
|
||||||
@@ -132,6 +132,9 @@ AiPlayerbot.AllowAccountBots = 1
|
|||||||
# Allow/deny bots in the player's guild
|
# Allow/deny bots in the player's guild
|
||||||
AiPlayerbot.AllowGuildBots = 1
|
AiPlayerbot.AllowGuildBots = 1
|
||||||
|
|
||||||
|
# Allow linking accounts for shared alt-bot control
|
||||||
|
AiPlayerbot.AllowTrustedAccountBots = 1
|
||||||
|
|
||||||
# Random bot guild count
|
# Random bot guild count
|
||||||
AiPlayerbot.RandomBotGuildCount = 20
|
AiPlayerbot.RandomBotGuildCount = 20
|
||||||
|
|
||||||
@@ -790,7 +793,7 @@ AiPlayerbot.RandomBotAutoJoinBG = 0
|
|||||||
# Known issue: When enabling a lot of brackats in combination with multiple instances,
|
# Known issue: When enabling a lot of brackats in combination with multiple instances,
|
||||||
# can lead to more instances created by bots than intended (over-queuing).
|
# can lead to more instances created by bots than intended (over-queuing).
|
||||||
#
|
#
|
||||||
# This section controls the level brackets and
|
# This section controls the level brackets and
|
||||||
# automatic bot participation in battlegrounds and arenas.
|
# automatic bot participation in battlegrounds and arenas.
|
||||||
#
|
#
|
||||||
# Brackets:
|
# Brackets:
|
||||||
@@ -1179,7 +1182,7 @@ AiPlayerbot.PremadeSpecLink.11.3.80 = -553202032322010053100030310511-205503012
|
|||||||
###################################
|
###################################
|
||||||
|
|
||||||
####################################################################################################
|
####################################################################################################
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
|
||||||
@@ -1231,7 +1234,7 @@ AiPlayerbot.WorldBuff.0.11.3.80.80 = 53760,57358 #DRUID FERAL
|
|||||||
###################################
|
###################################
|
||||||
|
|
||||||
####################################################################################################
|
####################################################################################################
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
|
||||||
|
|||||||
7
data/sql/playerbots/base/playerbotds_account_keys.sql
Normal file
7
data/sql/playerbots/base/playerbotds_account_keys.sql
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
DROP TABLE IF EXISTS `playerbot_account_keys`;
|
||||||
|
|
||||||
|
CREATE TABLE `playerbot_account_keys` (
|
||||||
|
`account_id` INT PRIMARY KEY,
|
||||||
|
`security_key` VARCHAR(255) NOT NULL,
|
||||||
|
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
|
) ENGINE=INNODB DEFAULT CHARSET=latin1;
|
||||||
9
data/sql/playerbots/base/playerbots_account_links.sql
Normal file
9
data/sql/playerbots/base/playerbots_account_links.sql
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
DROP TABLE IF EXISTS `playerbot_account_links`;
|
||||||
|
|
||||||
|
CREATE TABLE `playerbot_account_links` (
|
||||||
|
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
`account_id` INT NOT NULL,
|
||||||
|
`linked_account_id` INT NOT NULL,
|
||||||
|
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
UNIQUE KEY `account_link` (`account_id`, `linked_account_id`)
|
||||||
|
) ENGINE=INNODB DEFAULT CHARSET=latin1;
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
DROP TABLE IF EXISTS `playerbot_account_links`;
|
||||||
|
|
||||||
|
CREATE TABLE `playerbot_account_links` (
|
||||||
|
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
`account_id` INT NOT NULL,
|
||||||
|
`linked_account_id` INT NOT NULL,
|
||||||
|
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
UNIQUE KEY `account_link` (`account_id`, `linked_account_id`)
|
||||||
|
) ENGINE=INNODB DEFAULT CHARSET=latin1;
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `playerbot_account_keys`;
|
||||||
|
|
||||||
|
CREATE TABLE `playerbot_account_keys` (
|
||||||
|
`account_id` INT PRIMARY KEY,
|
||||||
|
`security_key` VARCHAR(255) NOT NULL,
|
||||||
|
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
|
) ENGINE=INNODB DEFAULT CHARSET=latin1;
|
||||||
@@ -128,6 +128,7 @@ bool PlayerbotAIConfig::Initialize()
|
|||||||
|
|
||||||
allowAccountBots = sConfigMgr->GetOption<bool>("AiPlayerbot.AllowAccountBots", true);
|
allowAccountBots = sConfigMgr->GetOption<bool>("AiPlayerbot.AllowAccountBots", true);
|
||||||
allowGuildBots = sConfigMgr->GetOption<bool>("AiPlayerbot.AllowGuildBots", true);
|
allowGuildBots = sConfigMgr->GetOption<bool>("AiPlayerbot.AllowGuildBots", true);
|
||||||
|
allowTrustedAccountBots = sConfigMgr->GetOption<bool>("AiPlayerbot.AllowTrustedAccountBots", true);
|
||||||
randomBotGuildNearby = sConfigMgr->GetOption<bool>("AiPlayerbot.RandomBotGuildNearby", false);
|
randomBotGuildNearby = sConfigMgr->GetOption<bool>("AiPlayerbot.RandomBotGuildNearby", false);
|
||||||
randomBotInvitePlayer = sConfigMgr->GetOption<bool>("AiPlayerbot.RandomBotInvitePlayer", false);
|
randomBotInvitePlayer = sConfigMgr->GetOption<bool>("AiPlayerbot.RandomBotInvitePlayer", false);
|
||||||
inviteChat = sConfigMgr->GetOption<bool>("AiPlayerbot.InviteChat", false);
|
inviteChat = sConfigMgr->GetOption<bool>("AiPlayerbot.InviteChat", false);
|
||||||
@@ -554,7 +555,7 @@ bool PlayerbotAIConfig::Initialize()
|
|||||||
{
|
{
|
||||||
sRandomPlayerbotMgr->Init();
|
sRandomPlayerbotMgr->Init();
|
||||||
}
|
}
|
||||||
|
|
||||||
sRandomItemMgr->Init();
|
sRandomItemMgr->Init();
|
||||||
sRandomItemMgr->InitAfterAhBot();
|
sRandomItemMgr->InitAfterAhBot();
|
||||||
sPlayerbotTextMgr->LoadBotTexts();
|
sPlayerbotTextMgr->LoadBotTexts();
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ public:
|
|||||||
bool IsInPvpProhibitedArea(uint32 id);
|
bool IsInPvpProhibitedArea(uint32 id);
|
||||||
|
|
||||||
bool enabled;
|
bool enabled;
|
||||||
bool allowAccountBots, allowGuildBots;
|
bool allowAccountBots, allowGuildBots, allowTrustedAccountBots;
|
||||||
bool randomBotGuildNearby, randomBotInvitePlayer, inviteChat;
|
bool randomBotGuildNearby, randomBotInvitePlayer, inviteChat;
|
||||||
uint32 globalCoolDown, reactDelay, maxWaitForMove, disableMoveSplinePath, maxMovementSearchTime, expireActionTime,
|
uint32 globalCoolDown, reactDelay, maxWaitForMove, disableMoveSplinePath, maxMovementSearchTime, expireActionTime,
|
||||||
dispelAuraDuration, passiveDelay, repeatDelay, errorDelay, rpgDelay, sitDelay, returnDelay, lootDelay;
|
dispelAuraDuration, passiveDelay, repeatDelay, errorDelay, rpgDelay, sitDelay, returnDelay, lootDelay;
|
||||||
|
|||||||
@@ -9,7 +9,9 @@
|
|||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <istream>
|
#include <istream>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <openssl/sha.h>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
|
#include <iomanip>
|
||||||
|
|
||||||
#include "ChannelMgr.h"
|
#include "ChannelMgr.h"
|
||||||
#include "CharacterCache.h"
|
#include "CharacterCache.h"
|
||||||
@@ -93,21 +95,22 @@ void PlayerbotHolder::AddPlayerBot(ObjectGuid playerGuid, uint32 masterAccountId
|
|||||||
uint32 accountId = sCharacterCache->GetCharacterAccountIdByGuid(playerGuid);
|
uint32 accountId = sCharacterCache->GetCharacterAccountIdByGuid(playerGuid);
|
||||||
if (!accountId)
|
if (!accountId)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
WorldSession* masterSession = masterAccountId ? sWorldSessionMgr->FindSession(masterAccountId) : nullptr;
|
WorldSession* masterSession = masterAccountId ? sWorldSessionMgr->FindSession(masterAccountId) : nullptr;
|
||||||
Player* masterPlayer = masterSession ? masterSession->GetPlayer() : nullptr;
|
Player* masterPlayer = masterSession ? masterSession->GetPlayer() : nullptr;
|
||||||
|
|
||||||
bool isRndbot = !masterAccountId;
|
bool isRndbot = !masterAccountId;
|
||||||
bool sameAccount = sPlayerbotAIConfig->allowAccountBots && accountId == masterAccountId;
|
bool sameAccount = sPlayerbotAIConfig->allowAccountBots && accountId == masterAccountId;
|
||||||
Guild* guild = masterPlayer ? sGuildMgr->GetGuildById(masterPlayer->GetGuildId()) : nullptr;
|
Guild* guild = masterPlayer ? sGuildMgr->GetGuildById(masterPlayer->GetGuildId()) : nullptr;
|
||||||
bool sameGuild = sPlayerbotAIConfig->allowGuildBots && guild && guild->GetMember(playerGuid);
|
bool sameGuild = sPlayerbotAIConfig->allowGuildBots && guild && guild->GetMember(playerGuid);
|
||||||
bool addClassBot = sRandomPlayerbotMgr->IsAddclassBot(playerGuid.GetCounter());
|
bool addClassBot = sRandomPlayerbotMgr->IsAddclassBot(playerGuid.GetCounter());
|
||||||
|
bool linkedAccount = sPlayerbotAIConfig->allowTrustedAccountBots && IsAccountLinked(accountId, masterAccountId);
|
||||||
|
|
||||||
bool allowed = true;
|
bool allowed = true;
|
||||||
std::ostringstream out;
|
std::ostringstream out;
|
||||||
std::string botName;
|
std::string botName;
|
||||||
sCharacterCache->GetCharacterNameByGuid(playerGuid, botName);
|
sCharacterCache->GetCharacterNameByGuid(playerGuid, botName);
|
||||||
if (!isRndbot && !sameAccount && !sameGuild && !addClassBot)
|
if (!isRndbot && !sameAccount && !sameGuild && !addClassBot && !linkedAccount)
|
||||||
{
|
{
|
||||||
allowed = false;
|
allowed = false;
|
||||||
out << "Failure: You are not allowed to control bot " << botName.c_str();
|
out << "Failure: You are not allowed to control bot " << botName.c_str();
|
||||||
@@ -144,13 +147,20 @@ void PlayerbotHolder::AddPlayerBot(ObjectGuid playerGuid, uint32 masterAccountId
|
|||||||
}
|
}
|
||||||
|
|
||||||
botLoading.insert(playerGuid);
|
botLoading.insert(playerGuid);
|
||||||
|
|
||||||
// Always login in with world session to avoid race condition
|
// Always login in with world session to avoid race condition
|
||||||
sWorld->AddQueryHolderCallback(CharacterDatabase.DelayQueryHolder(holder))
|
sWorld->AddQueryHolderCallback(CharacterDatabase.DelayQueryHolder(holder))
|
||||||
.AfterComplete([this](SQLQueryHolderBase const& holder)
|
.AfterComplete([this](SQLQueryHolderBase const& holder)
|
||||||
{ HandlePlayerBotLoginCallback(static_cast<PlayerbotLoginQueryHolder const&>(holder)); });
|
{ HandlePlayerBotLoginCallback(static_cast<PlayerbotLoginQueryHolder const&>(holder)); });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool PlayerbotHolder::IsAccountLinked(uint32 accountId, uint32 linkedAccountId)
|
||||||
|
{
|
||||||
|
QueryResult result = PlayerbotsDatabase.Query(
|
||||||
|
"SELECT 1 FROM playerbot_account_links WHERE account_id = {} AND linked_account_id = {}", accountId, linkedAccountId);
|
||||||
|
return result != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
void PlayerbotHolder::HandlePlayerBotLoginCallback(PlayerbotLoginQueryHolder const& holder)
|
void PlayerbotHolder::HandlePlayerBotLoginCallback(PlayerbotLoginQueryHolder const& holder)
|
||||||
{
|
{
|
||||||
uint32 botAccountId = holder.GetAccountId();
|
uint32 botAccountId = holder.GetAccountId();
|
||||||
@@ -181,7 +191,7 @@ void PlayerbotHolder::HandlePlayerBotLoginCallback(PlayerbotLoginQueryHolder con
|
|||||||
{
|
{
|
||||||
LOG_DEBUG("mod-playerbots", "Master session found but no player is associated for master account ID: {}", masterAccount);
|
LOG_DEBUG("mod-playerbots", "Master session found but no player is associated for master account ID: {}", masterAccount);
|
||||||
}
|
}
|
||||||
|
|
||||||
sRandomPlayerbotMgr->OnPlayerLogin(bot);
|
sRandomPlayerbotMgr->OnPlayerLogin(bot);
|
||||||
OnBotLogin(bot);
|
OnBotLogin(bot);
|
||||||
|
|
||||||
@@ -425,7 +435,7 @@ void PlayerbotHolder::DisablePlayerBot(ObjectGuid guid)
|
|||||||
|
|
||||||
void PlayerbotHolder::RemoveFromPlayerbotsMap(ObjectGuid guid)
|
void PlayerbotHolder::RemoveFromPlayerbotsMap(ObjectGuid guid)
|
||||||
{
|
{
|
||||||
playerBots.erase(guid);
|
playerBots.erase(guid);
|
||||||
}
|
}
|
||||||
|
|
||||||
Player* PlayerbotHolder::GetPlayerBot(ObjectGuid playerGuid) const
|
Player* PlayerbotHolder::GetPlayerBot(ObjectGuid playerGuid) const
|
||||||
@@ -451,7 +461,7 @@ void PlayerbotHolder::OnBotLogin(Player* const bot)
|
|||||||
|
|
||||||
sPlayerbotsMgr->AddPlayerbotData(bot, true);
|
sPlayerbotsMgr->AddPlayerbotData(bot, true);
|
||||||
playerBots[bot->GetGUID()] = bot;
|
playerBots[bot->GetGUID()] = bot;
|
||||||
|
|
||||||
OnBotLoginInternal(bot);
|
OnBotLoginInternal(bot);
|
||||||
|
|
||||||
PlayerbotAI* botAI = GET_PLAYERBOT_AI(bot);
|
PlayerbotAI* botAI = GET_PLAYERBOT_AI(bot);
|
||||||
@@ -674,8 +684,11 @@ std::string const PlayerbotHolder::ProcessBotCommand(std::string const cmd, Obje
|
|||||||
if (!accountId)
|
if (!accountId)
|
||||||
return "character not found";
|
return "character not found";
|
||||||
|
|
||||||
if (!sPlayerbotAIConfig->allowAccountBots && accountId != masterAccountId)
|
if (!sPlayerbotAIConfig->allowAccountBots && accountId != masterAccountId &&
|
||||||
return "you can only add bots from your own account";
|
!(sPlayerbotAIConfig->allowTrustedAccountBots && IsAccountLinked(accountId, masterAccountId)))
|
||||||
|
{
|
||||||
|
return "you can only add bots from your own account or linked accounts";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AddPlayerBot(guid, masterAccountId);
|
AddPlayerBot(guid, masterAccountId);
|
||||||
@@ -701,12 +714,12 @@ std::string const PlayerbotHolder::ProcessBotCommand(std::string const cmd, Obje
|
|||||||
|
|
||||||
if (!bot)
|
if (!bot)
|
||||||
return "bot not found";
|
return "bot not found";
|
||||||
|
|
||||||
bool addClassBot = sRandomPlayerbotMgr->IsAddclassBot(guid.GetCounter());
|
bool addClassBot = sRandomPlayerbotMgr->IsAddclassBot(guid.GetCounter());
|
||||||
|
|
||||||
if (!addClassBot)
|
if (!addClassBot)
|
||||||
return "ERROR: You can not use this command on non-addclass bot.";
|
return "ERROR: You can not use this command on non-addclass bot.";
|
||||||
|
|
||||||
if (!admin)
|
if (!admin)
|
||||||
{
|
{
|
||||||
Player* master = ObjectAccessor::FindConnectedPlayer(masterguid);
|
Player* master = ObjectAccessor::FindConnectedPlayer(masterguid);
|
||||||
@@ -732,7 +745,7 @@ std::string const PlayerbotHolder::ProcessBotCommand(std::string const cmd, Obje
|
|||||||
{
|
{
|
||||||
return "Initialization already in progress, please wait.";
|
return "Initialization already in progress, please wait.";
|
||||||
}
|
}
|
||||||
|
|
||||||
int gs;
|
int gs;
|
||||||
if (cmd == "init=white" || cmd == "init=common")
|
if (cmd == "init=white" || cmd == "init=common")
|
||||||
{
|
{
|
||||||
@@ -1705,3 +1718,121 @@ PlayerbotMgr* PlayerbotsMgr::GetPlayerbotMgr(Player* player)
|
|||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PlayerbotMgr::HandleSetSecurityKeyCommand(Player* player, const std::string& key)
|
||||||
|
{
|
||||||
|
uint32 accountId = player->GetSession()->GetAccountId();
|
||||||
|
|
||||||
|
// Hash the security key using SHA-256
|
||||||
|
unsigned char hash[SHA256_DIGEST_LENGTH];
|
||||||
|
SHA256((unsigned char*)key.c_str(), key.size(), hash);
|
||||||
|
|
||||||
|
// Convert the hash to a hexadecimal string
|
||||||
|
std::ostringstream hashedKey;
|
||||||
|
for (int i = 0; i < SHA256_DIGEST_LENGTH; ++i)
|
||||||
|
hashedKey << std::hex << std::setw(2) << std::setfill('0') << (int)hash[i];
|
||||||
|
|
||||||
|
// Store the hashed key in the database
|
||||||
|
PlayerbotsDatabase.Execute(
|
||||||
|
"REPLACE INTO playerbot_account_keys (account_id, security_key) VALUES ({}, '{}')",
|
||||||
|
accountId, hashedKey.str());
|
||||||
|
|
||||||
|
ChatHandler(player->GetSession()).PSendSysMessage("Security key set successfully.");
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlayerbotMgr::HandleLinkAccountCommand(Player* player, const std::string& accountName, const std::string& key)
|
||||||
|
{
|
||||||
|
QueryResult result = LoginDatabase.Query("SELECT id FROM account WHERE username = '{}'", accountName);
|
||||||
|
if (!result)
|
||||||
|
{
|
||||||
|
ChatHandler(player->GetSession()).PSendSysMessage("Account not found.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Field* fields = result->Fetch();
|
||||||
|
uint32 linkedAccountId = fields[0].Get<uint32>();
|
||||||
|
|
||||||
|
result = PlayerbotsDatabase.Query("SELECT security_key FROM playerbot_account_keys WHERE account_id = {}", linkedAccountId);
|
||||||
|
if (!result)
|
||||||
|
{
|
||||||
|
ChatHandler(player->GetSession()).PSendSysMessage("Invalid security key.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hash the provided key
|
||||||
|
unsigned char hash[SHA256_DIGEST_LENGTH];
|
||||||
|
SHA256((unsigned char*)key.c_str(), key.size(), hash);
|
||||||
|
|
||||||
|
// Convert the hash to a hexadecimal string
|
||||||
|
std::ostringstream hashedKey;
|
||||||
|
for (int i = 0; i < SHA256_DIGEST_LENGTH; ++i)
|
||||||
|
hashedKey << std::hex << std::setw(2) << std::setfill('0') << (int)hash[i];
|
||||||
|
|
||||||
|
// Compare the hashed key with the stored hashed key
|
||||||
|
std::string storedKey = result->Fetch()->Get<std::string>();
|
||||||
|
if (hashedKey.str() != storedKey)
|
||||||
|
{
|
||||||
|
ChatHandler(player->GetSession()).PSendSysMessage("Invalid security key.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 accountId = player->GetSession()->GetAccountId();
|
||||||
|
PlayerbotsDatabase.Execute(
|
||||||
|
"INSERT IGNORE INTO playerbot_account_links (account_id, linked_account_id) VALUES ({}, {})",
|
||||||
|
accountId, linkedAccountId);
|
||||||
|
PlayerbotsDatabase.Execute(
|
||||||
|
"INSERT IGNORE INTO playerbot_account_links (account_id, linked_account_id) VALUES ({}, {})",
|
||||||
|
linkedAccountId, accountId);
|
||||||
|
|
||||||
|
ChatHandler(player->GetSession()).PSendSysMessage("Account linked successfully.");
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlayerbotMgr::HandleViewLinkedAccountsCommand(Player* player)
|
||||||
|
{
|
||||||
|
uint32 accountId = player->GetSession()->GetAccountId();
|
||||||
|
QueryResult result = PlayerbotsDatabase.Query("SELECT linked_account_id FROM playerbot_account_links WHERE account_id = {}", accountId);
|
||||||
|
|
||||||
|
if (!result)
|
||||||
|
{
|
||||||
|
ChatHandler(player->GetSession()).PSendSysMessage("No linked accounts.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ChatHandler(player->GetSession()).PSendSysMessage("Linked accounts:");
|
||||||
|
do
|
||||||
|
{
|
||||||
|
Field* fields = result->Fetch();
|
||||||
|
uint32 linkedAccountId = fields[0].Get<uint32>();
|
||||||
|
|
||||||
|
QueryResult accountResult = LoginDatabase.Query("SELECT username FROM account WHERE id = {}", linkedAccountId);
|
||||||
|
if (accountResult)
|
||||||
|
{
|
||||||
|
Field* accountFields = accountResult->Fetch();
|
||||||
|
std::string username = accountFields[0].Get<std::string>();
|
||||||
|
ChatHandler(player->GetSession()).PSendSysMessage("- {}", username.c_str());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ChatHandler(player->GetSession()).PSendSysMessage("- Unknown account");
|
||||||
|
}
|
||||||
|
} while (result->NextRow());
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlayerbotMgr::HandleUnlinkAccountCommand(Player* player, const std::string& accountName)
|
||||||
|
{
|
||||||
|
QueryResult result = LoginDatabase.Query("SELECT id FROM account WHERE username = '{}'", accountName);
|
||||||
|
if (!result)
|
||||||
|
{
|
||||||
|
ChatHandler(player->GetSession()).PSendSysMessage("Account not found.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Field* fields = result->Fetch();
|
||||||
|
uint32 linkedAccountId = fields[0].Get<uint32>();
|
||||||
|
uint32 accountId = player->GetSession()->GetAccountId();
|
||||||
|
|
||||||
|
PlayerbotsDatabase.Execute("DELETE FROM playerbot_account_links WHERE (account_id = {} AND linked_account_id = {}) OR (account_id = {} AND linked_account_id = {})",
|
||||||
|
accountId, linkedAccountId, linkedAccountId, accountId);
|
||||||
|
|
||||||
|
ChatHandler(player->GetSession()).PSendSysMessage("Account unlinked successfully.");
|
||||||
|
}
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ public:
|
|||||||
virtual ~PlayerbotHolder(){};
|
virtual ~PlayerbotHolder(){};
|
||||||
|
|
||||||
void AddPlayerBot(ObjectGuid guid, uint32 masterAccountId);
|
void AddPlayerBot(ObjectGuid guid, uint32 masterAccountId);
|
||||||
|
bool IsAccountLinked(uint32 accountId, uint32 masterAccountId);
|
||||||
void HandlePlayerBotLoginCallback(PlayerbotLoginQueryHolder const& holder);
|
void HandlePlayerBotLoginCallback(PlayerbotLoginQueryHolder const& holder);
|
||||||
|
|
||||||
void LogoutPlayerBot(ObjectGuid guid);
|
void LogoutPlayerBot(ObjectGuid guid);
|
||||||
@@ -82,6 +83,11 @@ public:
|
|||||||
|
|
||||||
void SaveToDB();
|
void SaveToDB();
|
||||||
|
|
||||||
|
void HandleSetSecurityKeyCommand(Player* player, const std::string& key);
|
||||||
|
void HandleLinkAccountCommand(Player* player, const std::string& accountName, const std::string& key);
|
||||||
|
void HandleViewLinkedAccountsCommand(Player* player);
|
||||||
|
void HandleUnlinkAccountCommand(Player* player, const std::string& accountName);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void OnBotLoginInternal(Player* const bot) override;
|
void OnBotLoginInternal(Player* const bot) override;
|
||||||
void CheckTellErrors(uint32 elapsed);
|
void CheckTellErrors(uint32 elapsed);
|
||||||
|
|||||||
@@ -33,12 +33,21 @@ public:
|
|||||||
static ChatCommandTable playerbotsDebugCommandTable = {
|
static ChatCommandTable playerbotsDebugCommandTable = {
|
||||||
{"bg", HandleDebugBGCommand, SEC_GAMEMASTER, Console::Yes},
|
{"bg", HandleDebugBGCommand, SEC_GAMEMASTER, Console::Yes},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static ChatCommandTable playerbotsAccountCommandTable = {
|
||||||
|
{"setKey", HandleSetSecurityKeyCommand, SEC_PLAYER, Console::No},
|
||||||
|
{"link", HandleLinkAccountCommand, SEC_PLAYER, Console::No},
|
||||||
|
{"linkedAccounts", HandleViewLinkedAccountsCommand, SEC_PLAYER, Console::No},
|
||||||
|
{"unlink", HandleUnlinkAccountCommand, SEC_PLAYER, Console::No},
|
||||||
|
};
|
||||||
|
|
||||||
static ChatCommandTable playerbotsCommandTable = {
|
static ChatCommandTable playerbotsCommandTable = {
|
||||||
{"bot", HandlePlayerbotCommand, SEC_PLAYER, Console::No},
|
{"bot", HandlePlayerbotCommand, SEC_PLAYER, Console::No},
|
||||||
{"gtask", HandleGuildTaskCommand, SEC_GAMEMASTER, Console::Yes},
|
{"gtask", HandleGuildTaskCommand, SEC_GAMEMASTER, Console::Yes},
|
||||||
{"pmon", HandlePerfMonCommand, SEC_GAMEMASTER, Console::Yes},
|
{"pmon", HandlePerfMonCommand, SEC_GAMEMASTER, Console::Yes},
|
||||||
{"rndbot", HandleRandomPlayerbotCommand, SEC_GAMEMASTER, Console::Yes},
|
{"rndbot", HandleRandomPlayerbotCommand, SEC_GAMEMASTER, Console::Yes},
|
||||||
{"debug", playerbotsDebugCommandTable},
|
{"debug", playerbotsDebugCommandTable},
|
||||||
|
{"account", playerbotsAccountCommandTable},
|
||||||
};
|
};
|
||||||
|
|
||||||
static ChatCommandTable commandTable = {
|
static ChatCommandTable commandTable = {
|
||||||
@@ -101,6 +110,103 @@ public:
|
|||||||
{
|
{
|
||||||
return BGTactics::HandleConsoleCommand(handler, args);
|
return BGTactics::HandleConsoleCommand(handler, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool HandleSetSecurityKeyCommand(ChatHandler* handler, char const* args)
|
||||||
|
{
|
||||||
|
if (!args || !*args)
|
||||||
|
{
|
||||||
|
handler->PSendSysMessage("Usage: .playerbots account setKey <securityKey>");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Player* player = handler->GetSession()->GetPlayer();
|
||||||
|
std::string key = args;
|
||||||
|
|
||||||
|
PlayerbotMgr* mgr = sPlayerbotsMgr->GetPlayerbotMgr(player);
|
||||||
|
if (mgr)
|
||||||
|
{
|
||||||
|
mgr->HandleSetSecurityKeyCommand(player, key);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
handler->PSendSysMessage("PlayerbotMgr instance not found.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool HandleLinkAccountCommand(ChatHandler* handler, char const* args)
|
||||||
|
{
|
||||||
|
if (!args || !*args)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
char* accountName = strtok((char*)args, " ");
|
||||||
|
char* key = strtok(nullptr, " ");
|
||||||
|
|
||||||
|
if (!accountName || !key)
|
||||||
|
{
|
||||||
|
handler->PSendSysMessage("Usage: .playerbots account link <accountName> <securityKey>");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Player* player = handler->GetSession()->GetPlayer();
|
||||||
|
|
||||||
|
PlayerbotMgr* mgr = sPlayerbotsMgr->GetPlayerbotMgr(player);
|
||||||
|
if (mgr)
|
||||||
|
{
|
||||||
|
mgr->HandleLinkAccountCommand(player, accountName, key);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
handler->PSendSysMessage("PlayerbotMgr instance not found.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool HandleViewLinkedAccountsCommand(ChatHandler* handler, char const* /*args*/)
|
||||||
|
{
|
||||||
|
Player* player = handler->GetSession()->GetPlayer();
|
||||||
|
|
||||||
|
PlayerbotMgr* mgr = sPlayerbotsMgr->GetPlayerbotMgr(player);
|
||||||
|
if (mgr)
|
||||||
|
{
|
||||||
|
mgr->HandleViewLinkedAccountsCommand(player);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
handler->PSendSysMessage("PlayerbotMgr instance not found.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool HandleUnlinkAccountCommand(ChatHandler* handler, char const* args)
|
||||||
|
{
|
||||||
|
if (!args || !*args)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
char* accountName = strtok((char*)args, " ");
|
||||||
|
if (!accountName)
|
||||||
|
{
|
||||||
|
handler->PSendSysMessage("Usage: .playerbots account unlink <accountName>");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Player* player = handler->GetSession()->GetPlayer();
|
||||||
|
|
||||||
|
PlayerbotMgr* mgr = sPlayerbotsMgr->GetPlayerbotMgr(player);
|
||||||
|
if (mgr)
|
||||||
|
{
|
||||||
|
mgr->HandleUnlinkAccountCommand(player, accountName);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
handler->PSendSysMessage("PlayerbotMgr instance not found.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
void AddSC_playerbots_commandscript() { new playerbots_commandscript(); }
|
void AddSC_playerbots_commandscript() { new playerbots_commandscript(); }
|
||||||
|
|||||||
Reference in New Issue
Block a user