1st commit

This commit is contained in:
UltraNix
2021-12-06 11:16:04 +01:00
parent 7b92ac90ae
commit 2cab3258bb
26 changed files with 557 additions and 19 deletions

View File

@@ -20,3 +20,7 @@
DatabaseWorkerPool<WorldDatabaseConnection> WorldDatabase;
DatabaseWorkerPool<CharacterDatabaseConnection> CharacterDatabase;
DatabaseWorkerPool<LoginDatabaseConnection> LoginDatabase;
#ifdef PLAYERBOTS
DatabaseWorkerPool<PlayerbotDatabaseConnection> PlayerbotDatabase;
#endif

View File

@@ -25,6 +25,10 @@
#include "Implementation/LoginDatabase.h"
#include "Implementation/WorldDatabase.h"
#ifdef PLAYERBOTS
#include "PlayerbotDatabase.h"
#endif
#include "Field.h"
#include "PreparedStatement.h"
#include "QueryCallback.h"
@@ -38,4 +42,9 @@ AC_DATABASE_API extern DatabaseWorkerPool<CharacterDatabaseConnection> Character
/// Accessor to the realm/login database
AC_DATABASE_API extern DatabaseWorkerPool<LoginDatabaseConnection> LoginDatabase;
#ifdef PLAYERBOTS
/// Accessor to the playerbot database
AC_DATABASE_API extern DatabaseWorkerPool<PlayerbotDatabaseConnection> PlayerbotDatabase;
#endif
#endif

View File

@@ -33,6 +33,10 @@ class CharacterDatabaseConnection;
class LoginDatabaseConnection;
class WorldDatabaseConnection;
#ifdef PLAYERBOTS
class PlayerbotDatabaseConnection;
#endif
class PreparedStatementBase;
template<typename T>
@@ -42,6 +46,10 @@ using CharacterDatabasePreparedStatement = PreparedStatement<CharacterDatabaseCo
using LoginDatabasePreparedStatement = PreparedStatement<LoginDatabaseConnection>;
using WorldDatabasePreparedStatement = PreparedStatement<WorldDatabaseConnection>;
#ifdef PLAYERBOTS
using PlayerbotDatabasePreparedStatement = PreparedStatement<PlayerbotDatabaseConnection>;
#endif
class PreparedResultSet;
using PreparedQueryResult = std::shared_ptr<PreparedResultSet>;
using PreparedQueryResultFuture = std::future<PreparedQueryResult>;
@@ -71,6 +79,10 @@ using CharacterDatabaseTransaction = SQLTransaction<CharacterDatabaseConnection>
using LoginDatabaseTransaction = SQLTransaction<LoginDatabaseConnection>;
using WorldDatabaseTransaction = SQLTransaction<WorldDatabaseConnection>;
#ifdef PLAYERBOTS
using PlayerbotDatabaseTransaction = SQLTransaction<PlayerbotDatabaseConnection>;
#endif
class SQLQueryHolderBase;
using QueryResultHolderFuture = std::future<void>;
using QueryResultHolderPromise = std::promise<void>;
@@ -82,6 +94,10 @@ using CharacterDatabaseQueryHolder = SQLQueryHolder<CharacterDatabaseConnection>
using LoginDatabaseQueryHolder = SQLQueryHolder<LoginDatabaseConnection>;
using WorldDatabaseQueryHolder = SQLQueryHolder<WorldDatabaseConnection>;
#ifdef PLAYERBOTS
using PlayerbotDatabaseQueryHolder = SQLQueryHolder<PlayerbotDatabaseConnection>;
#endif
class SQLQueryHolderCallback;
// mysql

View File

@@ -204,3 +204,8 @@ template AC_DATABASE_API
DatabaseLoader& DatabaseLoader::AddDatabase<CharacterDatabaseConnection>(DatabaseWorkerPool<CharacterDatabaseConnection>&, std::string const&);
template AC_DATABASE_API
DatabaseLoader& DatabaseLoader::AddDatabase<WorldDatabaseConnection>(DatabaseWorkerPool<WorldDatabaseConnection>&, std::string const&);
#ifdef PLAYERBOTS
template AC_DATABASE_API
DatabaseLoader& DatabaseLoader::AddDatabase<PlayerbotDatabaseConnection>(DatabaseWorkerPool<PlayerbotDatabaseConnection>&, std::string const&);
#endif

View File

@@ -48,8 +48,13 @@ public:
DATABASE_LOGIN = 1,
DATABASE_CHARACTER = 2,
DATABASE_WORLD = 4,
#ifdef PLAYERBOTS
DATABASE_PLAYERBOT = 8,
DATABASE_MASK_ALL = DATABASE_LOGIN | DATABASE_CHARACTER | DATABASE_WORLD | DATABASE_PLAYERBOT
#else
DATABASE_MASK_ALL = DATABASE_LOGIN | DATABASE_CHARACTER | DATABASE_WORLD
#endif
};
[[nodiscard]] uint32 GetUpdateFlags() const
@@ -57,6 +62,11 @@ public:
return _updateFlags;
}
void SetUpdateFlags(uint32 newUpdateFlags)
{
_updateFlags |= newUpdateFlags;
}
private:
bool OpenDatabases();
bool PopulateDatabases();
@@ -73,7 +83,7 @@ private:
std::string const _logger;
std::string_view _modulesList;
bool const _autoSetup;
uint32 const _updateFlags;
uint32 _updateFlags;
std::queue<Predicate> _open, _populate, _update, _prepare;
std::stack<Closer> _close;

View File

@@ -39,6 +39,10 @@
#include <sstream>
#endif
#ifdef PLAYERBOTS
#include "PlayerbotDatabase.h"
#endif
#if MARIADB_VERSION_ID >= 100600
#define MIN_MYSQL_SERVER_VERSION 100200u
#define MIN_MYSQL_CLIENT_VERSION 30203u
@@ -530,3 +534,7 @@ void DatabaseWorkerPool<T>::ExecuteOrAppend(SQLTransaction<T>& trans, PreparedSt
template class AC_DATABASE_API DatabaseWorkerPool<LoginDatabaseConnection>;
template class AC_DATABASE_API DatabaseWorkerPool<WorldDatabaseConnection>;
template class AC_DATABASE_API DatabaseWorkerPool<CharacterDatabaseConnection>;
#ifdef PLAYERBOTS
template class AC_DATABASE_API DatabaseWorkerPool<PlayerbotDatabaseConnection>;
#endif

View File

@@ -89,7 +89,7 @@ void LoginDatabaseConnection::DoPrepareStatements()
PrepareStatement(LOGIN_UPD_MUTE_TIME_LOGIN, "UPDATE account SET mutetime = ? WHERE id = ?", CONNECTION_ASYNC);
PrepareStatement(LOGIN_UPD_LAST_IP, "UPDATE account SET last_ip = ? WHERE username = ?", CONNECTION_ASYNC);
PrepareStatement(LOGIN_UPD_LAST_ATTEMPT_IP, "UPDATE account SET last_attempt_ip = ? WHERE username = ?", CONNECTION_ASYNC);
PrepareStatement(LOGIN_UPD_ACCOUNT_ONLINE, "UPDATE account SET online = ? WHERE id = ?", CONNECTION_ASYNC);
PrepareStatement(LOGIN_UPD_ACCOUNT_ONLINE, "UPDATE account SET online = 1 WHERE id = ?", CONNECTION_ASYNC);
PrepareStatement(LOGIN_UPD_UPTIME_PLAYERS, "UPDATE uptime SET uptime = ?, maxplayers = ? WHERE realmid = ? AND starttime = ?", CONNECTION_ASYNC);
PrepareStatement(LOGIN_DEL_OLD_LOGS, "DELETE FROM logs WHERE (time + ?) < ?", CONNECTION_ASYNC);
PrepareStatement(LOGIN_DEL_ACCOUNT_ACCESS, "DELETE FROM account_access WHERE id = ?", CONNECTION_ASYNC);

View File

@@ -160,6 +160,40 @@ std::string DBUpdater<CharacterDatabaseConnection>::GetDBModuleName()
return "db-characters";
}
#ifdef PLAYERBOTS
// Playerbot Database
template<>
std::string DBUpdater<PlayerbotDatabaseConnection>::GetConfigEntry()
{
return "Updates.Playerbot";
}
template<>
std::string DBUpdater<PlayerbotDatabaseConnection>::GetTableName()
{
return "Playerbot";
}
template<>
std::string DBUpdater<PlayerbotDatabaseConnection>::GetBaseFilesDirectory()
{
return BuiltInConfig::GetSourceDirectory() + "/modules/mod-playerbots/sql/base/db_playerbot/";
}
template<>
bool DBUpdater<PlayerbotDatabaseConnection>::IsEnabled(uint32 const updateMask)
{
// This way silences warnings under msvc
return (updateMask & DatabaseLoader::DATABASE_PLAYERBOT) ? true : false;
}
template<>
std::string DBUpdater<PlayerbotDatabaseConnection>::GetDBModuleName()
{
return "db-playerbot";
}
#endif
// All
template<class T>
BaseLocation DBUpdater<T>::GetBaseLocationType()
@@ -514,3 +548,7 @@ void DBUpdater<T>::ApplyFile(DatabaseWorkerPool<T>& pool, std::string const& hos
template class AC_DATABASE_API DBUpdater<LoginDatabaseConnection>;
template class AC_DATABASE_API DBUpdater<WorldDatabaseConnection>;
template class AC_DATABASE_API DBUpdater<CharacterDatabaseConnection>;
#ifdef PLAYERBOTS
template class AC_DATABASE_API DBUpdater<PlayerbotDatabaseConnection>;
#endif

View File

@@ -36,6 +36,8 @@ typedef std::map<uint32, uint32> AreaFlagByMapID;
typedef std::tuple<int16, int8, int32> WMOAreaTableKey;
typedef std::map<WMOAreaTableKey, WMOAreaTableEntry const*> WMOAreaInfoByTripple;
typedef std::multimap<uint32, CharSectionsEntry const*> CharSectionsMap;
DBCStorage <AreaTableEntry> sAreaTableStore(AreaTableEntryfmt);
DBCStorage <AreaGroupEntry> sAreaGroupStore(AreaGroupEntryfmt);
DBCStorage <AreaPOIEntry> sAreaPOIStore(AreaPOIEntryfmt);
@@ -51,6 +53,10 @@ DBCStorage <BattlemasterListEntry> sBattlemasterListStore(BattlemasterListEntryf
DBCStorage <BarberShopStyleEntry> sBarberShopStyleStore(BarberShopStyleEntryfmt);
DBCStorage <CharStartOutfitEntry> sCharStartOutfitStore(CharStartOutfitEntryfmt);
std::map<uint32, CharStartOutfitEntry const*> sCharStartOutfitMap;
DBCStorage <CharSectionsEntry> sCharSectionsStore(CharSectionsEntryfmt);
CharSectionsMap sCharSectionMap;
DBCStorage <CharTitlesEntry> sCharTitlesStore(CharTitlesEntryfmt);
DBCStorage <ChatChannelsEntry> sChatChannelsStore(ChatChannelsEntryfmt);
DBCStorage <ChrClassesEntry> sChrClassesStore(ChrClassesEntryfmt);
@@ -72,6 +78,10 @@ DBCStorage <DurabilityCostsEntry> sDurabilityCostsStore(DurabilityCostsfmt);
DBCStorage <EmotesEntry> sEmotesStore(EmotesEntryfmt);
DBCStorage <EmotesTextEntry> sEmotesTextStore(EmotesTextEntryfmt);
typedef std::tuple<uint32, uint32, uint32> EmotesTextSoundKey;
static std::map<EmotesTextSoundKey, EmotesTextSoundEntry const*> sEmotesTextSoundMap;
DBCStorage <EmotesTextSoundEntry> sEmotesTextSoundStore(EmotesTextSoundEntryfmt);
typedef std::map<uint32, SimpleFactionsList> FactionTeamMap;
static FactionTeamMap sFactionTeamMap;
DBCStorage <FactionEntry> sFactionStore(FactionEntryfmt);
@@ -275,6 +285,7 @@ void LoadDBCStores(const std::string& dataPath)
LOAD_DBC(sBattlemasterListStore, "BattlemasterList.dbc", "battlemasterlist_dbc");
LOAD_DBC(sBarberShopStyleStore, "BarberShopStyle.dbc", "barbershopstyle_dbc");
LOAD_DBC(sCharStartOutfitStore, "CharStartOutfit.dbc", "charstartoutfit_dbc");
LOAD_DBC(sCharSectionsStore, "CharSections.dbc", "charsections_dbc");
LOAD_DBC(sCharTitlesStore, "CharTitles.dbc", "chartitles_dbc");
LOAD_DBC(sChatChannelsStore, "ChatChannels.dbc", "chatchannels_dbc");
LOAD_DBC(sChrClassesStore, "ChrClasses.dbc", "chrclasses_dbc");
@@ -293,6 +304,7 @@ void LoadDBCStores(const std::string& dataPath)
LOAD_DBC(sDurabilityQualityStore, "DurabilityQuality.dbc", "durabilityquality_dbc");
LOAD_DBC(sEmotesStore, "Emotes.dbc", "emotes_dbc");
LOAD_DBC(sEmotesTextStore, "EmotesText.dbc", "emotestext_dbc");
LOAD_DBC(sEmotesTextSoundStore, "EmotesTextSound.dbc", "emotetextsound_dbc");
LOAD_DBC(sFactionStore, "Faction.dbc", "faction_dbc");
LOAD_DBC(sFactionTemplateStore, "FactionTemplate.dbc", "factiontemplate_dbc");
LOAD_DBC(sGameObjectDisplayInfoStore, "GameObjectDisplayInfo.dbc", "gameobjectdisplayinfo_dbc");
@@ -377,6 +389,10 @@ void LoadDBCStores(const std::string& dataPath)
for (CharStartOutfitEntry const* outfit : sCharStartOutfitStore)
sCharStartOutfitMap[outfit->Race | (outfit->Class << 8) | (outfit->Gender << 16)] = outfit;
for (CharSectionsEntry const* charSection : sCharSectionsStore)
if (charSection->Race && ((1 << (charSection->Race - 1)) & RACEMASK_ALL_PLAYABLE) != 0) //ignore Nonplayable races
sCharSectionMap.insert({ charSection->GenType | (charSection->Gender << 8) | (charSection->Race << 16), charSection });
for (FactionEntry const* faction : sFactionStore)
{
if (faction->team)
@@ -398,6 +414,9 @@ void LoadDBCStores(const std::string& dataPath)
std::swap(*(float*)(&info->maxZ), *(float*)(&info->minZ));
}
for (EmotesTextSoundEntry const* emoteTextSound : sEmotesTextSoundStore)
sEmotesTextSoundMap[EmotesTextSoundKey(emoteTextSound->EmotesTextId, emoteTextSound->RaceId, emoteTextSound->SexId)] = emoteTextSound;
// fill data
for (MapDifficultyEntry const* entry : sMapDifficultyStore)
sMapDifficultyMap[MAKE_PAIR32(entry->MapId, entry->Difficulty)] = MapDifficulty(entry->resetTime, entry->maxPlayers, entry->areaTriggerText[0] != '\0');
@@ -1089,6 +1108,18 @@ CharStartOutfitEntry const* GetCharStartOutfitEntry(uint8 race, uint8 class_, ui
return itr->second;
}
CharSectionsEntry const* GetCharSectionEntry(uint8 race, CharSectionType genType, uint8 gender, uint8 type, uint8 color)
{
std::pair<CharSectionsMap::const_iterator, CharSectionsMap::const_iterator> eqr = sCharSectionMap.equal_range(uint32(genType) | uint32(gender << 8) | uint32(race << 16));
for (CharSectionsMap::const_iterator itr = eqr.first; itr != eqr.second; ++itr)
{
if (itr->second->Type == type && itr->second->Color == color)
return itr->second;
}
return nullptr;
}
/// Returns LFGDungeonEntry for a specific map and difficulty. Will return first found entry if multiple dungeons use the same map (such as Scarlet Monastery)
LFGDungeonEntry const* GetLFGDungeon(uint32 mapId, Difficulty difficulty)
{
@@ -1134,3 +1165,9 @@ SkillRaceClassInfoEntry const* GetSkillRaceClassInfo(uint32 skill, uint8 race, u
return nullptr;
}
EmotesTextSoundEntry const* FindTextSoundEmoteFor(uint32 emote, uint32 race, uint32 gender)
{
auto itr = sEmotesTextSoundMap.find(EmotesTextSoundKey(emote, race, gender));
return itr != sEmotesTextSoundMap.end() ? itr->second : nullptr;
}

View File

@@ -63,6 +63,8 @@ PvPDifficultyEntry const* GetBattlegroundBracketById(uint32 mapid, BattlegroundB
CharStartOutfitEntry const* GetCharStartOutfitEntry(uint8 race, uint8 class_, uint8 gender);
CharSectionsEntry const* GetCharSectionEntry(uint8 race, CharSectionType genType, uint8 gender, uint8 type, uint8 color);
LFGDungeonEntry const* GetLFGDungeon(uint32 mapId, Difficulty difficulty);
uint32 GetDefaultMapLight(uint32 mapId);
@@ -70,6 +72,8 @@ typedef std::unordered_multimap<uint32, SkillRaceClassInfoEntry const*> SkillRac
typedef std::pair<SkillRaceClassInfoMap::iterator, SkillRaceClassInfoMap::iterator> SkillRaceClassInfoBounds;
SkillRaceClassInfoEntry const* GetSkillRaceClassInfo(uint32 skill, uint8 race, uint8 class_);
EmotesTextSoundEntry const* FindTextSoundEmoteFor(uint32 emote, uint32 race, uint32 gender);
extern DBCStorage <AchievementEntry> sAchievementStore;
extern DBCStorage <AchievementCriteriaEntry> sAchievementCriteriaStore;
extern DBCStorage <AchievementCategoryEntry> sAchievementCategoryStore;
@@ -82,6 +86,7 @@ extern DBCStorage <BarberShopStyleEntry> sBarberShopStyleStore;
extern DBCStorage <BattlemasterListEntry> sBattlemasterListStore;
extern DBCStorage <ChatChannelsEntry> sChatChannelsStore;
extern DBCStorage <CharStartOutfitEntry> sCharStartOutfitStore;
extern DBCStorage <CharSectionsEntry> sCharSectionsStore;
extern DBCStorage <CharTitlesEntry> sCharTitlesStore;
extern DBCStorage <ChrClassesEntry> sChrClassesStore;
extern DBCStorage <ChrRacesEntry> sChrRacesStore;
@@ -99,6 +104,7 @@ extern DBCStorage <DurabilityCostsEntry> sDurabilityCostsStore;
extern DBCStorage <DurabilityQualityEntry> sDurabilityQualityStore;
extern DBCStorage <EmotesEntry> sEmotesStore;
extern DBCStorage <EmotesTextEntry> sEmotesTextStore;
extern DBCStorage <EmotesTextSoundEntry> sEmotesTextSoundStore;
extern DBCStorage <FactionEntry> sFactionStore;
extern DBCStorage <FactionTemplateEntry> sFactionTemplateStore;
extern DBCStorage <GameObjectDisplayInfoEntry> sGameObjectDisplayInfoStore;

View File

@@ -401,6 +401,22 @@ namespace lfg
return LFG_COMPATIBLES_WITH_LESS_PLAYERS;
}
#ifdef PLAYERBOTS
bool nonBotFound = false;
for (uint8 i = 0; i < 5 && check.guids[i]; ++i)
{
ObjectGuid guid = check.guids[i];
Player* player = ObjectAccessor::FindPlayer(guid);
if (guid.IsGroup() || (player && !player->GetPlayerbotAI()))
{
nonBotFound = true;
break;
}
}
if (!nonBotFound)
return LFG_INCOMPATIBLES_HAS_IGNORES;
#endif
proposal.queues = strGuids;
proposal.isNew = numLfgGroups != 1 || sLFGMgr->GetOldState(proposal.group) != LFG_STATE_DUNGEON;

View File

@@ -1038,6 +1038,11 @@ void Item::SendUpdateSockets()
// time.
void Item::SendTimeUpdate(Player* owner)
{
#ifdef PLAYERBOTS
if (!owner || !owner->IsInWorld() || owner->GetPlayerbotAI())
return;
#endif
uint32 duration = GetUInt32Value(ITEM_FIELD_DURATION);
if (!duration)
return;

View File

@@ -260,7 +260,7 @@ enum SocketColor
#define SOCKET_COLOR_ALL (SOCKET_COLOR_META | SOCKET_COLOR_RED | SOCKET_COLOR_YELLOW | SOCKET_COLOR_BLUE)
enum InventoryType
enum InventoryType : uint32
{
INVTYPE_NON_EQUIP = 0,
INVTYPE_HEAD = 1,

View File

@@ -92,6 +92,10 @@
#include "WorldPacket.h"
#include "WorldSession.h"
#ifdef PLAYERBOTS
#include "Playerbot.h"
#endif
enum CharacterFlags
{
CHARACTER_FLAG_NONE = 0x00000000,
@@ -410,6 +414,11 @@ Player::Player(WorldSession* session): Unit(true), m_mover(this)
m_isInstantFlightOn = true;
#ifdef PLAYERBOTS
_playerbotAI = nullptr;
_playerbotMgr = nullptr;
#endif
sScriptMgr->OnConstructPlayer(this);
}
@@ -461,6 +470,14 @@ Player::~Player()
u->RemovePlayerFromVision(this);
} while (!m_isInSharedVisionOf.empty());
}
#ifdef PLAYERBOTS
delete _playerbotAI;
_playerbotAI = nullptr;
delete _playerbotMgr;
_playerbotMgr = nullptr;
#endif
}
void Player::CleanupsBeforeDelete(bool finalCleanup)
@@ -15435,3 +15452,34 @@ std::string Player::GetPlayerName()
return "|Hplayer:" + name + "|h" + color + name + "|h|r";
}
#ifdef PLAYERBOTS
void Player::SetPlayerbotAI(PlayerbotAI* ai)
{
ASSERT(!_playerbotAI && !_playerbotMgr);
_playerbotAI = ai;
}
PlayerbotAI* Player::GetPlayerbotAI()
{
return _playerbotAI;
}
void Player::SetPlayerbotMgr(PlayerbotMgr* mgr)
{
ASSERT(!_playerbotAI && !_playerbotMgr);
_playerbotMgr = mgr;
}
PlayerbotMgr* Player::GetPlayerbotMgr()
{
return _playerbotMgr;
}
void Player::SetBotDeathTimer()
{
m_deathTimer = 0;
}
#endif

View File

@@ -60,6 +60,9 @@ class PlayerSocial;
class SpellCastTargets;
class UpdateMask;
class PlayerbotAI;
class PlayerbotMgr;
typedef std::deque<Mail*> PlayerMails;
typedef void(*bgZoneRef)(Battleground*, WorldPacket&);
@@ -660,7 +663,7 @@ enum PlayerSlots
#define INVENTORY_SLOT_BAG_0 255
enum EquipmentSlots // 19 slots
enum EquipmentSlots : uint32 // 19 slots
{
EQUIPMENT_SLOT_START = 0,
EQUIPMENT_SLOT_HEAD = 0,
@@ -1247,7 +1250,7 @@ public:
InventoryResult CanBankItem(uint8 bag, uint8 slot, ItemPosCountVec& dest, Item* pItem, bool swap, bool not_loading = true) const;
InventoryResult CanUseItem(Item* pItem, bool not_loading = true) const;
[[nodiscard]] bool HasItemTotemCategory(uint32 TotemCategory) const;
bool IsTotemCategoryCompatiableWith(const ItemTemplate* pProto, uint32 requiredTotemCategoryId) const;
bool IsTotemCategoryCompatiableWith(ItemTemplate const* pProto, uint32 requiredTotemCategoryId) const;
InventoryResult CanUseItem(ItemTemplate const* pItem) const;
[[nodiscard]] InventoryResult CanUseAmmo(uint32 item) const;
InventoryResult CanRollForItemInLFG(ItemTemplate const* item, WorldObject const* lootedObject) const;
@@ -1274,7 +1277,7 @@ public:
void SetAmmo(uint32 item);
void RemoveAmmo();
[[nodiscard]] float GetAmmoDPS() const { return m_ammoDPS; }
bool CheckAmmoCompatibility(const ItemTemplate* ammo_proto) const;
bool CheckAmmoCompatibility(ItemTemplate const* ammo_proto) const;
void QuickEquipItem(uint16 pos, Item* pItem);
void VisualizeItem(uint8 slot, Item* pItem);
void SetVisibleItemSlot(uint8 slot, Item* pItem);
@@ -2589,15 +2592,16 @@ public:
std::string GetMapAreaAndZoneString();
std::string GetCoordsMapAreaAndZoneString();
void SetFarSightDistance(float radius);
void ResetFarSightDistance();
Optional<float> GetFarSightDistance() const;
// Playerbot mod
// A Player can either have a playerbotMgr (to manage its bots), or have playerbotAI (if it is a bot), or
// neither. Code that enables bots must create the playerbotMgr and set it using SetPlayerbotMgr.
void SetPlayerbotAI(PlayerbotAI* ai);
PlayerbotAI* GetPlayerbotAI();
void SetPlayerbotMgr(PlayerbotMgr* mgr);
PlayerbotMgr* GetPlayerbotMgr();
void SetBotDeathTimer();
float GetSightRange(const WorldObject* target = nullptr) const override;
std::string GetPlayerName();
protected:
protected:
// Gamemaster whisper whitelist
WhisperListContainer WhisperList;
@@ -2952,6 +2956,10 @@ private:
WorldLocation _corpseLocation;
Optional<float> _farSightDistance = { };
// Playerbot mod
PlayerbotAI* _playerbotAI;
PlayerbotMgr* _playerbotMgr;
};
void AddItemsSetItem(Player* player, Item* item);

View File

@@ -38,6 +38,10 @@
#include "Vehicle.h"
#include "WeatherMgr.h"
#ifdef PLAYERBOTS
#include "Playerbot.h"
#endif
// Zone Interval should be 1 second
constexpr auto ZONE_UPDATE_INTERVAL = 1000;
@@ -434,6 +438,18 @@ void Player::Update(uint32 p_time)
m_delayed_unit_relocation_timer = 0;
RemoveFromNotify(NOTIFY_VISIBILITY_CHANGED);
}
#ifdef PLAYERBOTS
if (_playerbotAI)
{
_playerbotAI->UpdateAI(p_time);
}
if (_playerbotMgr)
{
_playerbotMgr->UpdateAI(p_time);
}
#endif
}
void Player::UpdateMirrorTimers()

View File

@@ -250,10 +250,12 @@ public:
GroupJoinBattlegroundResult CanJoinBattlegroundQueue(Battleground const* bgTemplate, BattlegroundQueueTypeId bgQueueTypeId, uint32 MinPlayerCount, uint32 MaxPlayerCount, bool isRated, uint32 arenaSlot);
void ChangeMembersGroup(ObjectGuid guid, uint8 group);
void SetTargetIcon(uint8 id, ObjectGuid whoGuid, ObjectGuid targetGuid);
void SetGroupMemberFlag(ObjectGuid guid, bool apply, GroupMemberFlags flag);
void RemoveUniqueGroupMemberFlag(GroupMemberFlags flag);
void SetTargetIcon(uint8 id, ObjectGuid whoGuid, ObjectGuid targetGuid);
ObjectGuid const GetTargetIcon(uint8 id) const { return m_targetIcons[i]; }
Difficulty GetDifficulty(bool isRaid) const;
Difficulty GetDungeonDifficulty() const;
Difficulty GetRaidDifficulty() const;
@@ -292,6 +294,8 @@ public:
bool CountRollVote(ObjectGuid playerGUID, ObjectGuid Guid, uint8 Choise);
void EndRoll(Loot* loot, Map* allowedMap);
Rolls GetRolls() const { return RollId; }
// related to disenchant rolls
void ResetMaxEnchantingLevel();

View File

@@ -56,6 +56,10 @@
#include "WorldPacket.h"
#include "WorldSession.h"
#ifdef PLAYERBOTS
#include "Playerbot.h"
#endif
class LoginQueryHolder : public CharacterDatabaseQueryHolder
{
private:
@@ -208,6 +212,22 @@ bool LoginQueryHolder::Initialize()
return res;
}
#ifdef PLAYERBOTS
class PlayerbotLoginQueryHolder : public LoginQueryHolder
{
private:
uint32 masterAccountId;
PlayerbotHolder* playerbotHolder;
public:
PlayerbotLoginQueryHolder(PlayerbotHolder* playerbotHolder, uint32 masterAccount, uint32 accountId, ObjectGuid guid)
: LoginQueryHolder(accountId, guid), masterAccountId(masterAccount), playerbotHolder(playerbotHolder) { }
uint32 GetMasterAccountId() const { return masterAccountId; }
PlayerbotHolder* GetPlayerbotHolder() { return playerbotHolder; }
};
#endif
void WorldSession::HandleCharEnum(PreparedQueryResult result)
{
WorldPacket data(SMSG_CHAR_ENUM, 100); // we guess size
@@ -901,8 +921,7 @@ void WorldSession::HandlePlayerLoginFromDB(LoginQueryHolder const& holder)
CharacterDatabase.Execute(stmt);
LoginDatabasePreparedStatement* loginStmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_ACCOUNT_ONLINE);
loginStmt->setUInt32(0, realm.Id.Realm);
loginStmt->setUInt32(1, GetAccountId());
loginStmt->setUInt32(0, GetAccountId());
LoginDatabase.Execute(loginStmt);
pCurrChar->SetInGameTime(World::GetGameTimeMS());
@@ -1106,6 +1125,14 @@ void WorldSession::HandlePlayerLoginFromDB(LoginQueryHolder const& holder)
}
}
#ifdef PLAYERBOTS
if (!pCurrChar->GetPlayerbotAI())
{
pCurrChar->SetPlayerbotMgr(new PlayerbotMgr(pCurrChar));
sRandomPlayerbotMgr->OnPlayerLogin(pCurrChar);
}
#endif
sScriptMgr->OnPlayerLogin(pCurrChar);
if (pCurrChar->HasAtLoginFlag(AT_LOGIN_FIRST))
@@ -2546,3 +2573,65 @@ void WorldSession::SendSetPlayerDeclinedNamesResult(DeclinedNameResult result, O
data << guid;
SendPacket(&data);
}
#ifdef PLAYERBOTS
void PlayerbotHolder::AddPlayerBot(ObjectGuid playerGuid, uint32 masterAccountId)
{
// has bot already been added?
if (ObjectAccessor::FindConnectedPlayer(playerGuid))
{
return;
}
uint32 accountId = sObjectMgr->GetPlayerAccountIdByGUID(playerGuid.GetCounter());
if (!accountId)
{
return;
}
PlayerbotLoginQueryHolder* holder = new PlayerbotLoginQueryHolder(this, masterAccountId, accountId, playerGuid);
if (!holder->Initialize())
{
delete holder; // delete all unprocessed queries
return;
}
QueryResultHolderFuture future = CharacterDatabase.DelayQueryHolder(holder);
SQLQueryHolder* param;
future.get(param);
PlayerbotHolder* playerbotHolder = holder->GetPlayerbotHolder();
uint32 masterAccount = holder->GetMasterAccountId();
WorldSession* masterSession = masterAccount ? sWorld->FindSession(masterAccount) : NULL;
// The bot's WorldSession is owned by the bot's Player object
// The bot's WorldSession is deleted by PlayerbotMgr::LogoutPlayerBot
uint32 botAccountId = holder->GetAccountId();
WorldSession* botSession = new WorldSession(botAccountId, NULL, SEC_PLAYER, EXPANSION_WRATH_OF_THE_LICH_KING, time_t(0), LOCALE_enUS, false, false, false, 0);
botSession->SetAddress("bot");
botSession->HandlePlayerLoginFromDB(holder); // will delete lqh
Player* bot = botSession->GetPlayer();
if (!bot)
{
return;
}
bool allowed = false;
if (botAccountId == masterAccount)
allowed = true;
else if (masterSession && sPlayerbotAIConfig->allowGuildBots && bot->GetGuildId() == masterSession->GetPlayer()->GetGuildId())
allowed = true;
else if (sPlayerbotAIConfig->IsInRandomAccountList(botAccountId))
allowed = true;
if (allowed)
playerbotHolder->OnBotLogin(bot);
else if (masterSession)
{
ChatHandler ch(masterSession);
ch.PSendSysMessage("You are not allowed to control bot %s...", bot->GetName());
playerbotHolder->LogoutPlayerBot(bot->GetGUID());
}
}
#endif

View File

@@ -39,6 +39,10 @@
#include "WorldPacket.h"
#include "WorldSession.h"
#ifdef PLAYERBOTS
#include "Playerbot.h"
#endif
inline bool isNasty(uint8 c)
{
if (c == '\t')
@@ -409,7 +413,16 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recvData)
if (!senderIsPlayer && !sender->isAcceptWhispers() && !sender->IsInWhisperWhiteList(receiver->GetGUID()))
sender->AddWhisperWhiteList(receiver->GetGUID());
GetPlayer()->Whisper(msg, Language(lang), receiver);
#ifdef PLAYERBOTS
if (receiver->GetPlayerbotAI())
{
receiver->GetPlayerbotAI()->HandleCommand(type, msg, GetPlayer());
GetPlayer()->m_speakTime = 0;
GetPlayer()->m_speakCount = 0;
}
else
#endif
GetPlayer()->Whisper(msg, Language(lang), receiver);
}
break;
case CHAT_MSG_PARTY:
@@ -432,6 +445,21 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recvData)
return;
}
#ifdef PLAYERBOTS
for (GroupReference* itr = group->GetFirstMember(); itr != NULL; itr = itr->next())
{
if (Player* player = itr->GetSource())
{
if (player->GetPlayerbotAI())
{
player->GetPlayerbotAI()->HandleCommand(type, msg, GetPlayer());
GetPlayer()->m_speakTime = 0;
GetPlayer()->m_speakCount = 0;
}
}
}
#endif
sScriptMgr->OnPlayerChat(GetPlayer(), type, lang, msg, group);
WorldPacket data;
@@ -454,6 +482,22 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recvData)
guild->BroadcastToGuild(this, false, msg, lang == LANG_ADDON ? LANG_ADDON : LANG_UNIVERSAL);
}
#ifdef PLAYERBOTS
if (PlayerbotMgr* mgr = GetPlayer()->GetPlayerbotMgr())
{
for (PlayerBotMap::const_iterator it = mgr->GetPlayerBotsBegin(); it != mgr->GetPlayerBotsEnd(); ++it)
{
if (Player* const bot = it->second)
{
if (bot->GetGuildId() == GetPlayer()->GetGuildId())
{
bot->GetPlayerbotAI()->HandleCommand(type, msg, GetPlayer());
}
}
}
}
#endif
}
}
break;
@@ -491,6 +535,21 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recvData)
return;
}
#ifdef PLAYERBOTS
for (GroupReference* itr = group->GetFirstMember(); itr != NULL; itr = itr->next())
{
if (Player* player = itr->GetSource())
{
if (player->GetPlayerbotAI())
{
player->GetPlayerbotAI()->HandleCommand(type, msg, GetPlayer());
GetPlayer()->m_speakTime = 0;
GetPlayer()->m_speakCount = 0;
}
}
}
#endif
sScriptMgr->OnPlayerChat(GetPlayer(), type, lang, msg, group);
WorldPacket data;
@@ -514,6 +573,21 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recvData)
return;
}
#ifdef PLAYERBOTS
for (GroupReference* itr = group->GetFirstMember(); itr != NULL; itr = itr->next())
{
if (Player* player = itr->GetSource())
{
if (player->GetPlayerbotAI())
{
player->GetPlayerbotAI()->HandleCommand(type, msg, GetPlayer());
GetPlayer()->m_speakTime = 0;
GetPlayer()->m_speakCount = 0;
}
}
}
#endif
sScriptMgr->OnPlayerChat(GetPlayer(), type, lang, msg, group);
WorldPacket data;
@@ -532,6 +606,21 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recvData)
return;
}
#ifdef PLAYERBOTS
for (GroupReference* itr = group->GetFirstMember(); itr != NULL; itr = itr->next())
{
if (Player* player = itr->GetSource())
{
if (player->GetPlayerbotAI())
{
player->GetPlayerbotAI()->HandleCommand(type, msg, GetPlayer());
GetPlayer()->m_speakTime = 0;
GetPlayer()->m_speakCount = 0;
}
}
}
#endif
sScriptMgr->OnPlayerChat(GetPlayer(), type, lang, msg, group);
// In battleground, raid warning is sent only to players in battleground - code is ok
@@ -598,6 +687,14 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recvData)
return;
}
#ifdef PLAYERBOTS
if (_player->GetPlayerbotMgr() && chn->GetFlags() & 0x18)
{
_player->GetPlayerbotMgr()->HandleCommand(type, msg);
}
sRandomPlayerbotMgr->HandleCommand(type, msg, _player);
#endif
sScriptMgr->OnPlayerChat(sender, type, lang, msg, chn);
chn->Say(sender->GetGUID(), msg.c_str(), lang);

View File

@@ -51,6 +51,10 @@
#include "WorldSocket.h"
#include <zlib.h>
#ifdef PLAYERBOTS
#include "Playerbot.h"
#endif
namespace
{
std::string const DefaultPlayerName = "<none>";
@@ -211,6 +215,20 @@ void WorldSession::SendPacket(WorldPacket const* packet)
return;
}
#ifdef PLAYERBOTS
if (Player* player = GetPlayer())
{
if (PlayerbotAI* playerbotAI = player->GetPlayerbotAI())
{
playerbotAI->HandleBotOutgoingPacket(*packet);
}
else if (PlayerbotMgr* playerbotMgr = GetPlayer()->GetPlayerbotMgr())
{
playerbotMgr->HandleMasterOutgoingPacket(*packet);
}
}
#endif
if (!m_Socket)
return;
@@ -287,6 +305,11 @@ void WorldSession::LogUnprocessedTail(WorldPacket* packet)
/// Update the WorldSession (triggered by World update)
bool WorldSession::Update(uint32 diff, PacketFilter& updater)
{
#ifdef PLAYERBOTS
if (GetPlayer() && GetPlayer()->GetPlayerbotAI())
return true;
#endif
///- Before we process anything:
/// If necessary, kick the player because the client didn't send anything for too long
/// (or they've been idling in character select)
@@ -347,6 +370,11 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater)
opHandle->Call(this, *packet);
LogUnprocessedTail(packet);
#ifdef PLAYERBOTS
if (_player && _player->GetPlayerbotMgr())
_player->GetPlayerbotMgr()->HandleMasterIncomingPacket(*packet);
#endif
}
break;
case STATUS_TRANSFER:
@@ -457,6 +485,11 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater)
ProcessQueryCallbacks();
#ifdef PLAYERBOTS
if (GetPlayer() && GetPlayer()->GetPlayerbotMgr())
GetPlayer()->GetPlayerbotMgr()->UpdateSessions(0);
#endif
//check if we are safe to proceed with logout
//logout procedure should happen only in World::UpdateSessions() method!!!
if (updater.ProcessUnsafe())
@@ -613,6 +646,7 @@ void WorldSession::LogoutPlayer(bool save)
// there are some positive auras from boss encounters that can be kept by logging out and logging in after boss is dead, and may be used on next bosses
_player->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_CHANGE_MAP);
#ifndef PLAYERBOTS
///- If the player is in a group (or invited), remove him. If the group if then only 1 person, disband the group.
_player->UninviteFromGroup();
@@ -621,6 +655,7 @@ void WorldSession::LogoutPlayer(bool save)
if (_player->GetGroup() && !_player->GetGroup()->isRaidGroup() && !_player->GetGroup()->isLFGGroup() && m_Socket)
_player->RemoveFromGroup();
#endif
// pussywizard: checked second time after being removed from a group
if (!_player->IsBeingTeleportedFar() && !_player->m_InstanceValid && !_player->IsGameMaster())
_player->RepopAtGraveyard();
@@ -1614,3 +1649,17 @@ void WorldSession::SendTimeSync()
_timeSyncTimer = _timeSyncNextCounter == 0 ? 5000 : 10000;
_timeSyncNextCounter++;
}
#ifdef PLAYERBOTS
void WorldSession::HandleBotPackets()
{
WorldPacket* packet;
while (_recvQueue.next(packet))
{
OpcodeClient opcode = static_cast<OpcodeClient>(packet->GetOpcode());
ClientOpcodeHandler const* opHandle = opcodeTable[opcode];
opHandle->Call(this, *packet);
delete packet;
}
}
#endif

View File

@@ -442,6 +442,11 @@ public:
// Time Synchronisation
void ResetTimeSync();
void SendTimeSync();
#ifdef PLAYERBOTS
void HandleBotPackets();
#endif
public: // opcodes handlers
void Handle_NULL(WorldPacket& null); // not used
void Handle_EarlyProccess(WorldPacket& recvPacket); // just mark packets processed in WorldSocket::OnRead
@@ -984,6 +989,8 @@ public: // opcodes handlers
bool GetShouldSetOfflineInDB() const { return _shouldSetOfflineInDB; }
bool IsSocketClosed() const;
void SetAddress(std::string const& address) { m_Address = address; }
/*
* CALLBACKS
*/

View File

@@ -92,6 +92,10 @@
#include <boost/asio/ip/address.hpp>
#include <cmath>
#ifdef PLAYERBOTS
#include "RandomPlayerbotMgr.h"
#endif
std::atomic_long World::m_stopEvent = false;
uint8 World::m_ExitCode = SHUTDOWN_EXIT_CODE;
uint32 World::m_worldLoopCounter = 0;
@@ -2274,6 +2278,11 @@ void World::Update(uint32 diff)
ResetGuildCap();
}
#ifdef PLAYERBOTS
sRandomPlayerbotMgr->UpdateAI(diff);
sRandomPlayerbotMgr->UpdateSessions(diff);
#endif
// pussywizard:
// acquire mutex now, this is kind of waiting for listing thread to finish it's work (since it can't process next packet)
// so we don't have to do it in every packet that modifies auctions
@@ -2432,6 +2441,9 @@ void World::Update(uint32 diff)
CharacterDatabase.KeepAlive();
LoginDatabase.KeepAlive();
WorldDatabase.KeepAlive();
#ifdef PLAYERBOTS
PlayerbotDatabase.KeepAlive();
#endif
}
{
@@ -2719,6 +2731,10 @@ void World::ShutdownServ(uint32 time, uint32 options, uint8 exitcode, const std:
ShutdownMsg(true, nullptr, reason);
}
#ifdef PLAYERBOTS
sRandomPlayerbotMgr->LogoutAllBots();
#endif
sScriptMgr->OnShutdownInitiate(ShutdownExitCode(exitcode), ShutdownMask(options));
}

View File

@@ -627,6 +627,33 @@ struct CharStartOutfitEntry
//int32 ItemInventorySlot[MAX_OUTFIT_ITEMS]; // 53-76 not required at server side
};
enum CharSectionFlags
{
SECTION_FLAG_PLAYER = 0x01,
SECTION_FLAG_DEATH_KNIGHT = 0x04
};
enum CharSectionType
{
SECTION_TYPE_SKIN = 0,
SECTION_TYPE_FACE = 1,
SECTION_TYPE_FACIAL_HAIR = 2,
SECTION_TYPE_HAIR = 3,
SECTION_TYPE_UNDERWEAR = 4
};
struct CharSectionsEntry
{
//uint32 Id;
uint32 Race;
uint32 Gender;
uint32 GenType;
//char* TexturePath[3];
uint32 Flags;
uint32 Type;
uint32 Color;
};
struct CharTitlesEntry
{
uint32 ID; // 0, title ids, for example in Quest::GetCharTitleId()
@@ -864,6 +891,15 @@ struct EmotesTextEntry
uint32 textid;
};
struct EmotesTextSoundEntry
{
uint32 Id; // 0
uint32 EmotesTextId; // 1
uint32 RaceId; // 2
uint32 SexId; // 3, 0 male / 1 female
uint32 SoundId; // 4
};
struct FactionEntry
{
uint32 ID; // 0 m_ID

View File

@@ -29,6 +29,7 @@ char constexpr BankBagSlotPricesEntryfmt[] = "ni";
char constexpr BarberShopStyleEntryfmt[] = "nixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxiii";
char constexpr BattlemasterListEntryfmt[] = "niiiiiiiiixssssssssssssssssxiixx";
char constexpr CharStartOutfitEntryfmt[] = "dbbbXiiiiiiiiiiiiiiiiiiiiiiiixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
char constexpr CharSectionsEntryfmt[] = "diiixxxiii";
char constexpr CharTitlesEntryfmt[] = "nxssssssssssssssssxssssssssssssssssxi";
char constexpr ChatChannelsEntryfmt[] = "nixssssssssssssssssxxxxxxxxxxxxxxxxxx"; // ChatChannelsEntryfmt, index not used (more compact store)
char constexpr ChrClassesEntryfmt[] = "nxixssssssssssssssssxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxixii";
@@ -47,6 +48,7 @@ char constexpr DurabilityCostsfmt[] = "niiiiiiiiiiiiiiiiiiiiiiiiiiiii";
char constexpr DurabilityQualityfmt[] = "nf";
char constexpr EmotesEntryfmt[] = "nxxiiix";
char constexpr EmotesTextEntryfmt[] = "nxixxxxxxxxxxxxxxxx";
char constexpr EmotesTextSoundEntryfmt[] = "niiii";
char constexpr FactionEntryfmt[] = "niiiiiiiiiiiiiiiiiiffixssssssssssssssssxxxxxxxxxxxxxxxxxx";
char constexpr FactionTemplateEntryfmt[] = "niiiiiiiiiiiii";
char constexpr GameObjectDisplayInfofmt[] = "nsxxxxxxxxxxffffffx";

View File

@@ -3116,7 +3116,7 @@ enum WeatherType
#define MAX_WEATHER_TYPE 4
// EnumUtils: DESCRIBE THIS
enum ChatMsg
enum ChatMsg : uint32
{
CHAT_MSG_ADDON = 0xFFFFFFFF,
CHAT_MSG_SYSTEM = 0x00,

View File

@@ -456,6 +456,14 @@ bool StartDB()
if (!loader.Load())
return false;
#ifdef PLAYERBOTS
DatabaseLoader playerbotLoader("server.playerbot");
playerbotLoader.SetUpdateFlags(sConfigMgr->GetOption<bool>("Playerbot.Updates.EnableDatabases", true) ? DatabaseLoader::DATABASE_PLAYERBOT : 0);
playerbotLoader.AddDatabase(PlayerbotDatabase, "Playerbot");
if (!playerbotLoader.Load())
return false;
#endif
///- Get the realm Id from the configuration file
realm.Id.Realm = sConfigMgr->GetIntDefault("RealmID", 0);
if (!realm.Id.Realm)
@@ -499,6 +507,10 @@ void StopDB()
WorldDatabase.Close();
LoginDatabase.Close();
#ifdef PLAYERBOTS
PlayerbotDatabase.Close();
#endif
MySQL::Library_End();
}