Core/Common: Tokenizer -> Trinity::Tokenize

This commit is contained in:
Treeston authored and Ovahlord committed 2025-07-30 20:51:19 +02:00
1 parent 95329dc15c
commit f95a8bfdca
32 files changed
+414 -354

No files matched your search

+23 -21
View File
@@ -17,6 +17,8 @@
#include "AppenderConsole.h" #include "AppenderConsole.h"
#include "LogMessage.h" #include "LogMessage.h"
#include "StringFormat.h"
#include "StringConvert.h"
#include "Util.h" #include "Util.h"
#include <sstream> #include <sstream>
@@ -24,17 +26,17 @@
#include <Windows.h> #include <Windows.h>
#endif #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) : Appender(id, name, level, flags), _colored(false)
{ {
for (uint8 i = 0; i < NUM_ENABLED_LOG_LEVELS; ++i) for (uint8 i = 0; i < NUM_ENABLED_LOG_LEVELS; ++i)
_colors[i] = ColorTypes(MaxColors); _colors[i] = ColorTypes(NUM_COLOR_TYPES);
if (!extraArgs.empty()) if (3 < args.size())
InitColors(extraArgs[0]); 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()) if (str.empty())
{ {
@@ -42,23 +44,23 @@ void AppenderConsole::InitColors(std::string const& str)
return; return;
} }
int color[NUM_ENABLED_LOG_LEVELS]; std::vector<std::string_view> colorStrs = Trinity::Tokenize(str, ' ', false);
if (colorStrs.size() != NUM_ENABLED_LOG_LEVELS)
std::istringstream ss(str);
for (uint8 i = 0; i < NUM_ENABLED_LOG_LEVELS; ++i)
{ {
ss >> color[i]; 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()));
if (!ss)
return;
if (color[i] < 0 || color[i] >= MaxColors)
return;
} }
for (uint8 i = 0; i < NUM_ENABLED_LOG_LEVELS; ++i) 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 && *color < NUM_COLOR_TYPES)
_colors[i] = static_cast<ColorTypes>(*color);
else
{
throw InvalidAppenderArgsException(Trinity::StringFormat("Log::CreateAppenderFromConfig: Invalid color '%u' for log level %s on console appender %s",
std::string(colorStrs[i]).c_str(), static_cast<uint32>(i), name.c_str()));
}
}
_colored = true; _colored = true;
} }
@@ -66,7 +68,7 @@ void AppenderConsole::InitColors(std::string const& str)
void AppenderConsole::SetColor(bool stdout_stream, ColorTypes color) void AppenderConsole::SetColor(bool stdout_stream, ColorTypes color)
{ {
#if TRINITY_PLATFORM == TRINITY_PLATFORM_WINDOWS #if TRINITY_PLATFORM == TRINITY_PLATFORM_WINDOWS
static WORD WinColorFG[MaxColors] = static WORD WinColorFG[NUM_COLOR_TYPES] =
{ {
0, // BLACK 0, // BLACK
FOREGROUND_RED, // RED FOREGROUND_RED, // RED
@@ -127,7 +129,7 @@ void AppenderConsole::SetColor(bool stdout_stream, ColorTypes color)
BG_WHITE BG_WHITE
}; };
static uint8 UnixColorFG[MaxColors] = static uint8 UnixColorFG[NUM_COLOR_TYPES] =
{ {
FG_BLACK, // BLACK FG_BLACK, // BLACK
FG_RED, // RED FG_RED, // RED
@@ -146,7 +148,7 @@ void AppenderConsole::SetColor(bool stdout_stream, ColorTypes color)
FG_WHITE // LWHITE 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 #endif
} }
+5 -6
View File
@@ -36,19 +36,18 @@ enum ColorTypes
LBLUE, LBLUE,
LMAGENTA, LMAGENTA,
LCYAN, LCYAN,
WHITE WHITE,
NUM_COLOR_TYPES // SKIP
}; };
const uint8 MaxColors = uint8(WHITE) + 1;
class TC_COMMON_API AppenderConsole : public Appender class TC_COMMON_API AppenderConsole : public Appender
{ {
public: public:
static constexpr AppenderType type = APPENDER_CONSOLE; static constexpr AppenderType type = APPENDER_CONSOLE;
AppenderConsole(uint8 _id, std::string const& name, LogLevel level, AppenderFlags flags, std::vector<char const*> extraArgs); AppenderConsole(uint8 _id, std::string const& name, LogLevel level, AppenderFlags flags, std::vector<std::string_view> const& args);
void InitColors(const std::string& init_str); void InitColors(std::string const& name, std::string_view init_str);
AppenderType getType() const override { return type; } AppenderType getType() const override { return type; }
private: private:
void SetColor(bool stdout_stream, ColorTypes color); void SetColor(bool stdout_stream, ColorTypes color);
+17 -10
View File
@@ -18,23 +18,25 @@
#include "AppenderFile.h" #include "AppenderFile.h"
#include "Log.h" #include "Log.h"
#include "LogMessage.h" #include "LogMessage.h"
#include "StringConvert.h"
#include "Util.h"
#include <algorithm> #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), Appender(id, name, level, flags),
logfile(nullptr), logfile(nullptr),
_logDir(sLog->GetLogsDir()), _logDir(sLog->GetLogsDir()),
_maxFileSize(0), _maxFileSize(0),
_fileSize(0) _fileSize(0)
{ {
if (extraArgs.empty()) if (args.size() < 4)
throw InvalidAppenderArgsException(Trinity::StringFormat("Log::CreateAppenderFromConfig: Missing file name for appender %s\n", name.c_str())); 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"; std::string mode = "a";
if (extraArgs.size() > 1) if (4 < args.size())
mode = extraArgs[1]; mode.assign(args[4]);
if (flags & APPENDER_FLAGS_USE_TIMESTAMP) if (flags & APPENDER_FLAGS_USE_TIMESTAMP)
{ {
@@ -45,14 +47,19 @@ AppenderFile::AppenderFile(uint8 id, std::string const& name, LogLevel level, Ap
_fileName += sLog->GetLogsTimestamp(); _fileName += sLog->GetLogsTimestamp();
} }
if (extraArgs.size() > 2) if (5 < args.size())
_maxFileSize = atoi(extraArgs[2]); {
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"); _dynamicName = std::string::npos != _fileName.find("%s");
_backup = (flags & APPENDER_FLAGS_MAKE_FILE_BACKUP) != 0; _backup = (flags & APPENDER_FLAGS_MAKE_FILE_BACKUP) != 0;
if (!_dynamicName) if (!_dynamicName)
logfile = OpenFile(_fileName, mode, !strcmp(mode, "w") && _backup); logfile = OpenFile(_fileName, mode, (mode == "w") && _backup);
} }
AppenderFile::~AppenderFile() AppenderFile::~AppenderFile()
+1 -1
View File
@@ -26,7 +26,7 @@ class TC_COMMON_API AppenderFile : public Appender
public: public:
static constexpr AppenderType type = APPENDER_FILE; 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(); ~AppenderFile();
FILE* OpenFile(std::string const& name, std::string const& mode, bool backup); FILE* OpenFile(std::string const& name, std::string const& mode, bool backup);
AppenderType getType() const override { return type; } AppenderType getType() const override { return type; }
+23 -32
View File
@@ -26,6 +26,7 @@
#include "LogMessage.h" #include "LogMessage.h"
#include "LogOperation.h" #include "LogOperation.h"
#include "Strand.h" #include "Strand.h"
#include "StringConvert.h"
#include "Util.h" #include "Util.h"
#include <sstream> #include <sstream>
@@ -47,7 +48,7 @@ uint8 Log::NextAppenderId()
return AppenderId++; return AppenderId++;
} }
Appender* Log::GetAppenderByName(std::string const& name) Appender* Log::GetAppenderByName(std::string_view name)
{ {
auto it = appenders.begin(); auto it = appenders.begin();
while (it != appenders.end() && it->second && it->second->getName() != name) 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 // if type = Console. optional1 = Color
std::string options = sConfigMgr->GetStringDefault(appenderName, ""); std::string options = sConfigMgr->GetStringDefault(appenderName, "");
Tokenizer tokens(options, ','); std::vector<std::string_view> tokens = Trinity::Tokenize(options, ',', true);
auto iter = tokens.begin();
size_t size = tokens.size(); size_t const size = tokens.size();
std::string name = appenderName.substr(9); std::string name = appenderName.substr(9);
if (size < 2) if (size < 2)
@@ -79,33 +79,30 @@ void Log::CreateAppenderFromConfig(std::string const& appenderName)
} }
AppenderFlags flags = APPENDER_FLAGS_NONE; AppenderFlags flags = APPENDER_FLAGS_NONE;
AppenderType type = AppenderType(atoi(*iter++)); AppenderType type = AppenderType(Trinity::StringTo<uint8>(tokens[0]).value_or(APPENDER_INVALID));
LogLevel level = LogLevel(atoi(*iter++)); LogLevel level = LogLevel(Trinity::StringTo<uint8>(tokens[1]).value_or(LOG_LEVEL_INVALID));
if (level > LOG_LEVEL_FATAL)
{
fprintf(stderr, "Log::CreateAppenderFromConfig: Wrong Log Level %d for appender %s\n", level, name.c_str());
return;
}
if (size > 2)
flags = AppenderFlags(atoi(*iter++));
auto factoryFunction = appenderFactory.find(type); auto factoryFunction = appenderFactory.find(type);
if (factoryFunction == appenderFactory.end()) if (factoryFunction == appenderFactory.end())
{ {
fprintf(stderr, "Log::CreateAppenderFromConfig: Unknown type %d for appender %s\n", type, 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 (level > NUM_ENABLED_LOG_LEVELS)
{
fprintf(stderr, "Log::CreateAppenderFromConfig: Wrong Log Level '%s' for appender %s\n", std::string(tokens[1]).c_str(), name.c_str());
return; return;
} }
try 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); appenders[appender->getId()].reset(appender);
} }
catch (InvalidAppenderArgsException const& iaae) catch (InvalidAppenderArgsException const& iaae)
{ {
fprintf(stderr, "%s", iaae.what()); fprintf(stderr, "%s\n", iaae.what());
} }
} }
@@ -126,8 +123,7 @@ void Log::CreateLoggerFromConfig(std::string const& appenderName)
return; return;
} }
Tokenizer tokens(options, ','); std::vector<std::string_view> tokens = Trinity::Tokenize(options, ',', true);
Tokenizer::const_iterator iter = tokens.begin();
if (tokens.size() != 2) if (tokens.size() != 2)
{ {
@@ -142,10 +138,10 @@ void Log::CreateLoggerFromConfig(std::string const& appenderName)
return; return;
} }
level = LogLevel(atoi(*iter++)); level = LogLevel(Trinity::StringTo<uint8>(tokens[0]).value_or(LOG_LEVEL_INVALID));
if (level > LOG_LEVEL_FATAL) 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; return;
} }
@@ -155,20 +151,15 @@ void Log::CreateLoggerFromConfig(std::string const& appenderName)
logger = Trinity::make_unique<Logger>(name, level); logger = Trinity::make_unique<Logger>(name, level);
//fprintf(stdout, "Log::CreateLoggerFromConfig: Created Logger %s, Level %u\n", name.c_str(), level); //fprintf(stdout, "Log::CreateLoggerFromConfig: Created Logger %s, Level %u\n", name.c_str(), level);
std::istringstream ss(*iter); for (std::string_view appenderName : Trinity::Tokenize(tokens[1], ' ', false))
std::string str;
ss >> str;
while (ss)
{ {
if (Appender* appender = GetAppenderByName(str)) if (Appender* appender = GetAppenderByName(appenderName))
{ {
logger->addAppender(appender->getId(), appender); logger->addAppender(appender->getId(), appender);
//fprintf(stdout, "Log::CreateLoggerFromConfig: Added Appender %s to Logger %s\n", appender->getName().c_str(), name.c_str()); //fprintf(stdout, "Log::CreateLoggerFromConfig: Added Appender %s to Logger %s\n", appender->getName().c_str(), name.c_str());
} }
else else
fprintf(stderr, "Error while configuring Appender %s in Logger %s. Appender does not exist", str.c_str(), name.c_str()); fprintf(stderr, "Error while configuring Appender %s in Logger %s. Appender does not exist\n", std::string(appenderName).c_str(), name.c_str());
ss >> str;
} }
} }
@@ -193,7 +184,7 @@ void Log::ReadLoggersFromConfig()
Close(); // Clean any Logger or Appender created 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); appenders[appender->getId()].reset(appender);
Logger* rootLogger = new Logger(LOGGER_ROOT, LOG_LEVEL_ERROR); Logger* rootLogger = new Logger(LOGGER_ROOT, LOG_LEVEL_ERROR);
+4 -4
View File
@@ -40,12 +40,12 @@ namespace Trinity
#define LOGGER_ROOT "root" #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> 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 class TC_COMMON_API Log
@@ -103,7 +103,7 @@ class TC_COMMON_API Log
void write(std::unique_ptr<LogMessage>&& msg) const; void write(std::unique_ptr<LogMessage>&& msg) const;
Logger const* GetLoggerByType(std::string const& type) const; Logger const* GetLoggerByType(std::string const& type) const;
Appender* GetAppenderByName(std::string const& name); Appender* GetAppenderByName(std::string_view name);
uint8 NextAppenderId(); uint8 NextAppenderId();
void CreateAppenderFromConfig(std::string const& name); void CreateAppenderFromConfig(std::string const& name);
void CreateLoggerFromConfig(std::string const& name); void CreateLoggerFromConfig(std::string const& name);
+9 -4
View File
@@ -18,7 +18,9 @@
#ifndef LogCommon_h__ #ifndef LogCommon_h__
#define LogCommon_h__ #define LogCommon_h__
enum LogLevel #include "Define.h"
enum LogLevel : uint8
{ {
LOG_LEVEL_DISABLED = 0, LOG_LEVEL_DISABLED = 0,
LOG_LEVEL_TRACE = 1, LOG_LEVEL_TRACE = 1,
@@ -28,7 +30,8 @@ enum LogLevel
LOG_LEVEL_ERROR = 5, LOG_LEVEL_ERROR = 5,
LOG_LEVEL_FATAL = 6, LOG_LEVEL_FATAL = 6,
NUM_ENABLED_LOG_LEVELS = 6 NUM_ENABLED_LOG_LEVELS = LOG_LEVEL_FATAL, // SKIP
LOG_LEVEL_INVALID = 0xFF // SKIP
}; };
enum AppenderType : uint8 enum AppenderType : uint8
@@ -36,10 +39,12 @@ enum AppenderType : uint8
APPENDER_NONE, APPENDER_NONE,
APPENDER_CONSOLE, APPENDER_CONSOLE,
APPENDER_FILE, APPENDER_FILE,
APPENDER_DB APPENDER_DB,
APPENDER_INVALID = 0xFF // SKIP
}; };
enum AppenderFlags enum AppenderFlags : uint8
{ {
APPENDER_FLAGS_NONE = 0x00, APPENDER_FLAGS_NONE = 0x00,
APPENDER_FLAGS_PREFIX_TIMESTAMP = 0x01, APPENDER_FLAGS_PREFIX_TIMESTAMP = 0x01,
+1 -1
View File
@@ -80,7 +80,7 @@ void Metric::LoadFromConfigs()
return; return;
} }
Tokenizer tokens(connectionInfo, ';'); std::vector<std::string_view> tokens = Trinity::Tokenize(connectionInfo, ';', true);
if (tokens.size() != 3) if (tokens.size() != 3)
{ {
TC_LOG_ERROR("metric", "'Metric.ConnectionInfo' specified with wrong format in configuration file."); TC_LOG_ERROR("metric", "'Metric.ConnectionInfo' specified with wrong format in configuration file.");
+44 -49
View File
@@ -19,6 +19,7 @@
#include "Common.h" #include "Common.h"
#include "Containers.h" #include "Containers.h"
#include "IpAddress.h" #include "IpAddress.h"
#include "StringConvert.h"
#include "StringFormat.h" #include "StringFormat.h"
#include <utf8.h> #include <utf8.h>
#include <algorithm> #include <algorithm>
@@ -50,39 +51,22 @@ void Trinity::VerifyOsVersion()
#endif #endif
} }
Tokenizer::Tokenizer(const std::string &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]; std::vector<std::string_view> tokens;
memcpy(m_str, src.c_str(), src.length() + 1);
if (vectorReserve) size_t start = 0;
m_storage.reserve(vectorReserve); for (size_t end = str.find(sep); end != std::string_view::npos; end = str.find(sep, start))
char* posold = m_str;
char* posnew = m_str;
for (;;)
{ {
if (*posnew == sep) if (keepEmpty || (start < end))
{ tokens.push_back(str.substr(start, end - start));
if (keepEmptyStrings || posold != posnew) start = end+1;
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);
break;
}
++posnew;
} }
if (keepEmpty || (start < str.length()))
tokens.push_back(str.substr(start));
return tokens;
} }
void stripLineInvisibleChars(std::string &str) void stripLineInvisibleChars(std::string &str)
@@ -183,32 +167,43 @@ std::string secsToTimeString(uint64 timeInSecs, bool shortText, bool hoursOnly)
return ss.str(); return ss.str();
} }
int64 MoneyStringToMoney(std::string const& moneyString) Optional<int64> MoneyStringToMoney(std::string const& moneyString)
{ {
int64 money = 0; int64 money = 0;
if (!(std::count(moneyString.begin(), moneyString.end(), 'g') == 1 || bool hadG = false;
std::count(moneyString.begin(), moneyString.end(), 's') == 1 || bool hadS = false;
std::count(moneyString.begin(), moneyString.end(), 'c') == 1)) bool hadC = false;
return 0; // Bad format
Tokenizer tokens(moneyString, ' '); for (std::string_view token : Trinity::Tokenize(moneyString, ' ', false))
for (Tokenizer::const_iterator itr = tokens.begin(); itr != tokens.end(); ++itr)
{ {
std::string tokenString(*itr); uint32 unit;
size_t gCount = std::count(tokenString.begin(), tokenString.end(), 'g'); switch (token[token.length() - 1])
size_t sCount = std::count(tokenString.begin(), tokenString.end(), 's'); {
size_t cCount = std::count(tokenString.begin(), tokenString.end(), 'c'); case 'g':
if (gCount + sCount + cCount != 1) if (hadG) return std::nullopt;
return 0; 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;
}
uint64 amount = strtoull(*itr, nullptr, 10); Optional<uint64> amount = Trinity::StringTo<uint32>(token.substr(0, token.length() - 1));
if (gCount == 1) if (amount)
money += amount * 100 * 100; money += (unit * *amount);
else if (sCount == 1) else
money += amount * 100; return std::nullopt;
else if (cCount == 1)
money += amount;
} }
return money; return money;
+10 -26
View File
@@ -20,7 +20,7 @@
#include "Define.h" #include "Define.h"
#include "Errors.h" #include "Errors.h"
#include "Optional.h"
#include <string> #include <string>
#include <sstream> #include <sstream>
#include <vector> #include <vector>
@@ -30,37 +30,21 @@ namespace Trinity
TC_COMMON_API void VerifyOsVersion(); TC_COMMON_API void VerifyOsVersion();
} }
class TC_COMMON_API Tokenizer namespace Trinity
{ {
public: TC_COMMON_API std::vector<std::string_view> Tokenize(std::string_view str, char sep, bool keepEmpty);
typedef std::vector<char const*> StorageType;
typedef StorageType::size_type size_type; /* 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;
typedef StorageType::const_iterator const_iterator; /* the delete overload means we need to make this explicit */
typedef StorageType::reference reference; inline std::vector<std::string_view> Tokenize(char const* str, char sep, bool keepEmpty) { return Tokenize(std::string_view(str ? str : ""), sep, keepEmpty); }
typedef StorageType::const_reference const_reference; }
public:
Tokenizer(const std::string &src, char const sep, uint32 vectorReserve = 0, bool keepEmptyStrings = true);
~Tokenizer() { delete[] m_str; }
const_iterator begin() const { return m_storage.begin(); }
const_iterator end() const { return m_storage.end(); }
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;
};
TC_COMMON_API void stripLineInvisibleChars(std::string &src); TC_COMMON_API void stripLineInvisibleChars(std::string &src);
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 struct tm* localtime_r(time_t const* time, struct tm *result);
TC_COMMON_API time_t LocalTimeToUTCTime(time_t time); TC_COMMON_API time_t LocalTimeToUTCTime(time_t time);
@@ -33,16 +33,16 @@
MySQLConnectionInfo::MySQLConnectionInfo(std::string const& infoString) MySQLConnectionInfo::MySQLConnectionInfo(std::string const& infoString)
{ {
Tokenizer tokens(infoString, ';'); std::vector<std::string_view> tokens = Trinity::Tokenize(infoString, ';', true);
if (tokens.size() != 5) if (tokens.size() != 5)
return; return;
uint8 i = 0; host.assign(tokens[0]);
host.assign(tokens[i++]); port_or_socket.assign(tokens[1]);
port_or_socket.assign(tokens[i++]); user.assign(tokens[2]);
user.assign(tokens[i++]); password.assign(tokens[3]);
password.assign(tokens[i++]); database.assign(tokens[4]);
database.assign(tokens[i++]);
} }
MySQLConnection::MySQLConnection(MySQLConnectionInfo& connInfo) : MySQLConnection::MySQLConnection(MySQLConnectionInfo& connInfo) :
+1 -1
View File
@@ -20,7 +20,7 @@
#include "LogMessage.h" #include "LogMessage.h"
#include "PreparedStatement.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) { } : Appender(id, name, level), realmId(0), enabled(false) { }
AppenderDB::~AppenderDB() { } AppenderDB::~AppenderDB() { }
+1 -1
View File
@@ -25,7 +25,7 @@ class TC_DATABASE_API AppenderDB: public Appender
public: public:
static constexpr AppenderType type = APPENDER_DB; 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(); ~AppenderDB();
void setRealmId(uint32 realmId) override; void setRealmId(uint32 realmId) override;
@@ -43,6 +43,7 @@
#include "ReputationMgr.h" #include "ReputationMgr.h"
#include "ScriptMgr.h" #include "ScriptMgr.h"
#include "SpellMgr.h" #include "SpellMgr.h"
#include "StringConvert.h"
#include "World.h" #include "World.h"
#include "WorldSession.h" #include "WorldSession.h"
#include "WorldStateMgr.h" #include "WorldStateMgr.h"
@@ -733,9 +734,9 @@ void AchievementMgr<Guild>::LoadFromDB(PreparedQueryResult achievementResult, Pr
CompletedAchievementData& ca = m_completedAchievements[achievementid]; CompletedAchievementData& ca = m_completedAchievements[achievementid];
ca.date = time_t(fields[1].GetUInt32()); ca.date = time_t(fields[1].GetUInt32());
Tokenizer guids(fields[2].GetString(), ' '); for (std::string_view guid : Trinity::Tokenize(fields[2].GetStringView(), ' ', false))
for (uint32 i = 0; i < guids.size(); ++i) if (Optional<ObjectGuid::LowType> parsedGuid = Trinity::StringTo<ObjectGuid::LowType>(guid))
ca.guids.insert(ObjectGuid(HighGuid::Player, uint32(atol(guids[i])))); ca.guids.insert(ObjectGuid(HighGuid::Player, *parsedGuid));
ca.changed = false; ca.changed = false;
+6 -6
View File
@@ -28,6 +28,7 @@
#include "ObjectMgr.h" #include "ObjectMgr.h"
#include "Player.h" #include "Player.h"
#include "SocialMgr.h" #include "SocialMgr.h"
#include "StringConvert.h"
#include "World.h" #include "World.h"
Channel::Channel(uint32 channelId, uint32 team /*= 0*/, AreaTableEntry const* zoneEntry /*= nullptr*/) : Channel::Channel(uint32 channelId, uint32 team /*= 0*/, AreaTableEntry const* zoneEntry /*= nullptr*/) :
@@ -86,14 +87,13 @@ Channel::Channel(std::string const& name, uint32 team /*= 0*/) :
if (!db_BannedList.empty()) if (!db_BannedList.empty())
{ {
Tokenizer tokens(db_BannedList, ' '); for (std::string_view guid : Trinity::Tokenize(db_BannedList, ' ', false))
for (auto const& token : tokens)
{ {
ObjectGuid banned_guid(uint64(atoull(token))); ObjectGuid banned(Trinity::StringTo<uint64>(guid).value_or(0));
if (banned_guid) if (banned)
{ {
TC_LOG_DEBUG("chat.system", "Channel(%s) loaded player %s into bannedStore", name.c_str(), banned_guid.ToString().c_str()); TC_LOG_DEBUG("chat.system", "Channel(%s) loaded player %s into bannedStore", name.c_str(), banned.ToString().c_str());
_bannedStore.insert(banned_guid); _bannedStore.insert(banned);
} }
} }
} }
+15 -6
View File
@@ -23,6 +23,7 @@
#include "OutdoorPvP.h" #include "OutdoorPvP.h"
#include "Player.h" #include "Player.h"
#include "SpellMgr.h" #include "SpellMgr.h"
#include "StringConvert.h"
#include "VMapManager2.h" #include "VMapManager2.h"
#include "World.h" #include "World.h"
@@ -103,16 +104,24 @@ void LoadDisables()
if (flags & SPELL_DISABLE_MAP) if (flags & SPELL_DISABLE_MAP)
{ {
Tokenizer tokens(params_0, ','); for (std::string_view mapStr : Trinity::Tokenize(params_0, ',', true))
for (uint8 i = 0; i < tokens.size(); ) {
data.params[0].insert(atoi(tokens[i++])); 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) if (flags & SPELL_DISABLE_AREA)
{ {
Tokenizer tokens(params_1, ','); for (std::string_view areaStr : Trinity::Tokenize(params_1, ',', true))
for (uint8 i = 0; i < tokens.size(); ) {
data.params[1].insert(atoi(tokens[i++])); 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; break;
+1 -1
View File
@@ -662,7 +662,7 @@ enum class SpellShapeshiftFormFlags : int32
DEFINE_ENUM_FLAG(SpellShapeshiftFormFlags); DEFINE_ENUM_FLAG(SpellShapeshiftFormFlags);
constexpr uint8 TaxiMaskSize = 114; static constexpr uint8 TaxiMaskSize = 114;
typedef std::array<uint8, TaxiMaskSize> TaxiMask; typedef std::array<uint8, TaxiMaskSize> TaxiMask;
enum TaxiNodeFlags enum TaxiNodeFlags
+5 -1
View File
@@ -177,7 +177,11 @@ bool Corpse::LoadCorpseFromDB(ObjectGuid::LowType guid, Field* fields)
SetObjectScale(1.0f); SetObjectScale(1.0f);
SetUInt32Value(CORPSE_FIELD_DISPLAY_ID, fields[5].GetUInt32()); 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_1, fields[7].GetUInt32());
SetUInt32Value(CORPSE_FIELD_BYTES_2, fields[8].GetUInt32()); SetUInt32Value(CORPSE_FIELD_BYTES_2, fields[8].GetUInt32());
SetUInt32Value(CORPSE_FIELD_FLAGS, fields[9].GetUInt8()); SetUInt32Value(CORPSE_FIELD_FLAGS, fields[9].GetUInt8());
+16 -3
View File
@@ -32,6 +32,7 @@
#include "ScriptMgr.h" #include "ScriptMgr.h"
#include "SpellInfo.h" #include "SpellInfo.h"
#include "SpellMgr.h" #include "SpellMgr.h"
#include "StringConvert.h"
#include "TradeData.h" #include "TradeData.h"
#include "UpdateData.h" #include "UpdateData.h"
#include "World.h" #include "World.h"
@@ -427,7 +428,10 @@ bool Item::LoadFromDB(ObjectGuid::LowType guid, ObjectGuid owner_guid, Field* fi
ItemTemplate const* proto = GetTemplate(); ItemTemplate const* proto = GetTemplate();
if (!proto) if (!proto)
{
TC_LOG_ERROR("entities.item", "Invalid entry %u for item %s. Refusing to load.", GetEntry(), GetGUID().ToString().c_str());
return false; return false;
}
// set owner (not if item is only loaded for gbank/auction/mail // set owner (not if item is only loaded for gbank/auction/mail
if (owner_guid) if (owner_guid)
@@ -447,10 +451,17 @@ bool Item::LoadFromDB(ObjectGuid::LowType guid, ObjectGuid owner_guid, Field* fi
need_save = true; 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) if (tokens.size() == MAX_ITEM_PROTO_SPELLS)
{
for (uint8 i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i) 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()); SetUInt32Value(ITEM_FIELD_FLAGS, fields[5].GetUInt32());
// Remove bind flag for items vs BIND_NONE set // Remove bind flag for items vs BIND_NONE set
@@ -460,7 +471,9 @@ bool Item::LoadFromDB(ObjectGuid::LowType guid, ObjectGuid owner_guid, Field* fi
need_save = true; 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());
m_randomEnchantment.Type = ItemRandomEnchantmentType(fields[7].GetUInt8()); m_randomEnchantment.Type = ItemRandomEnchantmentType(fields[7].GetUInt8());
m_randomEnchantment.Id = fields[8].GetUInt32(); m_randomEnchantment.Id = fields[8].GetUInt32();
if (m_randomEnchantment.Type == ItemRandomEnchantmentType::Property) if (m_randomEnchantment.Type == ItemRandomEnchantmentType::Property)
+10 -5
View File
@@ -45,6 +45,7 @@
#include "SpellAuraEffects.h" #include "SpellAuraEffects.h"
#include "SpellDefines.h" #include "SpellDefines.h"
#include "SpellMgr.h" #include "SpellMgr.h"
#include "StringConvert.h"
#include "TemporarySummon.h" #include "TemporarySummon.h"
#include "Totem.h" #include "Totem.h"
#include "Transport.h" #include "Transport.h"
@@ -783,21 +784,25 @@ uint32 Object::GetUpdateFieldData(Player const* target, uint32*& flags) const
return visibleFlag; 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()) if (data.empty())
return; return false;
Tokenizer tokens(data, ' ', count); std::vector<std::string_view> tokens = Trinity::Tokenize(data, ' ', false);
if (tokens.size() != count) if (tokens.size() != count)
return; return false;
for (uint32 index = 0; index < count; ++index) 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); _changesMask.SetBit(startOffset + index);
} }
return true;
} }
void Object::SetInt32Value(uint16 index, int32 value) void Object::SetInt32Value(uint16 index, int32 value)
+1 -1
View File
@@ -239,7 +239,7 @@ class TC_GAME_API Object
void _InitValues(); void _InitValues();
void _Create(ObjectGuid::LowType guidlow, uint32 entry, HighGuid guidhigh); void _Create(ObjectGuid::LowType guidlow, uint32 entry, HighGuid guidhigh);
std::string _ConcatFields(uint16 startIndex, uint16 size) const; 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; uint32 GetUpdateFieldData(Player const* target, uint32*& flags) const;
+41 -60
View File
@@ -101,6 +101,7 @@
#include "SpellHistory.h" #include "SpellHistory.h"
#include "SpellMgr.h" #include "SpellMgr.h"
#include "SpellPackets.h" #include "SpellPackets.h"
#include "StringConvert.h"
#include "TerrainMgr.h" #include "TerrainMgr.h"
#include "TicketMgr.h" #include "TicketMgr.h"
#include "TradeData.h" #include "TradeData.h"
@@ -16408,23 +16409,6 @@ void Player::SendBindPointUpdate() const
SendDirectMessage(packet.Write()); 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 bool Player::IsLoading() const
{ {
return GetSession()->PlayerLoading(); return GetSession()->PlayerLoading();
@@ -16450,7 +16434,7 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder const& hol
{ {
std::string name = "<unknown>"; std::string name = "<unknown>";
sCharacterCache->GetCharacterNameByGuid(guid, name); 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; return false;
} }
@@ -16462,13 +16446,13 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder const& hol
// player should be able to load/delete character only with correct account! // player should be able to load/delete character only with correct account!
if (dbAccountId != GetSession()->GetAccountId()) 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; return false;
} }
if (holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_BANNED)) 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; return false;
} }
@@ -16493,7 +16477,7 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder const& hol
uint8 gender = fields[5].GetUInt8(); uint8 gender = fields[5].GetUInt8();
if (!IsValidGender(gender)) 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; return false;
} }
@@ -16505,15 +16489,18 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder const& hol
PlayerInfo const* info = sObjectMgr->GetPlayerInfo(getRace(), getClass()); PlayerInfo const* info = sObjectMgr->GetPlayerInfo(getRace(), getClass());
if (!info) 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; return false;
} }
SetUInt32Value(UNIT_FIELD_LEVEL, fields[6].GetUInt8()); SetUInt32Value(UNIT_FIELD_LEVEL, fields[6].GetUInt8());
SetUInt32Value(PLAYER_XP, fields[7].GetUInt32()); SetUInt32Value(PLAYER_XP, fields[7].GetUInt32());
_LoadIntoDataField(fields[60].GetString(), PLAYER_EXPLORED_ZONES_1, PLAYER_EXPLORED_ZONES_SIZE); if (!_LoadIntoDataField(fields[60].GetString(), PLAYER_EXPLORED_ZONES_1, PLAYER_EXPLORED_ZONES_SIZE))
_LoadIntoDataField(fields[62].GetString(), PLAYER__FIELD_KNOWN_TITLES, KNOWN_TITLES_SIZE*2); TC_LOG_WARN("entities.player.loading", "Player::LoadFromDB: Player (%s) has invalid exploredzones data (%s). Forcing partial load.", guid.ToString().c_str(), fields[60].GetCString());
if (!_LoadIntoDataField(fields[62].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[62].GetCString());
SetObjectScale(1.0f); SetObjectScale(1.0f);
SetFloatValue(UNIT_FIELD_HOVERHEIGHT, 1.0f); SetFloatValue(UNIT_FIELD_HOVERHEIGHT, 1.0f);
@@ -16546,7 +16533,7 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder const& hol
GetByteValue(PLAYER_BYTES_2, PLAYER_BYTES_2_OFFSET_FACIAL_STYLE), // facial hair GetByteValue(PLAYER_BYTES_2, PLAYER_BYTES_2_OFFSET_FACIAL_STYLE), // facial hair
GetByteValue(PLAYER_BYTES, PLAYER_BYTES_OFFSET_SKIN_ID))) // skin color GetByteValue(PLAYER_BYTES, PLAYER_BYTES_OFFSET_SKIN_ID))) // skin color
{ {
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; return false;
} }
@@ -16640,7 +16627,7 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder const& hol
bool player_at_bg = false; bool player_at_bg = false;
if (!mapEntry || !IsPositionValid()) 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()); guid.ToString().c_str(), mapId, GetPositionX(), GetPositionY(), GetPositionZ(), GetOrientation());
RelocateToHomebind(); RelocateToHomebind();
} }
@@ -16686,7 +16673,7 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder const& hol
//if (mapId == MAPID_INVALID) -- code kept for reference //if (mapId == MAPID_INVALID) -- code kept for reference
if (int16(mapId) == int16(-1)) // Battleground Entry Point not found (???) 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()); guid.ToString().c_str());
RelocateToHomebind(); RelocateToHomebind();
} }
@@ -16732,7 +16719,7 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder const& hol
std::fabs(m_movementInfo.transport.pos.GetPositionY()) > 250.0f || std::fabs(m_movementInfo.transport.pos.GetPositionY()) > 250.0f ||
std::fabs(m_movementInfo.transport.pos.GetPositionZ()) > 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); guid.ToString().c_str(), x, y, z, o);
m_movementInfo.transport.Reset(); m_movementInfo.transport.Reset();
@@ -16749,7 +16736,7 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder const& hol
} }
else 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); guid.ToString().c_str(), transLowGUID);
RelocateToHomebind(); RelocateToHomebind();
@@ -16775,12 +16762,12 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder const& hol
if (!nodeEntry) // don't know taxi start node, teleport to homebind 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, teleport to homebind.", GetGUID().ToString().c_str());
RelocateToHomebind(); RelocateToHomebind();
} }
else // has start node, teleport to it 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, teleport to original node.", GetGUID().ToString().c_str());
mapId = nodeEntry->ContinentID; mapId = nodeEntry->ContinentID;
Relocate(nodeEntry->Pos.X, nodeEntry->Pos.Y, nodeEntry->Pos.Z, 0.0f); Relocate(nodeEntry->Pos.X, nodeEntry->Pos.Y, nodeEntry->Pos.Z, 0.0f);
} }
@@ -16809,7 +16796,7 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder const& hol
{ {
if (GetSession()->GetExpansion() < mapEntry->Expansion()) if (GetSession()->GetExpansion() < mapEntry->Expansion())
{ {
TC_LOG_DEBUG("entities.player.loading", "Player::LoadFromDB: Player '%s' (%s) using client without required expansion tried login at non accessible map %u", TC_LOG_DEBUG("entities.player.loading.loading", "Player::LoadFromDB: Player '%s' (%s) using client without required expansion tried login at non accessible map %u",
GetName().c_str(), GetGUID().ToString().c_str(), mapId); GetName().c_str(), GetGUID().ToString().c_str(), mapId);
RelocateToHomebind(); RelocateToHomebind();
} }
@@ -16880,7 +16867,7 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder const& hol
} }
else 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()); m_name.c_str(), guid.ToString().c_str(), mapId, GetPositionX(), GetPositionY(), GetPositionZ(), GetOrientation());
RelocateToHomebind(); RelocateToHomebind();
map = nullptr; map = nullptr;
@@ -16894,7 +16881,7 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder const& hol
map = sMapMgr->CreateMap(mapId, this); map = sMapMgr->CreateMap(mapId, this);
if (!map) 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()); m_name.c_str(), guid.ToString().c_str(), mapId, GetPositionX(), GetPositionY(), GetPositionZ(), GetOrientation());
return false; return false;
} }
@@ -16944,29 +16931,30 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder const& hol
if (GetSpecsCount() > MAX_TALENT_SPECS || GetActiveSpec() > MAX_TALENT_SPEC || GetSpecsCount() < MIN_TALENT_SPECS) if (GetSpecsCount() > MAX_TALENT_SPECS || GetActiveSpec() > MAX_TALENT_SPEC || GetSpecsCount() < MIN_TALENT_SPECS)
{ {
SetActiveSpec(0); SetActiveSpec(0);
TC_LOG_ERROR("entities.player", "Player %s(GUID: %u) has SpecCount = %u and ActiveSpec = %u.", GetName().c_str(), GetGUID().GetCounter(), GetSpecsCount(), GetActiveSpec()); TC_LOG_ERROR("entities.player.loading", "Player %s(GUID: %u) has SpecCount = %u and ActiveSpec = %u.", GetName().c_str(), GetGUID().GetCounter(), GetSpecsCount(), GetActiveSpec());
} }
// Only load selected specializations, learning mastery spells requires this // Only load selected specializations, learning mastery spells requires this
Tokenizer talentTrees(fields[31].GetString(), ' ', MAX_TALENT_SPECS); std::vector<std::string_view> talentTrees = Trinity::Tokenize(fields[31].GetStringView(), ' ', false);
for (uint8 i = 0; i < MAX_TALENT_SPECS; ++i) for (uint8 i = 0; i < MAX_TALENT_SPECS; ++i)
{ {
if (i >= talentTrees.size()) if (i >= talentTrees.size())
break; break;
uint32 talentTree = atol(talentTrees[i]); Optional<uint32> talentTree = Trinity::StringTo<uint32>(talentTrees[i]);
if (sTalentTabStore.LookupEntry(talentTree)) if (talentTree && sTalentTabStore.LookupEntry(*talentTree))
SetPrimaryTalentTree(i, talentTree); SetPrimaryTalentTree(i, *talentTree);
} }
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[37].GetUInt16(); uint32 extraflags = fields[37].GetUInt16();
m_stableSlots = fields[38].GetUInt8(); m_stableSlots = fields[38].GetUInt8();
if (m_stableSlots > MAX_PET_STABLES) if (m_stableSlots > MAX_PET_STABLES)
{ {
TC_LOG_ERROR("entities.player", "Player::LoadFromDB: Player (%s) can't have more stable slots than %u, but has %u in DB", TC_LOG_ERROR("entities.player.loading", "Player::LoadFromDB: Player (%s) can't have more stable slots than %u, but has %u in DB",
GetGUID().ToString().c_str(), MAX_PET_STABLES, uint32(m_stableSlots)); GetGUID().ToString().c_str(), MAX_PET_STABLES, uint32(m_stableSlots));
m_stableSlots = MAX_PET_STABLES; m_stableSlots = MAX_PET_STABLES;
} }
@@ -17144,9 +17132,10 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder const& hol
if (i >= talentTrees.size()) if (i >= talentTrees.size())
break; break;
uint32 talentTree = atol(talentTrees[i]); Optional<uint32> talentTree = Trinity::StringTo<uint32>(talentTrees[i]);
if (talentTree != 0 && !sTalentTabStore.LookupEntry(talentTree) && i == GetActiveSpec()) if (talentTree)
SetAtLoginFlag(AT_LOGIN_RESET_TALENTS); // invalid tree, reset talents if (*talentTree > 0 && !sTalentTabStore.LookupEntry(*talentTree) && i == GetActiveSpec())
SetAtLoginFlag(AT_LOGIN_RESET_TALENTS); // invalid tree, reset talents
} }
// We neeed to update the armor specialization after the talenttree was set // We neeed to update the armor specialization after the talenttree was set
@@ -17717,11 +17706,14 @@ Item* Player::_LoadItem(CharacterDatabaseTransaction& trans, uint32 zoneId, uint
stmt->setUInt32(0, item->GetGUID().GetCounter()); stmt->setUInt32(0, item->GetGUID().GetCounter());
if (PreparedQueryResult result = CharacterDatabase.Query(stmt)) if (PreparedQueryResult result = CharacterDatabase.Query(stmt))
{ {
std::string strGUID = (*result)[0].GetString();
Tokenizer GUIDlist(strGUID, ' ');
GuidSet looters; GuidSet looters;
for (Tokenizer::const_iterator itr = GUIDlist.begin(); itr != GUIDlist.end(); ++itr) for (std::string_view guidStr : Trinity::Tokenize((*result)[0].GetStringView(), ' ', false))
looters.insert(ObjectGuid::Create<HighGuid::Player>(uint32(atoul(*itr)))); {
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()) if (looters.size() > 1 && item->GetTemplate()->GetMaxStackSize() == 1 && item->IsSoulBound())
{ {
@@ -17733,7 +17725,7 @@ Item* Player::_LoadItem(CharacterDatabaseTransaction& trans, uint32 zoneId, uint
} }
else else
{ {
TC_LOG_DEBUG("entities.player.loading", "Player::_LoadInventory: player (GUID: %u, name: '%s') has item (GUID: %u, entry: %u) with ITEM_FIELD_FLAG_BOP_TRADEABLE flag, but without data in item_soulbound_trade_data. Removing flag.", TC_LOG_WARN("entities.player.loading", "Player::_LoadInventory: player (GUID: %u, name: '%s') has item (GUID: %u, entry: %u) with ITEM_FIELD_FLAG_BOP_TRADEABLE flag, but without data in item_soulbound_trade_data. Removing flag.",
GetGUID().GetCounter(), GetName().c_str(), item->GetGUID().GetCounter(), item->GetEntry()); GetGUID().GetCounter(), GetName().c_str(), item->GetGUID().GetCounter(), item->GetEntry());
item->RemoveFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_BOP_TRADEABLE); item->RemoveFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_BOP_TRADEABLE);
} }
@@ -20068,17 +20060,6 @@ void Player::SavePositionInDB(WorldLocation const& loc, uint16 zoneId, ObjectGui
CharacterDatabase.ExecuteOrAppend(trans, stmt); 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::Customize(CharacterCustomizeInfo const* customizeInfo, CharacterDatabaseTransaction& trans) void Player::Customize(CharacterCustomizeInfo const* customizeInfo, CharacterDatabaseTransaction& trans)
{ {
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GENDER_AND_APPEARANCE); CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GENDER_AND_APPEARANCE);
-3
View File
@@ -1444,8 +1444,6 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
bool IsLoading() const override; bool IsLoading() const override;
void Initialize(ObjectGuid::LowType guid); 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 uint32 GetZoneIdFromDB(ObjectGuid guid);
static bool LoadPositionFromDB(uint32& mapid, float& x, float& y, float& z, float& o, bool& in_flight, ObjectGuid guid); static bool LoadPositionFromDB(uint32& mapid, float& x, float& y, float& z, float& o, bool& in_flight, ObjectGuid guid);
@@ -1463,7 +1461,6 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
void SaveInventoryAndGoldToDB(CharacterDatabaseTransaction& trans); // fast save function for item/money cheating preventing void SaveInventoryAndGoldToDB(CharacterDatabaseTransaction& trans); // fast save function for item/money cheating preventing
void SaveGoldToDB(CharacterDatabaseTransaction& trans) const; void SaveGoldToDB(CharacterDatabaseTransaction& trans) const;
static void SetUInt32ValueInArray(Tokenizer& data, uint16 index, uint32 value);
static void Customize(CharacterCustomizeInfo const* customizeInfo, CharacterDatabaseTransaction& trans); static void Customize(CharacterCustomizeInfo const* customizeInfo, CharacterDatabaseTransaction& trans);
static void SavePositionInDB(WorldLocation const& loc, uint16 zoneId, ObjectGuid guid, CharacterDatabaseTransaction& trans); static void SavePositionInDB(WorldLocation const& loc, uint16 zoneId, ObjectGuid guid, CharacterDatabaseTransaction& trans);
+25 -11
View File
@@ -19,6 +19,7 @@
#include "DBCStores.h" #include "DBCStores.h"
#include "ObjectMgr.h" #include "ObjectMgr.h"
#include "Player.h" #include "Player.h"
#include "StringConvert.h"
#include <sstream> #include <sstream>
void PlayerTaxi::InitTaxiNodesForLevel(uint32 race, uint32 chrClass, uint8 level) void PlayerTaxi::InitTaxiNodesForLevel(uint32 race, uint32 chrClass, uint8 level)
@@ -68,16 +69,26 @@ void PlayerTaxi::InitTaxiNodesForLevel(uint32 race, uint32 chrClass, uint8 level
} }
} }
void PlayerTaxi::LoadTaxiMask(std::string const &data) bool PlayerTaxi::LoadTaxiMask(std::string const& data)
{ {
Tokenizer tokens(data, ' '); bool warn = false;
std::vector<std::string_view> tokens = Trinity::Tokenize(data, ' ', false);
uint8 index = 0; for (uint8 index = 0; (index < TaxiMaskSize) && (index < tokens.size()); ++index)
for (Tokenizer::const_iterator iter = tokens.begin(); index < TaxiMaskSize && iter != tokens.end(); ++iter, ++index)
{ {
// load and set bits only for existing taxi nodes if (Optional<uint32> mask = Trinity::StringTo<uint32>(tokens[index]))
m_taximask[index] = sTaxiNodesMask[index] & atoul(*iter); {
// 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) void PlayerTaxi::AppendTaximaskTo(ByteBuffer& data, bool all)
@@ -99,12 +110,15 @@ bool PlayerTaxi::LoadTaxiDestinationsFromString(std::string const& values, uint3
{ {
ClearTaxiDestinations(); ClearTaxiDestinations();
Tokenizer Tokenizer(values, ' '); std::vector<std::string_view> tokens = Trinity::Tokenize(values, ' ', false);
auto itr = tokens.begin();
for (Tokenizer::const_iterator iter = Tokenizer.begin(); iter != Tokenizer.end(); ++iter) while ((++itr) != tokens.end())
{ {
uint32 node = atoul(*iter); if (Optional<uint32> node = Trinity::StringTo<uint32>(*itr))
AddTaxiDestination(node); AddTaxiDestination(*node);
else
return false;
} }
if (m_TaxiDestinations.empty()) if (m_TaxiDestinations.empty())
+2 -2
View File
@@ -33,7 +33,7 @@ class TC_GAME_API PlayerTaxi
~PlayerTaxi() { } ~PlayerTaxi() { }
// Nodes // Nodes
void InitTaxiNodesForLevel(uint32 race, uint32 chrClass, uint8 level); 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 bool IsTaximaskNodeKnown(uint32 nodeidx) const
{ {
@@ -56,7 +56,7 @@ class TC_GAME_API PlayerTaxi
void AppendTaximaskTo(ByteBuffer& data, bool all); void AppendTaximaskTo(ByteBuffer& data, bool all);
// Destinations // Destinations
bool LoadTaxiDestinationsFromString(std::string const& values, uint32 team); [[nodiscard]] bool LoadTaxiDestinationsFromString(std::string const& values, uint32 team);
std::string SaveTaxiDestinationsToString(); std::string SaveTaxiDestinationsToString();
void ClearTaxiDestinations() { m_TaxiDestinations.clear(); } void ClearTaxiDestinations() { m_TaxiDestinations.clear(); }
+13 -12
View File
@@ -19,6 +19,7 @@
#include "Creature.h" #include "Creature.h"
#include "SpellInfo.h" #include "SpellInfo.h"
#include "SpellMgr.h" #include "SpellMgr.h"
#include "StringConvert.h"
CharmInfo::CharmInfo(Unit* unit) CharmInfo::CharmInfo(Unit* unit)
: _unit(unit), _CommandState(COMMAND_FOLLOW), _petnumber(0), _oldReactState(REACT_PASSIVE), : _unit(unit), _CommandState(COMMAND_FOLLOW), _petnumber(0), _oldReactState(REACT_PASSIVE),
@@ -236,29 +237,29 @@ void CharmInfo::LoadPetActionBar(const std::string& data)
{ {
InitPetActionBar(); 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) if (tokens.size() != (ACTION_BAR_INDEX_END-ACTION_BAR_INDEX_START) * 2)
return; // non critical, will reset to default return; // non critical, will reset to default
uint8 index = ACTION_BAR_INDEX_START; auto iter = tokens.begin();
Tokenizer::const_iterator iter = tokens.begin(); for (uint8 index = ACTION_BAR_INDEX_START; index < ACTION_BAR_INDEX_END; ++index)
for (; index < ACTION_BAR_INDEX_END; ++iter, ++index)
{ {
// use unsigned cast to avoid sign negative format use at long-> ActiveStates (int) conversion Optional<uint8> type = Trinity::StringTo<uint8>(*(iter++));
ActiveStates type = ActiveStates(atol(*iter)); Optional<uint32> action = Trinity::StringTo<uint32>(*(iter++));
++iter;
uint32 action = atoul(*iter);
PetActionBar[index].SetActionAndType(action, type); if (!type || !action)
continue;
PetActionBar[index].SetActionAndType(*action, static_cast<ActiveStates>(*type));
// check correctness // check correctness
if (PetActionBar[index].IsActionBarForSpell()) if (PetActionBar[index].IsActionBarForSpell())
{ {
SpellInfo const* spelInfo = sSpellMgr->GetSpellInfo(PetActionBar[index].GetAction()); SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(PetActionBar[index].GetAction());
if (!spelInfo) if (!spellInfo)
SetActionBar(index, 0, ACT_PASSIVE); SetActionBar(index, 0, ACT_PASSIVE);
else if (!spelInfo->IsAutocastable()) else if (!spellInfo->IsAutocastable())
SetActionBar(index, PetActionBar[index].GetAction(), ACT_PASSIVE); SetActionBar(index, PetActionBar[index].GetAction(), ACT_PASSIVE);
} }
} }
+41 -24
View File
@@ -55,6 +55,7 @@
#include "SpellAuras.h" #include "SpellAuras.h"
#include "SpellMgr.h" #include "SpellMgr.h"
#include "SpellScript.h" #include "SpellScript.h"
#include "StringConvert.h"
#include "TemporarySummon.h" #include "TemporarySummon.h"
#include "TerrainMgr.h" #include "TerrainMgr.h"
#include "ThreadPool.h" #include "ThreadPool.h"
@@ -640,28 +641,36 @@ void ObjectMgr::LoadCreatureTemplateAddons()
creatureAddon.meleeAnimKit = fields[12].GetUInt16(); creatureAddon.meleeAnimKit = fields[12].GetUInt16();
creatureAddon.visibilityDistanceType = VisibilityDistanceType(fields[13].GetUInt8()); creatureAddon.visibilityDistanceType = VisibilityDistanceType(fields[13].GetUInt8());
Tokenizer tokens(fields[14].GetString(), ' '); for (std::string_view aura : Trinity::Tokenize(fields[14].GetStringView(), ' ', false))
uint8 i = 0;
creatureAddon.auras.resize(tokens.size());
for (Tokenizer::const_iterator itr = tokens.begin(); itr != tokens.end(); ++itr)
{ {
SpellInfo const* AdditionalSpellInfo = sSpellMgr->GetSpellInfo(atoul(*itr)); SpellInfo const* spellInfo = nullptr;
if (!AdditionalSpellInfo) 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; continue;
} }
if (AdditionalSpellInfo->HasAura(SPELL_AURA_CONTROL_VEHICLE)) if (spellInfo->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)); 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; continue;
} }
creatureAddon.auras[i++] = atoul(*itr); /*
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, spellInfo->Id);
continue;
}
*/
creatureAddon.auras.push_back(spellInfo->Id);
} }
if (creatureAddon.mount) if (creatureAddon.mount)
@@ -1198,28 +1207,36 @@ void ObjectMgr::LoadCreatureAddons()
creatureAddon.meleeAnimKit = fields[12].GetUInt16(); creatureAddon.meleeAnimKit = fields[12].GetUInt16();
creatureAddon.visibilityDistanceType = VisibilityDistanceType(fields[13].GetUInt8()); creatureAddon.visibilityDistanceType = VisibilityDistanceType(fields[13].GetUInt8());
Tokenizer tokens(fields[14].GetString(), ' '); for (std::string_view aura : Trinity::Tokenize(fields[14].GetStringView(), ' ', false))
uint8 i = 0;
creatureAddon.auras.resize(tokens.size());
for (Tokenizer::const_iterator itr = tokens.begin(); itr != tokens.end(); ++itr)
{ {
SpellInfo const* AdditionalSpellInfo = sSpellMgr->GetSpellInfo(atoul(*itr)); SpellInfo const* spellInfo = nullptr;
if (!AdditionalSpellInfo) 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; continue;
} }
if (AdditionalSpellInfo->HasAura(SPELL_AURA_CONTROL_VEHICLE)) if (spellInfo->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)); 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; continue;
} }
creatureAddon.auras[i++] = atoul(*itr); /*
if (spellInfo->GetDuration() > 0)
{
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(spellInfo->Id);
} }
if (creatureAddon.mount) if (creatureAddon.mount)
+18 -11
View File
@@ -53,6 +53,7 @@
#include "ScriptMgr.h" #include "ScriptMgr.h"
#include "SharedDefines.h" #include "SharedDefines.h"
#include "SocialMgr.h" #include "SocialMgr.h"
#include "StringConvert.h"
#include "SystemPackets.h" #include "SystemPackets.h"
#include "World.h" #include "World.h"
#include "WorldPacket.h" #include "WorldPacket.h"
@@ -2167,18 +2168,24 @@ void WorldSession::HandleCharFactionOrRaceChangeCallback(std::shared_ptr<Charact
// Title conversion // Title conversion
if (!knownTitlesStr.empty()) if (!knownTitlesStr.empty())
{ {
uint32 const ktcount = KNOWN_TITLES_SIZE * 2; std::vector<std::string_view> tokens = Trinity::Tokenize(knownTitlesStr, ' ', false);
uint32 knownTitles[ktcount]; std::array<uint32, KNOWN_TITLES_SIZE * 2> knownTitles;
Tokenizer tokens(knownTitlesStr, ' ', ktcount);
if (tokens.size() != ktcount) for (uint32 index = 0; index < knownTitles.size(); ++index)
{ {
SendCharFactionChange(CHAR_CREATE_ERROR, factionChangeInfo.get()); Optional<uint32> thisMask;
return; if (index < tokens.size())
} thisMask = Trinity::StringTo<uint32>(tokens[index]);
for (uint32 index = 0; index < ktcount; ++index) if (thisMask)
knownTitles[index] = atoul(tokens[index]); 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) for (std::map<uint32, uint32>::const_iterator it = sObjectMgr->FactionChangeTitles.begin(); it != sObjectMgr->FactionChangeTitles.end(); ++it)
{ {
@@ -2216,8 +2223,8 @@ void WorldSession::HandleCharFactionOrRaceChangeCallback(std::shared_ptr<Charact
} }
std::ostringstream ss; std::ostringstream ss;
for (uint32 index = 0; index < ktcount; ++index) for (uint32 mask : knownTitles)
ss << knownTitles[index] << ' '; ss << mask << ' ';
stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_TITLES_FACTION_CHANGE); stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_TITLES_FACTION_CHANGE);
stmt->setString(0, ss.str()); stmt->setString(0, ss.str());
@@ -18,8 +18,10 @@
#include "CharacterPackets.h" #include "CharacterPackets.h"
#include "DBCStores.h" #include "DBCStores.h"
#include "Field.h" #include "Field.h"
#include "Log.h"
#include "ObjectMgr.h" #include "ObjectMgr.h"
#include "Player.h" #include "Player.h"
#include "StringConvert.h"
#include "World.h" #include "World.h"
WorldPackets::Character::EnumCharactersResult::CharacterInfo::CharacterInfo(Field* fields) WorldPackets::Character::EnumCharactersResult::CharacterInfo::CharacterInfo(Field* fields)
@@ -95,23 +97,45 @@ WorldPackets::Character::EnumCharactersResult::CharacterInfo::CharacterInfo(Fiel
} }
} }
Tokenizer equipment(fields[22].GetString(), ' '); std::vector<std::string_view> equipment = Trinity::Tokenize(fields[22].GetStringView(), ' ', false);
ListPosition = fields[24].GetUInt8(); ListPosition = fields[24].GetUInt8();
for (uint8 slot = 0; slot < INVENTORY_SLOT_BAG_END; ++slot) for (uint8 slot = 0; slot < INVENTORY_SLOT_BAG_END; ++slot)
{ {
uint32 visualBase = slot * 2; uint32 const visualBase = slot * 2;
uint32 itemId = Player::GetUInt32ValueFromArray(equipment, visualBase); Optional<uint32> itemId;
ItemTemplate const* proto = sObjectMgr->GetItemTemplate(itemId); if (visualBase < equipment.size())
itemId = Trinity::StringTo<uint32>(equipment[visualBase]);
ItemTemplate const* proto = nullptr;
if (itemId)
proto = sObjectMgr->GetItemTemplate(*itemId);
if (!proto) if (!proto)
{
if (!itemId || *itemId)
{
TC_LOG_WARN("entities.player.loading", "Player %u has invalid equipment '%s' in `equipmentcache` at index %u. Skipped.",
Guid.GetCounter(), (visualBase < equipment.size()) ? std::string(equipment[visualBase]).c_str() : "<none>", visualBase);
}
continue; continue;
}
SpellItemEnchantmentEntry const* enchant = nullptr; SpellItemEnchantmentEntry const* enchant = nullptr;
uint32 enchants = Player::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.GetCounter(), ((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) for (uint8 enchantSlot = PERM_ENCHANTMENT_SLOT; enchantSlot <= TEMP_ENCHANTMENT_SLOT; ++enchantSlot)
{ {
// values stored in 2 uint16 // values stored in 2 uint16
uint32 enchantId = 0x0000FFFF & (enchants >> enchantSlot * 16); uint32 enchantId = 0x0000FFFF & ((*enchants) >> enchantSlot * 16);
if (!enchantId) if (!enchantId)
continue; continue;
@@ -23,6 +23,7 @@
#include "Map.h" #include "Map.h"
#include "ObjectMgr.h" #include "ObjectMgr.h"
#include "ScriptMgr.h" #include "ScriptMgr.h"
#include "StringConvert.h"
#include "World.h" #include "World.h"
#include "WorldStatePackets.h" #include "WorldStatePackets.h"
@@ -52,78 +53,76 @@ void WorldStateMgr::LoadFromDB()
worldState.Id = id; worldState.Id = id;
worldState.DefaultValue = fields[1].GetInt32(); worldState.DefaultValue = fields[1].GetInt32();
Tokenizer tokens(fields[2].GetString(), ' '); std::string_view mapIds = fields[2].GetStringView();
uint8 i = 0; for (std::string_view mapIdToken : Trinity::Tokenize(mapIds, ',', false))
for (Tokenizer::const_iterator itr = tokens.begin(); itr != tokens.end(); ++itr, ++i)
{ {
int32 mapId = atoi(*itr); Optional<int32> mapId = Trinity::StringTo<int32>(mapIdToken);
if (!mapId) if (!mapId)
{ {
TC_LOG_ERROR("sql.sql", "Table `world_state` contains a world state %d with non-integer MapID (%s), map ignored", TC_LOG_ERROR("sql.sql", "Table `world_state` contains a world state %d with non-integer MapID (%s), map ignored",
id, *itr); id, mapIdToken.data());
continue; continue;
} }
if (!sMapStore.LookupEntry(mapId) && mapId != WORLDSTATE_ANY_MAP) if (!sMapStore.LookupEntry(*mapId) && mapId != WORLDSTATE_ANY_MAP)
{ {
TC_LOG_ERROR("sql.sql", "Table `world_state` contains a world state %d with invalid MapID (%u), map ignored", TC_LOG_ERROR("sql.sql", "Table `world_state` contains a world state %d with invalid MapID (%u), map ignored",
id, mapId); id, *mapId);
continue; continue;
} }
worldState.MapIds.insert(mapId); worldState.MapIds.insert(*mapId);
} }
if (i > 0 && worldState.MapIds.empty()) if (!mapIds.empty() && worldState.MapIds.empty())
{ {
TC_LOG_ERROR("sql.sql", "Table `world_state` contains a world state %d with nonempty MapIDs but no valid map id was found, ignored", TC_LOG_ERROR("sql.sql", "Table `world_state` contains a world state %i with nonempty MapIDs (%s) but no valid map id was found, ignored",
id); id, mapIds.data());
continue; continue;
} }
Tokenizer tokens2(fields[3].GetString(), ' '); std::string_view areaIds = fields[3].GetStringView();
i = 0;
if (!worldState.MapIds.empty()) if (!worldState.MapIds.empty())
{ {
for (Tokenizer::const_iterator itr = tokens2.begin(); itr != tokens2.end(); ++itr, ++i) for (std::string_view areaIdToken : Trinity::Tokenize(areaIds, ',', false))
{ {
uint32 areaId = atoul(*itr); Optional<uint32> areaId = Trinity::StringTo<uint32>(areaIdToken);
if (!areaId) if (!areaId)
{ {
TC_LOG_ERROR("sql.sql", "Table `world_state` contains a world state %d with non-integer AreaID, area ignored", TC_LOG_ERROR("sql.sql", "Table `world_state` contains a world state %i with non-integer AreaID (%s), area ignored",
id); id, areaIdToken.data());
continue; continue;
} }
AreaTableEntry const* areaTableEntry = sAreaTableStore.LookupEntry(areaId); AreaTableEntry const* areaTableEntry = sAreaTableStore.LookupEntry(*areaId);
if (!areaTableEntry) if (!areaTableEntry)
{ {
TC_LOG_ERROR("sql.sql", "Table `world_state` contains a world state %d with invalid AreaID (%u), area ignored", TC_LOG_ERROR("sql.sql", "Table `world_state` contains a world state %d with invalid AreaID (%u), area ignored",
id, areaId); id, *areaId);
continue; continue;
} }
if (worldState.MapIds.find(areaTableEntry->ContinentID) == worldState.MapIds.end()) if (worldState.MapIds.find(areaTableEntry->ContinentID) == worldState.MapIds.end())
{ {
TC_LOG_ERROR("sql.sql", "Table `world_state` contains a world state %d with AreaID (%u) not on any of required maps, area ignored", TC_LOG_ERROR("sql.sql", "Table `world_state` contains a world state %d with AreaID (%u) not on any of required maps, area ignored",
id, areaId); id, *areaId);
continue; continue;
} }
worldState.AreaIds.insert(areaId); worldState.AreaIds.insert(*areaId);
} }
if (i > 0 && worldState.AreaIds.empty()) if (!areaIds.empty() && worldState.AreaIds.empty())
{ {
TC_LOG_ERROR("sql.sql", "Table `world_state` contains a world state %d with nonempty AreaIDs but no valid area id was found, ignored", TC_LOG_ERROR("sql.sql", "Table `world_state` contains a world state %i with nonempty AreaIDs (%s) but no valid area id was found, ignored",
id); id, areaIds.data());
continue; continue;
} }
} }
else if (tokens2.size() > 0) else if (!areaIds.empty())
{ {
TC_LOG_ERROR("sql.sql", "Table `world_state` contains a world state %u with nonempty AreaIDs but is a realm wide world state, area requirement ignored", TC_LOG_ERROR("sql.sql", "Table `world_state` contains a world state %i with nonempty AreaIDs (%s) but is a realm wide world state, area requirement ignored",
id); id, areaIds.data());
} }
worldState.ScriptId = sObjectMgr->GetScriptId(fields[4].GetString()); worldState.ScriptId = sObjectMgr->GetScriptId(fields[4].GetString());
+9 -3
View File
@@ -33,6 +33,7 @@ EndScriptData */
#include "Player.h" #include "Player.h"
#include "RBAC.h" #include "RBAC.h"
#include "ReputationMgr.h" #include "ReputationMgr.h"
#include "StringConvert.h"
#include "WorldSession.h" #include "WorldSession.h"
class modify_commandscript : public CommandScript class modify_commandscript : public CommandScript
@@ -558,11 +559,16 @@ public:
if (handler->HasLowerSecurity(target, ObjectGuid::Empty)) if (handler->HasLowerSecurity(target, ObjectGuid::Empty))
return false; return false;
int64 moneyToAdd = 0; Optional<int64> moneyToAddO = 0;
if (strchr(args, 'g') || strchr(args, 's') || strchr(args, 'c')) if (strchr(args, 'g') || strchr(args, 's') || strchr(args, 'c'))
moneyToAdd = MoneyStringToMoney(std::string(args)); moneyToAddO = MoneyStringToMoney(std::string(args));
else else
moneyToAdd = atol(args); moneyToAddO = Trinity::StringTo<int64>(args);
if (!moneyToAddO)
return false;
int64 moneyToAdd = *moneyToAddO;
uint64 targetMoney = target->GetMoney(); uint64 targetMoney = target->GetMoney();
+5 -6
View File
@@ -42,6 +42,7 @@ EndScriptData */
#include "SkillExtraItems.h" #include "SkillExtraItems.h"
#include "SmartAI.h" #include "SmartAI.h"
#include "SpellMgr.h" #include "SpellMgr.h"
#include "StringConvert.h"
#include "TicketMgr.h" #include "TicketMgr.h"
#include "WardenCheckMgr.h" #include "WardenCheckMgr.h"
#include "WaypointManager.h" #include "WaypointManager.h"
@@ -196,7 +197,7 @@ public:
HandleReloadGameTeleCommand(handler, ""); HandleReloadGameTeleCommand(handler, "");
HandleReloadCreatureMovementOverrideCommand(handler, ""); HandleReloadCreatureMovementOverrideCommand(handler, "");
HandleReloadCreatureSummonGroupsCommand(handler, ""); HandleReloadCreatureSummonGroupsCommand(handler);
HandleReloadVehicleAccessoryCommand(handler, ""); HandleReloadVehicleAccessoryCommand(handler, "");
HandleReloadVehicleTemplateAccessoryCommand(handler, ""); HandleReloadVehicleTemplateAccessoryCommand(handler, "");
@@ -408,7 +409,7 @@ public:
return true; return true;
} }
static bool HandleReloadCreatureSummonGroupsCommand(ChatHandler* handler, char const* /*args*/) static bool HandleReloadCreatureSummonGroupsCommand(ChatHandler* handler)
{ {
TC_LOG_INFO("misc", "Reloading creature summon groups..."); TC_LOG_INFO("misc", "Reloading creature summon groups...");
sObjectMgr->LoadTempSummons(); sObjectMgr->LoadTempSummons();
@@ -421,11 +422,9 @@ public:
if (!*args) if (!*args)
return false; return false;
Tokenizer entries(std::string(args), ' '); for (std::string_view entryStr : Trinity::Tokenize(args, ' ', false))
for (Tokenizer::const_iterator itr = entries.begin(); itr != entries.end(); ++itr)
{ {
uint32 entry = uint32(atoi(*itr)); uint32 entry = Trinity::StringTo<uint32>(entryStr).value_or(0);
WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_CREATURE_TEMPLATE); WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_CREATURE_TEMPLATE);
stmt->setUInt32(0, entry); stmt->setUInt32(0, entry);