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