diff options
author | Treeston <treeston.mmoc@gmail.com> | 2020-08-28 00:11:16 +0200 |
---|---|---|
committer | Shauren <shauren.trinity@gmail.com> | 2022-02-04 00:27:14 +0100 |
commit | 9f97fdd31a3b9a06b6acfa1101d105e43687e824 (patch) | |
tree | 027f81c18e7733fa3554cf1dd704a0900d254725 | |
parent | 6e45c371c4098942e0085a71577a07b17725ee93 (diff) |
Core/Common: Tokenizer -> Trinity::Tokenize (PR: #25327)
(cherry picked from commit 534a2388b7c662c8796aabb1ec8cb424879799b6)
46 files changed, 658 insertions, 423 deletions
diff --git a/src/common/Logging/AppenderConsole.cpp b/src/common/Logging/AppenderConsole.cpp index 86e7634f1b9..af2117c6d0c 100644 --- a/src/common/Logging/AppenderConsole.cpp +++ b/src/common/Logging/AppenderConsole.cpp @@ -17,6 +17,9 @@ #include "AppenderConsole.h" #include "LogMessage.h" +#include "SmartEnum.h" +#include "StringFormat.h" +#include "StringConvert.h" #include "Util.h" #include <sstream> @@ -24,17 +27,17 @@ #include <Windows.h> #endif -AppenderConsole::AppenderConsole(uint8 id, std::string const& name, LogLevel level, AppenderFlags flags, std::vector<char const*> extraArgs) +AppenderConsole::AppenderConsole(uint8 id, std::string const& name, LogLevel level, AppenderFlags flags, std::vector<std::string_view> const& args) : Appender(id, name, level, flags), _colored(false) { for (uint8 i = 0; i < NUM_ENABLED_LOG_LEVELS; ++i) - _colors[i] = ColorTypes(MaxColors); + _colors[i] = ColorTypes(NUM_COLOR_TYPES); - if (!extraArgs.empty()) - InitColors(extraArgs[0]); + if (3 < args.size()) + InitColors(name, args[3]); } -void AppenderConsole::InitColors(std::string const& str) +void AppenderConsole::InitColors(std::string const& name, std::string_view str) { if (str.empty()) { @@ -42,23 +45,23 @@ void AppenderConsole::InitColors(std::string const& str) return; } - int color[NUM_ENABLED_LOG_LEVELS]; - - std::istringstream ss(str); - - for (uint8 i = 0; i < NUM_ENABLED_LOG_LEVELS; ++i) + std::vector<std::string_view> colorStrs = Trinity::Tokenize(str, ' ', false); + if (colorStrs.size() != NUM_ENABLED_LOG_LEVELS) { - ss >> color[i]; - - if (!ss) - return; - - if (color[i] < 0 || color[i] >= MaxColors) - return; + throw InvalidAppenderArgsException(Trinity::StringFormat("Log::CreateAppenderFromConfig: Invalid color data '%s' for console appender %s (expected %u entries, got %zu)", + std::string(str).c_str(), name.c_str(), NUM_ENABLED_LOG_LEVELS, colorStrs.size())); } for (uint8 i = 0; i < NUM_ENABLED_LOG_LEVELS; ++i) - _colors[i] = ColorTypes(color[i]); + { + if (Optional<uint8> color = Trinity::StringTo<uint8>(colorStrs[i]); color && EnumUtils::IsValid<ColorTypes>(*color)) + _colors[i] = static_cast<ColorTypes>(*color); + else + { + throw InvalidAppenderArgsException(Trinity::StringFormat("Log::CreateAppenderFromConfig: Invalid color '%s' for log level %s on console appender %s", + std::string(colorStrs[i]).c_str(), EnumUtils::ToTitle(static_cast<LogLevel>(i)), name.c_str())); + } + } _colored = true; } @@ -66,7 +69,7 @@ void AppenderConsole::InitColors(std::string const& str) void AppenderConsole::SetColor(bool stdout_stream, ColorTypes color) { #if TRINITY_PLATFORM == TRINITY_PLATFORM_WINDOWS - static WORD WinColorFG[MaxColors] = + static WORD WinColorFG[NUM_COLOR_TYPES] = { 0, // BLACK FOREGROUND_RED, // RED @@ -127,7 +130,7 @@ void AppenderConsole::SetColor(bool stdout_stream, ColorTypes color) BG_WHITE }; - static uint8 UnixColorFG[MaxColors] = + static uint8 UnixColorFG[NUM_COLOR_TYPES] = { FG_BLACK, // BLACK FG_RED, // RED @@ -146,7 +149,7 @@ void AppenderConsole::SetColor(bool stdout_stream, ColorTypes color) FG_WHITE // LWHITE }; - fprintf((stdout_stream? stdout : stderr), "\x1b[%d%sm", UnixColorFG[color], (color >= YELLOW && color < MaxColors ? ";1" : "")); + fprintf((stdout_stream? stdout : stderr), "\x1b[%d%sm", UnixColorFG[color], (color >= YELLOW && color < NUM_COLOR_TYPES ? ";1" : "")); #endif } diff --git a/src/common/Logging/AppenderConsole.h b/src/common/Logging/AppenderConsole.h index 72c2bf98e10..6c6be4b6c59 100644 --- a/src/common/Logging/AppenderConsole.h +++ b/src/common/Logging/AppenderConsole.h @@ -20,6 +20,7 @@ #include "Appender.h" +// EnumUtils: DESCRIBE THIS enum ColorTypes { BLACK, @@ -36,19 +37,18 @@ enum ColorTypes LBLUE, LMAGENTA, LCYAN, - WHITE + WHITE, + NUM_COLOR_TYPES // SKIP }; -const uint8 MaxColors = uint8(WHITE) + 1; - class TC_COMMON_API AppenderConsole : public Appender { public: - typedef std::integral_constant<AppenderType, APPENDER_CONSOLE>::type TypeIndex; + static constexpr AppenderType type = APPENDER_CONSOLE; - AppenderConsole(uint8 _id, std::string const& name, LogLevel level, AppenderFlags flags, std::vector<char const*> extraArgs); - void InitColors(const std::string& init_str); - AppenderType getType() const override { return TypeIndex::value; } + AppenderConsole(uint8 _id, std::string const& name, LogLevel level, AppenderFlags flags, std::vector<std::string_view> const& args); + void InitColors(std::string const& name, std::string_view init_str); + AppenderType getType() const override { return type; } private: void SetColor(bool stdout_stream, ColorTypes color); diff --git a/src/common/Logging/AppenderFile.cpp b/src/common/Logging/AppenderFile.cpp index 3cfd6b950a6..bb38cade4e4 100644 --- a/src/common/Logging/AppenderFile.cpp +++ b/src/common/Logging/AppenderFile.cpp @@ -18,23 +18,25 @@ #include "AppenderFile.h" #include "Log.h" #include "LogMessage.h" +#include "StringConvert.h" +#include "Util.h" #include <algorithm> -AppenderFile::AppenderFile(uint8 id, std::string const& name, LogLevel level, AppenderFlags flags, std::vector<char const*> extraArgs) : +AppenderFile::AppenderFile(uint8 id, std::string const& name, LogLevel level, AppenderFlags flags, std::vector<std::string_view> const& args) : Appender(id, name, level, flags), logfile(nullptr), _logDir(sLog->GetLogsDir()), _maxFileSize(0), _fileSize(0) { - if (extraArgs.empty()) - throw InvalidAppenderArgsException(Trinity::StringFormat("Log::CreateAppenderFromConfig: Missing file name for appender %s\n", name.c_str())); + if (args.size() < 4) + throw InvalidAppenderArgsException(Trinity::StringFormat("Log::CreateAppenderFromConfig: Missing file name for appender %s", name.c_str())); - _fileName = extraArgs[0]; + _fileName.assign(args[3]); - char const* mode = "a"; - if (extraArgs.size() > 1) - mode = extraArgs[1]; + std::string mode = "a"; + if (4 < args.size()) + mode.assign(args[4]); if (flags & APPENDER_FLAGS_USE_TIMESTAMP) { @@ -45,14 +47,19 @@ AppenderFile::AppenderFile(uint8 id, std::string const& name, LogLevel level, Ap _fileName += sLog->GetLogsTimestamp(); } - if (extraArgs.size() > 2) - _maxFileSize = atoi(extraArgs[2]); + if (5 < args.size()) + { + if (Optional<uint32> size = Trinity::StringTo<uint32>(args[5])) + _maxFileSize = *size; + else + throw InvalidAppenderArgsException(Trinity::StringFormat("Log::CreateAppenderFromConfig: Invalid size '%s' for appender %s", std::string(args[5]).c_str(), name.c_str())); + } _dynamicName = std::string::npos != _fileName.find("%s"); _backup = (flags & APPENDER_FLAGS_MAKE_FILE_BACKUP) != 0; if (!_dynamicName) - logfile = OpenFile(_fileName, mode, !strcmp(mode, "w") && _backup); + logfile = OpenFile(_fileName, mode, (mode == "w") && _backup); } AppenderFile::~AppenderFile() diff --git a/src/common/Logging/AppenderFile.h b/src/common/Logging/AppenderFile.h index a320e90eb2b..c360e81a2ae 100644 --- a/src/common/Logging/AppenderFile.h +++ b/src/common/Logging/AppenderFile.h @@ -24,12 +24,12 @@ class TC_COMMON_API AppenderFile : public Appender { public: - typedef std::integral_constant<AppenderType, APPENDER_FILE>::type TypeIndex; + static constexpr AppenderType type = APPENDER_FILE; - AppenderFile(uint8 id, std::string const& name, LogLevel level, AppenderFlags flags, std::vector<char const*> extraArgs); + AppenderFile(uint8 id, std::string const& name, LogLevel level, AppenderFlags flags, std::vector<std::string_view> const& args); ~AppenderFile(); FILE* OpenFile(std::string const& name, std::string const& mode, bool backup); - AppenderType getType() const override { return TypeIndex::value; } + AppenderType getType() const override { return type; } private: void CloseFile(); diff --git a/src/common/Logging/Log.cpp b/src/common/Logging/Log.cpp index 6c364105a7b..fba5ac84aaf 100644 --- a/src/common/Logging/Log.cpp +++ b/src/common/Logging/Log.cpp @@ -25,6 +25,7 @@ #include "LogMessage.h" #include "LogOperation.h" #include "Strand.h" +#include "StringConvert.h" #include "Util.h" #include <chrono> #include <sstream> @@ -47,7 +48,7 @@ uint8 Log::NextAppenderId() return AppenderId++; } -Appender* Log::GetAppenderByName(std::string const& name) +Appender* Log::GetAppenderByName(std::string_view name) { auto it = appenders.begin(); while (it != appenders.end() && it->second && it->second->getName() != name) @@ -65,10 +66,9 @@ void Log::CreateAppenderFromConfigLine(std::string const& appenderName, std::str // if type = File. optional1 = file and option2 = mode // if type = Console. optional1 = Color - Tokenizer tokens(options, ','); - auto iter = tokens.begin(); + std::vector<std::string_view> tokens = Trinity::Tokenize(options, ',', true); - size_t size = tokens.size(); + size_t const size = tokens.size(); std::string name = appenderName.substr(9); if (size < 2) @@ -78,33 +78,41 @@ void Log::CreateAppenderFromConfigLine(std::string const& appenderName, std::str } AppenderFlags flags = APPENDER_FLAGS_NONE; - AppenderType type = AppenderType(atoi(*iter++)); - LogLevel level = LogLevel(atoi(*iter++)); + AppenderType type = AppenderType(Trinity::StringTo<uint8>(tokens[0]).value_or(APPENDER_INVALID)); + LogLevel level = LogLevel(Trinity::StringTo<uint8>(tokens[1]).value_or(LOG_LEVEL_INVALID)); - if (level > LOG_LEVEL_FATAL) + auto factoryFunction = appenderFactory.find(type); + if (factoryFunction == appenderFactory.end()) { - fprintf(stderr, "Log::CreateAppenderFromConfig: Wrong Log Level %d for appender %s\n", level, name.c_str()); + fprintf(stderr, "Log::CreateAppenderFromConfig: Unknown type '%s' for appender %s\n", std::string(tokens[0]).c_str(), name.c_str()); return; } - if (size > 2) - flags = AppenderFlags(atoi(*iter++)); - - auto factoryFunction = appenderFactory.find(type); - if (factoryFunction == appenderFactory.end()) + if (level > NUM_ENABLED_LOG_LEVELS) { - fprintf(stderr, "Log::CreateAppenderFromConfig: Unknown type %d for appender %s\n", type, name.c_str()); + fprintf(stderr, "Log::CreateAppenderFromConfig: Wrong Log Level '%s' for appender %s\n", std::string(tokens[1]).c_str(), name.c_str()); return; } + if (size > 2) + { + if (Optional<uint8> flagsVal = Trinity::StringTo<uint8>(tokens[2])) + flags = AppenderFlags(*flagsVal); + else + { + fprintf(stderr, "Log::CreateAppenderFromConfig: Unknown flags '%s' for appender %s\n", std::string(tokens[2]).c_str(), name.c_str()); + return; + } + } + try { - Appender* appender = factoryFunction->second(NextAppenderId(), name, level, flags, std::vector<char const*>(iter, tokens.end())); + Appender* appender = factoryFunction->second(NextAppenderId(), name, level, flags, tokens); appenders[appender->getId()].reset(appender); } catch (InvalidAppenderArgsException const& iaae) { - fprintf(stderr, "%s", iaae.what()); + fprintf(stderr, "%s\n", iaae.what()); } } @@ -119,7 +127,6 @@ void Log::CreateLoggerFromConfigLine(std::string const& loggerName, std::string return; LogLevel level = LOG_LEVEL_DISABLED; - uint8 type = uint8(-1); std::string name = loggerName.substr(7); @@ -129,8 +136,7 @@ void Log::CreateLoggerFromConfigLine(std::string const& loggerName, std::string return; } - Tokenizer tokens(options, ','); - Tokenizer::const_iterator iter = tokens.begin(); + std::vector<std::string_view> tokens = Trinity::Tokenize(options, ',', true); if (tokens.size() != 2) { @@ -145,10 +151,10 @@ void Log::CreateLoggerFromConfigLine(std::string const& loggerName, std::string return; } - level = LogLevel(atoi(*iter++)); - if (level > LOG_LEVEL_FATAL) + level = LogLevel(Trinity::StringTo<uint8>(tokens[0]).value_or(LOG_LEVEL_INVALID)); + if (level > NUM_ENABLED_LOG_LEVELS) { - fprintf(stderr, "Log::CreateLoggerFromConfig: Wrong Log Level %u for logger %s\n", type, name.c_str()); + fprintf(stderr, "Log::CreateLoggerFromConfig: Wrong Log Level '%s' for logger %s\n", std::string(tokens[0]).c_str(), name.c_str()); return; } @@ -158,20 +164,15 @@ void Log::CreateLoggerFromConfigLine(std::string const& loggerName, std::string logger = std::make_unique<Logger>(name, level); //fprintf(stdout, "Log::CreateLoggerFromConfig: Created Logger %s, Level %u\n", name.c_str(), level); - std::istringstream ss(*iter); - std::string str; - - ss >> str; - while (ss) + for (std::string_view appenderName : Trinity::Tokenize(tokens[1], ' ', false)) { - if (Appender* appender = GetAppenderByName(str)) + if (Appender* appender = GetAppenderByName(appenderName)) { logger->addAppender(appender->getId(), appender); //fprintf(stdout, "Log::CreateLoggerFromConfig: Added Appender %s to Logger %s\n", appender->getName().c_str(), name.c_str()); } else - fprintf(stderr, "Error while configuring Appender %s in Logger %s. Appender does not exist", str.c_str(), name.c_str()); - ss >> str; + fprintf(stderr, "Error while configuring Appender %s in Logger %s. Appender does not exist\n", std::string(appenderName).c_str(), name.c_str()); } } @@ -201,7 +202,7 @@ void Log::ReadLoggersFromConfig() Close(); // Clean any Logger or Appender created - AppenderConsole* appender = new AppenderConsole(NextAppenderId(), "Console", LOG_LEVEL_DEBUG, APPENDER_FLAGS_NONE, std::vector<char const*>()); + AppenderConsole* appender = new AppenderConsole(NextAppenderId(), "Console", LOG_LEVEL_DEBUG, APPENDER_FLAGS_NONE, {}); appenders[appender->getId()].reset(appender); Logger* rootLogger = new Logger(LOGGER_ROOT, LOG_LEVEL_ERROR); diff --git a/src/common/Logging/Log.h b/src/common/Logging/Log.h index a496687ab57..5ec20040187 100644 --- a/src/common/Logging/Log.h +++ b/src/common/Logging/Log.h @@ -40,12 +40,12 @@ namespace Trinity #define LOGGER_ROOT "root" -typedef Appender*(*AppenderCreatorFn)(uint8 id, std::string const& name, LogLevel level, AppenderFlags flags, std::vector<char const*>&& extraArgs); +typedef Appender*(*AppenderCreatorFn)(uint8 id, std::string const& name, LogLevel level, AppenderFlags flags, std::vector<std::string_view> const& extraArgs); template <class AppenderImpl> -Appender* CreateAppender(uint8 id, std::string const& name, LogLevel level, AppenderFlags flags, std::vector<char const*>&& extraArgs) +Appender* CreateAppender(uint8 id, std::string const& name, LogLevel level, AppenderFlags flags, std::vector<std::string_view> const& extraArgs) { - return new AppenderImpl(id, name, level, flags, std::forward<std::vector<char const*>>(extraArgs)); + return new AppenderImpl(id, name, level, flags, extraArgs); } class TC_COMMON_API Log @@ -90,8 +90,7 @@ class TC_COMMON_API Log template<class AppenderImpl> void RegisterAppender() { - using Index = typename AppenderImpl::TypeIndex; - RegisterAppender(Index::value, &CreateAppender<AppenderImpl>); + RegisterAppender(AppenderImpl::type, &CreateAppender<AppenderImpl>); } std::string const& GetLogsDir() const { return m_logsDir; } @@ -105,7 +104,7 @@ class TC_COMMON_API Log void write(std::unique_ptr<LogMessage>&& msg) const; Logger const* GetLoggerByType(std::string const& type) const; - Appender* GetAppenderByName(std::string const& name); + Appender* GetAppenderByName(std::string_view name); uint8 NextAppenderId(); void CreateAppenderFromConfig(std::string const& name); void CreateLoggerFromConfig(std::string const& name); diff --git a/src/common/Logging/LogCommon.h b/src/common/Logging/LogCommon.h index 04df9fb31d5..35844e0e0f7 100644 --- a/src/common/Logging/LogCommon.h +++ b/src/common/Logging/LogCommon.h @@ -18,7 +18,10 @@ #ifndef LogCommon_h__ #define LogCommon_h__ -enum LogLevel +#include "Define.h" + +// EnumUtils: DESCRIBE THIS +enum LogLevel : uint8 { LOG_LEVEL_DISABLED = 0, LOG_LEVEL_TRACE = 1, @@ -28,18 +31,22 @@ enum LogLevel LOG_LEVEL_ERROR = 5, LOG_LEVEL_FATAL = 6, - NUM_ENABLED_LOG_LEVELS = 6 + NUM_ENABLED_LOG_LEVELS = LOG_LEVEL_FATAL, // SKIP + LOG_LEVEL_INVALID = 0xFF // SKIP }; +// EnumUtils: DESCRIBE THIS enum AppenderType : uint8 { APPENDER_NONE, APPENDER_CONSOLE, APPENDER_FILE, - APPENDER_DB + APPENDER_DB, + + APPENDER_INVALID = 0xFF // SKIP }; -enum AppenderFlags +enum AppenderFlags : uint8 { APPENDER_FLAGS_NONE = 0x00, APPENDER_FLAGS_PREFIX_TIMESTAMP = 0x01, diff --git a/src/common/Logging/enuminfo_AppenderConsole.cpp b/src/common/Logging/enuminfo_AppenderConsole.cpp new file mode 100644 index 00000000000..1b5562b1f84 --- /dev/null +++ b/src/common/Logging/enuminfo_AppenderConsole.cpp @@ -0,0 +1,103 @@ +/* + * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "AppenderConsole.h" +#include "Define.h" +#include "SmartEnum.h" +#include <stdexcept> + +namespace Trinity::Impl::EnumUtilsImpl +{ + +/********************************************************************\ +|* data for enum 'ColorTypes' in 'AppenderConsole.h' auto-generated *| +\********************************************************************/ +template <> +TC_API_EXPORT EnumText EnumUtils<ColorTypes>::ToString(ColorTypes value) +{ + switch (value) + { + case BLACK: return { "BLACK", "BLACK", "" }; + case RED: return { "RED", "RED", "" }; + case GREEN: return { "GREEN", "GREEN", "" }; + case BROWN: return { "BROWN", "BROWN", "" }; + case BLUE: return { "BLUE", "BLUE", "" }; + case MAGENTA: return { "MAGENTA", "MAGENTA", "" }; + case CYAN: return { "CYAN", "CYAN", "" }; + case GREY: return { "GREY", "GREY", "" }; + case YELLOW: return { "YELLOW", "YELLOW", "" }; + case LRED: return { "LRED", "LRED", "" }; + case LGREEN: return { "LGREEN", "LGREEN", "" }; + case LBLUE: return { "LBLUE", "LBLUE", "" }; + case LMAGENTA: return { "LMAGENTA", "LMAGENTA", "" }; + case LCYAN: return { "LCYAN", "LCYAN", "" }; + case WHITE: return { "WHITE", "WHITE", "" }; + default: throw std::out_of_range("value"); + } +} + +template <> +TC_API_EXPORT size_t EnumUtils<ColorTypes>::Count() { return 15; } + +template <> +TC_API_EXPORT ColorTypes EnumUtils<ColorTypes>::FromIndex(size_t index) +{ + switch (index) + { + case 0: return BLACK; + case 1: return RED; + case 2: return GREEN; + case 3: return BROWN; + case 4: return BLUE; + case 5: return MAGENTA; + case 6: return CYAN; + case 7: return GREY; + case 8: return YELLOW; + case 9: return LRED; + case 10: return LGREEN; + case 11: return LBLUE; + case 12: return LMAGENTA; + case 13: return LCYAN; + case 14: return WHITE; + default: throw std::out_of_range("index"); + } +} + +template <> +TC_API_EXPORT size_t EnumUtils<ColorTypes>::ToIndex(ColorTypes value) +{ + switch (value) + { + case BLACK: return 0; + case RED: return 1; + case GREEN: return 2; + case BROWN: return 3; + case BLUE: return 4; + case MAGENTA: return 5; + case CYAN: return 6; + case GREY: return 7; + case YELLOW: return 8; + case LRED: return 9; + case LGREEN: return 10; + case LBLUE: return 11; + case LMAGENTA: return 12; + case LCYAN: return 13; + case WHITE: return 14; + default: throw std::out_of_range("value"); + } +} +} diff --git a/src/common/Logging/enuminfo_LogCommon.cpp b/src/common/Logging/enuminfo_LogCommon.cpp new file mode 100644 index 00000000000..de7d35e118e --- /dev/null +++ b/src/common/Logging/enuminfo_LogCommon.cpp @@ -0,0 +1,124 @@ +/* + * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "LogCommon.h" +#include "Define.h" +#include "SmartEnum.h" +#include <stdexcept> + +namespace Trinity::Impl::EnumUtilsImpl +{ + +/************************************************************\ +|* data for enum 'LogLevel' in 'LogCommon.h' auto-generated *| +\************************************************************/ +template <> +TC_API_EXPORT EnumText EnumUtils<LogLevel>::ToString(LogLevel value) +{ + switch (value) + { + case LOG_LEVEL_DISABLED: return { "LOG_LEVEL_DISABLED", "LOG_LEVEL_DISABLED", "" }; + case LOG_LEVEL_TRACE: return { "LOG_LEVEL_TRACE", "LOG_LEVEL_TRACE", "" }; + case LOG_LEVEL_DEBUG: return { "LOG_LEVEL_DEBUG", "LOG_LEVEL_DEBUG", "" }; + case LOG_LEVEL_INFO: return { "LOG_LEVEL_INFO", "LOG_LEVEL_INFO", "" }; + case LOG_LEVEL_WARN: return { "LOG_LEVEL_WARN", "LOG_LEVEL_WARN", "" }; + case LOG_LEVEL_ERROR: return { "LOG_LEVEL_ERROR", "LOG_LEVEL_ERROR", "" }; + case LOG_LEVEL_FATAL: return { "LOG_LEVEL_FATAL", "LOG_LEVEL_FATAL", "" }; + default: throw std::out_of_range("value"); + } +} + +template <> +TC_API_EXPORT size_t EnumUtils<LogLevel>::Count() { return 7; } + +template <> +TC_API_EXPORT LogLevel EnumUtils<LogLevel>::FromIndex(size_t index) +{ + switch (index) + { + case 0: return LOG_LEVEL_DISABLED; + case 1: return LOG_LEVEL_TRACE; + case 2: return LOG_LEVEL_DEBUG; + case 3: return LOG_LEVEL_INFO; + case 4: return LOG_LEVEL_WARN; + case 5: return LOG_LEVEL_ERROR; + case 6: return LOG_LEVEL_FATAL; + default: throw std::out_of_range("index"); + } +} + +template <> +TC_API_EXPORT size_t EnumUtils<LogLevel>::ToIndex(LogLevel value) +{ + switch (value) + { + case LOG_LEVEL_DISABLED: return 0; + case LOG_LEVEL_TRACE: return 1; + case LOG_LEVEL_DEBUG: return 2; + case LOG_LEVEL_INFO: return 3; + case LOG_LEVEL_WARN: return 4; + case LOG_LEVEL_ERROR: return 5; + case LOG_LEVEL_FATAL: return 6; + default: throw std::out_of_range("value"); + } +} + +/****************************************************************\ +|* data for enum 'AppenderType' in 'LogCommon.h' auto-generated *| +\****************************************************************/ +template <> +TC_API_EXPORT EnumText EnumUtils<AppenderType>::ToString(AppenderType value) +{ + switch (value) + { + case APPENDER_NONE: return { "APPENDER_NONE", "APPENDER_NONE", "" }; + case APPENDER_CONSOLE: return { "APPENDER_CONSOLE", "APPENDER_CONSOLE", "" }; + case APPENDER_FILE: return { "APPENDER_FILE", "APPENDER_FILE", "" }; + case APPENDER_DB: return { "APPENDER_DB", "APPENDER_DB", "" }; + default: throw std::out_of_range("value"); + } +} + +template <> +TC_API_EXPORT size_t EnumUtils<AppenderType>::Count() { return 4; } + +template <> +TC_API_EXPORT AppenderType EnumUtils<AppenderType>::FromIndex(size_t index) +{ + switch (index) + { + case 0: return APPENDER_NONE; + case 1: return APPENDER_CONSOLE; + case 2: return APPENDER_FILE; + case 3: return APPENDER_DB; + default: throw std::out_of_range("index"); + } +} + +template <> +TC_API_EXPORT size_t EnumUtils<AppenderType>::ToIndex(AppenderType value) +{ + switch (value) + { + case APPENDER_NONE: return 0; + case APPENDER_CONSOLE: return 1; + case APPENDER_FILE: return 2; + case APPENDER_DB: return 3; + default: throw std::out_of_range("value"); + } +} +} diff --git a/src/common/Metric/Metric.cpp b/src/common/Metric/Metric.cpp index b5762dbd8e2..97d68568a3f 100644 --- a/src/common/Metric/Metric.cpp +++ b/src/common/Metric/Metric.cpp @@ -89,7 +89,7 @@ void Metric::LoadFromConfigs() return; } - Tokenizer tokens(connectionInfo, ';'); + std::vector<std::string_view> tokens = Trinity::Tokenize(connectionInfo, ';', true); if (tokens.size() != 3) { TC_LOG_ERROR("metric", "'Metric.ConnectionInfo' specified with wrong format in configuration file."); diff --git a/src/common/Utilities/Util.cpp b/src/common/Utilities/Util.cpp index f3f76569d11..317f8c754f8 100644 --- a/src/common/Utilities/Util.cpp +++ b/src/common/Utilities/Util.cpp @@ -19,6 +19,7 @@ #include "Common.h" #include "Containers.h" #include "IpAddress.h" +#include "StringConvert.h" #include "StringFormat.h" #include <utf8.h> #include <algorithm> @@ -35,39 +36,22 @@ #include <arpa/inet.h> #endif -Tokenizer::Tokenizer(std::string_view src, const char sep, uint32 vectorReserve /*= 0*/, bool keepEmptyStrings /*= true*/) +std::vector<std::string_view> Trinity::Tokenize(std::string_view str, char sep, bool keepEmpty) { - m_str = new char[src.length() + 1]; - memcpy(m_str, src.data(), src.length() + 1); + std::vector<std::string_view> tokens; - if (vectorReserve) - m_storage.reserve(vectorReserve); - - char* posold = m_str; - char* posnew = m_str; - - for (;;) + size_t start = 0; + for (size_t end = str.find(sep); end != std::string_view::npos; end = str.find(sep, start)) { - if (*posnew == sep) - { - if (keepEmptyStrings || posold != posnew) - m_storage.push_back(posold); - - posold = posnew + 1; - *posnew = '\0'; - } - else if (*posnew == '\0') - { - // Hack like, but the old code accepted these kind of broken strings, - // so changing it would break other things - if (posold != posnew) - m_storage.push_back(posold); + if (keepEmpty || (start < end)) + tokens.push_back(str.substr(start, end - start)); + start = end+1; + } - break; - } + if (keepEmpty || (start < str.length())) + tokens.push_back(str.substr(start)); - ++posnew; - } + return tokens; } #if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__)) @@ -210,32 +194,43 @@ std::string secsToTimeString(uint64 timeInSecs, TimeFormat timeFormat, bool hour return ss.str(); } -int64 MoneyStringToMoney(std::string const& moneyString) +Optional<int64> MoneyStringToMoney(std::string const& moneyString) { int64 money = 0; - if (!(std::count(moneyString.begin(), moneyString.end(), 'g') == 1 || - std::count(moneyString.begin(), moneyString.end(), 's') == 1 || - std::count(moneyString.begin(), moneyString.end(), 'c') == 1)) - return 0; // Bad format + bool hadG = false; + bool hadS = false; + bool hadC = false; - Tokenizer tokens(moneyString, ' '); - for (char const* token : tokens) + for (std::string_view token : Trinity::Tokenize(moneyString, ' ', false)) { - std::string tokenString(token); - size_t gCount = std::count(tokenString.begin(), tokenString.end(), 'g'); - size_t sCount = std::count(tokenString.begin(), tokenString.end(), 's'); - size_t cCount = std::count(tokenString.begin(), tokenString.end(), 'c'); - if (gCount + sCount + cCount != 1) - return 0; - - uint64 amount = strtoull(token, nullptr, 10); - if (gCount == 1) - money += amount * 100 * 100; - else if (sCount == 1) - money += amount * 100; - else if (cCount == 1) - money += amount; + uint32 unit; + switch (token[token.length() - 1]) + { + case 'g': + if (hadG) return std::nullopt; + hadG = true; + unit = 100 * 100; + break; + case 's': + if (hadS) return std::nullopt; + hadS = true; + unit = 100; + break; + case 'c': + if (hadC) return std::nullopt; + hadC = true; + unit = 1; + break; + default: + return std::nullopt; + } + + Optional<uint64> amount = Trinity::StringTo<uint32>(token.substr(0, token.length() - 1)); + if (amount) + money += (unit * *amount); + else + return std::nullopt; } return money; diff --git a/src/common/Utilities/Util.h b/src/common/Utilities/Util.h index 28d0285d74d..8708405882e 100644 --- a/src/common/Utilities/Util.h +++ b/src/common/Utilities/Util.h @@ -37,35 +37,19 @@ enum class TimeFormat : uint8 Numeric // 1:2:3:4 }; -class TC_COMMON_API Tokenizer +namespace Trinity { -public: - typedef std::vector<char const*> StorageType; - - typedef StorageType::size_type size_type; - - typedef StorageType::const_iterator const_iterator; - typedef StorageType::reference reference; - typedef StorageType::const_reference const_reference; - -public: - Tokenizer(std::string_view src, char const sep, uint32 vectorReserve = 0, bool keepEmptyStrings = true); - ~Tokenizer() { delete[] m_str; } + TC_COMMON_API std::vector<std::string_view> Tokenize(std::string_view str, char sep, bool keepEmpty); - const_iterator begin() const { return m_storage.begin(); } - const_iterator end() const { return m_storage.end(); } + /* this would return string_view into temporary otherwise */ + std::vector<std::string_view> Tokenize(std::string&&, char, bool) = delete; + std::vector<std::string_view> Tokenize(std::string const&&, char, bool) = delete; - size_type size() const { return m_storage.size(); } - - reference operator [] (size_type i) { return m_storage[i]; } - const_reference operator [] (size_type i) const { return m_storage[i]; } - -private: - char* m_str; - StorageType m_storage; -}; + /* the delete overload means we need to make this explicit */ + inline std::vector<std::string_view> Tokenize(char const* str, char sep, bool keepEmpty) { return Tokenize(std::string_view(str ? str : ""), sep, keepEmpty); } +} -TC_COMMON_API int64 MoneyStringToMoney(std::string const& moneyString); +TC_COMMON_API Optional<int64> MoneyStringToMoney(std::string const& moneyString); TC_COMMON_API struct tm* localtime_r(time_t const* time, struct tm *result); TC_COMMON_API time_t LocalTimeToUTCTime(time_t time); 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 96b00648ffa..2f41da9b70f 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/Achievements/AchievementMgr.cpp b/src/server/game/Achievements/AchievementMgr.cpp index cbc73da75e5..6affb4cb5ed 100644 --- a/src/server/game/Achievements/AchievementMgr.cpp +++ b/src/server/game/Achievements/AchievementMgr.cpp @@ -33,6 +33,7 @@ #include "Mail.h" #include "ObjectMgr.h" #include "RBAC.h" +#include "StringConvert.h" #include "World.h" #include "WorldSession.h" #include <sstream> @@ -756,9 +757,9 @@ void GuildAchievementMgr::LoadFromDB(PreparedQueryResult achievementResult, Prep CompletedAchievementData& ca = _completedAchievements[achievementid]; ca.Date = fields[1].GetInt64(); - Tokenizer guids(fields[2].GetString(), ' '); - for (uint32 i = 0; i < guids.size(); ++i) - ca.CompletingPlayers.insert(ObjectGuid::Create<HighGuid::Player>(uint64(strtoull(guids[i], nullptr, 10)))); + for (std::string_view guid : Trinity::Tokenize(fields[2].GetStringView(), ' ', false)) + if (Optional<ObjectGuid::LowType> parsedGuid = Trinity::StringTo<ObjectGuid::LowType>(guid)) + ca.CompletingPlayers.insert(ObjectGuid::Create<HighGuid::Player>(*parsedGuid)); ca.Changed = false; diff --git a/src/server/game/BlackMarket/BlackMarketMgr.cpp b/src/server/game/BlackMarket/BlackMarketMgr.cpp index a0a595c3616..f543f14bfe1 100644 --- a/src/server/game/BlackMarket/BlackMarketMgr.cpp +++ b/src/server/game/BlackMarket/BlackMarketMgr.cpp @@ -30,6 +30,7 @@ #include "ObjectMgr.h" #include "Player.h" #include "Realm.h" +#include "StringConvert.h" #include "World.h" #include "WorldSession.h" #include <sstream> @@ -368,10 +369,10 @@ bool BlackMarketTemplate::LoadFromDB(Field* fields) Duration = static_cast<time_t>(fields[5].GetUInt32()); Chance = fields[6].GetFloat(); - Tokenizer bonusListIDsTok(fields[7].GetString(), ' '); std::vector<int32> bonusListIDs; - for (char const* token : bonusListIDsTok) - bonusListIDs.push_back(int32(atol(token))); + for (std::string_view token : Trinity::Tokenize(fields[7].GetStringView(), ' ', false)) + if (Optional<int32> bonusListID = Trinity::StringTo<int32>(token)) + bonusListIDs.push_back(*bonusListID); if (!bonusListIDs.empty()) { diff --git a/src/server/game/Chat/Channels/Channel.cpp b/src/server/game/Chat/Channels/Channel.cpp index 7f5a6cc8aec..46a4df0df76 100644 --- a/src/server/game/Chat/Channels/Channel.cpp +++ b/src/server/game/Chat/Channels/Channel.cpp @@ -31,6 +31,7 @@ #include "ObjectMgr.h" #include "Player.h" #include "SocialMgr.h" +#include "StringConvert.h" #include "World.h" #include "WorldSession.h" #include <sstream> @@ -73,11 +74,10 @@ Channel::Channel(ObjectGuid const& guid, std::string const& name, uint32 team /* _channelName(name), _zoneEntry(nullptr) { - Tokenizer tokens(banList, ' '); - for (auto const& token : tokens) + for (std::string_view guid : Trinity::Tokenize(banList, ' ', false)) { // legacy db content might not have 0x prefix, account for that - std::string bannedGuidStr(memcmp(token, "0x", 2) ? token + 2 : token); + std::string bannedGuidStr(guid.size() > 2 && guid.substr(0, 2) == "0x" ? guid.substr(2) : guid); ObjectGuid banned; banned.SetRawValue(uint64(strtoull(bannedGuidStr.substr(0, 16).c_str(), nullptr, 16)), uint64(strtoull(bannedGuidStr.substr(16).c_str(), nullptr, 16))); if (!banned) diff --git a/src/server/game/Chat/Chat.cpp b/src/server/game/Chat/Chat.cpp index 3a0e77bd294..75acbffcbd3 100644 --- a/src/server/game/Chat/Chat.cpp +++ b/src/server/game/Chat/Chat.cpp @@ -180,7 +180,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] << "||"; @@ -190,7 +190,7 @@ void ChatHandler::SendSysMessage(const char *str, bool escapeCharacters) } WorldPackets::Chat::Chat packet; - for (const auto& line : Tokenizer{msg, '\n'}) + for (std::string_view line : Trinity::Tokenize(str, '\n', true)) { packet.Initialize(CHAT_MSG_SYSTEM, LANG_UNIVERSAL, nullptr, nullptr, line); m_session->SendPacket(packet.Write()); @@ -200,7 +200,7 @@ void ChatHandler::SendSysMessage(const char *str, bool escapeCharacters) void ChatHandler::SendGlobalSysMessage(const char *str) { WorldPackets::Chat::Chat packet; - for (const auto& line : Tokenizer{str, '\n'}) + for (std::string_view line : Trinity::Tokenize(str, '\n', true)) { packet.Initialize(CHAT_MSG_SYSTEM, LANG_UNIVERSAL, nullptr, nullptr, line); sWorld->SendGlobalMessage(packet.Write()); @@ -210,7 +210,7 @@ void ChatHandler::SendGlobalSysMessage(const char *str) void ChatHandler::SendGlobalGMSysMessage(const char *str) { WorldPackets::Chat::Chat packet; - for (const auto& line : Tokenizer{str, '\n'}) + for (std::string_view line : Trinity::Tokenize(str, '\n', true)) { packet.Initialize(CHAT_MSG_SYSTEM, LANG_UNIVERSAL, nullptr, nullptr, line); sWorld->SendGlobalGMMessage(packet.Write()); diff --git a/src/server/game/Chat/LanguageMgr.cpp b/src/server/game/Chat/LanguageMgr.cpp index ec2a65f9013..c30cfa9b965 100644 --- a/src/server/game/Chat/LanguageMgr.cpp +++ b/src/server/game/Chat/LanguageMgr.cpp @@ -216,13 +216,12 @@ std::string LanguageMgr::Translate(std::string const& msg, uint32 language, Loca std::string result; result.reserve(textToTranslate.length()); - Tokenizer tokens(textToTranslate, ' '); - for (char const* str : tokens) + for (std::string_view str : Trinity::Tokenize(textToTranslate, ' ', false)) { - uint32 wordLen = std::min(18u, uint32(strlen(str))); + uint32 wordLen = std::min(18u, uint32(str.length())); if (LanguageMgr::WordList const* wordGroup = FindWordGroup(language, wordLen)) { - uint32 wordHash = SStrHash(str, true); + uint32 wordHash = SStrHash(str.data(), true); uint8 idxInsideGroup = wordHash % wordGroup->size(); char const* replacementWord = (*wordGroup)[idxInsideGroup]; @@ -233,7 +232,7 @@ std::string LanguageMgr::Translate(std::string const& msg, uint32 language, Loca case LOCALE_zhCN: case LOCALE_zhTW: { - size_t length = std::min(strlen(str), strlen(replacementWord)); + size_t length = std::min(str.length(), strlen(replacementWord)); for (size_t i = 0; i < length; ++i) { if (str[i] >= 'A' && str[i] <= 'Z') diff --git a/src/server/game/Conditions/DisableMgr.cpp b/src/server/game/Conditions/DisableMgr.cpp index d3ba318cc1a..15af1065d2a 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" @@ -109,16 +110,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/DataStores/GameTables.cpp b/src/server/game/DataStores/GameTables.cpp index d77b805d404..ba847f9197d 100644 --- a/src/server/game/DataStores/GameTables.cpp +++ b/src/server/game/DataStores/GameTables.cpp @@ -55,7 +55,7 @@ inline uint32 LoadGameTable(std::vector<std::string>& errors, GameTable<T>& stor return 0; } - Tokenizer columnDefs(headers, '\t', 0, false); + std::vector<std::string_view> columnDefs = Trinity::Tokenize(headers, '\t', false); ASSERT(columnDefs.size() - 1 == sizeof(T) / sizeof(float), "GameTable '%s' has different count of columns " SZFMTD " than expected by size of C++ structure (" SZFMTD ").", @@ -67,13 +67,13 @@ inline uint32 LoadGameTable(std::vector<std::string>& errors, GameTable<T>& stor std::string line; while (std::getline(stream, line)) { - Tokenizer values(line, '\t', uint32(columnDefs.size())); - if (!values.size()) + std::vector<std::string_view> values = Trinity::Tokenize(line, '\t', true); + if (values.empty()) break; // make end point just after last nonempty token auto end = values.begin() + values.size() - 1; - while (!strlen(*end) && end != values.begin()) + while (end->empty() && end != values.begin()) --end; if (values.begin() == end) @@ -91,7 +91,7 @@ inline uint32 LoadGameTable(std::vector<std::string>& errors, GameTable<T>& stor data.emplace_back(); float* row = reinterpret_cast<float*>(&data.back()); for (auto itr = values.begin() + 1; itr != end; ++itr) - *row++ = strtof(*itr, nullptr); + *row++ = strtof(itr->data(), nullptr); } storage.SetData(std::move(data)); diff --git a/src/server/game/Entities/Corpse/Corpse.cpp b/src/server/game/Entities/Corpse/Corpse.cpp index 5fabe946041..2a6abe5a30a 100644 --- a/src/server/game/Entities/Corpse/Corpse.cpp +++ b/src/server/game/Entities/Corpse/Corpse.cpp @@ -26,6 +26,7 @@ #include "ObjectAccessor.h" #include "PhasingHandler.h" #include "Player.h" +#include "StringConvert.h" #include "UpdateData.h" #include "World.h" #include <sstream> @@ -185,10 +186,10 @@ bool Corpse::LoadCorpseFromDB(ObjectGuid::LowType guid, Field* fields) SetObjectScale(1.0f); SetDisplayId(fields[5].GetUInt32()); - Tokenizer items(fields[6].GetString(), ' ', EQUIPMENT_SLOT_END); + std::vector<std::string_view> items = Trinity::Tokenize(fields[6].GetStringView(), ' ', EQUIPMENT_SLOT_END); if (items.size() == EQUIPMENT_SLOT_END) for (uint32 index = 0; index < EQUIPMENT_SLOT_END; ++index) - SetItem(index, atoul(items[index])); + SetItem(index, Trinity::StringTo<uint32>(items[index]).value_or(0)); SetRace(fields[7].GetUInt8()); SetClass(fields[8].GetUInt8()); diff --git a/src/server/game/Entities/Item/Item.cpp b/src/server/game/Entities/Item/Item.cpp index 83725a16a78..8912559e0f0 100644 --- a/src/server/game/Entities/Item/Item.cpp +++ b/src/server/game/Entities/Item/Item.cpp @@ -40,6 +40,7 @@ #include "ScriptMgr.h" #include "SpellInfo.h" #include "SpellMgr.h" +#include "StringConvert.h" #include "TradeData.h" #include "UpdateData.h" #include "World.h" @@ -846,7 +847,10 @@ bool Item::LoadFromDB(ObjectGuid::LowType guid, ObjectGuid ownerGuid, Field* fie 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; + } _bonusData.Initialize(proto); @@ -900,17 +904,18 @@ bool Item::LoadFromDB(ObjectGuid::LowType guid, ObjectGuid ownerGuid, Field* fie SetContext(ItemContext(fields[17].GetUInt8())); - Tokenizer bonusListString(fields[18].GetString(), ' '); + std::vector<std::string_view> bonusListString = Trinity::Tokenize(fields[18].GetStringView(), ' ', false); std::vector<int32> bonusListIDs; bonusListIDs.reserve(bonusListString.size()); - for (char const* token : bonusListString) - bonusListIDs.push_back(atoi(token)); + for (std::string_view token : bonusListString) + if (Optional<int32> bonusListID = Trinity::StringTo<int32>(token)) + bonusListIDs.push_back(*bonusListID); SetBonuses(std::move(bonusListIDs)); // load charges after bonuses, they can add more item effects - Tokenizer tokens(fields[6].GetString(), ' ', proto->Effects.size()); + std::vector<std::string_view> tokens = Trinity::Tokenize(fields[6].GetStringView(), ' ', false); for (uint8 i = 0; i < m_itemData->SpellCharges.size() && i < _bonusData.EffectCount && i < tokens.size(); ++i) - SetSpellCharges(i, atoi(tokens[i])); + SetSpellCharges(i, Trinity::StringTo<int32>(tokens[i]).value_or(0)); SetModifier(ITEM_MODIFIER_TRANSMOG_APPEARANCE_ALL_SPECS, fields[19].GetUInt32()); SetModifier(ITEM_MODIFIER_TRANSMOG_APPEARANCE_SPEC_1, fields[20].GetUInt32()); @@ -939,11 +944,11 @@ bool Item::LoadFromDB(ObjectGuid::LowType guid, ObjectGuid ownerGuid, Field* fie for (uint32 i = 0; i < MAX_GEM_SOCKETS; ++i) { gemData[i].ItemId = fields[37 + i * gemFields].GetUInt32(); - Tokenizer gemBonusListIDs(fields[38 + i * gemFields].GetString(), ' '); + std::vector<std::string_view> gemBonusListIDs = Trinity::Tokenize(fields[38 + i * gemFields].GetStringView(), ' ', false); uint32 b = 0; - for (char const* token : gemBonusListIDs) - if (uint32 bonusListID = atoul(token)) - gemData[i].BonusListIDs[b++] = bonusListID; + for (std::string_view token : gemBonusListIDs) + if (Optional<uint16> bonusListID = Trinity::StringTo<uint16>(token)) + gemData[i].BonusListIDs[b++] = *bonusListID; gemData[i].Context = fields[39 + i * gemFields].GetUInt8(); if (gemData[i].ItemId) @@ -954,15 +959,15 @@ bool Item::LoadFromDB(ObjectGuid::LowType guid, ObjectGuid ownerGuid, Field* fie SetModifier(ITEM_MODIFIER_ARTIFACT_KNOWLEDGE_LEVEL, fields[50].GetUInt32()); // Enchants must be loaded after all other bonus/scaling data - Tokenizer enchantmentTokens(fields[8].GetString(), ' '); + std::vector<std::string_view> enchantmentTokens = Trinity::Tokenize(fields[8].GetStringView(), ' ', false); if (enchantmentTokens.size() == MAX_ENCHANTMENT_SLOT * MAX_ENCHANTMENT_OFFSET) { for (uint32 i = 0; i < MAX_ENCHANTMENT_SLOT; ++i) { auto enchantmentField = m_values.ModifyValue(&Item::m_itemData).ModifyValue(&UF::ItemData::Enchantment, i); - SetUpdateFieldValue(enchantmentField.ModifyValue(&UF::ItemEnchantment::ID), atoul(enchantmentTokens[i * MAX_ENCHANTMENT_OFFSET + 0])); - SetUpdateFieldValue(enchantmentField.ModifyValue(&UF::ItemEnchantment::Duration), atoul(enchantmentTokens[i * MAX_ENCHANTMENT_OFFSET + 1])); - SetUpdateFieldValue(enchantmentField.ModifyValue(&UF::ItemEnchantment::Charges), atoi(enchantmentTokens[i * MAX_ENCHANTMENT_OFFSET + 2])); + SetUpdateFieldValue(enchantmentField.ModifyValue(&UF::ItemEnchantment::ID), Trinity::StringTo<int32>(enchantmentTokens[i * MAX_ENCHANTMENT_OFFSET + 0]).value_or(0)); + SetUpdateFieldValue(enchantmentField.ModifyValue(&UF::ItemEnchantment::Duration), Trinity::StringTo<uint32>(enchantmentTokens[i * MAX_ENCHANTMENT_OFFSET + 1]).value_or(0)); + SetUpdateFieldValue(enchantmentField.ModifyValue(&UF::ItemEnchantment::Charges), Trinity::StringTo<int16>(enchantmentTokens[i * MAX_ENCHANTMENT_OFFSET + 2]).value_or(0)); } } m_randomBonusListId = fields[9].GetUInt32(); diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp index fe8e65b22d2..0831c4e4fb4 100644 --- a/src/server/game/Entities/Object/Object.cpp +++ b/src/server/game/Entities/Object/Object.cpp @@ -45,6 +45,7 @@ #include "SpellAuraEffects.h" #include "SpellMgr.h" #include "SpellPackets.h" +#include "StringConvert.h" #include "TemporarySummon.h" #include "Totem.h" #include "Transport.h" diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index a8ceac5faf8..be54db2944e 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -110,6 +110,7 @@ #include "SpellHistory.h" #include "SpellMgr.h" #include "SpellPackets.h" +#include "StringConvert.h" #include "TalentPackets.h" #include "ToyPackets.h" #include "TradeData.h" @@ -6523,7 +6524,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; @@ -17610,7 +17611,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; } @@ -17782,23 +17783,6 @@ void Player::SendPlayerBound(ObjectGuid const& binderGuid, uint32 areaId) const 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(); @@ -17811,7 +17795,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; } @@ -17970,13 +17954,13 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder* holder) // player should be able to load/delete character only with correct account! if (fields.account != 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(), fields.account); + 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(), fields.account); 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; } @@ -18000,7 +17984,7 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder* holder) if (!IsValidGender(fields.gender)) { - TC_LOG_ERROR("entities.player", "Player::LoadFromDB: Player (%s) has wrong gender (%u), can't load.", guid.ToString().c_str(), uint32(fields.gender)); + TC_LOG_ERROR("entities.player.loading", "Player::LoadFromDB: Player (%s) has wrong gender (%u), can't load.", guid.ToString().c_str(), uint32(fields.gender)); return false; } @@ -18012,26 +17996,23 @@ 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.level, false); SetXP(fields.xp); - Tokenizer exploredZones(fields.exploredZones, ' '); + std::vector<std::string_view> exploredZones = Trinity::Tokenize(fields.exploredZones, ' ', false); if (exploredZones.size() == PLAYER_EXPLORED_ZONES_SIZE * 2) for (std::size_t i = 0; i < exploredZones.size(); ++i) SetUpdateFieldFlagValue(m_values.ModifyValue(&Player::m_activePlayerData).ModifyValue(&UF::ActivePlayerData::ExploredZones, i / 2), - (uint64(atoul(exploredZones[i])) << (32 * (i % 2)))); + Trinity::StringTo<uint64>(exploredZones[i]).value_or(UI64LIT(0)) << (32 * (i % 2))); - Tokenizer knownTitles(fields.knownTitles, ' '); - if (!(knownTitles.size() % 2)) - { - for (std::size_t i = 0; i < knownTitles.size(); ++i) - SetUpdateFieldFlagValue(m_values.ModifyValue(&Player::m_activePlayerData).ModifyValue(&UF::ActivePlayerData::KnownTitles, i / 2), - (uint64(atoul(knownTitles[i])) << (32 * (i % 2)))); - } + std::vector<std::string_view> knownTitles = Trinity::Tokenize(fields.knownTitles, ' ', false); + for (std::size_t i = 0; i < knownTitles.size(); ++i) + SetUpdateFieldFlagValue(m_values.ModifyValue(&Player::m_activePlayerData).ModifyValue(&UF::ActivePlayerData::KnownTitles, i / 2), + Trinity::StringTo<uint64>(knownTitles[i]).value_or(UI64LIT(0)) << (32 * (i % 2))); SetObjectScale(1.0f); SetHoverHeight(1.0f); @@ -18069,7 +18050,7 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder* holder) if (!GetSession()->ValidateAppearance(Races(GetRace()), Classes(GetClass()), fields.gender, MakeChrCustomizationChoiceRange(customizations))) { - 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; } @@ -18114,7 +18095,7 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder* holder) SetRaidDifficultyID(CheckLoadedRaidDifficultyID(fields.raidDifficulty)); SetLegacyRaidDifficultyID(CheckLoadedLegacyRaidDifficultyID(fields.legacyRaidDifficulty)); -#define RelocateToHomebind(){ mapId = m_homebind.GetMapId(); instanceId = 0; WorldRelocate(m_homebind); } + auto RelocateToHomebind = [this, &mapId, &instanceId]() { mapId = m_homebind.GetMapId(); instanceId = 0; WorldRelocate(m_homebind); }; _LoadGroup(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_GROUP)); @@ -18133,7 +18114,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(); } @@ -18179,7 +18160,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(); } @@ -18211,7 +18192,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(); @@ -18228,7 +18209,7 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder* holder) } else { - TC_LOG_ERROR("entities.player", "Player::LoadFromDB: Player (%s) has problems with transport guid (" UI64FMTD "). Teleport to bind location.", + TC_LOG_ERROR("entities.player.loading", "Player::LoadFromDB: Player (%s) has problems with transport guid (" UI64FMTD "). Teleport to bind location.", guid.ToString().c_str(), fields.transguid); RelocateToHomebind(); @@ -18254,12 +18235,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(), fields.taxi_path.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(), fields.taxi_path.c_str()); mapId = nodeEntry->ContinentID; Relocate(nodeEntry->Pos.X, nodeEntry->Pos.Y, nodeEntry->Pos.Z, 0.0f); } @@ -18365,7 +18346,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; } @@ -18409,7 +18390,8 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder* holder) SetTalentResetCost(fields.resettalents_cost); SetTalentResetTime(fields.resettalents_time); - m_taxi.LoadTaxiMask(fields.taximask); // must be before InitTaxiNodesForLevel + if (!m_taxi.LoadTaxiMask(fields.taximask)) // 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.taximask.c_str()); uint32 extraflags = fields.extra_flags; @@ -19161,9 +19143,9 @@ void Player::_LoadVoidStorage(PreparedQueryResult result) uint32 artifactKnowledgeLevel = fields[6].GetUInt32(); ItemContext context = ItemContext(fields[7].GetUInt8()); std::vector<int32> bonusListIDs; - Tokenizer bonusListIdTokens(fields[8].GetString(), ' '); - for (char const* token : bonusListIdTokens) - bonusListIDs.push_back(atoul(token)); + for (std::string_view bonusListIDtoken : Trinity::Tokenize(fields[8].GetStringView(), ' ', false)) + if (Optional<int32> bonusListID = Trinity::StringTo<int32>(bonusListIDtoken)) + bonusListIDs.push_back(*bonusListID); if (!itemId) { @@ -19253,7 +19235,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->RemoveItemFlag(ITEM_FIELD_FLAG_REFUNDABLE); } @@ -19265,11 +19247,9 @@ Item* Player::_LoadItem(CharacterDatabaseTransaction& trans, uint32 zoneId, uint stmt->setUInt64(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>(uint64(strtoull(*itr, nullptr, 10)))); + for (std::string_view guidStr : Trinity::Tokenize((*result)[0].GetStringView(), ' ', false)) + looters.insert(ObjectGuid::Create<HighGuid::Player>(Trinity::StringTo<uint64>(guidStr).value_or(UI64LIT(0)))); if (looters.size() > 1 && item->GetTemplate()->GetMaxStackSize() == 1 && item->IsSoulBound()) { @@ -19281,7 +19261,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->RemoveItemFlag(ITEM_FIELD_FLAG_BOP_TRADEABLE); } @@ -21650,17 +21630,6 @@ void Player::SavePositionInDB(WorldLocation const& loc, uint16 zoneId, ObjectGui CharacterDatabase.ExecuteOrAppend(trans, stmt); } -void Player::SetUInt32ValueInArray(Tokenizer& Tokenizer, uint16 index, uint32 value) -{ - char buf[11]; - snprintf(buf, 11, "%u", value); - - if (index >= Tokenizer.size()) - return; - - Tokenizer[index] = buf; -} - void Player::SendAttackSwingCantAttack() const { SendDirectMessage(WorldPackets::Combat::AttackSwingError(WorldPackets::Combat::AttackSwingError::CantAttack).Write()); diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 8efa94ff758..f79818ffec8 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -1664,8 +1664,6 @@ class TC_GAME_API Player : public Unit, public GridObject<Player> bool LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder* holder); bool IsLoading() const override; - 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); @@ -1684,7 +1682,6 @@ class TC_GAME_API Player : public Unit, public GridObject<Player> static void SaveCustomizations(CharacterDatabaseTransaction trans, ObjectGuid::LowType guid, Trinity::IteratorPair<UF::ChrCustomizationChoice const*> customizations); - static void SetUInt32ValueInArray(Tokenizer& data, uint16 index, uint32 value); static void SavePositionInDB(WorldLocation const& loc, uint16 zoneId, ObjectGuid guid, CharacterDatabaseTransaction& trans); static void DeleteFromDB(ObjectGuid playerguid, uint32 accountId, bool updateRealmChars = true, bool deleteFinally = false); diff --git a/src/server/game/Entities/Player/PlayerTaxi.cpp b/src/server/game/Entities/Player/PlayerTaxi.cpp index 7bd13b6c759..729edb9dfb4 100644 --- a/src/server/game/Entities/Player/PlayerTaxi.cpp +++ b/src/server/game/Entities/Player/PlayerTaxi.cpp @@ -19,6 +19,7 @@ #include "DB2Stores.h" #include "ObjectMgr.h" #include "Player.h" +#include "StringConvert.h" #include "TaxiPackets.h" #include <limits> #include <sstream> @@ -95,16 +96,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, ' '); - - std::size_t 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 (size_t 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(WorldPackets::Taxi::ShowTaxiNodes& data, bool all) @@ -125,16 +136,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 fd962967f8b..16a238a02da 100644 --- a/src/server/game/Entities/Player/PlayerTaxi.h +++ b/src/server/game/Entities/Player/PlayerTaxi.h @@ -40,7 +40,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 { @@ -64,7 +64,7 @@ class TC_GAME_API PlayerTaxi TaxiMask const& GetTaxiMask() const { return m_taximask; } // 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 c5bee109aff..c4206927bbe 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -75,6 +75,7 @@ #include "SpellInfo.h" #include "SpellMgr.h" #include "SpellPackets.h" +#include "StringConvert.h" #include "TemporarySummon.h" #include "Totem.h" #include "Transport.h" @@ -9531,29 +9532,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(), _unit->GetMap()->GetDifficultyID()); - if (!spelInfo) + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(PetActionBar[index].GetAction(), _unit->GetMap()->GetDifficultyID()); + 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 60babf771db..f19ca62a94d 100644 --- a/src/server/game/Entities/Unit/UnitDefines.h +++ b/src/server/game/Entities/Unit/UnitDefines.h @@ -370,7 +370,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/Events/GameEventMgr.cpp b/src/server/game/Events/GameEventMgr.cpp index 0450104364f..d27b7b12a4e 100644 --- a/src/server/game/Events/GameEventMgr.cpp +++ b/src/server/game/Events/GameEventMgr.cpp @@ -30,6 +30,7 @@ #include "ObjectMgr.h" #include "Player.h" #include "PoolMgr.h" +#include "StringConvert.h" #include "World.h" #include "WorldStatePackets.h" @@ -856,9 +857,9 @@ void GameEventMgr::LoadFromDB() vItem.PlayerConditionId = fields[8].GetUInt32(); vItem.IgnoreFiltering = fields[9].GetBool(); - Tokenizer bonusListIDsTok(fields[7].GetString(), ' '); - for (char const* token : bonusListIDsTok) - vItem.BonusListIDs.push_back(int32(atol(token))); + for (std::string_view token : Trinity::Tokenize(fields[7].GetStringView(), ' ', false)) + if (Optional<int32> bonusListID = Trinity::StringTo<int32>(token)) + vItem.BonusListIDs.push_back(*bonusListID); // check validity with event's npcflag if (!sObjectMgr->IsVendorItemValid(entry, vItem, nullptr, nullptr, event_npc_flag)) diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index 67a025c4756..f92c7390848 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -58,6 +58,7 @@ #include "SpellInfo.h" #include "SpellMgr.h" #include "SpellScript.h" +#include "StringConvert.h" #include "TemporarySummon.h" #include "Timer.h" #include "TransportMgr.h" @@ -675,34 +676,34 @@ void ObjectMgr::LoadCreatureTemplateAddons() creatureAddon.meleeAnimKit = fields[8].GetUInt16(); creatureAddon.visibilityDistanceType = VisibilityDistanceType(fields[9].GetUInt8()); - Tokenizer tokens(fields[10].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[10].GetStringView(), ' ', false)) { - uint32 spellId = uint32(atoul(*itr)); - SpellInfo const* AdditionalSpellInfo = sSpellMgr->GetSpellInfo(spellId, DIFFICULTY_NONE); - if (!AdditionalSpellInfo) + SpellInfo const* spellInfo = nullptr; + if (Optional<uint32> spellId = Trinity::StringTo<uint32>(aura)) + spellInfo = sSpellMgr->GetSpellInfo(*spellId, DIFFICULTY_NONE); + + if (!spellInfo) { - TC_LOG_ERROR("sql.sql", "Creature (Entry: %u) has wrong spell %u defined in `auras` field in `creature_template_addon`.", entry, spellId); + 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 %u defined in `auras` field in `creature_template_addon`.", entry, spellId); + 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(), spellId) != 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 %u) in `auras` field in `creature_template_addon`.", entry, spellId); + 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 %u) in `auras` field in `creature_template_addon`.", entry, spellId); + 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(spellId); + creatureAddon.auras.push_back(spellInfo->Id); } if (creatureAddon.mount) @@ -1220,34 +1221,34 @@ void ObjectMgr::LoadCreatureAddons() creatureAddon.meleeAnimKit = fields[8].GetUInt16(); creatureAddon.visibilityDistanceType = VisibilityDistanceType(fields[9].GetUInt8()); - Tokenizer tokens(fields[10].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[10].GetStringView(), ' ', false)) { - uint32 spellId = uint32(atoul(*itr)); - SpellInfo const* AdditionalSpellInfo = sSpellMgr->GetSpellInfo(spellId, DIFFICULTY_NONE); - if (!AdditionalSpellInfo) + SpellInfo const* spellInfo = nullptr; + if (Optional<uint32> spellId = Trinity::StringTo<uint32>(aura)) + spellInfo = sSpellMgr->GetSpellInfo(*spellId, DIFFICULTY_NONE); + + if (!spellInfo) { - TC_LOG_ERROR("sql.sql", "Creature (GUID: " UI64FMTD ") has wrong spell %u defined in `auras` field in `creature_addon`.", guid, spellId); + TC_LOG_ERROR("sql.sql", "Creature (GUID: " UI64FMTD ") 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: " UI64FMTD ") has SPELL_AURA_CONTROL_VEHICLE aura %u defined in `auras` field in `creature_addon`.", guid, spellId); + if (spellInfo->HasAura(SPELL_AURA_CONTROL_VEHICLE)) + TC_LOG_ERROR("sql.sql", "Creature (GUID: " UI64FMTD ") 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(), spellId) != creatureAddon.auras.end()) + if (std::find(creatureAddon.auras.begin(), creatureAddon.auras.end(), spellInfo->Id) != creatureAddon.auras.end()) { - TC_LOG_ERROR("sql.sql", "Creature (GUID: " UI64FMTD ") has duplicate aura (spell %u) in `auras` field in `creature_addon`.", guid, spellId); + TC_LOG_ERROR("sql.sql", "Creature (GUID: " UI64FMTD ") 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: " UI64FMTD ") has temporary aura (spell %u) in `auras` field in `creature_addon`.", guid, spellId); + TC_LOG_ERROR("sql.sql", "Creature (GUID: " UI64FMTD ") has temporary aura (spell %u) in `auras` field in `creature_addon`.", guid, spellInfo->Id); continue; } - creatureAddon.auras.push_back(spellId); + creatureAddon.auras.push_back(spellInfo->Id); } if (creatureAddon.mount) @@ -2048,12 +2049,11 @@ void ObjectMgr::LoadTempSummons() inline std::vector<Difficulty> ParseSpawnDifficulties(std::string const& difficultyString, std::string const& table, ObjectGuid::LowType spawnId, uint32 mapId, std::set<Difficulty> const& mapDifficulties) { - Tokenizer tokens(difficultyString, ',', 0, false); std::vector<Difficulty> difficulties; bool isTransportMap = sObjectMgr->IsTransportMap(mapId); - for (char const* token : tokens) + for (std::string_view token : Trinity::Tokenize(difficultyString, ',', false)) { - Difficulty difficultyId = Difficulty(strtoul(token, nullptr, 10)); + Difficulty difficultyId = Difficulty(Trinity::StringTo<std::underlying_type_t<Difficulty>>(token).value_or(DIFFICULTY_NONE)); if (difficultyId && !sDifficultyStore.LookupEntry(difficultyId)) { TC_LOG_ERROR("sql.sql", "Table `%s` has %s (GUID: " UI64FMTD ") with non invalid difficulty id %u, skipped.", @@ -9439,9 +9439,9 @@ uint32 ObjectMgr::LoadReferenceVendor(int32 vendor, int32 item, std::set<uint32> vItem.PlayerConditionId = fields[6].GetUInt32(); vItem.IgnoreFiltering = fields[7].GetBool(); - Tokenizer bonusListIDsTok(fields[5].GetString(), ' '); - for (char const* token : bonusListIDsTok) - vItem.BonusListIDs.push_back(int32(atol(token))); + for (std::string_view token : Trinity::Tokenize(fields[5].GetStringView(), ' ', false)) + if (Optional<int32> bonusListID = Trinity::StringTo<int32>(token)) + vItem.BonusListIDs.push_back(*bonusListID); if (!IsVendorItemValid(vendor, vItem, nullptr, skip_vendors)) continue; @@ -9496,9 +9496,9 @@ void ObjectMgr::LoadVendors() vItem.PlayerConditionId = fields[7].GetUInt32(); vItem.IgnoreFiltering = fields[8].GetBool(); - Tokenizer bonusListIDsTok(fields[6].GetString(), ' '); - for (char const* token : bonusListIDsTok) - vItem.BonusListIDs.push_back(int32(atol(token))); + for (std::string_view token : Trinity::Tokenize(fields[6].GetStringView(), ' ', false)) + if (Optional<int32> bonusListID = Trinity::StringTo<int32>(token)) + vItem.BonusListIDs.push_back(*bonusListID); if (!IsVendorItemValid(entry, vItem, nullptr, &skip_vendors)) continue; @@ -10960,10 +10960,10 @@ void ObjectMgr::LoadPlayerChoices() int32 choiceId = fields[0].GetInt32(); int32 responseId = fields[1].GetInt32(); uint32 itemId = fields[2].GetUInt32(); - Tokenizer bonusListIDsTok(fields[3].GetString(), ' '); std::vector<int32> bonusListIds; - for (char const* token : bonusListIDsTok) - bonusListIds.push_back(int32(atol(token))); + for (std::string_view token : Trinity::Tokenize(fields[3].GetStringView(), ' ', false)) + if (Optional<int32> bonusListID = Trinity::StringTo<int32>(token)) + bonusListIds.push_back(*bonusListID); int32 quantity = fields[4].GetInt32(); PlayerChoice* choice = Trinity::Containers::MapGetValuePtr(_playerChoices, choiceId); @@ -11102,10 +11102,10 @@ void ObjectMgr::LoadPlayerChoices() int32 choiceId = fields[0].GetInt32(); int32 responseId = fields[1].GetInt32(); uint32 itemId = fields[2].GetUInt32(); - Tokenizer bonusListIDsTok(fields[3].GetString(), ' '); std::vector<int32> bonusListIds; - for (char const* token : bonusListIDsTok) - bonusListIds.push_back(int32(atol(token))); + for (std::string_view token : Trinity::Tokenize(fields[3].GetStringView(), ' ', false)) + if (Optional<int32> bonusListID = Trinity::StringTo<int32>(token)) + bonusListIds.push_back(*bonusListID); int32 quantity = fields[4].GetInt32(); PlayerChoice* choice = Trinity::Containers::MapGetValuePtr(_playerChoices, choiceId); diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp index 7e44225f8da..09e945981af 100644 --- a/src/server/game/Handlers/CharacterHandler.cpp +++ b/src/server/game/Handlers/CharacterHandler.cpp @@ -58,6 +58,7 @@ #include "ReputationMgr.h" #include "ScriptMgr.h" #include "SocialMgr.h" +#include "StringConvert.h" #include "SystemPackets.h" #include "Util.h" #include "World.h" @@ -2505,11 +2506,20 @@ void WorldSession::HandleCharRaceOrFactionChangeCallback(std::shared_ptr<WorldPa // Title conversion if (!knownTitlesStr.empty()) { + std::vector<std::string_view> tokens = Trinity::Tokenize(knownTitlesStr, ' ', false); std::vector<uint32> knownTitles; - Tokenizer tokens(knownTitlesStr, ' '); - for (uint32 index = 0; index < tokens.size(); ++index) - knownTitles.push_back(atoul(tokens[index])); + for (std::string_view token : tokens) + { + if (Optional<uint32> thisMask = Trinity::StringTo<uint32>(token)) + knownTitles.push_back(*thisMask); + else + { + TC_LOG_WARN("entities.player", "%s has invalid title data '%s' - skipped, this may result in titles being lost", + GetPlayerInfo().c_str(), std::string(token).c_str()); + knownTitles.push_back(0); + } + } for (std::map<uint32, uint32>::const_iterator it = sObjectMgr->FactionChangeTitles.begin(); it != sObjectMgr->FactionChangeTitles.end(); ++it) { @@ -2553,8 +2563,8 @@ void WorldSession::HandleCharRaceOrFactionChangeCallback(std::shared_ptr<WorldPa } std::ostringstream ss; - for (uint32 index = 0; index < knownTitles.size(); ++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/Loot/LootItemStorage.cpp b/src/server/game/Loot/LootItemStorage.cpp index 59881e178a7..3347dba6aa8 100644 --- a/src/server/game/Loot/LootItemStorage.cpp +++ b/src/server/game/Loot/LootItemStorage.cpp @@ -23,6 +23,7 @@ #include "LootMgr.h" #include "ObjectMgr.h" #include "Player.h" +#include "StringConvert.h" #include <sstream> #include <unordered_map> @@ -87,11 +88,9 @@ void LootItemStorage::LoadStorageFromDB() lootItem.needs_quest = fields[8].GetBool(); lootItem.randomBonusListId = fields[9].GetUInt32(); lootItem.context = ItemContext(fields[10].GetUInt8()); - Tokenizer bonusLists(fields[11].GetString(), ' '); - std::transform(bonusLists.begin(), bonusLists.end(), std::back_inserter(lootItem.BonusListIDs), [](char const* token) - { - return int32(strtol(token, nullptr, 10)); - }); + for (std::string_view bonusList : Trinity::Tokenize(fields[11].GetStringView(), ' ', false)) + if (Optional<int32> bonusListID = Trinity::StringTo<int32>(bonusList)) + lootItem.BonusListIDs.push_back(*bonusListID); storedContainer.AddLootItem(lootItem, trans); diff --git a/src/server/game/Server/Packets/CharacterPackets.cpp b/src/server/game/Server/Packets/CharacterPackets.cpp index bde4aadf903..c73e2ef68ab 100644 --- a/src/server/game/Server/Packets/CharacterPackets.cpp +++ b/src/server/game/Server/Packets/CharacterPackets.cpp @@ -20,6 +20,7 @@ #include "Field.h" #include "ObjectMgr.h" #include "Player.h" +#include "StringConvert.h" #include "World.h" namespace UF @@ -132,7 +133,7 @@ EnumCharactersResult::CharacterInfo::CharacterInfo(Field* fields) ProfessionIds[0] = 0; ProfessionIds[1] = 0; - Tokenizer equipment(fields[17].GetString(), ' '); + std::vector<std::string_view> equipment = Trinity::Tokenize(fields[17].GetStringView(), ' ', false); ListPosition = fields[19].GetUInt8(); LastPlayedTime = fields[20].GetInt64(); if (ChrSpecializationEntry const* spec = sDB2Manager.GetChrSpecializationByIndex(ClassID, fields[21].GetUInt8())) @@ -143,11 +144,11 @@ EnumCharactersResult::CharacterInfo::CharacterInfo(Field* fields) for (uint8 slot = 0; slot < INVENTORY_SLOT_BAG_END; ++slot) { uint32 visualBase = slot * 5; - VisualItems[slot].InvType = Player::GetUInt32ValueFromArray(equipment, visualBase); - VisualItems[slot].DisplayID = Player::GetUInt32ValueFromArray(equipment, visualBase + 1); - VisualItems[slot].DisplayEnchantID = Player::GetUInt32ValueFromArray(equipment, visualBase + 2); - VisualItems[slot].Subclass = Player::GetUInt32ValueFromArray(equipment, visualBase + 3); - VisualItems[slot].SecondaryItemModifiedAppearanceID = Player::GetUInt32ValueFromArray(equipment, visualBase + 4); + VisualItems[slot].InvType = Trinity::StringTo<uint8>(equipment[visualBase + 0]).value_or(0); + VisualItems[slot].DisplayID = Trinity::StringTo<uint32>(equipment[visualBase + 1]).value_or(0); + VisualItems[slot].DisplayEnchantID = Trinity::StringTo<uint32>(equipment[visualBase + 2]).value_or(0); + VisualItems[slot].Subclass = Trinity::StringTo<uint8>(equipment[visualBase + 3]).value_or(0); + VisualItems[slot].SecondaryItemModifiedAppearanceID = Trinity::StringTo<int32>(equipment[visualBase + 4]).value_or(0); } } diff --git a/src/server/game/Server/Packets/ChatPackets.cpp b/src/server/game/Server/Packets/ChatPackets.cpp index 6ac809ecc95..efb1eb4809e 100644 --- a/src/server/game/Server/Packets/ChatPackets.cpp +++ b/src/server/game/Server/Packets/ChatPackets.cpp @@ -102,8 +102,8 @@ WorldPackets::Chat::Chat::Chat(Chat const& chat) : ServerPacket(SMSG_CHAT, chat. { } -void WorldPackets::Chat::Chat::Initialize(ChatMsg chatType, Language language, WorldObject const* sender, WorldObject const* receiver, std::string message, - uint32 achievementId /*= 0*/, std::string channelName /*= ""*/, LocaleConstant locale /*= DEFAULT_LOCALE*/, std::string addonPrefix /*= ""*/) +void WorldPackets::Chat::Chat::Initialize(ChatMsg chatType, Language language, WorldObject const* sender, WorldObject const* receiver, std::string_view message, + uint32 achievementId /*= 0*/, std::string_view channelName /*= ""*/, LocaleConstant locale /*= DEFAULT_LOCALE*/, std::string_view addonPrefix /*= ""*/) { // Clear everything because same packet can be used multiple times Clear(); @@ -131,7 +131,7 @@ void WorldPackets::Chat::Chat::Initialize(ChatMsg chatType, Language language, W AchievementID = achievementId; _Channel = std::move(channelName); Prefix = std::move(addonPrefix); - ChatText = std::move(message); + ChatText = message; } void WorldPackets::Chat::Chat::SetSender(WorldObject const* sender, LocaleConstant locale) diff --git a/src/server/game/Server/Packets/ChatPackets.h b/src/server/game/Server/Packets/ChatPackets.h index cb161ef3169..2b23f2f2562 100644 --- a/src/server/game/Server/Packets/ChatPackets.h +++ b/src/server/game/Server/Packets/ChatPackets.h @@ -149,8 +149,8 @@ namespace WorldPackets Chat() : ServerPacket(SMSG_CHAT, 100) { } Chat(Chat const& chat); - void Initialize(ChatMsg chatType, Language language, WorldObject const* sender, WorldObject const* receiver, std::string message, uint32 achievementId = 0, - std::string channelName = "", LocaleConstant locale = DEFAULT_LOCALE, std::string addonPrefix = ""); + void Initialize(ChatMsg chatType, Language language, WorldObject const* sender, WorldObject const* receiver, std::string_view message, uint32 achievementId = 0, + std::string_view channelName = "", LocaleConstant locale = DEFAULT_LOCALE, std::string_view addonPrefix = ""); void SetSender(WorldObject const* sender, LocaleConstant locale); void SetReceiver(WorldObject const* receiver, LocaleConstant locale); diff --git a/src/server/scripts/Commands/cs_battlenet_account.cpp b/src/server/scripts/Commands/cs_battlenet_account.cpp index c4f0dff6c01..03ff81c0a20 100644 --- a/src/server/scripts/Commands/cs_battlenet_account.cpp +++ b/src/server/scripts/Commands/cs_battlenet_account.cpp @@ -325,19 +325,8 @@ public: return true; } - static bool HandleAccountLinkCommand(ChatHandler* handler, char const* args) + static bool HandleAccountLinkCommand(ChatHandler* handler, std::string const& bnetAccountName, std::string const& gameAccountName) { - Tokenizer tokens(args, ' ', 2); - if (tokens.size() != 2) - { - handler->SendSysMessage(LANG_CMD_SYNTAX); - handler->SetSentErrorMessage(true); - return false; - } - - std::string bnetAccountName = tokens[0]; - std::string gameAccountName = tokens[1]; - switch (Battlenet::AccountMgr::LinkWithGameAccount(bnetAccountName, gameAccountName)) { case AccountOpResult::AOR_OK: diff --git a/src/server/scripts/Commands/cs_misc.cpp b/src/server/scripts/Commands/cs_misc.cpp index b6dceef1101..99b507bb61c 100644 --- a/src/server/scripts/Commands/cs_misc.cpp +++ b/src/server/scripts/Commands/cs_misc.cpp @@ -1250,12 +1250,9 @@ public: // semicolon separated bonuslist ids (parse them after all arguments are extracted by strtok!) if (bonuses) - { - Tokenizer tokens(bonuses, ';'); - for (char const* token : tokens) - if (int32 bonusListId = atoi(token)) - bonusListIDs.push_back(bonusListId); - } + for (std::string_view token : Trinity::Tokenize(bonuses, ';', false)) + if (Optional<int32> bonusListId = Trinity::StringTo<int32>(token)) + bonusListIDs.push_back(*bonusListId); ItemContext itemContext = ItemContext::NONE; if (context) @@ -1364,11 +1361,9 @@ public: // semicolon separated bonuslist ids (parse them after all arguments are extracted by strtok!) if (bonuses) - { - Tokenizer tokens(bonuses, ';'); - for (char const* token : tokens) - bonusListIDs.push_back(atoul(token)); - } + for (std::string_view token : Trinity::Tokenize(bonuses, ';', false)) + if (Optional<int32> bonusListId = Trinity::StringTo<int32>(token)) + bonusListIDs.push_back(*bonusListId); ItemContext itemContext = ItemContext::NONE; if (context) diff --git a/src/server/scripts/Commands/cs_modify.cpp b/src/server/scripts/Commands/cs_modify.cpp index 84fbdd8cdfe..972c3761168 100644 --- a/src/server/scripts/Commands/cs_modify.cpp +++ b/src/server/scripts/Commands/cs_modify.cpp @@ -566,11 +566,16 @@ public: if (handler->HasLowerSecurity(target, ObjectGuid::Empty)) return false; - int64 moneyToAdd = 0; + Optional<int64> moneyToAddO = 0; if (strchr(args, 'g') || strchr(args, 's') || strchr(args, 'c')) - moneyToAdd = MoneyStringToMoney(std::string(args)); + moneyToAddO = MoneyStringToMoney(std::string(args)); else - moneyToAdd = atoll(args); + moneyToAddO = Trinity::StringTo<int64>(args); + + if (!moneyToAddO) + return false; + + int64 moneyToAdd = *moneyToAddO; uint64 targetMoney = target->GetMoney(); diff --git a/src/server/scripts/Commands/cs_npc.cpp b/src/server/scripts/Commands/cs_npc.cpp index d30d77f4f39..8107ef086d6 100644 --- a/src/server/scripts/Commands/cs_npc.cpp +++ b/src/server/scripts/Commands/cs_npc.cpp @@ -304,11 +304,9 @@ public: vItem.Type = type; if (fbonuslist) - { - Tokenizer bonusListIDsTok(fbonuslist, ';'); - for (char const* token : bonusListIDsTok) - vItem.BonusListIDs.push_back(int32(atol(token))); - } + for (std::string_view token : Trinity::Tokenize(fbonuslist, ';', false)) + if (Optional<int32> bonusListID = Trinity::StringTo<int32>(token)) + vItem.BonusListIDs.push_back(*bonusListID); if (!sObjectMgr->IsVendorItemValid(vendor_entry, vItem, handler->GetSession()->GetPlayer())) { diff --git a/src/server/scripts/Commands/cs_reload.cpp b/src/server/scripts/Commands/cs_reload.cpp index 17992ddddba..c25403bd88f 100644 --- a/src/server/scripts/Commands/cs_reload.cpp +++ b/src/server/scripts/Commands/cs_reload.cpp @@ -46,6 +46,7 @@ EndScriptData */ #include "SkillExtraItems.h" #include "SmartAI.h" #include "SpellMgr.h" +#include "StringConvert.h" #include "SupportMgr.h" #include "WaypointManager.h" #include "World.h" @@ -205,7 +206,7 @@ public: HandleReloadGameTeleCommand(handler, ""); HandleReloadCreatureMovementOverrideCommand(handler, ""); - HandleReloadCreatureSummonGroupsCommand(handler, ""); + HandleReloadCreatureSummonGroupsCommand(handler); HandleReloadVehicleAccessoryCommand(handler, ""); HandleReloadVehicleTemplateAccessoryCommand(handler, ""); @@ -420,7 +421,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(); @@ -433,11 +434,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 = atoul(*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/Packets/ByteBuffer.h b/src/server/shared/Packets/ByteBuffer.h index 32f6bcbaee9..40c3782806d 100644 --- a/src/server/shared/Packets/ByteBuffer.h +++ b/src/server/shared/Packets/ByteBuffer.h @@ -300,20 +300,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) |