Core/Common: Tokenizer -> Trinity::Tokenize
This commit is contained in:
1 parent
95329dc15c
commit
f95a8bfdca
32 files changed
+414
-354
No files matched your search
@@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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.");
|
||||||
|
|||||||
@@ -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
@@ -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) :
|
||||||
|
|||||||
@@ -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() { }
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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());
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|
||||||
|
|||||||
@@ -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())
|
||||||
|
|||||||
@@ -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(); }
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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());
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
Reference in new issue
Block a user