diff options
| author | Treeston <treeston.mmoc@gmail.com> | 2020-08-28 00:11:16 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-08-28 00:11:16 +0200 |
| commit | 534a2388b7c662c8796aabb1ec8cb424879799b6 (patch) | |
| tree | df01a59b06bbb376dfeb95f2d538ab43b082e20d /src/server | |
| parent | 7478c2c65aea853a2086c9c7ecc56c14ad6ee338 (diff) | |
Core/Common: Tokenizer -> Trinity::Tokenize (PR: #25327)
Diffstat (limited to 'src/server')
26 files changed, 269 insertions, 193 deletions
diff --git a/src/server/database/Database/Field.cpp b/src/server/database/Database/Field.cpp index b9d25b3da1b..258bc2078fb 100644 --- a/src/server/database/Database/Field.cpp +++ b/src/server/database/Database/Field.cpp @@ -237,6 +237,18 @@ std::string Field::GetString() const return std::string(string, data.length); } +std::string_view Field::GetStringView() const +{ + if (!data.value) + return {}; + + char const* const string = GetCString(); + if (!string) + return {}; + + return { string, data.length }; +} + std::vector<uint8> Field::GetBinary() const { std::vector<uint8> result; diff --git a/src/server/database/Database/Field.h b/src/server/database/Database/Field.h index dcb03344031..a871ef64bfd 100644 --- a/src/server/database/Database/Field.h +++ b/src/server/database/Database/Field.h @@ -21,6 +21,8 @@ #include "Define.h" #include "DatabaseEnvFwd.h" #include <array> +#include <string> +#include <string_view> #include <vector> enum class DatabaseFieldTypes : uint8 @@ -104,6 +106,7 @@ class TC_DATABASE_API Field double GetDouble() const; char const* GetCString() const; std::string GetString() const; + std::string_view GetStringView() const; std::vector<uint8> GetBinary() const; template <size_t S> std::array<uint8, S> GetBinary() const diff --git a/src/server/database/Database/MySQLConnection.cpp b/src/server/database/Database/MySQLConnection.cpp index 12463d8c46e..994c532b4c5 100644 --- a/src/server/database/Database/MySQLConnection.cpp +++ b/src/server/database/Database/MySQLConnection.cpp @@ -32,21 +32,19 @@ MySQLConnectionInfo::MySQLConnectionInfo(std::string const& infoString) { - Tokenizer tokens(infoString, ';'); + std::vector<std::string_view> tokens = Trinity::Tokenize(infoString, ';', true); if (tokens.size() != 5 && tokens.size() != 6) return; - uint8 i = 0; - - host.assign(tokens[i++]); - port_or_socket.assign(tokens[i++]); - user.assign(tokens[i++]); - password.assign(tokens[i++]); - database.assign(tokens[i++]); + host.assign(tokens[0]); + port_or_socket.assign(tokens[1]); + user.assign(tokens[2]); + password.assign(tokens[3]); + database.assign(tokens[4]); if (tokens.size() == 6) - ssl.assign(tokens[i++]); + ssl.assign(tokens[5]); } MySQLConnection::MySQLConnection(MySQLConnectionInfo& connInfo) : diff --git a/src/server/database/Logging/AppenderDB.cpp b/src/server/database/Logging/AppenderDB.cpp index 87910b49c30..5bac05b47e1 100644 --- a/src/server/database/Logging/AppenderDB.cpp +++ b/src/server/database/Logging/AppenderDB.cpp @@ -20,7 +20,7 @@ #include "LogMessage.h" #include "PreparedStatement.h" -AppenderDB::AppenderDB(uint8 id, std::string const& name, LogLevel level, AppenderFlags /*flags*/, std::vector<char const*> /*extraArgs*/) +AppenderDB::AppenderDB(uint8 id, std::string const& name, LogLevel level, AppenderFlags /*flags*/, std::vector<std::string_view> const& /*args*/) : Appender(id, name, level), realmId(0), enabled(false) { } AppenderDB::~AppenderDB() { } diff --git a/src/server/database/Logging/AppenderDB.h b/src/server/database/Logging/AppenderDB.h index 093678ca7ff..f4880df659a 100644 --- a/src/server/database/Logging/AppenderDB.h +++ b/src/server/database/Logging/AppenderDB.h @@ -23,13 +23,13 @@ class TC_DATABASE_API AppenderDB: public Appender { public: - typedef std::integral_constant<AppenderType, APPENDER_DB>::type TypeIndex; + static constexpr AppenderType type = APPENDER_DB; - AppenderDB(uint8 id, std::string const& name, LogLevel level, AppenderFlags flags, std::vector<char const*> extraArgs); + AppenderDB(uint8 id, std::string const& name, LogLevel level, AppenderFlags flags, std::vector<std::string_view> const& args); ~AppenderDB(); void setRealmId(uint32 realmId) override; - AppenderType getType() const override { return TypeIndex::value; } + AppenderType getType() const override { return type; } private: uint32 realmId; diff --git a/src/server/game/Chat/Channels/Channel.cpp b/src/server/game/Chat/Channels/Channel.cpp index b533e6901ef..ab3a3f30fbf 100644 --- a/src/server/game/Chat/Channels/Channel.cpp +++ b/src/server/game/Chat/Channels/Channel.cpp @@ -30,6 +30,7 @@ #include "ObjectMgr.h" #include "Player.h" #include "SocialMgr.h" +#include "StringConvert.h" #include "World.h" Channel::Channel(uint32 channelId, uint32 team /*= 0*/, AreaTableEntry const* zoneEntry /*= nullptr*/) : @@ -73,10 +74,9 @@ Channel::Channel(std::string const& name, uint32 team /*= 0*/, std::string const _channelPassword(), _zoneEntry(nullptr) { - Tokenizer tokens(banList, ' '); - for (auto const& token : tokens) + for (std::string_view guid : Trinity::Tokenize(banList, ' ', false)) { - ObjectGuid banned(uint64(atoull(token))); + ObjectGuid banned(Trinity::StringTo<uint64>(guid).value_or(0)); if (!banned) continue; diff --git a/src/server/game/Chat/Chat.cpp b/src/server/game/Chat/Chat.cpp index 7518b80050d..7413c6ec28c 100644 --- a/src/server/game/Chat/Chat.cpp +++ b/src/server/game/Chat/Chat.cpp @@ -175,7 +175,7 @@ void ChatHandler::SendSysMessage(const char *str, bool escapeCharacters) // Replace every "|" with "||" in msg if (escapeCharacters && msg.find('|') != std::string::npos) { - Tokenizer tokens{msg, '|'}; + std::vector<std::string_view> tokens = Trinity::Tokenize(msg, '|', true); std::ostringstream stream; for (size_t i = 0; i < tokens.size() - 1; ++i) stream << tokens[i] << "||"; @@ -185,7 +185,7 @@ void ChatHandler::SendSysMessage(const char *str, bool escapeCharacters) } WorldPacket data; - for (const auto& line : Tokenizer{msg, '\n'}) + for (std::string_view line : Trinity::Tokenize(str, '\n', true)) { BuildChatPacket(data, CHAT_MSG_SYSTEM, LANG_UNIVERSAL, nullptr, nullptr, line); m_session->SendPacket(&data); @@ -195,7 +195,7 @@ void ChatHandler::SendSysMessage(const char *str, bool escapeCharacters) void ChatHandler::SendGlobalSysMessage(const char *str) { WorldPacket data; - for (const auto& line : Tokenizer{str, '\n'}) + for (std::string_view line : Trinity::Tokenize(str, '\n', true)) { BuildChatPacket(data, CHAT_MSG_SYSTEM, LANG_UNIVERSAL, nullptr, nullptr, line); sWorld->SendGlobalMessage(&data); @@ -205,7 +205,7 @@ void ChatHandler::SendGlobalSysMessage(const char *str) void ChatHandler::SendGlobalGMSysMessage(const char *str) { WorldPacket data; - for (const auto& line : Tokenizer{str, '\n'}) + for (std::string_view line : Trinity::Tokenize(str, '\n', true)) { BuildChatPacket(data, CHAT_MSG_SYSTEM, LANG_UNIVERSAL, nullptr, nullptr, line); sWorld->SendGlobalGMMessage(&data); @@ -509,7 +509,7 @@ bool ChatHandler::ShowHelpForCommand(std::vector<ChatCommand> const& table, char return ShowHelpForSubCommands(table, "", cmd); } -size_t ChatHandler::BuildChatPacket(WorldPacket& data, ChatMsg chatType, Language language, ObjectGuid senderGUID, ObjectGuid receiverGUID, std::string const& message, uint8 chatTag, +size_t ChatHandler::BuildChatPacket(WorldPacket& data, ChatMsg chatType, Language language, ObjectGuid senderGUID, ObjectGuid receiverGUID, std::string_view message, uint8 chatTag, std::string const& senderName /*= ""*/, std::string const& receiverName /*= ""*/, uint32 achievementId /*= 0*/, bool gmMessage /*= false*/, std::string const& channelName /*= ""*/) { @@ -589,7 +589,7 @@ size_t ChatHandler::BuildChatPacket(WorldPacket& data, ChatMsg chatType, Languag return receiverGUIDPos; } -size_t ChatHandler::BuildChatPacket(WorldPacket& data, ChatMsg chatType, Language language, WorldObject const* sender, WorldObject const* receiver, std::string const& message, +size_t ChatHandler::BuildChatPacket(WorldPacket& data, ChatMsg chatType, Language language, WorldObject const* sender, WorldObject const* receiver, std::string_view message, uint32 achievementId /*= 0*/, std::string const& channelName /*= ""*/, LocaleConstant locale /*= DEFAULT_LOCALE*/) { ObjectGuid senderGUID; diff --git a/src/server/game/Chat/Chat.h b/src/server/game/Chat/Chat.h index 13e0c18c37a..4c1ec41ea64 100644 --- a/src/server/game/Chat/Chat.h +++ b/src/server/game/Chat/Chat.h @@ -46,12 +46,12 @@ class TC_GAME_API ChatHandler virtual ~ChatHandler() { } // Builds chat packet and returns receiver guid position in the packet to substitute in whisper builders - static size_t BuildChatPacket(WorldPacket& data, ChatMsg chatType, Language language, ObjectGuid senderGUID, ObjectGuid receiverGUID, std::string const& message, uint8 chatTag, + static size_t BuildChatPacket(WorldPacket& data, ChatMsg chatType, Language language, ObjectGuid senderGUID, ObjectGuid receiverGUID, std::string_view message, uint8 chatTag, std::string const& senderName = "", std::string const& receiverName = "", uint32 achievementId = 0, bool gmMessage = false, std::string const& channelName = ""); // Builds chat packet and returns receiver guid position in the packet to substitute in whisper builders - static size_t BuildChatPacket(WorldPacket& data, ChatMsg chatType, Language language, WorldObject const* sender, WorldObject const* receiver, std::string const& message, uint32 achievementId = 0, std::string const& channelName = "", LocaleConstant locale = DEFAULT_LOCALE); + static size_t BuildChatPacket(WorldPacket& data, ChatMsg chatType, Language language, WorldObject const* sender, WorldObject const* receiver, std::string_view message, uint32 achievementId = 0, std::string const& channelName = "", LocaleConstant locale = DEFAULT_LOCALE); static char* LineFromMessage(char*& pos) { char* start = strtok(pos, "\n"); pos = nullptr; return start; } diff --git a/src/server/game/Conditions/DisableMgr.cpp b/src/server/game/Conditions/DisableMgr.cpp index 7147e3c8e10..bcf1024affe 100644 --- a/src/server/game/Conditions/DisableMgr.cpp +++ b/src/server/game/Conditions/DisableMgr.cpp @@ -25,6 +25,7 @@ #include "OutdoorPvP.h" #include "Player.h" #include "SpellMgr.h" +#include "StringConvert.h" #include "VMapManager2.h" #include "World.h" @@ -105,16 +106,24 @@ void LoadDisables() if (flags & SPELL_DISABLE_MAP) { - Tokenizer tokens(params_0, ','); - for (uint8 i = 0; i < tokens.size(); ) - data.params[0].insert(atoi(tokens[i++])); + for (std::string_view mapStr : Trinity::Tokenize(params_0, ',', true)) + { + if (Optional<uint32> mapId = Trinity::StringTo<uint32>(mapStr)) + data.params[0].insert(*mapId); + else + TC_LOG_ERROR("sql.sql", "Disable map '%s' for spell %u is invalid, skipped.", std::string(mapStr).c_str(), entry); + } } if (flags & SPELL_DISABLE_AREA) { - Tokenizer tokens(params_1, ','); - for (uint8 i = 0; i < tokens.size(); ) - data.params[1].insert(atoi(tokens[i++])); + for (std::string_view areaStr : Trinity::Tokenize(params_0, ',', true)) + { + if (Optional<uint32> areaId = Trinity::StringTo<uint32>(areaStr)) + data.params[1].insert(*areaId); + else + TC_LOG_ERROR("sql.sql", "Disable area '%s' for spell %u is invalid, skipped.", std::string(areaStr).c_str(), entry); + } } break; diff --git a/src/server/game/Entities/Corpse/Corpse.cpp b/src/server/game/Entities/Corpse/Corpse.cpp index 5cd71aabf0a..d87403a8cea 100644 --- a/src/server/game/Entities/Corpse/Corpse.cpp +++ b/src/server/game/Entities/Corpse/Corpse.cpp @@ -165,7 +165,11 @@ bool Corpse::LoadCorpseFromDB(ObjectGuid::LowType guid, Field* fields) SetObjectScale(1.0f); SetUInt32Value(CORPSE_FIELD_DISPLAY_ID, fields[5].GetUInt32()); - _LoadIntoDataField(fields[6].GetString(), CORPSE_FIELD_ITEM, EQUIPMENT_SLOT_END); + if (!_LoadIntoDataField(fields[6].GetString(), CORPSE_FIELD_ITEM, EQUIPMENT_SLOT_END)) + { + TC_LOG_ERROR("entities.player", "Corpse (%s, owner: %s) is not created, given equipment info is not valid ('%s')", + GetGUID().ToString().c_str(), GetOwnerGUID().ToString().c_str(), fields[6].GetString().c_str()); + } SetUInt32Value(CORPSE_FIELD_BYTES_1, fields[7].GetUInt32()); SetUInt32Value(CORPSE_FIELD_BYTES_2, fields[8].GetUInt32()); SetUInt32Value(CORPSE_FIELD_GUILD, fields[9].GetUInt32()); diff --git a/src/server/game/Entities/Item/Item.cpp b/src/server/game/Entities/Item/Item.cpp index 97d4dcfaa07..75935cb7fba 100644 --- a/src/server/game/Entities/Item/Item.cpp +++ b/src/server/game/Entities/Item/Item.cpp @@ -31,6 +31,7 @@ #include "ScriptMgr.h" #include "SpellInfo.h" #include "SpellMgr.h" +#include "StringConvert.h" #include "Player.h" #include "TradeData.h" #include "UpdateData.h" @@ -421,7 +422,10 @@ bool Item::LoadFromDB(ObjectGuid::LowType guid, ObjectGuid owner_guid, Field* fi ItemTemplate const* proto = GetTemplate(); if (!proto) + { + TC_LOG_ERROR("entities.item", "Invalid entry %u for item %s. Refusing to load.", GetEntry(), GetGUID().ToString().c_str()); return false; + } // set owner (not if item is only loaded for gbank/auction/mail if (owner_guid) @@ -441,10 +445,17 @@ bool Item::LoadFromDB(ObjectGuid::LowType guid, ObjectGuid owner_guid, Field* fi need_save = true; } - Tokenizer tokens(fields[4].GetString(), ' ', MAX_ITEM_PROTO_SPELLS); + std::vector<std::string_view> tokens = Trinity::Tokenize(fields[4].GetStringView(), ' ', false); if (tokens.size() == MAX_ITEM_PROTO_SPELLS) + { for (uint8 i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i) - SetSpellCharges(i, atoi(tokens[i])); + { + if (Optional<int32> charges = Trinity::StringTo<int32>(tokens[i])) + SetSpellCharges(i, *charges); + else + TC_LOG_ERROR("entities.item", "Invalid charge info '%s' for item %s, charge data not loaded.", std::string(tokens[i]).c_str(), GetGUID().ToString().c_str()); + } + } SetUInt32Value(ITEM_FIELD_FLAGS, fields[5].GetUInt32()); // Remove bind flag for items vs NO_BIND set @@ -454,7 +465,9 @@ bool Item::LoadFromDB(ObjectGuid::LowType guid, ObjectGuid owner_guid, Field* fi need_save = true; } - _LoadIntoDataField(fields[6].GetString(), ITEM_FIELD_ENCHANTMENT_1_1, MAX_ENCHANTMENT_SLOT * MAX_ENCHANTMENT_OFFSET); + if (!_LoadIntoDataField(fields[6].GetString(), ITEM_FIELD_ENCHANTMENT_1_1, MAX_ENCHANTMENT_SLOT * MAX_ENCHANTMENT_OFFSET)) + TC_LOG_WARN("entities.item", "Invalid enchantment data '%s' for item %s. Forcing partial load.", fields[6].GetString().c_str(), GetGUID().ToString().c_str()); + SetInt32Value(ITEM_FIELD_RANDOM_PROPERTIES_ID, fields[7].GetInt16()); // recalculate suffix factor if (GetItemRandomPropertyId() < 0) diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp index ada272ac370..61f1251687c 100644 --- a/src/server/game/Entities/Object/Object.cpp +++ b/src/server/game/Entities/Object/Object.cpp @@ -39,6 +39,7 @@ #include "ReputationMgr.h" #include "SpellAuraEffects.h" #include "SpellMgr.h" +#include "StringConvert.h" #include "TemporarySummon.h" #include "Totem.h" #include "Transport.h" @@ -581,21 +582,25 @@ uint32 Object::GetUpdateFieldData(Player const* target, uint32*& flags) const return visibleFlag; } -void Object::_LoadIntoDataField(std::string const& data, uint32 startOffset, uint32 count) +bool Object::_LoadIntoDataField(std::string const& data, uint32 startOffset, uint32 count) { if (data.empty()) - return; + return false; - Tokenizer tokens(data, ' ', count); + std::vector<std::string_view> tokens = Trinity::Tokenize(data, ' ', false); if (tokens.size() != count) - return; + return false; for (uint32 index = 0; index < count; ++index) { - m_uint32Values[startOffset + index] = atoul(tokens[index]); + Optional<uint32> val = Trinity::StringTo<uint32>(tokens[index]); + if (!val) + return false; + m_uint32Values[startOffset + index] = *val; _changesMask.SetBit(startOffset + index); } + return true; } void Object::SetInt32Value(uint16 index, int32 value) diff --git a/src/server/game/Entities/Object/Object.h b/src/server/game/Entities/Object/Object.h index a95289937fd..954db82ec1e 100644 --- a/src/server/game/Entities/Object/Object.h +++ b/src/server/game/Entities/Object/Object.h @@ -201,7 +201,7 @@ class TC_GAME_API Object void _InitValues(); void _Create(ObjectGuid::LowType guidlow, uint32 entry, HighGuid guidhigh); std::string _ConcatFields(uint16 startIndex, uint16 size) const; - void _LoadIntoDataField(std::string const& data, uint32 startOffset, uint32 count); + [[nodiscard]] bool _LoadIntoDataField(std::string const& data, uint32 startOffset, uint32 count); uint32 GetUpdateFieldData(Player const* target, uint32*& flags) const; diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 07673a75159..af42846fea4 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -86,6 +86,7 @@ #include "SpellHistory.h" #include "SpellMgr.h" #include "SpellPackets.h" +#include "StringConvert.h" #include "TicketMgr.h" #include "TradeData.h" #include "Trainer.h" @@ -1540,27 +1541,48 @@ bool Player::BuildEnumData(PreparedQueryResult result, WorldPacket* data) *data << uint32(petLevel); *data << uint32(petFamily); - Tokenizer equipment(fields[22].GetString(), ' '); + std::vector<std::string_view> equipment = Trinity::Tokenize(fields[22].GetStringView(), ' ', false); for (uint8 slot = 0; slot < INVENTORY_SLOT_BAG_END; ++slot) { - uint32 visualBase = slot * 2; - uint32 itemId = GetUInt32ValueFromArray(equipment, visualBase); - ItemTemplate const* proto = sObjectMgr->GetItemTemplate(itemId); + uint32 const visualBase = slot * 2; + Optional<uint32> itemId; + if (visualBase < equipment.size()) + itemId = Trinity::StringTo<uint32>(equipment[visualBase]); + + ItemTemplate const* proto = nullptr; + if (itemId) + proto = sObjectMgr->GetItemTemplate(*itemId); + if (!proto) { + if (!itemId || *itemId) + { + TC_LOG_WARN("entities.player.loading", "Player %u has invalid equipment '%s' in `equipmentcache` at index %u. Skipped.", + guid, (visualBase < equipment.size()) ? std::string(equipment[visualBase]).c_str() : "<none>", visualBase); + } + *data << uint32(0); *data << uint8(0); *data << uint32(0); + continue; } SpellItemEnchantmentEntry const* enchant = nullptr; - uint32 enchants = GetUInt32ValueFromArray(equipment, visualBase + 1); + Optional<uint32> enchants; + if ((visualBase+1) < equipment.size()) + enchants = Trinity::StringTo<uint32>(equipment[visualBase + 1]); + if (!enchants) + { + TC_LOG_WARN("entities.player.loading", "Player %u has invalid enchantment info '%s' in `equipmentcache` at index %u. Skipped.", + guid, ((visualBase+1) < equipment.size()) ? std::string(equipment[visualBase + 1]).c_str() : "<none>", visualBase + 1); + enchants = 0; + } for (uint8 enchantSlot = PERM_ENCHANTMENT_SLOT; enchantSlot <= TEMP_ENCHANTMENT_SLOT; ++enchantSlot) { // values stored in 2 uint16 - uint32 enchantId = 0x0000FFFF & (enchants >> enchantSlot * 16); + uint32 enchantId = 0x0000FFFF & ((*enchants) >> enchantSlot * 16); if (!enchantId) continue; @@ -6750,7 +6772,7 @@ bool Player::RewardHonor(Unit* victim, uint32 groupsize, int32 honor, bool pvpto return true; } - // 'Inactive' this aura prevents the player from gaining honor points and battleground Tokenizer + // 'Inactive' this aura prevents the player from gaining honor points and battleground tokens if (HasAura(SPELL_AURA_PLAYER_INACTIVE)) return false; @@ -17030,7 +17052,7 @@ void Player::_LoadArenaTeamInfo(PreparedQueryResult result) ArenaTeam* arenaTeam = sArenaTeamMgr->GetArenaTeamById(arenaTeamId); if (!arenaTeam) { - TC_LOG_ERROR("entities.player", "Player::_LoadArenaTeamInfo: couldn't load arenateam %u", arenaTeamId); + TC_LOG_ERROR("entities.player.loading", "Player::_LoadArenaTeamInfo: couldn't load arenateam %u", arenaTeamId); continue; } @@ -17153,23 +17175,6 @@ void Player::SendBindPointUpdate() SendDirectMessage(packet.Write()); } -uint32 Player::GetUInt32ValueFromArray(Tokenizer const& data, uint16 index) -{ - if (index >= data.size()) - return 0; - - return (uint32)atoi(data[index]); -} - -float Player::GetFloatValueFromArray(Tokenizer const& data, uint16 index) -{ - float result; - uint32 temp = Player::GetUInt32ValueFromArray(data, index); - memcpy(&result, &temp, sizeof(result)); - - return result; -} - bool Player::IsLoading() const { return GetSession()->PlayerLoading(); @@ -17192,7 +17197,7 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder* holder) { std::string name = "<unknown>"; sCharacterCache->GetCharacterNameByGuid(guid, name); - TC_LOG_ERROR("entities.player", "Player::LoadFromDB: Player '%s' (%s) not found in table `characters`, can't load. ", name.c_str(), guid.ToString().c_str()); + TC_LOG_ERROR("entities.player.loading", "Player::LoadFromDB: Player '%s' (%s) not found in table `characters`, can't load. ", name.c_str(), guid.ToString().c_str()); return false; } @@ -17204,13 +17209,13 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder* holder) // player should be able to load/delete character only with correct account! if (dbAccountId != GetSession()->GetAccountId()) { - TC_LOG_ERROR("entities.player", "Player::LoadFromDB: Player (%s) loading from wrong account (is: %u, should be: %u)", guid.ToString().c_str(), GetSession()->GetAccountId(), dbAccountId); + TC_LOG_ERROR("entities.player.loading", "Player::LoadFromDB: Player (%s) loading from wrong account (is: %u, should be: %u)", guid.ToString().c_str(), GetSession()->GetAccountId(), dbAccountId); return false; } if (holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_BANNED)) { - TC_LOG_ERROR("entities.player", "Player::LoadFromDB: Player (%s) is banned, can't load.", guid.ToString().c_str()); + TC_LOG_ERROR("entities.player.loading", "Player::LoadFromDB: Player (%s) is banned, can't load.", guid.ToString().c_str()); return false; } @@ -17235,7 +17240,7 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder* holder) uint8 gender = fields[5].GetUInt8(); if (!IsValidGender(gender)) { - TC_LOG_ERROR("entities.player", "Player::LoadFromDB: Player (%s) has wrong gender (%u), can't load.", guid.ToString().c_str(), gender); + TC_LOG_ERROR("entities.player.loading", "Player::LoadFromDB: Player (%s) has wrong gender (%u), can't load.", guid.ToString().c_str(), gender); return false; } @@ -17247,15 +17252,18 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder* holder) PlayerInfo const* info = sObjectMgr->GetPlayerInfo(GetRace(), GetClass()); if (!info) { - TC_LOG_ERROR("entities.player", "Player::LoadFromDB: Player (%s) has wrong race/class (%u/%u), can't load.", guid.ToString().c_str(), GetRace(), GetClass()); + TC_LOG_ERROR("entities.player.loading", "Player::LoadFromDB: Player (%s) has wrong race/class (%u/%u), can't load.", guid.ToString().c_str(), GetRace(), GetClass()); return false; } SetLevel(fields[6].GetUInt8(), false); SetXP(fields[7].GetUInt32()); - _LoadIntoDataField(fields[66].GetString(), PLAYER_EXPLORED_ZONES_1, PLAYER_EXPLORED_ZONES_SIZE); - _LoadIntoDataField(fields[69].GetString(), PLAYER__FIELD_KNOWN_TITLES, KNOWN_TITLES_SIZE * 2); + if (!_LoadIntoDataField(fields[66].GetString(), PLAYER_EXPLORED_ZONES_1, PLAYER_EXPLORED_ZONES_SIZE)) + TC_LOG_WARN("entities.player.loading", "Player::LoadFromDB: Player (%s) has invalid exploredzones data (%s). Forcing partial load.", guid.ToString().c_str(), fields[66].GetCString()); + + if (!_LoadIntoDataField(fields[69].GetString(), PLAYER__FIELD_KNOWN_TITLES, KNOWN_TITLES_SIZE * 2)) + TC_LOG_WARN("entities.player.loading", "Player::LoadFromDB: Player (%s) has invalid knowntitles mask (%s). Forcing partial load.", guid.ToString().c_str(), fields[69].GetCString()); SetObjectScale(1.0f); SetFloatValue(UNIT_FIELD_HOVERHEIGHT, 1.0f); @@ -17283,7 +17291,7 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder* holder) fields[4].GetUInt8(), // class gender, GetHairStyleId(), GetHairColorId(), GetFaceId(), GetFacialStyle(), GetSkinId())) { - TC_LOG_ERROR("entities.player", "Player::LoadFromDB: Player (%s) has wrong Appearance values (Hair/Skin/Color), can't load.", guid.ToString().c_str()); + TC_LOG_ERROR("entities.player.loading", "Player::LoadFromDB: Player (%s) has wrong Appearance values (Hair/Skin/Color), can't load.", guid.ToString().c_str()); return false; } @@ -17341,7 +17349,7 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder* holder) std::string taxi_nodes = fields[42].GetString(); -#define RelocateToHomebind(){ mapId = m_homebindMapId; instanceId = 0; Relocate(m_homebindX, m_homebindY, m_homebindZ); } + auto RelocateToHomebind = [this, &mapId, &instanceId]() { mapId = m_homebindMapId; instanceId = 0; Relocate(m_homebindX, m_homebindY, m_homebindZ); }; _LoadGroup(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_GROUP)); @@ -17382,7 +17390,7 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder* holder) bool player_at_bg = false; if (!mapEntry || !IsPositionValid()) { - TC_LOG_ERROR("entities.player", "Player::LoadFromDB: Player (%s) has invalid coordinates (MapId: %u X: %f Y: %f Z: %f O: %f). Teleport to default race/class locations.", + TC_LOG_ERROR("entities.player.loading", "Player::LoadFromDB: Player (%s) has invalid coordinates (MapId: %u X: %f Y: %f Z: %f O: %f). Teleport to default race/class locations.", guid.ToString().c_str(), mapId, GetPositionX(), GetPositionY(), GetPositionZ(), GetOrientation()); RelocateToHomebind(); } @@ -17428,7 +17436,7 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder* holder) //if (mapId == MAPID_INVALID) -- code kept for reference if (int16(mapId) == int16(-1)) // Battleground Entry Point not found (???) { - TC_LOG_ERROR("entities.player", "Player::LoadFromDB: Player (%s) was in BG in database, but BG was not found and entry point was invalid! Teleport to default race/class locations.", + TC_LOG_ERROR("entities.player.loading", "Player::LoadFromDB: Player (%s) was in BG in database, but BG was not found and entry point was invalid! Teleport to default race/class locations.", guid.ToString().c_str()); RelocateToHomebind(); } @@ -17460,7 +17468,7 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder* holder) std::fabs(m_movementInfo.transport.pos.GetPositionY()) > 250.0f || std::fabs(m_movementInfo.transport.pos.GetPositionZ()) > 250.0f) { - TC_LOG_ERROR("entities.player", "Player::LoadFromDB: Player (%s) has invalid transport coordinates (X: %f Y: %f Z: %f O: %f). Teleport to bind location.", + TC_LOG_ERROR("entities.player.loading", "Player::LoadFromDB: Player (%s) has invalid transport coordinates (X: %f Y: %f Z: %f O: %f). Teleport to bind location.", guid.ToString().c_str(), x, y, z, o); m_movementInfo.transport.Reset(); @@ -17477,7 +17485,7 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder* holder) } else { - TC_LOG_ERROR("entities.player", "Player::LoadFromDB: Player (%s) has problems with transport guid (%u). Teleport to bind location.", + TC_LOG_ERROR("entities.player.loading", "Player::LoadFromDB: Player (%s) has problems with transport guid (%u). Teleport to bind location.", guid.ToString().c_str(), transLowGUID); RelocateToHomebind(); @@ -17503,12 +17511,12 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder* holder) if (!nodeEntry) // don't know taxi start node, teleport to homebind { - TC_LOG_ERROR("entities.player", "Player::LoadFromDB: Player (%s) has wrong data in taxi destination list, teleport to homebind.", GetGUID().ToString().c_str()); + TC_LOG_ERROR("entities.player.loading", "Player::LoadFromDB: Player (%s) has wrong data in taxi destination list (%s), teleport to homebind.", GetGUID().ToString().c_str(), taxi_nodes.c_str()); RelocateToHomebind(); } else // has start node, teleport to it { - TC_LOG_ERROR("entities.player", "Player::LoadFromDB: Player (%s) has too short taxi destination list, teleport to original node.", GetGUID().ToString().c_str()); + TC_LOG_ERROR("entities.player.loading", "Player::LoadFromDB: Player (%s) has too short taxi destination list (%s), teleport to original node.", GetGUID().ToString().c_str(), taxi_nodes.c_str()); mapId = nodeEntry->ContinentID; Relocate(nodeEntry->Pos.X, nodeEntry->Pos.Y, nodeEntry->Pos.Z, 0.0f); } @@ -17608,7 +17616,7 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder* holder) } else { - TC_LOG_ERROR("entities.player", "Player::LoadFromDB: Player '%s' (%s) Map: %u, X: %f, Y: %f, Z: %f, O: %f. Areatrigger not found.", + TC_LOG_ERROR("entities.player.loading", "Player::LoadFromDB: Player '%s' (%s) Map: %u, X: %f, Y: %f, Z: %f, O: %f. Areatrigger not found.", m_name.c_str(), guid.ToString().c_str(), mapId, GetPositionX(), GetPositionY(), GetPositionZ(), GetOrientation()); RelocateToHomebind(); map = nullptr; @@ -17622,7 +17630,7 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder* holder) map = sMapMgr->CreateMap(mapId, this); if (!map) { - TC_LOG_ERROR("entities.player", "Player::LoadFromDB: Player '%s' (%s) Map: %u, X: %f, Y: %f, Z: %f, O: %f. Invalid default map coordinates or instance couldn't be created.", + TC_LOG_ERROR("entities.player.loading", "Player::LoadFromDB: Player '%s' (%s) Map: %u, X: %f, Y: %f, Z: %f, O: %f. Invalid default map coordinates or instance couldn't be created.", m_name.c_str(), guid.ToString().c_str(), mapId, GetPositionX(), GetPositionY(), GetPositionZ(), GetOrientation()); return false; } @@ -17665,7 +17673,8 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder* holder) m_resetTalentsCost = fields[29].GetUInt32(); m_resetTalentsTime = time_t(fields[30].GetUInt32()); - m_taxi.LoadTaxiMask(fields[22].GetString()); // must be before InitTaxiNodesForLevel + if (!m_taxi.LoadTaxiMask(fields[22].GetString())) // must be before InitTaxiNodesForLevel + TC_LOG_WARN("entities.player.loading", "Player::LoadFromDB: Player (%s) has invalid taximask (%s) in DB. Forced partial load.", GetGUID().ToString().c_str(), fields[22].GetString().c_str()); uint32 extraflags = fields[36].GetUInt16(); @@ -17751,7 +17760,7 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder* holder) // sanity check if (m_specsCount > MAX_TALENT_SPECS || m_activeSpec > MAX_TALENT_SPEC || m_specsCount < MIN_TALENT_SPECS) { - TC_LOG_ERROR("entities.player", "Player::LoadFromDB: Player %s (%s) has invalid SpecCount = %u and/or invalid ActiveSpec = %u.", + TC_LOG_ERROR("entities.player.loading", "Player::LoadFromDB: Player %s (%s) has invalid SpecCount = %u and/or invalid ActiveSpec = %u.", GetName().c_str(), GetGUID().ToString().c_str(), uint32(m_specsCount), uint32(m_activeSpec)); m_activeSpec = 0; } @@ -18305,7 +18314,7 @@ Item* Player::_LoadItem(CharacterDatabaseTransaction& trans, uint32 zoneId, uint } else { - TC_LOG_DEBUG("entities.player.loading", "Player::_LoadInventory: player (%s, name: '%s') has item (%s) with refundable flags, but without data in item_refund_instance. Removing flag.", + TC_LOG_WARN("entities.player.loading", "Player::_LoadInventory: player (%s, name: '%s') has item (%s) with refundable flags, but without data in item_refund_instance. Removing flag.", GetGUID().ToString().c_str(), GetName().c_str(), item->GetGUID().ToString().c_str()); item->RemoveFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_REFUNDABLE); } @@ -18317,11 +18326,14 @@ Item* Player::_LoadItem(CharacterDatabaseTransaction& trans, uint32 zoneId, uint stmt->setUInt32(0, item->GetGUID().GetCounter()); if (PreparedQueryResult result = CharacterDatabase.Query(stmt)) { - std::string strGUID = (*result)[0].GetString(); - Tokenizer GUIDlist(strGUID, ' '); GuidSet looters; - for (Tokenizer::const_iterator itr = GUIDlist.begin(); itr != GUIDlist.end(); ++itr) - looters.insert(ObjectGuid::Create<HighGuid::Player>(uint32(strtoul(*itr, nullptr, 10)))); + for (std::string_view guidStr : Trinity::Tokenize((*result)[0].GetStringView(), ' ', false)) + { + if (Optional<ObjectGuid::LowType> guid = Trinity::StringTo<ObjectGuid::LowType>(guidStr)) + looters.insert(ObjectGuid::Create<HighGuid::Player>(*guid)); + else + TC_LOG_WARN("entities.player.loading", "Player::_LoadInventory: invalid item_soulbound_trade_data GUID '%s' for item %s. Skipped.", std::string(guidStr).c_str(), item->GetGUID().ToString().c_str()); + } if (looters.size() > 1 && item->GetTemplate()->GetMaxStackSize() == 1 && item->IsSoulBound()) { @@ -18333,7 +18345,7 @@ Item* Player::_LoadItem(CharacterDatabaseTransaction& trans, uint32 zoneId, uint } else { - TC_LOG_DEBUG("entities.player.loading", "Player::_LoadInventory: player (%s, name: '%s') has item (%s) with ITEM_FLAG_BOP_TRADEABLE flag, but without data in item_soulbound_trade_data. Removing flag.", + TC_LOG_WARN("entities.player.loading", "Player::_LoadInventory: player (%s, name: '%s') has item (%s) with ITEM_FLAG_BOP_TRADEABLE flag, but without data in item_soulbound_trade_data. Removing flag.", GetGUID().ToString().c_str(), GetName().c_str(), item->GetGUID().ToString().c_str()); item->RemoveFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_BOP_TRADEABLE); } @@ -20356,17 +20368,6 @@ void Player::SavePositionInDB(WorldLocation const& loc, uint16 zoneId, ObjectGui CharacterDatabase.ExecuteOrAppend(trans, stmt); } -void Player::SetUInt32ValueInArray(Tokenizer& tokens, uint16 index, uint32 value) -{ - char buf[11]; - snprintf(buf, 11, "%u", value); - - if (index >= tokens.size()) - return; - - tokens[index] = buf; -} - void Player::Customize(CharacterCustomizeInfo const* customizeInfo, CharacterDatabaseTransaction& trans) { CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GENDER_AND_APPEARANCE); diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 516f1af2a03..389247a55fb 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -1324,8 +1324,6 @@ class TC_GAME_API Player : public Unit, public GridObject<Player> bool IsLoading() const override; void Initialize(ObjectGuid::LowType guid); - static uint32 GetUInt32ValueFromArray(Tokenizer const& data, uint16 index); - static float GetFloatValueFromArray(Tokenizer const& data, uint16 index); static uint32 GetZoneIdFromDB(ObjectGuid guid); static bool LoadPositionFromDB(uint32& mapid, float& x, float& y, float& z, float& o, bool& in_flight, ObjectGuid guid); @@ -1341,7 +1339,6 @@ class TC_GAME_API Player : public Unit, public GridObject<Player> void SaveInventoryAndGoldToDB(CharacterDatabaseTransaction& trans); // fast save function for item/money cheating preventing void SaveGoldToDB(CharacterDatabaseTransaction& trans) const; - static void SetUInt32ValueInArray(Tokenizer& data, uint16 index, uint32 value); static void Customize(CharacterCustomizeInfo const* customizeInfo, CharacterDatabaseTransaction& trans); static void SavePositionInDB(WorldLocation const& loc, uint16 zoneId, ObjectGuid guid, CharacterDatabaseTransaction& trans); diff --git a/src/server/game/Entities/Player/PlayerTaxi.cpp b/src/server/game/Entities/Player/PlayerTaxi.cpp index a38959778a1..1ecd169f88b 100644 --- a/src/server/game/Entities/Player/PlayerTaxi.cpp +++ b/src/server/game/Entities/Player/PlayerTaxi.cpp @@ -19,6 +19,7 @@ #include "DBCStores.h" #include "ObjectMgr.h" #include "Player.h" +#include "StringConvert.h" #include <sstream> void PlayerTaxi::InitTaxiNodesForLevel(uint32 race, uint32 chrClass, uint8 level) @@ -61,16 +62,26 @@ void PlayerTaxi::InitTaxiNodesForLevel(uint32 race, uint32 chrClass, uint8 level SetTaximaskNode(213); //Shattered Sun Staging Area } -void PlayerTaxi::LoadTaxiMask(std::string const& data) +bool PlayerTaxi::LoadTaxiMask(std::string const& data) { - Tokenizer tokens(data, ' '); - - uint8 index = 0; - for (Tokenizer::const_iterator iter = tokens.begin(); index < TaxiMaskSize && iter != tokens.end(); ++iter, ++index) + bool warn = false; + std::vector<std::string_view> tokens = Trinity::Tokenize(data, ' ', false); + for (uint8 index = 0; (index < TaxiMaskSize) && (index < tokens.size()); ++index) { - // load and set bits only for existing taxi nodes - m_taximask[index] = sTaxiNodesMask[index] & atoul(*iter); + if (Optional<uint32> mask = Trinity::StringTo<uint32>(tokens[index])) + { + // load and set bits only for existing taxi nodes + m_taximask[index] = sTaxiNodesMask[index] & *mask; + if (m_taximask[index] != *mask) + warn = true; + } + else + { + m_taximask[index] = 0; + warn = true; + } } + return !warn; } void PlayerTaxi::AppendTaximaskTo(ByteBuffer& data, bool all) @@ -91,16 +102,22 @@ bool PlayerTaxi::LoadTaxiDestinationsFromString(const std::string& values, uint3 { ClearTaxiDestinations(); - Tokenizer tokens(values, ' '); - auto iter = tokens.begin(); - if (iter != tokens.end()) - m_flightMasterFactionId = atoul(*iter); + std::vector<std::string_view> tokens = Trinity::Tokenize(values, ' ', false); + auto itr = tokens.begin(); + if (itr != tokens.end()) + { + if (Optional<uint32> faction = Trinity::StringTo<uint32>(*itr)) + m_flightMasterFactionId = *faction; + else + return false; + } - ++iter; - for (; iter != tokens.end(); ++iter) + while ((++itr) != tokens.end()) { - uint32 node = atoul(*iter); - AddTaxiDestination(node); + if (Optional<uint32> node = Trinity::StringTo<uint32>(*itr)) + AddTaxiDestination(*node); + else + return false; } if (m_TaxiDestinations.empty()) diff --git a/src/server/game/Entities/Player/PlayerTaxi.h b/src/server/game/Entities/Player/PlayerTaxi.h index 8553eec8a12..4a7f8a713a9 100644 --- a/src/server/game/Entities/Player/PlayerTaxi.h +++ b/src/server/game/Entities/Player/PlayerTaxi.h @@ -33,7 +33,7 @@ class TC_GAME_API PlayerTaxi ~PlayerTaxi() { } // Nodes void InitTaxiNodesForLevel(uint32 race, uint32 chrClass, uint8 level); - void LoadTaxiMask(std::string const& data); + bool LoadTaxiMask(std::string const& data); bool IsTaximaskNodeKnown(uint32 nodeidx) const { @@ -56,7 +56,7 @@ class TC_GAME_API PlayerTaxi void AppendTaximaskTo(ByteBuffer& data, bool all); // Destinations - bool LoadTaxiDestinationsFromString(std::string const& values, uint32 team); + [[nodiscard]] bool LoadTaxiDestinationsFromString(std::string const& values, uint32 team); std::string SaveTaxiDestinationsToString(); void ClearTaxiDestinations() { m_TaxiDestinations.clear(); } diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 21e6b3cc17f..53243c1bf62 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -64,6 +64,7 @@ #include "SpellInfo.h" #include "SpellHistory.h" #include "SpellMgr.h" +#include "StringConvert.h" #include "TemporarySummon.h" #include "Transport.h" #include "Totem.h" @@ -9857,29 +9858,28 @@ void CharmInfo::LoadPetActionBar(const std::string& data) { InitPetActionBar(); - Tokenizer tokens(data, ' '); - + std::vector<std::string_view> tokens = Trinity::Tokenize(data, ' ', false); if (tokens.size() != (ACTION_BAR_INDEX_END-ACTION_BAR_INDEX_START) * 2) return; // non critical, will reset to default - uint8 index = ACTION_BAR_INDEX_START; - Tokenizer::const_iterator iter = tokens.begin(); - for (; index < ACTION_BAR_INDEX_END; ++iter, ++index) + auto iter = tokens.begin(); + for (uint8 index = ACTION_BAR_INDEX_START; index < ACTION_BAR_INDEX_END; ++index) { - // use unsigned cast to avoid sign negative format use at long-> ActiveStates (int) conversion - ActiveStates type = ActiveStates(atol(*iter)); - ++iter; - uint32 action = atoul(*iter); + Optional<uint8> type = Trinity::StringTo<uint8>(*(iter++)); + Optional<uint32> action = Trinity::StringTo<uint32>(*(iter++)); + + if (!type || !action) + continue; - PetActionBar[index].SetActionAndType(action, type); + PetActionBar[index].SetActionAndType(*action, static_cast<ActiveStates>(*type)); // check correctness if (PetActionBar[index].IsActionBarForSpell()) { - SpellInfo const* spelInfo = sSpellMgr->GetSpellInfo(PetActionBar[index].GetAction()); - if (!spelInfo) + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(PetActionBar[index].GetAction()); + if (!spellInfo) SetActionBar(index, 0, ACT_PASSIVE); - else if (!spelInfo->IsAutocastable()) + else if (!spellInfo->IsAutocastable()) SetActionBar(index, PetActionBar[index].GetAction(), ACT_PASSIVE); } } diff --git a/src/server/game/Entities/Unit/UnitDefines.h b/src/server/game/Entities/Unit/UnitDefines.h index c6115217f1d..1bd65509ed1 100644 --- a/src/server/game/Entities/Unit/UnitDefines.h +++ b/src/server/game/Entities/Unit/UnitDefines.h @@ -324,7 +324,7 @@ struct DeclinedName std::string name[MAX_DECLINED_NAME_CASES]; }; -enum ActiveStates +enum ActiveStates : uint8 { ACT_PASSIVE = 0x01, // 0x01 - passive ACT_DISABLED = 0x81, // 0x80 - castable diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index 57a773eab2b..c3d0cb0996f 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -49,6 +49,7 @@ #include "SpellAuras.h" #include "SpellMgr.h" #include "SpellScript.h" +#include "StringConvert.h" #include "TemporarySummon.h" #include "UpdateMask.h" #include "Util.h" @@ -735,33 +736,35 @@ void ObjectMgr::LoadCreatureTemplateAddons() creatureAddon.emote = fields[5].GetUInt32(); creatureAddon.visibilityDistanceType = VisibilityDistanceType(fields[6].GetUInt8()); - Tokenizer tokens(fields[7].GetString(), ' '); - creatureAddon.auras.reserve(tokens.size()); - for (Tokenizer::const_iterator itr = tokens.begin(); itr != tokens.end(); ++itr) + for (std::string_view aura : Trinity::Tokenize(fields[7].GetStringView(), ' ', false)) { - SpellInfo const* AdditionalSpellInfo = sSpellMgr->GetSpellInfo(atoul(*itr)); - if (!AdditionalSpellInfo) + + SpellInfo const* spellInfo = nullptr; + if (Optional<uint32> spellId = Trinity::StringTo<uint32>(aura)) + spellInfo = sSpellMgr->GetSpellInfo(*spellId); + + if (!spellInfo) { - TC_LOG_ERROR("sql.sql", "Creature (Entry: %u) has wrong spell %lu defined in `auras` field in `creature_template_addon`.", entry, atoul(*itr)); + TC_LOG_ERROR("sql.sql", "Creature (Entry: %u) has wrong spell '%s' defined in `auras` field in `creature_template_addon`.", entry, std::string(aura).c_str()); continue; } - if (AdditionalSpellInfo->HasAura(SPELL_AURA_CONTROL_VEHICLE)) - TC_LOG_ERROR("sql.sql", "Creature (Entry: %u) has SPELL_AURA_CONTROL_VEHICLE aura %lu defined in `auras` field in `creature_template_addon`.", entry, atoul(*itr)); + if (spellInfo->HasAura(SPELL_AURA_CONTROL_VEHICLE)) + TC_LOG_ERROR("sql.sql", "Creature (Entry: %u) has SPELL_AURA_CONTROL_VEHICLE aura %u defined in `auras` field in `creature_template_addon`.", entry, spellInfo->Id); - if (std::find(creatureAddon.auras.begin(), creatureAddon.auras.end(), atoul(*itr)) != creatureAddon.auras.end()) + if (std::find(creatureAddon.auras.begin(), creatureAddon.auras.end(), spellInfo->Id) != creatureAddon.auras.end()) { - TC_LOG_ERROR("sql.sql", "Creature (Entry: %u) has duplicate aura (spell %lu) in `auras` field in `creature_template_addon`.", entry, atoul(*itr)); + TC_LOG_ERROR("sql.sql", "Creature (Entry: %u) has duplicate aura (spell %u) in `auras` field in `creature_template_addon`.", entry, spellInfo->Id); continue; } - if (AdditionalSpellInfo->GetDuration() > 0) + if (spellInfo->GetDuration() > 0) { - TC_LOG_ERROR("sql.sql", "Creature (Entry: %u) has temporary aura (spell %lu) in `auras` field in `creature_template_addon`.", entry, atoul(*itr)); + TC_LOG_ERROR("sql.sql", "Creature (Entry: %u) has temporary aura (spell %u) in `auras` field in `creature_template_addon`.", entry, spellInfo->Id); continue; } - creatureAddon.auras.push_back(atoul(*itr)); + creatureAddon.auras.push_back(spellInfo->Id); } if (creatureAddon.mount) @@ -1270,33 +1273,34 @@ void ObjectMgr::LoadCreatureAddons() creatureAddon.emote = fields[5].GetUInt32(); creatureAddon.visibilityDistanceType = VisibilityDistanceType(fields[6].GetUInt8()); - Tokenizer tokens(fields[7].GetString(), ' '); - creatureAddon.auras.reserve(tokens.size()); - for (Tokenizer::const_iterator itr = tokens.begin(); itr != tokens.end(); ++itr) + for (std::string_view aura : Trinity::Tokenize(fields[7].GetStringView(), ' ', false)) { - SpellInfo const* AdditionalSpellInfo = sSpellMgr->GetSpellInfo(atoul(*itr)); - if (!AdditionalSpellInfo) + SpellInfo const* spellInfo = nullptr; + if (Optional<uint32> spellId = Trinity::StringTo<uint32>(aura)) + spellInfo = sSpellMgr->GetSpellInfo(*spellId); + + if (!spellInfo) { - TC_LOG_ERROR("sql.sql", "Creature (GUID: %u) has wrong spell %lu defined in `auras` field in `creature_addon`.", guid, atoul(*itr)); + TC_LOG_ERROR("sql.sql", "Creature (GUID: %u) has wrong spell '%s' defined in `auras` field in `creature_addon`.", guid, std::string(aura).c_str()); continue; } - if (AdditionalSpellInfo->HasAura(SPELL_AURA_CONTROL_VEHICLE)) - TC_LOG_ERROR("sql.sql", "Creature (GUID: %u) has SPELL_AURA_CONTROL_VEHICLE aura %lu defined in `auras` field in `creature_addon`.", guid, atoul(*itr)); + if (spellInfo->HasAura(SPELL_AURA_CONTROL_VEHICLE)) + TC_LOG_ERROR("sql.sql", "Creature (GUID: %u) has SPELL_AURA_CONTROL_VEHICLE aura %u defined in `auras` field in `creature_addon`.", guid, spellInfo->Id); - if (std::find(creatureAddon.auras.begin(), creatureAddon.auras.end(), atoul(*itr)) != creatureAddon.auras.end()) + if (std::find(creatureAddon.auras.begin(), creatureAddon.auras.end(), spellInfo->Id) != creatureAddon.auras.end()) { - TC_LOG_ERROR("sql.sql", "Creature (GUID: %u) has duplicate aura (spell %lu) in `auras` field in `creature_addon`.", guid, atoul(*itr)); + TC_LOG_ERROR("sql.sql", "Creature (GUID: %u) has duplicate aura (spell %u) in `auras` field in `creature_addon`.", guid, spellInfo->Id); continue; } - if (AdditionalSpellInfo->GetDuration() > 0) + if (spellInfo->GetDuration() > 0) { - TC_LOG_ERROR("sql.sql", "Creature (GUID: %u) has temporary aura (spell %lu) in `auras` field in `creature_addon`.", guid, atoul(*itr)); + TC_LOG_ERROR("sql.sql", "Creature (GUID: %u) has temporary aura (spell %u) in `auras` field in `creature_addon`.", guid, spellInfo->Id); continue; } - creatureAddon.auras.push_back(atoul(*itr)); + creatureAddon.auras.push_back(spellInfo->Id); } if (creatureAddon.mount) diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp index 5a56cb150e0..2f617b62c52 100644 --- a/src/server/game/Handlers/CharacterHandler.cpp +++ b/src/server/game/Handlers/CharacterHandler.cpp @@ -48,6 +48,7 @@ #include "ScriptMgr.h" #include "ServerMotd.h" #include "SocialMgr.h" +#include "StringConvert.h" #include "SystemPackets.h" #include "QueryHolder.h" #include "World.h" @@ -2068,18 +2069,24 @@ void WorldSession::HandleCharFactionOrRaceChangeCallback(std::shared_ptr<Charact // Title conversion if (!knownTitlesStr.empty()) { - uint32 const ktcount = KNOWN_TITLES_SIZE * 2; - uint32 knownTitles[ktcount]; - Tokenizer tokens(knownTitlesStr, ' ', ktcount); + std::vector<std::string_view> tokens = Trinity::Tokenize(knownTitlesStr, ' ', false); + std::array<uint32, KNOWN_TITLES_SIZE * 2> knownTitles; - if (tokens.size() != ktcount) + for (uint32 index = 0; index < knownTitles.size(); ++index) { - SendCharFactionChange(CHAR_CREATE_ERROR, factionChangeInfo.get()); - return; - } + Optional<uint32> thisMask; + if (index < tokens.size()) + thisMask = Trinity::StringTo<uint32>(tokens[index]); - for (uint32 index = 0; index < ktcount; ++index) - knownTitles[index] = atoul(tokens[index]); + if (thisMask) + knownTitles[index] = *thisMask; + else + { + TC_LOG_WARN("entities.player", "%s has invalid title data '%s' at index %u - skipped, this may result in titles being lost", + GetPlayerInfo().c_str(), (index < tokens.size()) ? std::string(tokens[index]).c_str() : "<none>", index); + knownTitles[index] = 0; + } + } for (std::map<uint32, uint32>::const_iterator it = sObjectMgr->FactionChangeTitles.begin(); it != sObjectMgr->FactionChangeTitles.end(); ++it) { @@ -2117,8 +2124,8 @@ void WorldSession::HandleCharFactionOrRaceChangeCallback(std::shared_ptr<Charact } std::ostringstream ss; - for (uint32 index = 0; index < ktcount; ++index) - ss << knownTitles[index] << ' '; + for (uint32 mask : knownTitles) + ss << mask << ' '; stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_TITLES_FACTION_CHANGE); stmt->setString(0, ss.str()); diff --git a/src/server/game/Motd/ServerMotd.cpp b/src/server/game/Motd/ServerMotd.cpp index c9f82a00fa7..f1a3f38abaa 100644 --- a/src/server/game/Motd/ServerMotd.cpp +++ b/src/server/game/Motd/ServerMotd.cpp @@ -36,10 +36,10 @@ void Motd::SetMotd(std::string motd) WorldPacket data(SMSG_MOTD); // new in 2.0.1 - Tokenizer motdTokens(motd, '@'); + std::vector<std::string_view> motdTokens = Trinity::Tokenize(motd, '@', true); data << uint32(motdTokens.size()); // line count - for (Tokenizer::const_reference token : motdTokens) + for (std::string_view token : motdTokens) data << token; MotdPacket = data; @@ -48,7 +48,7 @@ void Motd::SetMotd(std::string motd) return; std::ostringstream oss; - std::copy(motdTokens.begin(), motdTokens.end() - 1, std::ostream_iterator<char const*>(oss, "\n")); + std::copy(motdTokens.begin(), motdTokens.end() - 1, std::ostream_iterator<std::string_view>(oss, "\n")); oss << *(motdTokens.end() - 1); // copy back element FormattedMotd = oss.str(); } diff --git a/src/server/scripts/Commands/cs_modify.cpp b/src/server/scripts/Commands/cs_modify.cpp index e77d73bde9e..7a0f9522ad3 100644 --- a/src/server/scripts/Commands/cs_modify.cpp +++ b/src/server/scripts/Commands/cs_modify.cpp @@ -557,11 +557,16 @@ public: if (handler->HasLowerSecurity(target, ObjectGuid::Empty)) return false; - int32 moneyToAdd = 0; + Optional<int32> moneyToAddO = 0; if (strchr(args, 'g') || strchr(args, 's') || strchr(args, 'c')) - moneyToAdd = MoneyStringToMoney(std::string(args)); + moneyToAddO = MoneyStringToMoney(std::string(args)); else - moneyToAdd = atoi(args); + moneyToAddO = Trinity::StringTo<int32>(args); + + if (!moneyToAddO) + return false; + + int32 moneyToAdd = *moneyToAddO; uint32 targetMoney = target->GetMoney(); diff --git a/src/server/scripts/Commands/cs_reload.cpp b/src/server/scripts/Commands/cs_reload.cpp index 8c6e712806e..7804cac952a 100644 --- a/src/server/scripts/Commands/cs_reload.cpp +++ b/src/server/scripts/Commands/cs_reload.cpp @@ -42,6 +42,7 @@ EndScriptData */ #include "SkillExtraItems.h" #include "SmartAI.h" #include "SpellMgr.h" +#include "StringConvert.h" #include "TicketMgr.h" #include "WaypointManager.h" #include "World.h" @@ -198,7 +199,7 @@ public: HandleReloadGameTeleCommand(handler, ""); HandleReloadCreatureMovementOverrideCommand(handler, ""); - HandleReloadCreatureSummonGroupsCommand(handler, ""); + HandleReloadCreatureSummonGroupsCommand(handler); HandleReloadVehicleAccessoryCommand(handler, ""); HandleReloadVehicleTemplateAccessoryCommand(handler, ""); @@ -415,7 +416,7 @@ public: return true; } - static bool HandleReloadCreatureSummonGroupsCommand(ChatHandler* handler, char const* /*args*/) + static bool HandleReloadCreatureSummonGroupsCommand(ChatHandler* handler) { TC_LOG_INFO("misc", "Reloading creature summon groups..."); sObjectMgr->LoadTempSummons(); @@ -428,11 +429,9 @@ public: if (!*args) return false; - Tokenizer entries(std::string(args), ' '); - - for (Tokenizer::const_iterator itr = entries.begin(); itr != entries.end(); ++itr) + for (std::string_view entryStr : Trinity::Tokenize(args, ' ', false)) { - uint32 entry = uint32(atoi(*itr)); + uint32 entry = Trinity::StringTo<uint32>(entryStr).value_or(0); WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_CREATURE_TEMPLATE); stmt->setUInt32(0, entry); diff --git a/src/server/shared/DataStores/DBCEnums.h b/src/server/shared/DataStores/DBCEnums.h index fcd7bb560a5..02243813d5b 100644 --- a/src/server/shared/DataStores/DBCEnums.h +++ b/src/server/shared/DataStores/DBCEnums.h @@ -433,7 +433,7 @@ enum SummonPropFlags #define MAX_PET_TALENT_RANK 3 // use in calculations, expected <= MAX_TALENT_RANK #define MAX_TALENT_TABS 3 -#define TaxiMaskSize 14 +static constexpr size_t TaxiMaskSize = 14; typedef std::array<uint32, TaxiMaskSize> TaxiMask; enum TotemCategoryType diff --git a/src/server/shared/Packets/ByteBuffer.h b/src/server/shared/Packets/ByteBuffer.h index 149545d10d6..50c3c6a24f5 100644 --- a/src/server/shared/Packets/ByteBuffer.h +++ b/src/server/shared/Packets/ByteBuffer.h @@ -203,20 +203,22 @@ class TC_SHARED_API ByteBuffer return *this; } - ByteBuffer &operator<<(const std::string &value) + ByteBuffer &operator<<(std::string_view value) { if (size_t len = value.length()) - append((uint8 const*)value.c_str(), len); - append((uint8)0); + append(reinterpret_cast<uint8 const*>(value.data()), len); + append(static_cast<uint8>(0)); return *this; } - ByteBuffer &operator<<(const char *str) + ByteBuffer& operator<<(std::string const& str) { - if (size_t len = (str ? strlen(str) : 0)) - append((uint8 const*)str, len); - append((uint8)0); - return *this; + return operator<<(std::string_view(str)); + } + + ByteBuffer &operator<<(char const* str) + { + return operator<<(std::string_view(str ? str : "")); } ByteBuffer &operator>>(bool &value) |
