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